From 4d6ad5be1738c64b1de4274cafbd4b8f23ca287c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 12 Apr 2010 18:30:11 +0000 Subject: * Don't use ATerms for the abstract syntax trees anymore. Not finished yet. --- src/libexpr/eval.cc | 467 +++++++++++++++++++++++++++------------------------- 1 file changed, 244 insertions(+), 223 deletions(-) (limited to 'src/libexpr/eval.cc') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7434aa842242..8ead986b8125 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 @@ -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(""); 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::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[""]; + 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); -- cgit 1.4.1