aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-04-12 18:30:11 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-04-12 18:30:11 +0000
commit4d6ad5be1738c64b1de4274cafbd4b8f23ca287c (patch)
tree212ef4ad291875c8409d4b22c2ec07c9a1bbbacb /src/libexpr/eval.cc
parented711f73bce8786b1a37bd718eb97276d0916484 (diff)
* Don't use ATerms for the abstract syntax trees anymore. Not
finished yet.
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc467
1 files changed, 244 insertions, 223 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 7434aa842..8ead986b8 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -4,7 +4,6 @@
#include "util.hh"
#include "store-api.hh"
#include "derivations.hh"
-#include "nixexpr-ast.hh"
#include "globals.hh"
#include <cstring>
@@ -45,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v)
case tAttrs:
str << "{ ";
foreach (Bindings::iterator, i, *v.attrs)
- str << aterm2String(i->first) << " = " << i->second << "; ";
+ str << i->first << " = " << i->second << "; ";
str << "}";
break;
case tList:
@@ -96,8 +95,6 @@ EvalState::EvalState() : baseEnv(allocEnv())
nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0;
deepestStack = (char *) -1;
- initNixExprHelpers();
-
createBaseEnv();
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
@@ -112,9 +109,9 @@ EvalState::~EvalState()
void EvalState::addConstant(const string & name, Value & v)
{
- baseEnv.bindings[toATerm(name)] = v;
+ baseEnv.bindings[name] = v;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
- (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
+ (*baseEnv.bindings["builtins"].attrs)[name2] = v;
nrValues += 2;
}
@@ -126,9 +123,9 @@ void EvalState::addPrimOp(const string & name,
v.type = tPrimOp;
v.primOp.arity = arity;
v.primOp.fun = primOp;
- baseEnv.bindings[toATerm(name)] = v;
+ baseEnv.bindings[name] = v;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
- (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
+ (*baseEnv.bindings["builtins"].attrs)[name2] = v;
nrValues += 2;
}
@@ -212,12 +209,12 @@ void mkPath(Value & v, const char * s)
}
-static Value * lookupWith(Env * env, Sym name)
+static Value * lookupWith(Env * env, const Sym & name)
{
if (!env) return 0;
Value * v = lookupWith(env->up, name);
if (v) return v;
- Bindings::iterator i = env->bindings.find(sWith);
+ Bindings::iterator i = env->bindings.find("<with>");
if (i == env->bindings.end()) return 0;
Bindings::iterator j = i->second.attrs->find(name);
if (j != i->second.attrs->end()) return &j->second;
@@ -225,7 +222,7 @@ static Value * lookupWith(Env * env, Sym name)
}
-static Value * lookupVar(Env * env, Sym name)
+static Value * lookupVar(Env * env, const Sym & name)
{
/* First look for a regular variable binding for `name'. */
for (Env * env2 = env; env2; env2 = env2->up) {
@@ -251,7 +248,7 @@ static Value * lookupVar(Env * env, Sym name)
}
#endif
- throwEvalError("undefined variable `%1%'", aterm2String(name));
+ throwEvalError("undefined variable `%1%'", name);
}
@@ -284,7 +281,7 @@ void EvalState::mkAttrs(Value & v)
}
-void EvalState::mkThunk_(Value & v, Expr expr)
+void EvalState::mkThunk_(Value & v, Expr * expr)
{
mkThunk(v, baseEnv, expr);
}
@@ -302,11 +299,11 @@ void EvalState::evalFile(const Path & path, Value & v)
{
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
- Expr e = parseTrees.get(toATerm(path));
+ Expr * e = parseTrees[path];
if (!e) {
- e = parseExprFromFile(*this, path);
- parseTrees.set(toATerm(path), e);
+ e = parseExprFromFile(path);
+ parseTrees[path] = e;
}
try {
@@ -334,7 +331,7 @@ struct RecursionCounter
};
-void EvalState::eval(Env & env, Expr e, Value & v)
+void EvalState::eval(Env & env, Expr * e, Value & v)
{
/* When changing this function, make sure that you don't cause a
(large) increase in stack consumption! */
@@ -350,6 +347,9 @@ void EvalState::eval(Env & env, Expr e, Value & v)
nrEvaluated++;
+ e->eval(*this, env, v);
+
+#if 0
Sym name;
int n;
ATerm s; ATermList context, es;
@@ -357,138 +357,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
Expr e1, e2, e3, fun, arg, attrs;
Pattern pat; Expr body; Pos pos;
- if (matchVar(e, name)) {
- Value * v2 = lookupVar(&env, name);
- forceValue(*v2);
- v = *v2;
- }
-
- else if (matchInt(e, n))
- mkInt(v, n);
-
- else if (matchStr(e, s, context)) {
- assert(context == ATempty);
- mkString(v, ATgetName(ATgetAFun(s)));
- }
-
- else if (matchPath(e, s))
- mkPath(v, ATgetName(ATgetAFun(s)));
-
- else if (matchAttrs(e, es)) {
- mkAttrs(v);
- ATerm e2, pos;
- for (ATermIterator i(es); i; ++i) {
- if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
- Value & v2 = (*v.attrs)[name];
- nrValues++;
- mkThunk(v2, env, e2);
- }
- }
-
- else if (matchRec(e, rbnds, nrbnds)) {
- /* Create a new environment that contains the attributes in
- this `rec'. */
- Env & env2(allocEnv());
- env2.up = &env;
-
- v.type = tAttrs;
- v.attrs = &env2.bindings;
-
- /* The recursive attributes are evaluated in the new
- environment. */
- ATerm name, e2, pos;
- for (ATermIterator i(rbnds); i; ++i) {
- if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
- Value & v2 = env2.bindings[name];
- nrValues++;
- mkThunk(v2, env2, e2);
- }
-
- /* The non-recursive attributes, on the other hand, are
- evaluated in the original environment. */
- for (ATermIterator i(nrbnds); i; ++i) {
- if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
- Value & v2 = env2.bindings[name];
- nrValues++;
- mkThunk(v2, env, e2);
- }
- }
-
- else if (matchSelect(e, e2, name)) {
- Value v2;
- eval(env, e2, v2);
- forceAttrs(v2); // !!! eval followed by force is slightly inefficient
- Bindings::iterator i = v2.attrs->find(name);
- if (i == v2.attrs->end())
- throwEvalError("attribute `%1%' missing", aterm2String(name));
- try {
- forceValue(i->second);
- } catch (Error & e) {
- addErrorPrefix(e, "while evaluating the attribute `%1%':\n", aterm2String(name));
- throw;
- }
- v = i->second;
- }
-
- else if (matchFunction(e, pat, body, pos)) {
- v.type = tLambda;
- v.lambda.env = &env;
- v.lambda.pat = pat;
- v.lambda.body = body;
- }
-
- else if (matchCall(e, fun, arg)) {
- Value vFun;
- eval(env, fun, vFun);
- Value vArg;
- mkThunk(vArg, env, arg); // !!! should this be on the heap?
- callFunction(vFun, vArg, v);
- }
-
- else if (matchWith(e, attrs, body, pos)) {
- Env & env2(allocEnv());
- env2.up = &env;
-
- Value & vAttrs = env2.bindings[sWith];
- nrValues++;
- eval(env, attrs, vAttrs);
- forceAttrs(vAttrs);
-
- eval(env2, body, v);
- }
-
- else if (matchList(e, es)) {
- mkList(v, ATgetLength(es));
- for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
- mkThunk(v.list.elems[n], env, ATgetFirst(es));
- }
-
- else if (matchOpEq(e, e1, e2)) {
- Value v1; eval(env, e1, v1);
- Value v2; eval(env, e2, v2);
- mkBool(v, eqValues(v1, v2));
- }
-
- else if (matchOpNEq(e, e1, e2)) {
- Value v1; eval(env, e1, v1);
- Value v2; eval(env, e2, v2);
- mkBool(v, !eqValues(v1, v2));
- }
-
- else if (matchOpConcat(e, e1, e2)) {
- Value v1; eval(env, e1, v1);
- forceList(v1);
- Value v2; eval(env, e2, v2);
- forceList(v2);
- mkList(v, v1.list.length + v2.list.length);
- /* !!! This loses sharing with the original lists. We could
- use a tCopy node, but that would use more memory. */
- for (unsigned int n = 0; n < v1.list.length; ++n)
- v.list.elems[n] = v1.list.elems[n];
- for (unsigned int n = 0; n < v2.list.length; ++n)
- v.list.elems[n + v1.list.length] = v2.list.elems[n];
- }
-
else if (matchConcatStrings(e, es)) {
PathSet context;
std::ostringstream s;
@@ -521,10 +389,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
mkString(v, s.str(), context);
}
- /* Conditionals. */
- else if (matchIf(e, e1, e2, e3))
- eval(env, evalBool(env, e1) ? e2 : e3, v);
-
/* Assertions. */
else if (matchAssert(e, e1, e2, pos)) {
if (!evalBool(env, e1))
@@ -536,30 +400,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
else if (matchOpNot(e, e1))
mkBool(v, !evalBool(env, e1));
- /* Implication. */
- else if (matchOpImpl(e, e1, e2))
- return mkBool(v, !evalBool(env, e1) || evalBool(env, e2));
-
- /* Conjunction (logical AND). */
- else if (matchOpAnd(e, e1, e2))
- mkBool(v, evalBool(env, e1) && evalBool(env, e2));
-
- /* Disjunction (logical OR). */
- else if (matchOpOr(e, e1, e2))
- mkBool(v, evalBool(env, e1) || evalBool(env, e2));
-
- /* Attribute set update (//). */
- else if (matchOpUpdate(e, e1, e2)) {
- Value v2;
- eval(env, e1, v2);
-
- cloneAttrs(v2, v);
-
- eval(env, e2, v2);
- foreach (Bindings::iterator, i, *v2.attrs)
- (*v.attrs)[i->first] = i->second; // !!! sharing
- }
-
/* Attribute existence test (?). */
else if (matchOpHasAttr(e, e1, name)) {
Value vAttrs;
@@ -567,8 +407,130 @@ void EvalState::eval(Env & env, Expr e, Value & v)
forceAttrs(vAttrs);
mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
}
+#endif
+}
+
+
+void EvalState::eval(Expr * e, Value & v)
+{
+ eval(baseEnv, e, v);
+}
- else abort();
+
+bool EvalState::evalBool(Env & env, Expr * e)
+{
+ Value v;
+ eval(env, e, v);
+ if (v.type != tBool)
+ throwTypeError("value is %1% while a Boolean was expected", showType(v));
+ return v.boolean;
+}
+
+
+void ExprInt::eval(EvalState & state, Env & env, Value & v)
+{
+ mkInt(v, n);
+}
+
+
+void ExprString::eval(EvalState & state, Env & env, Value & v)
+{
+ mkString(v, s.c_str());
+}
+
+
+void ExprPath::eval(EvalState & state, Env & env, Value & v)
+{
+ mkPath(v, s.c_str());
+}
+
+
+void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
+{
+ if (recursive) {
+
+ /* Create a new environment that contains the attributes in
+ this `rec'. */
+ Env & env2(state.allocEnv());
+ env2.up = &env;
+
+ v.type = tAttrs;
+ v.attrs = &env2.bindings;
+
+ /* The recursive attributes are evaluated in the new
+ environment. */
+ foreach (Attrs::iterator, i, 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<string>::iterator, i, inherited) {
+ Value & v2 = env2.bindings[*i];
+ mkCopy(v2, *lookupVar(&env, *i));
+ }
+ }
+
+ else {
+ state.mkAttrs(v);
+ foreach (Attrs::iterator, i, attrs) {
+ Value & v2 = (*v.attrs)[i->first];
+ mkThunk(v2, env, i->second);
+ }
+ }
+}
+
+
+void ExprList::eval(EvalState & state, Env & env, Value & v)
+{
+ state.mkList(v, elems.size());
+ for (unsigned int n = 0; n < v.list.length; ++n)
+ mkThunk(v.list.elems[n], env, elems[n]);
+}
+
+
+void ExprVar::eval(EvalState & state, Env & env, Value & v)
+{
+ Value * v2 = lookupVar(&env, name);
+ state.forceValue(*v2);
+ v = *v2;
+}
+
+
+void ExprSelect::eval(EvalState & state, Env & env, Value & v)
+{
+ Value v2;
+ state.eval(env, e, v2);
+ state.forceAttrs(v2); // !!! eval followed by force is slightly inefficient
+ Bindings::iterator i = v2.attrs->find(name);
+ if (i == v2.attrs->end())
+ throwEvalError("attribute `%1%' missing", name);
+ try {
+ state.forceValue(i->second);
+ } catch (Error & e) {
+ addErrorPrefix(e, "while evaluating the attribute `%1%':\n", name);
+ throw;
+ }
+ v = i->second;
+}
+
+
+void ExprLambda::eval(EvalState & state, Env & env, Value & v)
+{
+ v.type = tLambda;
+ v.lambda.env = &env;
+ v.lambda.fun = this;
+}
+
+
+void ExprApp::eval(EvalState & state, Env & env, Value & v)
+{
+ Value vFun;
+ state.eval(env, e1, vFun);
+ Value vArg;
+ mkThunk(vArg, env, e2); // !!! should this be on the heap?
+ state.callFunction(vFun, vArg, v);
}
@@ -613,19 +575,17 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
Env & env2(allocEnv());
env2.up = fun.lambda.env;
- ATermList formals; ATerm ellipsis, name;
-
- if (matchVarPat(fun.lambda.pat, name)) {
- Value & vArg = env2.bindings[name];
+ if (!fun.lambda.fun->matchAttrs) {
+ Value & vArg = env2.bindings[fun.lambda.fun->arg];
nrValues++;
vArg = arg;
}
- else if (matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) {
+ else {
forceAttrs(arg);
- if (name != sNoAlias) {
- env2.bindings[name] = arg;
+ if (!fun.lambda.fun->arg.empty()) {
+ env2.bindings[fun.lambda.fun->arg] = arg;
nrValues++;
}
@@ -633,21 +593,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
there is no matching actual argument but the formal
argument has a default, use the default. */
unsigned int attrsUsed = 0;
- for (ATermIterator i(formals); i; ++i) {
- Expr def; Sym name;
- DefaultValue def2;
- if (!matchFormal(*i, name, def2)) abort(); /* can't happen */
-
- Bindings::iterator j = arg.attrs->find(name);
+ foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
+ Bindings::iterator j = arg.attrs->find(i->name);
- Value & v = env2.bindings[name];
+ Value & v = env2.bindings[i->name];
nrValues++;
if (j == arg.attrs->end()) {
- if (!matchDefaultValue(def2, def)) def = 0;
- if (def == 0) throwTypeError("the argument named `%1%' required by the function is missing",
- aterm2String(name));
- mkThunk(v, env2, def);
+ if (!i->def) throwTypeError("the argument named `%1%' required by the function is missing", i->name);
+ mkThunk(v, env2, i->def);
} else {
attrsUsed++;
mkCopy(v, j->second);
@@ -658,13 +612,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
argument (unless the attribute match specifies a `...').
TODO: show the names of the expected/unexpected
arguments. */
- if (ellipsis == eFalse && attrsUsed != arg.attrs->size())
+ if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
throwTypeError("function called with unexpected argument");
}
- else abort();
-
- eval(env2, fun.lambda.body, v);
+ eval(env2, fun.lambda.fun->body, v);
}
@@ -672,45 +624,114 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
{
forceValue(fun);
- ATerm name;
- ATermList formals;
- ATermBool ellipsis;
-
- if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) {
+ if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) {
res = fun;
return;
}
Value actualArgs;
mkAttrs(actualArgs);
-
- for (ATermIterator i(formals); i; ++i) {
- Expr name, def; ATerm def2;
- if (!matchFormal(*i, name, def2)) abort();
- Bindings::const_iterator j = args.find(name);
+
+ foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
+ Bindings::const_iterator j = args.find(i->name);
if (j != args.end())
- (*actualArgs.attrs)[name] = j->second;
- else if (!matchDefaultValue(def2, def))
- throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", aterm2String(name));
+ (*actualArgs.attrs)[i->name] = j->second;
+ else if (!i->def)
+ throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name);
}
callFunction(fun, actualArgs, res);
}
-void EvalState::eval(Expr e, Value & v)
+void ExprWith::eval(EvalState & state, Env & env, Value & v)
{
- eval(baseEnv, e, v);
+ Env & env2(state.allocEnv());
+ env2.up = &env;
+
+ Value & vAttrs = env2.bindings["<with>"];
+ state.eval(env, attrs, vAttrs);
+ state.forceAttrs(vAttrs);
+
+ state.eval(env2, body, v);
}
-bool EvalState::evalBool(Env & env, Expr e)
+void ExprIf::eval(EvalState & state, Env & env, Value & v)
{
- Value v;
- eval(env, e, v);
- if (v.type != tBool)
- throwTypeError("value is %1% while a Boolean was expected", showType(v));
- return v.boolean;
+ state.eval(env, state.evalBool(env, cond) ? then : else_, v);
+}
+
+
+void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
+{
+ Value v1; state.eval(env, e1, v1);
+ Value v2; state.eval(env, e2, v2);
+ mkBool(v, state.eqValues(v1, v2));
+}
+
+
+void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
+{
+ Value v1; state.eval(env, e1, v1);
+ Value v2; state.eval(env, e2, v2);
+ mkBool(v, !state.eqValues(v1, v2));
+}
+
+
+void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
+{
+ mkBool(v, state.evalBool(env, e1) && state.evalBool(env, e2));
+}
+
+
+void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
+{
+ mkBool(v, state.evalBool(env, e1) || state.evalBool(env, e2));
+}
+
+
+void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
+{
+ mkBool(v, !state.evalBool(env, e1) || state.evalBool(env, e2));
+}
+
+
+void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
+{
+ Value v2;
+ state.eval(env, e1, v2);
+ state.forceAttrs(v2);
+
+ state.cloneAttrs(v2, v);
+
+ state.eval(env, e2, v2);
+ state.forceAttrs(v2);
+
+ foreach (Bindings::iterator, i, *v2.attrs)
+ (*v.attrs)[i->first] = i->second; // !!! sharing
+}
+
+
+void ExprOpConcatStrings::eval(EvalState & state, Env & env, Value & v)
+{
+ abort();
+}
+
+
+void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
+{
+ Value v1; state.eval(env, e1, v1);
+ state.forceList(v1);
+ Value v2; state.eval(env, e2, v2);
+ state.forceList(v2);
+ state.mkList(v, v1.list.length + v2.list.length);
+ /* !!! This loses sharing with the original lists. We could use a
+ tCopy node, but that would use more memory. */
+ for (unsigned int n = 0; n < v1.list.length; ++n)
+ v.list.elems[n] = v1.list.elems[n];
+ for (unsigned int n = 0; n < v2.list.length; ++n)
+ v.list.elems[n + v1.list.length] = v2.list.elems[n];
}
@@ -827,7 +848,7 @@ string EvalState::forceStringNoCtx(Value & v)
bool EvalState::isDerivation(Value & v)
{
if (v.type != tAttrs) return false;
- Bindings::iterator i = v.attrs->find(toATerm("type"));
+ Bindings::iterator i = v.attrs->find("type");
return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation";
}
@@ -871,7 +892,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
}
if (v.type == tAttrs) {
- Bindings::iterator i = v.attrs->find(toATerm("outPath"));
+ Bindings::iterator i = v.attrs->find("outPath");
if (i == v.attrs->end())
throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
return coerceToString(i->second, context, coerceMore, copyToStore);