From b18d0a1eca367ff40348edb732d84ffded099d8c Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Fri, 28 Mar 2014 14:01:12 -0400 Subject: [PATCH] work on parsing type applications/signatures --- closure_conversion.js | 12 ++++++---- parse.js | 36 +++++++++++++++++++++--------- pprint.js | 48 ++++++++++++++++++++++++++------------- representation.js | 50 +++++++++++++++++++++-------------------- tokenize.js | 52 +++++++++++++++++++++++++++++++++---------- tools.js | 15 ++++++++++++- 6 files changed, 146 insertions(+), 67 deletions(-) diff --git a/closure_conversion.js b/closure_conversion.js index fc6ab07..7293ce9 100644 --- a/closure_conversion.js +++ b/closure_conversion.js @@ -2,7 +2,7 @@ * A closure is a triple of: * the bound variables in a function or let * the free variables in a function or let - * a function body or let body and bound values + * a function body or let body and bound values (if it is an escaping closure only) * The closure has the property that all of the free variables of the function or let * are in the environment, or an exception is raised because the variable is not bound * in the current environment. @@ -12,6 +12,10 @@ * call the function with the environment associated with it. * For the purposes of type checking it does not matter how the function gets called, the environment * is only used for looking up the types of names. Formal parameters are given type variables. + * + * The first phase of closure conversion is not really closure conversion exactly. + * All it does is find out the free variables in scope and tie those up into a data structure with their types later. + * The second phase will be done to the CPS language and closures will actually lambda-lifted out potentially. */ var rep = require("./representation.js"); @@ -102,7 +106,7 @@ function closure_convert(stx) { return new rep.Closure(bound_vars, free_variables, stx, []); } -function closure_convert_all(stx) { +function closure_convert_all(stx, env) { var closure; switch (stx.exprType) { case "Let": @@ -147,8 +151,8 @@ function test(src) { console.log(JSON.stringify(closure_convert_all(ast), null, 4)); } -console.log(pprint.pprint(parser.parse(pprint.pprint(parser.parse("if something then if a then if b then c else d else rtrrt else some_other_thing")[0]))[0])); - +//console.log(test(pprint.pprint(parser.parse(pprint.pprint(parser.parse("if something then if a then if b then c else d else rtrrt else some_other_thing")[0]))[0]))); +//console.log(pprint.pprint(parser.parse("def main (print let { a = def {f = (lambda a b -> (a+b))} f} (a 2 3))")[0])); module.export = { test : test, closureConvert : closure_convert_all diff --git a/parse.js b/parse.js index 795ec7b..245918f 100755 --- a/parse.js +++ b/parse.js @@ -553,27 +553,40 @@ function parse(tokens) { } var token = fst(tokens)[1]; tokens.pop(); - if (toktype === "stringlit") + if (toktype === "stringlit") { return new typ.StrT(token); - else if (toktype === "left_square") + } + else if (toktype === "left_square") { return parseList(tokens); - else if (toktype === "lambda") + } + else if (toktype === "lambda") { return parseLambda(tokens); - else if (toktype === "integer") + } + else if (toktype === "integer") { return new typ.IntT(token); - else if (toktype === "float") + } + else if (toktype === "float") { return new typ.FloatT(token); - else if (toktype === "identifier") + } + else if (toktype === "identifier") { return new typ.Name(token); - else if (toktype === "truelit" || toktype === "falselit") + } + else if (toktype === "constructor") { + return new typ.TypeOp(token); + } + else if (toktype === "truelit" || toktype === "falselit") { return new typ.BoolT(token); + } else if (toktype === "def" || - toktype === "let") + toktype === "let") { return parseDef(tokens, fst(tokens)[3], fst(tokens)[2]); - else if (toktype === "defop") + } + else if (toktype === "defop") { return parseDefOp(tokens, fst(tokens)[3], fst(tokens)[2]); - else if (toktype === "ifexp") + } + else if (toktype === "ifexp") { return parseIf(tokens); + } else if (toktype === "left_paren") { if (fst(tokens)[0] === "lambda") { tokens.pop(); @@ -610,4 +623,5 @@ module.exports = { parse : function(str) { return parseFull(tokenizer.tokenize(str)); } }; -//var istr = fs.readFileSync('/dev/stdin').toString(); +/*var istr = fs.readFileSync('/dev/stdin').toString(); +console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint));*/ diff --git a/pprint.js b/pprint.js index e67fc82..8656512 100644 --- a/pprint.js +++ b/pprint.js @@ -27,38 +27,56 @@ function pprintIf(ifexp) { } function pprint(expr) { - if (expr.exprType === "Name") + if (expr.exprType === "Name") { return expr.val; - else if (expr.exprType === "Bool") - if (expr.val) + } + else if (expr.exprType === "TypeOperator") { + return expr.val; + } + else if (expr.exprType === "Bool") { + if (expr.val) { return "True"; - else + } + else { return "False"; - else if (expr.exprType === "Integer") + } + } + else if (expr.exprType === "Integer") { return "("+expr.val+")"; - else if (expr.exprType === "Float") + } + else if (expr.exprType === "Float") { return "("+expr.val+")"; - else if (expr.exprType === "String") + } + else if (expr.exprType === "String") { return '"'+expr.val+'"'; - else if (expr.exprType === "Name") + } + else if (expr.exprType === "Name") { return expr.val; - else if (expr.exprType === "Application") + } + else if (expr.exprType === "Application") { return pprintApp(expr); - else if (expr.exprType === "Definition") + } + else if (expr.exprType === "Definition") { return pprintDef(expr); - else if (expr.exprType === "If") + } + else if (expr.exprType === "If") { return pprintIf(expr); - else if (expr.exprType === "Function") + } + else if (expr.exprType === "Function") { return pprintFunc(expr); - else if (expr.exprType === "Nil") + } + else if (expr.exprType === "Nil") { return "[]"; - else if (expr.exprType === "Unary") + } + else if (expr.exprType === "Unary") { return "("+expr.op.ident+" "+pprint(expr.val)+")"; - else if (expr.exprType === "Let") + } + else if (expr.exprType === "Let") { return "let {" + expr.pairs.map( function (v) { return pprint(v); }).join(" ; ") + "} in " + pprint(expr.body); + } } module.exports = {pprint : pprint}; diff --git a/representation.js b/representation.js index 646429b..ebe8dd7 100644 --- a/representation.js +++ b/representation.js @@ -164,13 +164,14 @@ function If(condition, thenexp, elseexp) { function TypeVar(name) { this.name = name; + this.exprType = "TypeVariable"; return this; } -function TypeOp(name, params, body) { +function TypeOp(name) { this.name = name; - this.params = params; - this.body = body; + this.val = name; + this.exprType = "TypeOperator" return this; } @@ -205,27 +206,28 @@ function makeGensym() { var gensym = makeGensym(); -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"], - "::" : [2, "Left"], - ":" : [1, "Left"], - "$" : [1, "Left"], - ">>" : [1, "Left"], - ">>=" : [1, "Left"], - "<$>" : [1, "Left"], - "." : [1, "Left"], - "," : [1, "Left"]}; +OPInfo = {"+" : [4, "Left"], + "-" : [4, "Left"], + "*" : [5, "Left"], + "/" : [5, "Left"], + "^" : [6, "Right"], + "++" : [4, "Left"], + "==" : [3, "Left"], + ">" : [3, "Left"], + ">=" : [3, "Left"], + "<" : [3, "Left"], + "<=" : [3, "Left"], + "&&" : [3, "Left"], + "||" : [3, "Left"], + "::" : [1, "Left"], + ":" : [2, "Left"], + "$" : [2, "Left"], + ">>" : [2, "Left"], + ">>=" : [2, "Left"], + "<$>" : [2, "Left"], + "." : [2, "Left"], + "," : [2, "Left"], + "->" : [2, "Right"]} module.exports = { IntT : IntT, diff --git a/tokenize.js b/tokenize.js index ccc8dce..23e226f 100755 --- a/tokenize.js +++ b/tokenize.js @@ -6,10 +6,10 @@ var error = require("./errors.js"); var operators = Object.keys(rep.OPInfo); var _ = require("underscore"); -function isDigit(a) { - if (!a) +function isDigit(c) { + if (!c) return false; - var code = a.charCodeAt(); + var code = c.charCodeAt(); if (isNaN(code)) { return false; } @@ -19,11 +19,11 @@ function isDigit(a) { code > 46); } -function isWhitespace(a) { - if (!a) +function isWhitespace(c) { + if (!c) return true; - var code = a.charCodeAt(); + var code = c.charCodeAt(); if (isNaN(code)) { return false; } @@ -34,8 +34,8 @@ function isWhitespace(a) { code === 11); } -function isIdentifier(a) { - var code = a.charCodeAt(); +function isIdentifier(c) { + var code = c.charCodeAt(); return (!isNaN(code) && code !== 41 && code !== 40 && @@ -46,6 +46,13 @@ function isIdentifier(a) { code !== 44); } +function isUpper(c) { + var code = c.charCodeAt(); + return (!isNaN(code) && + (code >= 65) && + (code <= 90)); +} + function tokenizeNum(tokstream, charnum, linenum) { var number = []; var code = tokstream[0].charCodeAt(); @@ -99,7 +106,10 @@ function tokenizeNum(tokstream, charnum, linenum) { * Everything after the operator goes back on to the token stream */ -function tokenizeIdent(tokstream, matchop, charnum, linenum) { +function tokenizeIdent(tokstream, + matchop, + charnum, + linenum) { var identifier = []; var n = 0; while ((!isWhitespace(tokstream[0])) && isIdentifier(tokstream[0]) && !matchop(tokstream)) { @@ -113,6 +123,18 @@ function tokenizeIdent(tokstream, matchop, charnum, linenum) { return [[n, ["identifier", identifier, charnum, linenum]]]; } +function tokenizeCtor(tokstream, + matchop, + charnum, + linenum) { + var ident = tokenizeIdent(tokstream, + matchop, + charnum, + linenum); + ident[0][1][0] = "constructor"; + return ident; +} + function tokenizeStr(tokstream, charnum, linenum) { var stringlit = []; var n = 1; @@ -232,9 +254,9 @@ function tokenize(tokstream, matchop) { break; /* falls through */ - case 45: // '-' + /*case 45: // '-' lambda = peek(tokstream, "arrow", "->"); - if (lambda) { + if (false) { tokens.push($.extend(lambda, [charnum, linenum])); tokstream = tokstream.substr(2); break; @@ -346,7 +368,12 @@ function tokenize(tokstream, matchop) { tokens.push(["identifier", op, charnum, linenum]); } else { - result = tokenizeIdent(tokstream, matchop, charnum, linenum); + if (isUpper(tokstream[0])) { + result = tokenizeCtor(tokstream, matchop, charnum, linenum); + } + else { + result = tokenizeIdent(tokstream, matchop, charnum, linenum); + } for(var index = 0; index < result.length; index++) { charnum++; tokens.push(result[index][1]); @@ -396,5 +423,6 @@ function tokenizeFull(input) { return tokenizeHelp(input, matchop, true); } + module.exports = {tokenize : tokenizeFull, isIdentifier : isIdentifier}; diff --git a/tools.js b/tools.js index 5e65e34..b4d387f 100644 --- a/tools.js +++ b/tools.js @@ -20,6 +20,18 @@ function min(a, b) { } } +function max(a, b) { + if (a > b) { + return 1; + } + else if (a < b) { + return -1; + } + else { + return 0; + } +} + function groupOps(ops) { return _.groupBy(ops.sort(), _.isEqual); } @@ -56,7 +68,8 @@ function operatorMatch(ops) { function (op) { return op.length > 0; }); - var rstring = ops.sort(min).reduce( + ops.sort(min); + var rstring = ops.reduce( function(acc, x) { if (!x || x.length < 1) { return "";