From d366da152a9eef770ca99bff610046119a74f711 Mon Sep 17 00:00:00 2001 From: nisstyre56 Date: Thu, 13 Mar 2014 03:29:24 -0400 Subject: [PATCH] full closure conversion sort of works, doesn't map variables on to types yet, will have to add that --- closure_conversion.js | 96 +++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/closure_conversion.js b/closure_conversion.js index 023f6d9..765565d 100644 --- a/closure_conversion.js +++ b/closure_conversion.js @@ -1,17 +1,12 @@ /* Takes an AST and converts all of the functions into closures. * A closure is a triple of: - * a mapping from names to expressions - * a mapping from names to type expressions - * a function (which includes the formal parameters and the body) - * The closure has the property that all of the free variables of the function + * 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 + * 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. - * A free variable is simply those that are not in the list of formal parameters. - * We start with the global environment and traverse the AST. Every time a new function is entered - * the current environment gets $.extended with the formal parameters of the function. - * When a let is encountered the current environment also gets $.extended. - * The algorithm continues for any further function definitions in that branch - * otherwise it just stops for that particular branch and continues with the rest of the AST + * A free variable is simply those that are not in the list of formal parameters or bound variables if it is a let * * Therefore in order to call a closure one must first extract the actual function and then * call the function with the environment associated with it. @@ -28,7 +23,7 @@ var $ = require("./tools.js"); var notEmpty = $.compose($.not, $.eq([])); -function fvs_helper(stx) { +function fvs(stx) { switch (stx.exprType) { case "Integer": return []; @@ -45,22 +40,22 @@ function fvs_helper(stx) { case "Let": return []; case "Unary": - return $.flatten([stx.op.ident, fvs_helper(stx.val)]); + return $.flatten([stx.op.ident, fvs(stx.val)]); case "Definition": - return $.flatten(fvs_helper(stx.val)); + return $.flatten(fvs(stx.val)); case "Application": - var vs = $.flatten(fvs_helper(stx.p)); - var f_fvs = $.flatten(fvs_helper(stx.func)); + 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_helper(stx.condition); - var then_fvs = fvs_helper(stx.thenexp); - var else_fvs = fvs_helper(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]); } else { - return $.flatten([fvs_helper(stx.condition), fvs_helper(stx.thenexp)]); + return $.flatten([fvs(stx.condition), fvs(stx.thenexp)]); } break; case "Name": @@ -68,7 +63,12 @@ function fvs_helper(stx) { } } -function fvs(stx) { +function closure_convert(stx) { + /* Takes a stx object that is either + * a lambda + * a let + * and returns a closure wrapped around that stx object + */ if (stx.exprType !== "Function" && stx.exprType !== "Let") { throw errors.JInternalError( @@ -79,7 +79,7 @@ function fvs(stx) { return a+" "+b; }, "")); } - var variables, free_variables, bound_vars; + var variables, free_variables, bound_vars, stx_type; switch (stx.exprType) { case "Let": @@ -87,19 +87,60 @@ function fvs(stx) { function (stx) { return stx.ident.ident; }); - var let_fvs = stx.pairs.map(fvs_helper); - var body_fvs = fvs_helper(stx.body); + var let_fvs = stx.pairs.map(fvs); + var body_fvs = fvs(stx.body); variables = $.flatten(let_fvs); $.extend(variables, $.flatten(body_fvs)); break; case "Function": bound_vars = [stx.p.ident,]; - variables = fvs_helper(stx.body); + variables = fvs(stx.body); + break; } - free_variables = $.difference($.unique(variables, bound_vars)); + free_variables = $.difference($.unique(variables), bound_vars); return new rep.Closure(bound_vars, free_variables, stx, []); } +function closure_convert_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); + return closure; + case "Function": + closure = closure_convert(stx); + closure.body.body = closure_convert_all(closure.body.body); + return closure; + case "Unary": + stx.val = closure_convert_all(stx.val); + return stx; + case "Application": + stx.func = closure_convert_all(stx.func); + stx.p = closure_convert_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); + return stx; + } + else { + stx.condition = closure_convert_all(stx.condition); + stx.thenexp = closure_convert_all(stx.thenexp); + return stx; + } + case "Definition": + stx.val = closure_convert_all(stx.val); + return stx; + default: + return 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)); @@ -109,5 +150,6 @@ function fvs(stx) { //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 -> (pi*e+c-a))")[0]; -console.log(fvs(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));