diff --git a/closure_conversion.js b/closure_conversion.js index 765565d..d8efe07 100644 --- a/closure_conversion.js +++ b/closure_conversion.js @@ -20,8 +20,9 @@ var errors = require("./errors.js"); var parser = require("./parse.js"); var pprint = require("./pprint.js"); var $ = require("./tools.js"); +var _ = require("underscore"); -var notEmpty = $.compose($.not, $.eq([])); +var notEmpty = _.compose($.not, _.partial(_.equal, [])); function fvs(stx) { switch (stx.exprType) { @@ -40,22 +41,22 @@ function fvs(stx) { case "Let": return []; case "Unary": - return $.flatten([stx.op.ident, fvs(stx.val)]); + return _.flatten([stx.op.ident, fvs(stx.val)]); case "Definition": - return $.flatten(fvs(stx.val)); + return _.flatten(fvs(stx.val)); case "Application": - var vs = $.flatten(fvs(stx.p)); - var f_fvs = $.flatten(fvs(stx.func)); - return $.flatten([vs, f_fvs]); + var vs = _.flatten(fvs(stx.p)); + var f_fvs = _.flatten(fvs(stx.func)); + return _.flatten([vs, f_fvs]); case "If": if (stx.elseexp) { var cond_fvs = fvs(stx.condition); var then_fvs = fvs(stx.thenexp); var else_fvs = fvs(stx.elseexp); - return $.flatten([cond_fvs, then_fvs, else_fvs]); + return _.flatten([cond_fvs, then_fvs, else_fvs]); } else { - return $.flatten([fvs(stx.condition), fvs(stx.thenexp)]); + return _.flatten([fvs(stx.condition), fvs(stx.thenexp)]); } break; case "Name": @@ -89,15 +90,15 @@ function closure_convert(stx) { }); var let_fvs = stx.pairs.map(fvs); var body_fvs = fvs(stx.body); - variables = $.flatten(let_fvs); - $.extend(variables, $.flatten(body_fvs)); + variables = _.flatten(let_fvs); + $.extend(variables, _.flatten(body_fvs)); break; case "Function": bound_vars = [stx.p.ident,]; variables = fvs(stx.body); break; } - free_variables = $.difference($.unique(variables), bound_vars); + free_variables = _.difference(_.uniq(variables), bound_vars); return new rep.Closure(bound_vars, free_variables, stx, []); } @@ -141,15 +142,14 @@ function closure_convert_all(stx) { } -//var ast = parser.parse("let { c = trtr a = let {tttt = (rtertret^yyyy) } let { dfsdf = let { asdsd = 3434 } gdfgdfg } (45+(asdddy*uyuy)) q = ((lambda x y -> (x+y)) 4 ui) } (^ wat (a+(ar*b*c^twerp+\"sdfdsfsdfsdfsdf\")*rtcccc))")[0]; -//var ast = parser.parse("let { a = let { b = let {dsdfgf = sddd } fdgfg } gggggg } t")[0]; -//console.log(pprint.pprint(ast)); -//var ast = parser.parse("let { a = 12 b = (a + t) } (a + b * d)")[0]; -//console.log(fvs(ast)); -//var ast = parser.parse("((lambda a b c -> (+ a b c)) 2 3.0 4)"); -//var ast = parser.parse("def (f a b c) 12")[0]; -//console.log(JSON.stringify(ast, null, 4)); -//console.log(pprint.pprint(ast)); -var ast = parser.parse("(lambda a -> if true then ((lambda b -> (+ a b)) q))")[0]; -console.log(JSON.stringify(closure_convert_all(ast), null, 4)); -//console.log(pprint.pprint(ast)); +function test(src) { + var ast = parser.parse(src)[0]; + console.log(JSON.stringify(closure_convert_all(ast), null, 4)); +} + +test("(lambda a -> (+ a b c))"); + +module.export = { + test : test, + closureConvert : closure_convert_all +}; diff --git a/desugar.js b/desugar.js index e9e1feb..cf79a35 100644 --- a/desugar.js +++ b/desugar.js @@ -5,7 +5,7 @@ */ var typ = require("./representation.js"); -var $ = require("./tools.js"); +var _ = require("underscore"); // Lists get desugared to nested function calls // i.e. (cons (cons (cons ...))) @@ -27,12 +27,12 @@ function desugarDefFunc(def) { } function curryFunc(ps, body) { - if ($.empty(ps)) { + if (_.isEmpty(ps)) { return desugar(body); } else { - return new typ.FuncT(desugar($.fst(ps)), - curryFunc($.rst(ps), body)); + return new typ.FuncT(desugar(_.first(ps)), + curryFunc(_.rest(ps), body)); } } diff --git a/parse.js b/parse.js index 1adb19b..1d7d4ac 100755 --- a/parse.js +++ b/parse.js @@ -2,7 +2,8 @@ var fs = require("fs"); var typ = require("./representation.js"); -var tool = require("./tools.js"); +var $ = require("./tools.js"); +var _ = require("underscore"); var tokenizer = require("./tokenize.js"); var desugarer = require("./desugar.js"); var pprint = require("./pprint.js"); @@ -166,7 +167,7 @@ function parseDefFunction(tokens) { } validLet = makeChecker(["Definition", "FunctionDefinition"]); -letEnd = tool.compose(tool.not, makeChecker(["right_brace"])); +letEnd = _.compose($.not, makeChecker(["right_brace"])); function parseLetForm(tokens, linenum, charnum) { if (!fst(tokens)) { @@ -444,8 +445,8 @@ function parseLambda(tokens) { } var invalidArguments = ["def", "comma", "right_paren", "right_square", "right_brace", "left_brace", "right_brace"]; -var validArgument = tool.compose(tool.not, makeChecker(invalidArguments)); -var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"])); +var validArgument = _.compose($.not, makeChecker(invalidArguments)); +var validArgTypes = _.compose($.not, makeChecker(["Definition"])); var validOperator = makeChecker(["identifier"]); /* Parses function application (either infix or prefix) */ @@ -576,7 +577,7 @@ function parse(tokens) { } } -var istr = fs.readFileSync('/dev/stdin').toString(); + function parseFull(tokenized) { var ast = []; try { @@ -595,11 +596,4 @@ module.exports = { parse : function(str) { return parseFull(tokenizer.tokenize(str)); } }; - - -console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint).join("\n")); - -//console.log(tokenizer.tokenize(istr)); -//console.log(parseFull(tokenizer.tokenize(istr))); - -//module.exports = {parse : tool.compose(parseFull, tokenizer.tokenize) }; +//var istr = fs.readFileSync('/dev/stdin').toString(); diff --git a/patterns.js b/patterns.js new file mode 100644 index 0000000..3dcf3e9 --- /dev/null +++ b/patterns.js @@ -0,0 +1,8 @@ +/* Lightweight pattern matching for lists of strings + * + */ +var $ = require("./tools.js"); + + + + diff --git a/representation.js b/representation.js index e357c9e..ea4ba57 100644 --- a/representation.js +++ b/representation.js @@ -1,5 +1,3 @@ -var tool = require("./tools.js"); - var Expression = { display : function() { @@ -25,6 +23,7 @@ function Closure(bound_vars, free_vars, body, env) { this.free_vars = free_vars; this.body = body; this.env = env; + this.exprType = "Closure"; return this; } diff --git a/tokenize.js b/tokenize.js index 9397b47..47ffcc4 100755 --- a/tokenize.js +++ b/tokenize.js @@ -1,9 +1,10 @@ #! /usr/bin/node var rep = require("./representation.js"); -var tools = require("./tools.js"); +var $ = require("./tools.js"); var error = require("./errors.js"); var operators = Object.keys(rep.OPInfo); +var _ = require("underscore"); function isDigit(a) { if (!a) @@ -337,25 +338,31 @@ function tokenize(tokstream, matchop) { return tokens; } -function tokenizeHelp(input, matchop) { +function tokenizeHelp(input, matchop, strip_whitespace) { try { return tokenize(input, matchop).reverse().filter(function(x) { - return x[0] !== "whitespace"; + if (strip_whitespace) { + return x[0] !== "whitespace"; + } + else { + return true; + } }); } catch (e) { console.log(e.stxerror()); process.exit(1); } } + var defop_pattern = ["defop", "integer", "identifier", "left_paren", "identifier", "identifier", "identifier", "right_paren"]; function tokenizeFull(input) { - var matchop = tools.opMatch(operators); - var initialPass = tokenizeHelp(input, matchop).reverse(); + var matchop = $.opMatch(operators); + var initialPass = tokenizeHelp(input, _.constant(false), true).reverse(); for (var i = 0; i < initialPass.length; i++) { - if (initialPass.slice(i, i+8).map(tools.fst).every( + if (initialPass.slice(i, i+8).map(_.first).every( function(x, i) { return x === defop_pattern[i]; })) { @@ -365,9 +372,8 @@ function tokenizeFull(input) { } operators = Object.keys(rep.OPInfo); - matchop = tools.opMatch(operators); - return tokenizeHelp(input, matchop); + matchop = $.opMatch(operators); + return tokenizeHelp(input, matchop, true); } - module.exports = {tokenize : tokenizeFull}; diff --git a/tools.js b/tools.js index a2b2084..bccb8b1 100644 --- a/tools.js +++ b/tools.js @@ -1,131 +1,34 @@ -function empty(xs) { - return xs.length === 0; -} - -function identity(a) { - return a; -} +var _ = require("underscore"); -function compose(f, g) { - return function(x) { - return f(g(x)); - }; +function empty(xs) { + return _.size(xs) < 1; } function not(x) { return !x; } -function on(g, f) { - return function(x,y) { - return g(f(x), f(y)); - }; -} - -function maxf(f, a, b) { - if (f(a) >= f(b)) - return a; - return b; -} - -function max(a, b) { - if (a > b) - return 1; - else if (a < b) - return -1; - else - return 0; -} - function min(a, b) { - if (a < b) + if (a < b) { return 1; - else if (a > b) - return -1; - else - return 0; -} - -function maxBy(f, xs) { - if (xs.length < 1) - return false; - return xs.reduce(function(maxval, a) { return maxf(f, maxval, a); }); -} - -function sortBy(f, xs) { - return xs.sort(f); -} - -function len(xs) { - return xs.length; -} - -function takeWhile(f, xs) { - var result = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i])) - result.push(xs[i]); - else - break; } - return result; -} - -function dropWhile(f, xs) { - for (i = 0; i < xs.length; i++) { - if (!f(xs[i])) - break; + else if (a > b) { + return -1; } - return xs.slice(i); -} - -function span(f, xs) { - return [takeWhile(f, xs), dropWhile(f, xs)]; -} - -function eq(a) { - return function(b) { - return a[0] === b[0]; - }; -} - -function fst(xs) { - return xs[0]; -} - -function rst(xs) { - return xs.slice(1,xs.length); -} - -function equal(a) { - return function(b) { - return a === b; - }; -} - -function groupBy(eq, xs) { - var groups = []; - var spanned; - while (xs.length > 0) { - spanned = span(eq(xs[0]), xs.slice(1)); - groups.push([xs[0]].concat(spanned[0])); - xs = spanned[1]; + else { + return 0; } - return groups; } function groupOps(ops) { - return groupBy(function (x) { return function(y) { return x === y; };}, ops.sort()); -} - -function unique(ops) { - return groupOps(ops).map(fst); + return _.groupBy(ops.sort(), _.isEqual); } function find(f, haystack) { for(var i = 0; i < haystack.length; i++) { - if (f(haystack[i])) + if (f(haystack[i])) { return i; + } } return false; } @@ -139,10 +42,14 @@ function dict(pairs) { } function flatten(xs) { - if (!(xs instanceof Array)) + if (!(xs instanceof Array)) { return xs; - if (xs.every(function (x) { return !(x instanceof Array); })) + } + if (xs.every(function (x) { + return !(x instanceof Array); + })) { return xs; + } return [].concat.apply([], xs); } @@ -151,21 +58,6 @@ function extend(xs, ys) { return xs; } -function difference(xs, ys) { - var difflist = groupOps(extend(xs, ys)); - return difflist.filter(function (group) { - if (group.length > 1) { - return false; - } - return true; - }).map(fst); -} - -/* - * Problem: - * >> > >>^ <- longest one must be matched - * regex? - */ RegExp.escape= function(s) { return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); }; @@ -178,36 +70,20 @@ function operatorMatch(ops) { var reg = new RegExp(rstring); return function(x) { var matched = reg.exec(x); - if (matched[0]) + if (matched[0]) { return matched[0]; - else + } + else { return false; + } }; } - -/* -var print = console.log; - -var testOps = [">>", ">>&", ">", "aaaaa:", ">="]; - -var matcher = operatorMatch(testOps); -print(matcher(">=")); -*/ - -module.exports = {compose : compose, - not : not, - on : on, - maxBy : maxBy, - len : len, - groupOps : groupOps, - opMatch : operatorMatch, - dict: dict, - unique : unique, - fst : fst, - rst : rst, - eq: eq, - extend : extend, - flatten : flatten, - difference : difference, - empty : empty }; +module.exports = { + not : not, + groupOps : groupOps, + opMatch : operatorMatch, + dict: dict, + extend : extend, + empty : empty, +};