From 7d47498b5ea1ad4685bad954e5407f628f7f5595 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 13 Apr 2010 13:42:25 +0000 Subject: [PATCH] * Evaluate lets directly (i.e. without desugaring to `rec { attrs...; = e; }.). This prevents the unnecessary allocation of an attribute set. --- src/libexpr/eval.cc | 25 +++++++++++++++++++++++++ src/libexpr/eval.hh | 1 + src/libexpr/nixexpr.cc | 10 ++++++++++ src/libexpr/nixexpr.hh | 8 ++++++++ src/libexpr/parser.y | 2 +- 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index ffeae8d73..fbd618d41 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::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 fe91db2ef..0491fc481 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 922066c23..0abc2a457 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::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 f0c05d435..ccddb1629 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 c1c17e2b2..b746e757e 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 ;