diff --git a/desugar.js b/desugar.js index 16fadad..40a242a 100644 --- a/desugar.js +++ b/desugar.js @@ -5,6 +5,7 @@ */ var typ = require("./representation.js"); +var errors = require("./errors.js"); var _ = require("underscore"); // Lists get desugared to nested function calls @@ -54,8 +55,9 @@ function sugarTypeApp(stx) { function desugar(stx) { switch (stx.exprType) { case "If": - if (stx.elseexp) + if (stx.elseexp) { return new typ.If(desugar(stx.condition), desugar(stx.thenexp), desugar(stx.elseexp)); + } return new typ.If(desugar(stx.condition), desugar(stx.thenexp)); case "FunctionDefinition": return desugarDefFunc(stx); @@ -70,6 +72,9 @@ function desugar(stx) { * In this case we actually *add* syntax here to differentiate type applications * from normal applications */ + if (!typ.isTypeExpr(stx.p)) { + throw errors.JInternalError("Type application error"); + } return sugarTypeApp(stx); } @@ -78,8 +83,9 @@ function desugar(stx) { stx.p) { return new typ.UnaryOp(desugar(stx.func), desugar(stx.p)); } - if (stx.p) + if (stx.p) { return new typ.App(desugar(stx.func), desugar(stx.p)); + } return new typ.App(stx.func); case "Function": return curryFunc(stx.p, stx.body); diff --git a/example.jl b/example.jl index 5c99288..bc75ac7 100644 --- a/example.jl +++ b/example.jl @@ -2,7 +2,7 @@ defop 2 Left (a ++#$ b) (a - b) -(qat :: A) +(qat :: (A -> B)) def qat (lambda a b c -> (a + b)) def (add a b) diff --git a/parse.js b/parse.js index eaefa35..b7bbda0 100755 --- a/parse.js +++ b/parse.js @@ -143,7 +143,9 @@ function parseList(tokens) { xs = []; } else { - xs = parseBetween(function (x) { return true; }, "comma", tokens, fst(tokens)[3], fst(tokens)[2]); + xs = parseBetween(function (x) { + return true; + }, "comma", tokens, fst(tokens)[3], fst(tokens)[2]); } if (!fst(tokens) || fst(tokens)[0] !== "right_square") { throw error.JSyntaxError(fst(tokens)[3], @@ -158,7 +160,7 @@ function parseList(tokens) { function parseDefFunction(tokens) { var fname = parse(tokens); var parameters; - if (fname.exprType != "Name") { + if (fname.exprType !== "Name") { throw error.JSyntaxError(fst(tokens)[3], fst(tokens)[2], "Expected an identifier in function definition"); @@ -647,4 +649,4 @@ module.exports = { parse : function(str) { tokenize : tokenizer.tokenize }; var istr = fs.readFileSync('/dev/stdin').toString(); -parseFull(tokenizer.tokenize(istr)).map(pprint.pprint); +console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint)); diff --git a/representation.js b/representation.js index 3df95fa..1563270 100644 --- a/representation.js +++ b/representation.js @@ -25,7 +25,42 @@ var TypeExpression = { isTypeExpr : true }; -var isTypeExpr = _.property("isTypeExpr"); +function isTypeExpr(x) { + return x.isTypeExpr !== undefined; +} + +function isIrregularTypeOp(x) { + return (x === "->"); +} + +function isTypeExprRec(stx, isTypeOp) { + if (isTypeExpr(stx)) { + return true; + } + if (stx.exprType === "Application") { + /* it might be a type application so recursively check it */ + if (stx.p !== undefined) { + return (isTypeExprRec(stx.p) && + isTypeExprRec(stx.func)); + } + else { + return isTypeExprRec(stx.func); + } + } + if (stx.exprType === "Name") { + /* Check if it might be a type operator that is not capitalized */ + return isIrregularTypeOp(stx.ident); + } + return false; +} + +function App(func, p) { + this.func = func; + this.exprType = "Application"; + if (p) + this.p = p; + return this; +} function Closure(bound_vars, free_vars, body, env) { this.bound_vars = bound_vars; @@ -41,7 +76,7 @@ function LetExp(pairs, body) { return (x.exprType === "Definition" || x.exprType === "FunctionDefinition"); })) { - throw Errors.JInternalError( + throw errors.JInternalError( "let can only be used to bind things to names or functions" ); } @@ -189,6 +224,8 @@ function TypeOp(name) { return this; } +TypeOp.prototype = TypeExpression; + function isTypeExpr(expr) { if (!expr.exprType) { throw errors.JInternalError(expr); @@ -198,15 +235,13 @@ function isTypeExpr(expr) { (expr.exprType === "TypeApplication")); } -TypeOp.prototype = TypeExpression; - function TypeApp(expression, type) { - if (isTypeExpr(expression)) { + if (isTypeExprRec(expression)) { throw errors.JInternalError( "Left-hand-side of type application must not be in the type language" ); } - if (!isTypeExpr(type)) { + if (!isTypeExprRec(type)) { throw errors.JInternalError( "Right-hand-side of type application must be a type expression" ); @@ -242,6 +277,8 @@ function makeGensym() { var gensym = makeGensym(); +//console.log(isTypeExpr(new Name("T"))); + OPInfo = {"+" : [3, "Left"], "-" : [3, "Left"], "*" : [4, "Left"], @@ -288,5 +325,6 @@ module.exports = TypeVar : TypeVar, TypeOp : TypeOp, TypeApp: TypeApp, - Closure : Closure + Closure : Closure, + isTypeExpr : isTypeExprRec }; diff --git a/tokenize.js b/tokenize.js index a4f37d1..3662933 100755 --- a/tokenize.js +++ b/tokenize.js @@ -400,11 +400,13 @@ function tokenizeFull(input) { var matchop; var initialPass = tokenizeHelp(input, _.constant(false), true).reverse(); for (var i = 0; i < initialPass.length; i++) { - if (initialPass.slice(i, i+8).map(_.first).every(checkPattern)) { - rep.OPInfo[initialPass[i+5][1]] = [parseInt(initialPass[i+1][1], 10), - initialPass[i+2][1]]; + if (initialPass.slice(i, i+8). + map(_.first). + every(checkPattern)) { + rep.OPInfo[initialPass[i+5][1]] = + [parseInt(initialPass[i+1][1], 10), + initialPass[i+2][1]]; } - } operators = Object.keys(rep.OPInfo); matchop = $.opMatch(operators); diff --git a/tools.js b/tools.js index b4d387f..e8a4bf5 100644 --- a/tools.js +++ b/tools.js @@ -5,7 +5,7 @@ function empty(xs) { } function not(x) { - return !x; + return !x; } function min(a, b) {