* Don't use ATerms for the abstract syntax trees anymore. Not
finished yet.
This commit is contained in:
		
							parent
							
								
									ed711f73bc
								
							
						
					
					
						commit
						4d6ad5be17
					
				
					 19 changed files with 693 additions and 579 deletions
				
			
		|  | @ -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 | ||||
| } | ||||
| 
 | ||||
|     else abort(); | ||||
| 
 | ||||
| void EvalState::eval(Expr * e, Value & v) | ||||
| { | ||||
|     eval(baseEnv, e, v); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue