diff options
Diffstat (limited to 'src/lift.cpp')
-rw-r--r-- | src/lift.cpp | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/src/lift.cpp b/src/lift.cpp index 6bd991b..67ae580 100644 --- a/src/lift.cpp +++ b/src/lift.cpp @@ -33,18 +33,26 @@ using namespace std; static const AST* lift_symbol(CEnv& cenv, Code& code, const ASymbol* sym) throw() { - if (!cenv.liftStack.empty() && cenv.name(cenv.liftStack.top().fn) == sym->sym()) { - return cenv.penv.sym("_me"); // Reference to innermost function - } else if (!cenv.liftStack.empty() && !cenv.code.innermost(sym)) { - // Replace symbol with code to access free variable from closure - const int32_t index = cenv.liftStack.top().index(sym); - return tup<ATuple>(sym->loc, cenv.penv.sym("."), - cenv.penv.sym("_me"), - new ALiteral<int32_t>(T_INT32, index, Cursor()), - NULL); - } else { - return sym; + if (!cenv.liftStack.empty()) { + CEnv::FreeVars& vars = cenv.liftStack.top(); + if (cenv.name(vars.fn) == sym->sym()) { + // Reference to innermost function, replace with "_me" + return cenv.penv.sym("_me"); + + } else if (!cenv.code.innermost(sym)) { + /* Free variable, replace with "(. _me i)" where i is the index + * of the free variable in the closure. + * If this free variable hasn't been encountered yet, it is appended + * to the closure (the calling lift_fn will use cenv.liftStack.top() + * to construct the closure after the fn body has been lifted). + */ + return tup<ATuple>(sym->loc, cenv.penv.sym("."), + cenv.penv.sym("_me"), + new ALiteral<int32_t>(T_INT32, vars.index(sym), Cursor()), + NULL); + } } + return sym; } static const AST* |