aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-04-14 15:01:04 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-04-14 15:01:04 +0000
commit110d1557782fac4f8cafa27e5cbbcdebefb7a4c7 (patch)
tree4ddae428d11619534363f4e9be8dc10e35e7e5ce
parent9985230c00226826949473c3862c0c3afea74aaf (diff)
* Implemented withs.
-rw-r--r--src/libexpr/eval-test.cc3
-rw-r--r--src/libexpr/eval.cc37
-rw-r--r--src/libexpr/nixexpr.cc12
-rw-r--r--src/libexpr/nixexpr.hh1
4 files changed, 38 insertions, 15 deletions
diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index bcd3670df..f87113e59 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -72,7 +72,8 @@ void run(Strings args)
doTest(state, "let { x = 1; body = x; }");
doTest(state, "with { x = 1; }; x");
doTest(state, "let x = 2; in with { x = 1; }; x"); // => 2
- doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 1
+ doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 2
+ doTest(state, "with { x = 1; }; with { y = 2; }; x"); // => 1
doTest(state, "[ 1 2 3 ]");
doTest(state, "[ 1 2 ] ++ [ 3 4 5 ]");
doTest(state, "123 == 123");
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 9c3c869bf..d93447010 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -253,8 +253,6 @@ Value * EvalState::lookupVar(Env * env, const Symbol & name)
Bindings::iterator j = i->second.attrs->find(name);
if (j != i->second.attrs->end()) return &j->second;
}
-
- throwEvalError("urgh! undefined variable `%1%'", name);
#endif
}
@@ -483,13 +481,15 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
void ExprVar::eval(EvalState & state, Env & env, Value & v)
{
- printMsg(lvlError, format("eval var %1% %2% %3%") % fromWith % level % displ);
-
+ Env * env2 = &env;
+ for (unsigned int l = level; l; --l, env2 = env2->up) ;
+
if (fromWith) {
- abort();
+ Bindings::iterator j = env2->values[0].attrs->find(name);
+ if (j == env2->values[0].attrs->end())
+ throwEvalError("undefined variable `%1%'", name);
+ v = j->second;
} else {
- Env * env2 = &env;
- for (unsigned int l = level; l; --l, env2 = env2->up) ;
state.forceValue(env2->values[displ]);
v = env2->values[displ];
}
@@ -655,17 +655,26 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
void ExprWith::eval(EvalState & state, Env & env, Value & v)
{
- abort();
-#if 0
- Env & env2(state.allocEnv());
+ Env & env2(state.allocEnv(1));
env2.up = &env;
- Value & vAttrs = env2.bindings[state.sWith];
- state.eval(env, attrs, vAttrs);
- state.forceAttrs(vAttrs);
+ state.eval(env, attrs, env2.values[0]);
+ state.forceAttrs(env2.values[0]);
+
+ /* If there is an enclosing `with', copy all attributes that don't
+ appear in this `with'. */
+ if (prevWith != -1) {
+ Env * env3 = &env;
+ for (unsigned int l = prevWith; l; --l, env3 = env3->up) ;
+
+ foreach (Bindings::iterator, i, *env3->values[0].attrs) {
+ Bindings::iterator j = env2.values[0].attrs->find(i->first);
+ if (j == env2.values[0].attrs->end())
+ (*env2.values[0].attrs)[i->first] = i->second; // !!! sharing
+ }
+ }
state.eval(env2, body, v);
-#endif
}
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 46cbb48ac..ab4fa6cba 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -264,6 +264,18 @@ void ExprLet::bindVars(const StaticEnv & env)
void ExprWith::bindVars(const StaticEnv & env)
{
+ /* Does this `with' have an enclosing `with'? If so, record its
+ level so that we can copy the attributes of the enclosing
+ `with'. */
+ const StaticEnv * curEnv;
+ unsigned int level;
+ prevWith = -1;
+ for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++)
+ if (curEnv->isWith) {
+ prevWith = level;
+ break;
+ }
+
attrs->bindVars(env);
StaticEnv newEnv(true, &env);
body->bindVars(newEnv);
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 0422e5cf4..f9ed34f58 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -170,6 +170,7 @@ struct ExprWith : Expr
{
Pos pos;
Expr * attrs, * body;
+ int prevWith;
ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
COMMON_METHODS
};