diff --git a/environments.js b/environments.js index 51ee39e..d88426e 100644 --- a/environments.js +++ b/environments.js @@ -3,13 +3,14 @@ * with a few built-in (a standard Prelude environment) */ -// returns the new environment after mutating it -// values = [(identifier, JLambda expression)] - var errors = require("./errors.js"); var rep = require("./representation.js"); +/* + * returns the new environment after mutating it + * values = [(identifier, JLambda expression)] + */ function extend(env, values) { var new_env = {}; var env_keys = Object.keys(env); @@ -42,14 +43,7 @@ function lookup(name, env) { return value; } -var prelude = makeEnv("prelude", [[new rep.Name("e"), new rep.FloatT(Math.E)], - [new rep.Name("pi"), new rep.FloatT(Math.PI)]]); - -var prelude_types = makeEnv("prelude_types", - [[new rep.Name("e"), new rep.TypeOp("Float", [], false)], - [new rep.Name("pi"), new rep.TypeOp("Float", [], false)]]); - -module.exports = { prelude : prelude, - prelude_types : prelude_types, - lookup : lookup, - extend : extend }; +module.exports = { + lookup : lookup, + extend : extend +}; diff --git a/example.jl b/example.jl index ada6c55..4599e01 100644 --- a/example.jl +++ b/example.jl @@ -1,7 +1,3 @@ -defop 2 Left (a ++ b) - (a - b) - - def foo# 3 deftype Foo (A -> B) @@ -40,9 +36,9 @@ def empty [] def getFile (readFile "./parse.js") -def fileLines - (getFile >>= - ((mapM_ putStrLn) . lines)) +;;def fileLines +;; (getFile >>= +;; ((mapM_ putStrLn) . lines)) def (testUnary n) ((-n) + n) @@ -94,3 +90,5 @@ def main (unary + fileLines + (print splitted)) + +def blah (3 / 4) diff --git a/closure_conversion.js b/free_vars.js similarity index 79% rename from closure_conversion.js rename to free_vars.js index ff8e104..602c31d 100644 --- a/closure_conversion.js +++ b/free_vars.js @@ -1,4 +1,4 @@ -/* Takes an AST and converts all of the functions into closures. +/* Takes an AST and converts all of the functions into "closures" * A closure is a triple of: * the bound variables in a function or let * the free variables in a function or let @@ -19,10 +19,8 @@ */ var rep = require("./representation.js"); -var env = require("./environments.js"); var errors = require("./errors.js"); var parser = require("./parse.js"); -var pprint = require("./pprint.js"); var $ = require("./tools.js"); var _ = require("underscore"); @@ -68,7 +66,7 @@ function fvs(stx) { } } -function closure_convert(stx) { +function annotate_fvs(stx) { /* Takes a stx object that is either * a lambda * a let @@ -106,40 +104,43 @@ function closure_convert(stx) { return new rep.Closure(bound_vars, free_variables, stx, []); } -function closure_convert_all(stx) { +/* + * This traverse the tree and gathers up all of the free variables of various functions/let bindings + */ +function annotate_fvs_all(stx) { var closure; switch (stx.exprType) { case "Let": - closure = closure_convert(stx); - closure.body.pairs = closure.body.pairs.map(closure_convert_all); - closure.body = closure_convert_all(closure.body.body); + closure = annotate_fvs(stx); + closure.body.pairs = closure.body.pairs.map(annotate_fvs_all); + closure.body = annotate_fvs_all(closure.body.body); return closure; case "Function": - closure = closure_convert(stx); - closure.body.body = closure_convert_all(closure.body.body); + closure = annotate_fvs(stx); + closure.body.body = annotate_fvs_all(closure.body.body); return closure; case "Unary": - stx.val = closure_convert_all(stx.val); + stx.val = annotate_fvs_all(stx.val); return stx; case "Application": - stx.func = closure_convert_all(stx.func); - stx.p = closure_convert_all(stx.p); + stx.func = annotate_fvs_all(stx.func); + stx.p = annotate_fvs_all(stx.p); return stx; case "If": if (stx.elseexp) { - stx.condition = closure_convert_all(stx.condition); - stx.thenexp = closure_convert_all(stx.thenexp); - stx.elseexp = closure_convert_all(stx.elseexp); + stx.condition = annotate_fvs_all(stx.condition); + stx.thenexp = annotate_fvs_all(stx.thenexp); + stx.elseexp = annotate_fvs_all(stx.elseexp); return stx; } else { - stx.condition = closure_convert_all(stx.condition); - stx.thenexp = closure_convert_all(stx.thenexp); + stx.condition = annotate_fvs_all(stx.condition); + stx.thenexp = annotate_fvs_all(stx.thenexp); return stx; } break; case "Definition": - stx.val = closure_convert_all(stx.val); + stx.val = annotate_fvs_all(stx.val); return stx; default: return stx; @@ -149,11 +150,11 @@ function closure_convert_all(stx) { function test(src) { var ast = parser.parse(src)[0]; - console.log(JSON.stringify(closure_convert_all(ast), null, 4)); + console.log(JSON.stringify(annotate_fvs_all(ast), null, 4)); } //console.log(test("if something then if a then if b then c else d else rtrrt else some_other_thing")); module.export = { test : test, - closureConvert : closure_convert_all + annotate_fvs: annotate_fvs_all }; diff --git a/parse.js b/parse.js index fa25ccb..2c4e23a 100755 --- a/parse.js +++ b/parse.js @@ -367,12 +367,17 @@ function parseDataType(tokens, linenum, charnum) { typeName.charnum, "Expected a type operator in data type definition"); } - parameters = parseMany(parse, + if (fst(tokens)[0] !== "right_paren") { + parameters = parseMany(parse, validName, validFormPar, tokens, charnum, linenum); + } + else { + parameters = []; + } if (!tokens || (fst(tokens)[0]) !== "right_paren") { throw error.JSyntaxError(_.last(parameters).linenum, _.last(parameters).charnum, @@ -402,7 +407,7 @@ function parseDefType(tokens, linenum, charnum) { } if (fst(tokens)[0] === "left_paren") { /* It's an actual data type definition - * i.e. not just a newtype + * i.e. not just an alias */ tokens.pop(); return parseDataType(tokens, linenum, charnum); @@ -424,7 +429,7 @@ function parseDefType(tokens, linenum, charnum) { if (lhs.exprType !== "TypeOperator") { throw error.JSyntaxError(lhs.linenum, lhs.charnum, - "left-hand side of type definition was not a type operator"); + "left-hand side of type alias was not a type operator"); } rhs = parse(tokens, linenum, charnum); @@ -432,7 +437,7 @@ function parseDefType(tokens, linenum, charnum) { rhs.exprType !== "TypeOperator") { throw error.JSyntaxError(rhs.linenum, rhs.charnum, - "was expecting an application or type operator on the right-hand side of a type definition"); + "was expecting an application or type operator on the right-hand side of a type alias"); } result = addSrcPos(new typ.DefType(lhs, rhs), tokens, rhs.linenum, rhs.charnum); return result; diff --git a/prelude.jl b/prelude.jl index f94ff6c..1ed259f 100644 --- a/prelude.jl +++ b/prelude.jl @@ -4,24 +4,29 @@ ;; Type definitions -deftype String (A300 Char) +deftype String (Vector Char) -deftype Int Intrinsic +deftype (Int) Intrinsic -deftype Float Intrinsic +deftype (Float) Intrinsic -deftype Char Intrinsic +deftype (Char) Intrinsic -deftype Byte Intrinsic +deftype (Byte) Intrinsic -deftype Void Intrinsic +deftype (Void) Intrinsic -deftype IO Intrinsic +deftype (IO a) Intrinsic + +deftype (Vector a) Intrinsic deftype (List a) (Empty | (Cons a (List a))) +deftype (Bottom) + Undefined + deftype (Maybe a) (Nothing | (Just a)) @@ -55,3 +60,59 @@ deftype (Either a b) ;; I/O functions (print :: (String -> (IO Void))) + +;; Operator definitions + +defop 3 Left (a + b) + (add a b) + +defop 3 Left (a - b) + (minus a b) + +defop 4 Left (a * b) + (mul a b) + +defop 4 Left (a / b) + (div a b) + +defop 5 Right (a ^ b) + (pow a b) + +defop 3 Left (a ++ b) + (listConcat a b) + +defop 2 Left (a == b) + (eq a b) + +defop 2 Left (a > b) + (gt a b) + +defop 2 Left (a >= b) + (gte a b) + +defop 2 Left (a < b) + (lt a b) + +defop 2 Left (a <= b) + (lte a b) + +defop 2 Left (a && b) + (and a b) + +defop 2 Left (a || b) + (or a b) + +defop 1 Left (x : xs) + (cons x xs) + +defop 1 Left (f $ x) + (fapply f x) + +defop 1 Left (f . g) + (compose f g) + +defop 1 Left (a | b) + (bitwiseOr a b) + +defop 1 Left (a & b) + (bitwiseAnd a b) diff --git a/representation.js b/representation.js index 3d843d3..39c3543 100644 --- a/representation.js +++ b/representation.js @@ -368,31 +368,11 @@ function makeGensym() { var gensym = makeGensym(); -//console.log(isTypeExpr(new Name("T"))); - -OPInfo = {"+" : [3, "Left"], - "-" : [3, "Left"], - "*" : [4, "Left"], - "/" : [4, "Left"], - "^" : [5, "Right"], - "++" : [3, "Left"], - "==" : [2, "Left"], - ">" : [2, "Left"], - ">=" : [2, "Left"], - "<" : [2, "Left"], - "<=" : [2, "Left"], - "&&" : [2, "Left"], - "||" : [2, "Left"], +OPInfo = { "::" : [2, "Left"], - ":" : [1, "Left"], - "$" : [1, "Left"], - ">>" : [1, "Left"], - ">>=" : [1, "Left"], - "<$>" : [1, "Left"], - "." : [1, "Left"], "," : [1, "Left"], - "->" : [1, "Right"], - "|" : [1, "Left"]}; + "->" : [1, "Right"] + }; module.exports = { diff --git a/tokenize.js b/tokenize.js index d04c61d..c522acd 100755 --- a/tokenize.js +++ b/tokenize.js @@ -1,5 +1,6 @@ #! /usr/bin/node +var fs = require("fs"); var rep = require("./representation.js"); var $ = require("./tools.js"); var error = require("./errors.js"); @@ -13,10 +14,7 @@ function isDigit(c) { if (isNaN(code)) { return false; } - return (46 < code && - code < 58 || - code < 58 && - code > 46); + return (47 < code && code < 58); } function isWhitespace(c) { @@ -411,8 +409,11 @@ function checkPattern(x, i) { } function tokenizeFull(input) { + var preludeSrc = fs.readFileSync("./prelude.jl"); var matchop; var initialPass = tokenizeHelp(input, _.constant(false), true).reverse(); + + input = [preludeSrc, input].join(""); for (var i = 0; i < initialPass.length; i++) { if (initialPass.slice(i, i+8). map(_.first). diff --git a/typecheck.js b/typecheck.js index 7c198c6..e105e94 100644 --- a/typecheck.js +++ b/typecheck.js @@ -13,7 +13,7 @@ var rep = require("./representation.js"); var env = require("./environments.js"); -var TypeOp = rep.TypeOp; -var TypeVar = rep.TypeVar; - - +/* + * Map all bindings with explicit type annotations in the environment + */ +function gather_annotations(stx) {