diff options
-rw-r--r-- | src/lift.cpp | 30 | ||||
-rw-r--r-- | src/resp.hpp | 2 | ||||
-rw-r--r-- | test/closure.resp | 2 |
3 files changed, 22 insertions, 12 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* diff --git a/src/resp.hpp b/src/resp.hpp index 24e79ff..7767d33 100644 --- a/src/resp.hpp +++ b/src/resp.hpp @@ -833,7 +833,7 @@ struct CEnv { for (; i != end(); ++i) if ((*i)->sym() == sym->sym()) break; - + if (i != end()) { return i - begin() + 1; } else { diff --git a/test/closure.resp b/test/closure.resp index fb5a41d..75e632b 100644 --- a/test/closure.resp +++ b/test/closure.resp @@ -1,3 +1,5 @@ +(def (test a b c) (fn (x) (* (+ x 0) a))) + (def (multiplier factor) (fn (x) (* (+ x 0) factor))) (def doubler (multiplier 2)) |