Browse Source

full closure conversion sort of works, doesn't map variables on to types yet, will have to add that

pull/1/head
nisstyre56 11 years ago
parent
commit
d366da152a
  1. 96
      closure_conversion.js

96
closure_conversion.js

@ -1,17 +1,12 @@
/* Takes an AST and converts all of the functions into closures. /* Takes an AST and converts all of the functions into closures.
* A closure is a triple of: * A closure is a triple of:
* a mapping from names to expressions * the bound variables in a function or let
* a mapping from names to type expressions * the free variables in a function or let
* a function (which includes the formal parameters and the body) * a function body or let body and bound values
* The closure has the property that all of the free variables of the function * 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 * are in the environment, or an exception is raised because the variable is not bound
* in the current environment. * in the current environment.
* A free variable is simply those that are not in the list of formal parameters. * A free variable is simply those that are not in the list of formal parameters or bound variables if it is a let
* 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
* *
* Therefore in order to call a closure one must first extract the actual function and then * 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. * call the function with the environment associated with it.
@ -28,7 +23,7 @@ var $ = require("./tools.js");
var notEmpty = $.compose($.not, $.eq([])); var notEmpty = $.compose($.not, $.eq([]));
function fvs_helper(stx) { function fvs(stx) {
switch (stx.exprType) { switch (stx.exprType) {
case "Integer": case "Integer":
return []; return [];
@ -45,22 +40,22 @@ function fvs_helper(stx) {
case "Let": case "Let":
return []; return [];
case "Unary": case "Unary":
return $.flatten([stx.op.ident, fvs_helper(stx.val)]); return $.flatten([stx.op.ident, fvs(stx.val)]);
case "Definition": case "Definition":
return $.flatten(fvs_helper(stx.val)); return $.flatten(fvs(stx.val));
case "Application": case "Application":
var vs = $.flatten(fvs_helper(stx.p)); var vs = $.flatten(fvs(stx.p));
var f_fvs = $.flatten(fvs_helper(stx.func)); var f_fvs = $.flatten(fvs(stx.func));
return $.flatten([vs, f_fvs]); return $.flatten([vs, f_fvs]);
case "If": case "If":
if (stx.elseexp) { if (stx.elseexp) {
var cond_fvs = fvs_helper(stx.condition); var cond_fvs = fvs(stx.condition);
var then_fvs = fvs_helper(stx.thenexp); var then_fvs = fvs(stx.thenexp);
var else_fvs = fvs_helper(stx.elseexp); var else_fvs = fvs(stx.elseexp);
return $.flatten([cond_fvs, then_fvs, else_fvs]); return $.flatten([cond_fvs, then_fvs, else_fvs]);
} }
else { else {
return $.flatten([fvs_helper(stx.condition), fvs_helper(stx.thenexp)]); return $.flatten([fvs(stx.condition), fvs(stx.thenexp)]);
} }
break; break;
case "Name": 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" && if (stx.exprType !== "Function" &&
stx.exprType !== "Let") { stx.exprType !== "Let") {
throw errors.JInternalError( throw errors.JInternalError(
@ -79,7 +79,7 @@ function fvs(stx) {
return a+" "+b; return a+" "+b;
}, "")); }, ""));
} }
var variables, free_variables, bound_vars; var variables, free_variables, bound_vars, stx_type;
switch (stx.exprType) { switch (stx.exprType) {
case "Let": case "Let":
@ -87,19 +87,60 @@ function fvs(stx) {
function (stx) { function (stx) {
return stx.ident.ident; return stx.ident.ident;
}); });
var let_fvs = stx.pairs.map(fvs_helper); var let_fvs = stx.pairs.map(fvs);
var body_fvs = fvs_helper(stx.body); var body_fvs = fvs(stx.body);
variables = $.flatten(let_fvs); variables = $.flatten(let_fvs);
$.extend(variables, $.flatten(body_fvs)); $.extend(variables, $.flatten(body_fvs));
break; break;
case "Function": case "Function":
bound_vars = [stx.p.ident,]; 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, []); 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 { 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]; //var ast = parser.parse("let { a = let { b = let {dsdfgf = sddd } fdgfg } gggggg } t")[0];
//console.log(pprint.pprint(ast)); //console.log(pprint.pprint(ast));
@ -109,5 +150,6 @@ function fvs(stx) {
//var ast = parser.parse("def (f a b c) 12")[0]; //var ast = parser.parse("def (f a b c) 12")[0];
//console.log(JSON.stringify(ast, null, 4)); //console.log(JSON.stringify(ast, null, 4));
//console.log(pprint.pprint(ast)); //console.log(pprint.pprint(ast));
var ast = parser.parse("(lambda a -> (pi*e+c-a))")[0]; var ast = parser.parse("(lambda a -> if true then ((lambda b -> (+ a b)) q))")[0];
console.log(fvs(ast)); console.log(JSON.stringify(closure_convert_all(ast), null, 4));
//console.log(pprint.pprint(ast));

Loading…
Cancel
Save