|
|
@ -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));
|
|
|
|