From 88c188411280181c724587ca085ab9357ca439a0 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Sun, 18 May 2014 18:51:01 -0400 Subject: [PATCH 1/6] missing semicolon --- tokenize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokenize.js b/tokenize.js index 907622e..d04c61d 100755 --- a/tokenize.js +++ b/tokenize.js @@ -310,7 +310,7 @@ function tokenize(tokstream, matchop) { if (deftype) { tokens.push(["deftype", "deftype", charnum, linenum]); tokstream = tokstream.substr(7); - break + break; } var def = peek(tokstream, "def", "def"); if (def) { From d36a8fe0d982c39e95fcb23596dcdab3bb2e152c Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Sun, 18 May 2014 18:58:42 -0400 Subject: [PATCH 2/6] a bunch of types and declarations, adopt the prefix that unboxed types are declared as Intrinsic for now --- prelude.jl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/prelude.jl b/prelude.jl index bd1a296..a4437f4 100644 --- a/prelude.jl +++ b/prelude.jl @@ -7,3 +7,23 @@ deftype String (List Char) deftype (List a) (Empty | (Cons a (List a))) + +deftype Int Intrinsic + +deftype Float Intrinsic + +deftype Char Intrinsic + +deftype Byte Intrinsic + +deftype Void Intrinsic + +(map :: ((a -> b) -> (List a) -> (List b))) + +(head :: ((List a) -> a)) + +(tail :: ((List a) -> (List a))) + +(!! :: (Int -> (List a) -> a)) + +(print :: (String -> (IO Void))) From 292517cb5c37e5bc25122f523988ec56ccbbdb18 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Sun, 18 May 2014 19:09:45 -0400 Subject: [PATCH 3/6] add type for the cons operator --- prelude.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prelude.jl b/prelude.jl index a4437f4..f66ce12 100644 --- a/prelude.jl +++ b/prelude.jl @@ -18,6 +18,8 @@ deftype Byte Intrinsic deftype Void Intrinsic +(: :: (a -> (List a) -> (List a))) + (map :: ((a -> b) -> (List a) -> (List b))) (head :: ((List a) -> a)) From 05742335bb67361bd068c071f787febce1367294 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Mon, 19 May 2014 17:41:02 -0400 Subject: [PATCH 4/6] give a better name to type declarations in the IR --- desugar.js | 14 +++++++------- parse.js | 3 +-- pprint.js | 2 +- representation.js | 22 +++++++++++----------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/desugar.js b/desugar.js index eb5f998..9da5d4e 100644 --- a/desugar.js +++ b/desugar.js @@ -47,14 +47,14 @@ function desugarLet(stx) { return new typ.LetExp(values, desugar(stx.body)); } -function sugarTypeApp(stx) { +function sugarTypeDecl(stx) { var type; var expression; type = stx.p; expression = desugar(stx.func.p); expression.linenum = stx.linenum; expression.charnum = stx.charnum; - return new typ.TypeApp(expression, type); + return new typ.TypeDecl(expression, type); } function desugarDefType(stx) { @@ -86,19 +86,19 @@ function desugar(stx) { case "Application": if ((stx.func.func !== undefined ) && (stx.func.func.ident === "::")) { - /* It's a type application probably (will be verified later) - * In this case we actually *add* syntax here to differentiate type applications - * from normal applications + /* It's a type declaration probably (will be verified later) + * In this case we actually *add* syntax here to differentiate type declarations + * from normal function application */ typeExpTest = typ.isTypeExpr(stx.p); if (typeExpTest.failed !== undefined && typeExpTest.failed) { throw errors.JInternalError( - "Type application error near line " + stx.linenum + " at character #"+stx.charnum + + "Type declaration error near line " + stx.linenum + " at character #"+stx.charnum + "\n"+typeExpTest.stx.exprType+" (" + typeExpTest.stx.val + ") found where a type operator or type application was expected"); } - return sugarTypeApp(stx); + return sugarTypeDecl(stx); } if ((stx.func.ident === "-" || diff --git a/parse.js b/parse.js index 780f9d7..d56d73d 100755 --- a/parse.js +++ b/parse.js @@ -801,8 +801,7 @@ function parseFull(tokenized) { var ast = []; try { while (tokenized.length > 0) { - var parsed = desugarer.desugar(parse(tokenized)); - ast.push(parsed); + ast.push(desugarer.desugar(parse(tokenized))); } return ast; } catch (e) { diff --git a/pprint.js b/pprint.js index 6986b0c..addfd76 100644 --- a/pprint.js +++ b/pprint.js @@ -94,7 +94,7 @@ function pprint(expr) { else if (expr.exprType === "TypeVar") { return "("+expr.name+")"; } - else if (expr.exprType === "TypeApplication") { + else if (expr.exprType === "TypeDeclaration") { return "( " + pprint(expr.expression) + " :: " + pprint(expr.type) + " )"; } } diff --git a/representation.js b/representation.js index 9db580d..be07c08 100644 --- a/representation.js +++ b/representation.js @@ -37,17 +37,17 @@ function isIrregularTypeOp(x) { return (x === "->"); } -function flattenTypeApp(stx) { +function flattenTypeDecl(stx) { if (isTypeExpr(stx)) { return true; } if (stx.exprType === "Application") { /* it might be a type application so recursively check it */ if (stx.p !== undefined) { - return _.flatten([flattenTypeApp(stx.p), flattenTypeApp(stx.func)]); + return _.flatten([flattenTypeDecl(stx.p), flattenTypeDecl(stx.func)]); } else { - return _.flatten([flattenTypeApp(stx.func)]); + return _.flatten([flattenTypeDecl(stx.func)]); } } if (stx.exprType === "Name") { @@ -66,7 +66,7 @@ function flattenTypeApp(stx) { function isTypeExprRec(stx) { - var flattened = flattenTypeApp(stx); + var flattened = flattenTypeDecl(stx); for(var i = 0; i < flattened.length; i++) { if (flattened[i].failed !== undefined && flattened[i].failed) { @@ -266,30 +266,30 @@ function isTypeExpr(expr) { } return ((expr.exprType === "TypeOperator") || (expr.exprType === "TypeVar") || - (expr.exprType === "TypeApplication")); + (expr.exprType === "TypeDeclaration")); } -function TypeApp(expression, type) { +function TypeDecl(expression, type) { if (isTypeExprRec(expression) && expression.exprType !== "Name") { throw errors.JSyntaxError( expression.linenum, expression.charnum, - "Left-hand-side of type application must not be in the type language" + "Left-hand-side of type declaration must not be in the type language" ); } if (!isTypeExprRec(type)) { throw errors.JInternalError( - "Right-hand-side of type application must be a type expression" + "Right-hand-side of type declaration must be a type expression" ); } this.expression = expression; this.type = type; - this.exprType = "TypeApplication"; + this.exprType = "TypeDeclaration"; return this; } -TypeApp.prototype = TypeExpression; +TypeDecl.prototype = TypeExpression; function DefType(lhs, rhs) { /* Both rhs and lhs are expected @@ -416,7 +416,7 @@ module.exports = gensym : gensym, TypeVar : TypeVar, TypeOp : TypeOp, - TypeApp: TypeApp, + TypeDecl : TypeDecl, Closure : Closure, isTypeExpr : isTypeExprRec, DefType : DefType, From 87a4176bdd2f1e251e9f378b5e7f6ad79805dae1 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Mon, 19 May 2014 17:58:09 -0400 Subject: [PATCH 5/6] fix bug with validity checking of type definitions --- example.jl | 3 +++ prelude.jl | 34 ++++++++++++++++++++++++++++++---- representation.js | 6 +++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/example.jl b/example.jl index f211604..9fd0152 100644 --- a/example.jl +++ b/example.jl @@ -1,6 +1,9 @@ defop 2 Left (a ++ b) (a - b) + +def foo# 3 + deftype Foo (A -> B) ;; here is a comment diff --git a/prelude.jl b/prelude.jl index f66ce12..f94ff6c 100644 --- a/prelude.jl +++ b/prelude.jl @@ -2,11 +2,9 @@ ;; It is sort of special in that it doesn't care whether there are any associated definitions ;; just that there are type definitions for that particular binding's name -deftype String (List Char) -deftype (List a) - (Empty | - (Cons a (List a))) +;; Type definitions +deftype String (A300 Char) deftype Int Intrinsic @@ -18,6 +16,22 @@ deftype Byte Intrinsic deftype Void Intrinsic +deftype IO Intrinsic + +deftype (List a) + (Empty | + (Cons a (List a))) + +deftype (Maybe a) + (Nothing | + (Just a)) + +deftype (Either a b) + ((Left a) | + (Right b)) + +;; List functions + (: :: (a -> (List a) -> (List a))) (map :: ((a -> b) -> (List a) -> (List b))) @@ -28,4 +42,16 @@ deftype Void Intrinsic (!! :: (Int -> (List a) -> a)) +(take :: (Int -> (List a) -> (Maybe (List a)))) + +(drop :: (Int -> (List a) -> (Maybe (List a)))) + +;; Optional functions + +(maybe :: (b -> (a -> b) -> (Maybe a) -> b)) + +(either :: ((b -> c) -> (b -> c) -> (Either a b) -> c)) + +;; I/O functions + (print :: (String -> (IO Void))) diff --git a/representation.js b/representation.js index be07c08..3d843d3 100644 --- a/representation.js +++ b/representation.js @@ -278,7 +278,7 @@ function TypeDecl(expression, type) { "Left-hand-side of type declaration must not be in the type language" ); } - if (!isTypeExprRec(type)) { + if (isTypeExprRec(type).failed) { throw errors.JInternalError( "Right-hand-side of type declaration must be a type expression" ); @@ -295,7 +295,7 @@ function DefType(lhs, rhs) { /* Both rhs and lhs are expected * to be fully desugared already */ - if (!isTypeExprRec(rhs) || + if (isTypeExprRec(rhs).failed || !isTypeExpr(lhs)) { throw errors.JSyntaxError( rhs.linenum, @@ -331,7 +331,7 @@ function DataType(name, params, type) { "which is a type operator"); } _.each(params, checkName); - if (!isTypeExprRec(type)) { + if (isTypeExprRec(type).failed) { throw errors.JSyntaxError( type.linenum, type.charnum, From a8e3afd9464bc17c1a7287e9da7ccf92749f8c47 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Mon, 19 May 2014 18:26:30 -0400 Subject: [PATCH 6/6] misc style improvements, improve error reporting line/char info --- example.jl | 3 +- parse.js | 173 +++++++++++++++++++++++++++-------------------------- 2 files changed, 90 insertions(+), 86 deletions(-) diff --git a/example.jl b/example.jl index 9fd0152..ada6c55 100644 --- a/example.jl +++ b/example.jl @@ -49,7 +49,7 @@ def (testUnary n) def (foo bar) let { - lol = [1, + lol = [1, (lambda qwerty blah -> [qerty, blah, (lambda whatever -> whatever)])] @@ -82,6 +82,7 @@ def r def def main let { + (f a) -> a unary = (print (testUnary 6)) splitted = def { xs = (fst (splitxs [12,3,4,56])) diff --git a/parse.js b/parse.js index d56d73d..fa25ccb 100755 --- a/parse.js +++ b/parse.js @@ -192,8 +192,8 @@ function parseDefFunction(tokens, linenum, charnum) { var body; if (fname.exprType !== "Name") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(linenum, + charnum, "Expected an identifier in function definition"); } if (fst(tokens)[0] === "right_paren") { @@ -204,17 +204,17 @@ function parseDefFunction(tokens, linenum, charnum) { validName, validFormPar, tokens, - fst(tokens)[2], - fst(tokens)[3]); + charnum, + linenum); } if (!tokens || (fst(tokens)[0]) !== "right_paren") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(linenum, + charnum, "Formal parameters must be followed by )"); } tokens.pop(); body = parse(tokens); - result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, linenum, charnum); + result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, body.linenum, body.charnum); return result; } @@ -235,32 +235,32 @@ function parseLetForm(tokens, linenum, charnum) { validLet, letEnd, tokens, - linenum, - charnum); + charnum, + linenum); if (fst(tokens) && fst(tokens)[0] !== "right_brace") { throw error.JSyntaxError(fst(tokens)[2], fst(tokens)[3], "let/def form must have a closing }"); } if (!fst(tokens)) { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(_.last(pairs).linenum, + _.last(pairs).charnum, "Unexpected end of source"); } tokens.pop(); if (tokens.length <= 0) { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(_.last(pairs).linenum, + _.last(pairs).charnum, "let/def form must have a body"); } body = parse(tokens); if (body.exprType === "Definition" || body.exprType === "FunctionDefinition") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(body.linenum, + body.charnum, "Body of a let/def expression cannot be a definition"); } - result = addSrcPos(new typ.LetExp(pairs, body), tokens, linenum, charnum); + result = addSrcPos(new typ.LetExp(pairs, body), tokens, body.linenum, body.charnum); return result; } @@ -284,12 +284,12 @@ function parseLetFunction(tokens, linenum, charnum) { validName, validFormPar, tokens, - fst(tokens)[2], - fst(tokens)[3]); + charnum, + linenum); } if ((fst(tokens)[0]) !== "right_paren") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(linenum, + charnum, "Formal parameters must be followed by )"); } tokens.pop(); @@ -300,7 +300,7 @@ function parseLetFunction(tokens, linenum, charnum) { } tokens.pop(); body = parse(tokens); - result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, linenum, charnum); + result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, body.linenum, body.charnum); return result; } @@ -310,46 +310,49 @@ function parseLetBinding(tokens, linenum, charnum) { var bound; if (name.exprType != "Name") { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(name.linenum, + name.charnum, "Expected an identifier in let/def binding"); } if (!fst(tokens) || fst(tokens)[1] !== "=") { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(name.linenum, + name.charnum, "An identifier in a let/def binding must be followed by ``=''"); } tokens.pop(); if (!notFollowedBy(tokens, ["comma", "arrow", "right_brace", "right_square"], - linenum, - charnum)) { - throw error.JSyntaxError(linenum, - charnum, + name.linenum, + name.charnum)) { + throw error.JSyntaxError(name.linenum, + name.charnum, "The binding of " + identifier.val + " must not be followed by " + fst(tokens)[0]); } bound = parse(tokens); if (bound.exprType === "Definition" || bound.exprType === "FunctionDefinition") { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(bound.linenum, + bound.charnum, "A definition cannot be the value of a binding"); } - result = addSrcPos(new typ.Def(name, bound), tokens, linenum, charnum); + result = addSrcPos(new typ.Def(name, bound), tokens, bound.linenum, bound.charnum); return result; } function parseLetItem(tokens) { + var linenum = fst(tokens)[3]; + var charnum = fst(tokens)[2]; + if (fst(tokens) && fst(tokens)[0] === "left_paren") { tokens.pop(); return parseLetFunction(tokens, - fst(tokens)[3], - fst(tokens)[2]); + linenum, + charnum); } else { return parseLetBinding(tokens, - fst(tokens)[3], - fst(tokens)[2]); + linenum, + charnum); } } @@ -365,14 +368,14 @@ function parseDataType(tokens, linenum, charnum) { "Expected a type operator in data type definition"); } parameters = parseMany(parse, - validName, - validFormPar, - tokens, - charnum, - linenum); + validName, + validFormPar, + tokens, + charnum, + linenum); if (!tokens || (fst(tokens)[0]) !== "right_paren") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(_.last(parameters).linenum, + _.last(parameters).charnum, "Data type parameters must be followed by )"); } tokens.pop(); @@ -414,8 +417,8 @@ function parseDefType(tokens, linenum, charnum) { else { lhs = parse(tokens, linenum, charnum); if (!tokens) { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(lhs.linenum, + lhs.charnum, "Unexpected end of source"); } if (lhs.exprType !== "TypeOperator") { @@ -431,7 +434,7 @@ function parseDefType(tokens, linenum, charnum) { rhs.charnum, "was expecting an application or type operator on the right-hand side of a type definition"); } - result = addSrcPos(new typ.DefType(lhs, rhs), tokens, linenum, charnum); + result = addSrcPos(new typ.DefType(lhs, rhs), tokens, rhs.linenum, rhs.charnum); return result; } } @@ -475,24 +478,22 @@ function parseDef(tokens, linenum, charnum) { else { identifier = parse(tokens); if (!fst(tokens)) - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(identifier.linenum, + identifier.charnum, "Unexpected end of source"); - linenum = fst(tokens)[3]; - charnum = fst(tokens)[2]; if (!notFollowedBy(tokens, ["comma", "arrow", "right_brace", "right_square"], - linenum, - charnum)) { - throw error.JSyntaxError(linenum, - charnum, + identifier.linenum, + identifier.charnum)) { + throw error.JSyntaxError(identifier.linenum, + identifier.charnum, "def " + identifier.val + " must not be followed by " + fst(tokens)[0]); } bound = parse(tokens); if (bound.exprType === "Definition" || bound.exprType === "FunctionDefinition") { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(bound.linenum, + bound.charnum, "A definition cannot be the value of a binding"); } result = addSrcPos(new typ.Def(identifier, bound), tokens, bound.linenum, bound.charnum); @@ -503,6 +504,7 @@ function parseDef(tokens, linenum, charnum) { function parseDefOp(tokens, linenum, charnum) { var result; var names; + var pattern; if (fst(tokens)[0] !== "integer" || fst(tokens)[1] < 1) { @@ -532,7 +534,7 @@ function parseDefOp(tokens, linenum, charnum) { charnum, "defop must be surrounded by exactly 3 identifiers"); } - var pattern = tokens.slice(tokens.length-3, + pattern = tokens.slice(tokens.length-3, tokens.length); tokens.pop(); tokens.pop(); tokens.pop(); if (fst(tokens)[0] !== "right_paren") { @@ -554,17 +556,19 @@ function parseDefOp(tokens, linenum, charnum) { names.slice(1,3), parse(tokens)), tokens, - linenum, - charnum); + _.last(names).linenum, + _.last(names).charnum); return result; } -function parseIf(tokens) { - var linenum = fst(tokens)[3]; - var charnum = fst(tokens)[2]; +function parseIf(tokens, linenum, charnum) { var result; + var ifC; + var thenC; + var elseC; + if (!notFollowedBy(tokens, ["def","comma","lambda"], linenum, @@ -574,32 +578,32 @@ function parseIf(tokens) { "``if'' cannot be followed by "+fst(tokens)[0]) ; } else { - var ifC = parse(tokens); + ifC = parse(tokens); if (!fst(tokens) || fst(tokens)[0] !== "thenexp") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(ifC.linenum, + ifC.charnum, "if ``exp'' must be folowed by ``then'' exp, not "+snd(tokens)[0]); } else { tokens.pop(); - var thenC = parse(tokens); + thenC = parse(tokens); if (fst(tokens) && fst(tokens)[0] === "elsexp") { tokens.pop(); if (_.size(tokens) < 1) { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(thenC.linenum, + thenC.charnum, "Unexpected end of source"); } else { - var elseC = parse(tokens); + elseC = parse(tokens); result = addSrcPos(new typ.If(ifC, thenC, elseC), tokens, elseC.linenum, elseC.charnum); return result; } } else { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(thenC.linenum, + thenC.charnum, "If expression must include an else variant"); } } @@ -613,9 +617,7 @@ function validFormPar(tok) { tok[1] !== "->"; } -function parseLambda(tokens) { - var linenum = fst(tokens)[2]; - var charnum = fst(tokens)[3]; +function parseLambda(tokens, linenum, charnum) { var result; var parameters = parseMany(parse, validName, @@ -624,8 +626,8 @@ function parseLambda(tokens) { charnum, linenum); if (fst(tokens)[1] !== "->") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(_.last(parameters).linenum, + _.last(parameters).charnum, "arrow must follow parameters in lambda, not "+fst(tokens)[0]); } tokens.pop(); @@ -643,20 +645,22 @@ function computeApp(tokens, charnum, linenum) { var lhs = parse(tokens); var next; var result; + var parameters; + if (fst(tokens)) { next = fst(tokens); } else { - throw error.JSyntaxError(linenum, - charnum, + throw error.JSyntaxError(lhs.linenum, + lhs.charnum, "Unexpected end of source"); } if (typ.OPInfo[next[1]]) { /* it's an infix expression */ - result = parseInfix(tokens, 1, lhs, linenum, charnum); + result = parseInfix(tokens, 1, lhs, lhs.linenum, lhs.charnum); if (!fst(tokens) || fst(tokens)[0] !== "right_paren") { - throw error.JSyntaxError(fst(tokens)[3], - fst(tokens)[2], + throw error.JSyntaxError(lhs.linenum, + lhs.charnum, "Mismatched parentheses or missing parenthesis on right-hand side"); } else { @@ -666,7 +670,6 @@ function computeApp(tokens, charnum, linenum) { } else { /* it's a prefix application */ - var parameters; if (fst(tokens)[0] !== "right_paren") { parameters = parseMany(parse, validArgTypes, @@ -744,7 +747,7 @@ function parse(tokens) { return parseList(tokens, linenum, charnum); } else if (toktype === "lambda") { - return parseLambda(tokens); + return parseLambda(tokens, linenum, charnum); } else if (toktype === "integer") { result = addSrcPos(new typ.IntT(token), tokens, linenum, charnum); @@ -777,12 +780,12 @@ function parse(tokens) { return parseDefOp(tokens, linenum, charnum); } else if (toktype === "ifexp") { - return parseIf(tokens); + return parseIf(tokens, linenum, charnum); } else if (toktype === "left_paren") { if (fst(tokens)[0] === "lambda") { tokens.pop(); - var parsed = parseLambda(tokens); + var parsed = parseLambda(tokens, linenum, charnum); tokens.pop(); return parsed; }