aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lift.cpp30
-rw-r--r--src/resp.hpp2
-rw-r--r--test/closure.resp2
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))