about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc25
-rw-r--r--src/libexpr/eval.hh1
-rw-r--r--src/libexpr/nixexpr.cc10
-rw-r--r--src/libexpr/nixexpr.hh8
-rw-r--r--src/libexpr/parser.y2
5 files changed, 45 insertions, 1 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index ffeae8d731..fbd618d417 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -456,6 +456,31 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
 }
 
 
+void ExprLet::eval(EvalState & state, Env & env, Value & v)
+{
+    /* Create a new environment that contains the attributes in this
+       `let'. */
+    Env & env2(state.allocEnv());
+    env2.up = &env;
+        
+    /* The recursive attributes are evaluated in the new
+       environment. */
+    foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) {
+        Value & v2 = env2.bindings[i->first];
+        mkThunk(v2, env2, i->second);
+    }
+
+    /* The inherited attributes, on the other hand, are evaluated in
+       the original environment. */
+    foreach (list<Symbol>::iterator, i, attrs->inherited) {
+        Value & v2 = env2.bindings[*i];
+        mkCopy(v2, *state.lookupVar(&env, *i));
+    }
+
+    state.eval(env2, body, v);
+}
+
+
 void ExprList::eval(EvalState & state, Env & env, Value & v)
 {
     state.mkList(v, elems.size());
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index fe91db2efd..0491fc481f 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -244,6 +244,7 @@ private:
 
     friend class ExprVar;
     friend class ExprAttrs;
+    friend class ExprLet;
 
 public:
     
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 922066c234..0abc2a4573 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -87,6 +87,16 @@ void ExprLambda::show(std::ostream & str)
     str << ": " << *body << ")";
 }
 
+void ExprLet::show(std::ostream & str)
+{
+    str << "let ";
+    foreach (list<Symbol>::iterator, i, attrs->inherited)
+        str << "inherit " << *i << "; ";
+    foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
+        str << i->first << " = " << *i->second << "; ";
+    str << "in " << *body;
+}
+
 void ExprWith::show(std::ostream & str)
 {
     str << "with " << *attrs << "; " << *body;
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index f0c05d4352..ccddb16298 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -139,6 +139,14 @@ struct ExprLambda : Expr
     COMMON_METHODS
 };
 
+struct ExprLet : Expr
+{
+    ExprAttrs * attrs;
+    Expr * body;
+    ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { };
+    COMMON_METHODS
+};
+
 struct ExprWith : Expr
 {
     Pos pos;
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index c1c17e2b26..b746e757eb 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -306,7 +306,7 @@ expr_function
   | WITH expr ';' expr_function
     { $$ = new ExprWith(CUR_POS, $2, $4); }
   | LET binds IN expr_function
-    { $2->attrs[data->sLetBody] = $4; $2->recursive = true; $$ = new ExprSelect($2, data->sLetBody); }
+    { $$ = new ExprLet($2, $4); }
   | expr_if
   ;