aboutsummaryrefslogtreecommitdiffstats
path: root/src/lift.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lift.cpp')
-rw-r--r--src/lift.cpp30
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*