* More operators / primops.
This commit is contained in:
		
							parent
							
								
									c9170be2bd
								
							
						
					
					
						commit
						47df476daa
					
				
					 5 changed files with 145 additions and 187 deletions
				
			
		|  | @ -72,6 +72,7 @@ void run(Strings args) | ||||||
|     //doTest("import ./foo.nix");
 |     //doTest("import ./foo.nix");
 | ||||||
|     doTest("map (x: __add 1 x) [ 1 2 3 ]"); |     doTest("map (x: __add 1 x) [ 1 2 3 ]"); | ||||||
|     doTest("map (builtins.add 1) [ 1 2 3 ]"); |     doTest("map (builtins.add 1) [ 1 2 3 ]"); | ||||||
|  |     doTest("builtins.hasAttr \"x\" { x = 1; }"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -167,6 +167,28 @@ static void mkThunk(Value & v, Env & env, Expr expr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | void mkString(Value & v, const char * s) | ||||||
|  | { | ||||||
|  |     v.type = tString; | ||||||
|  |     v.string.s = strdup(s); | ||||||
|  |     v.string.context = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void mkString(Value & v, const string & s, const PathSet & context) | ||||||
|  | { | ||||||
|  |     mkString(v, s.c_str()); | ||||||
|  |     // !!! context
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void mkPath(Value & v, const char * s) | ||||||
|  | { | ||||||
|  |     v.type = tPath; | ||||||
|  |     v.path = strdup(s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static Value * lookupWith(Env * env, Sym name) | static Value * lookupWith(Env * env, Sym name) | ||||||
| { | { | ||||||
|     if (!env) return 0; |     if (!env) return 0; | ||||||
|  | @ -206,7 +228,7 @@ static Value * lookupVar(Env * env, Sym name) | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|      |      | ||||||
|     throw Error("undefined variable"); |     throw Error(format("undefined variable `%1%'") % aterm2String(name)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -257,38 +279,35 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|     char x; |     char x; | ||||||
|     if (&x < deepestStack) deepestStack = &x; |     if (&x < deepestStack) deepestStack = &x; | ||||||
|      |      | ||||||
|     printMsg(lvlError, format("eval: %1%") % e); |     debug(format("eval: %1%") % e); | ||||||
| 
 | 
 | ||||||
|     nrEvaluated++; |     nrEvaluated++; | ||||||
| 
 | 
 | ||||||
|     Sym name; |     Sym name; | ||||||
|  |     int n; | ||||||
|  |     ATerm s; ATermList context, es; | ||||||
|  |     ATermList rbnds, nrbnds; | ||||||
|  |     Expr e1, e2, e3, fun, arg, attrs; | ||||||
|  |     Pattern pat; Expr body; Pos pos; | ||||||
|  |      | ||||||
|     if (matchVar(e, name)) { |     if (matchVar(e, name)) { | ||||||
|         Value * v2 = lookupVar(&env, name); |         Value * v2 = lookupVar(&env, name); | ||||||
|         forceValue(*v2); |         forceValue(*v2); | ||||||
|         v = *v2; |         v = *v2; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     int n; |     else if (matchInt(e, n)) | ||||||
|     if (matchInt(e, n)) { |  | ||||||
|         mkInt(v, n); |         mkInt(v, n); | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     ATerm s; ATermList context; |     else if (matchStr(e, s, context)) { | ||||||
|     if (matchStr(e, s, context)) { |  | ||||||
|         assert(context == ATempty); |         assert(context == ATempty); | ||||||
|         mkString(v, strdup(ATgetName(ATgetAFun(s)))); |         mkString(v, ATgetName(ATgetAFun(s))); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchPath(e, s)) { |     else if (matchPath(e, s)) | ||||||
|         mkPath(v, strdup(ATgetName(ATgetAFun(s)))); |         mkPath(v, ATgetName(ATgetAFun(s))); | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     ATermList es; |     else if (matchAttrs(e, es)) { | ||||||
|     if (matchAttrs(e, es)) { |  | ||||||
|         v.type = tAttrs; |         v.type = tAttrs; | ||||||
|         v.attrs = new Bindings; |         v.attrs = new Bindings; | ||||||
|         ATerm e2, pos; |         ATerm e2, pos; | ||||||
|  | @ -298,11 +317,9 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|             nrValues++; |             nrValues++; | ||||||
|             mkThunk(v2, env, e2); |             mkThunk(v2, env, e2); | ||||||
|         } |         } | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ATermList rbnds, nrbnds; |     else if (matchRec(e, rbnds, nrbnds)) { | ||||||
|     if (matchRec(e, rbnds, nrbnds)) { |  | ||||||
|         Env & env2(allocEnv()); |         Env & env2(allocEnv()); | ||||||
|         env2.up = &env; |         env2.up = &env; | ||||||
|          |          | ||||||
|  | @ -315,12 +332,9 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|             nrValues++; |             nrValues++; | ||||||
|             mkThunk(v2, env2, e2); |             mkThunk(v2, env2, e2); | ||||||
|         } |         } | ||||||
|          |  | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Expr e1, e2; |     else if (matchSelect(e, e2, name)) { | ||||||
|     if (matchSelect(e, e2, name)) { |  | ||||||
|         eval(env, e2, v); |         eval(env, e2, v); | ||||||
|         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 |         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 | ||||||
|         Bindings::iterator i = v.attrs->find(name); |         Bindings::iterator i = v.attrs->find(name); | ||||||
|  | @ -333,29 +347,23 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|             throw; |             throw; | ||||||
|         } |         } | ||||||
|         v = i->second; |         v = i->second; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Pattern pat; Expr body; Pos pos; |     else if (matchFunction(e, pat, body, pos)) { | ||||||
|     if (matchFunction(e, pat, body, pos)) { |  | ||||||
|         v.type = tLambda; |         v.type = tLambda; | ||||||
|         v.lambda.env = &env; |         v.lambda.env = &env; | ||||||
|         v.lambda.pat = pat; |         v.lambda.pat = pat; | ||||||
|         v.lambda.body = body; |         v.lambda.body = body; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Expr fun, arg; |     else if (matchCall(e, fun, arg)) { | ||||||
|     if (matchCall(e, fun, arg)) { |  | ||||||
|         eval(env, fun, v); |         eval(env, fun, v); | ||||||
|         Value vArg; |         Value vArg; | ||||||
|         mkThunk(vArg, env, arg); // !!! should this be on the heap?
 |         mkThunk(vArg, env, arg); // !!! should this be on the heap?
 | ||||||
|         callFunction(v, vArg, v); |         callFunction(v, vArg, v); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Expr attrs; |     else if (matchWith(e, attrs, body, pos)) { | ||||||
|     if (matchWith(e, attrs, body, pos)) { |  | ||||||
|         Env & env2(allocEnv()); |         Env & env2(allocEnv()); | ||||||
|         env2.up = &env; |         env2.up = &env; | ||||||
| 
 | 
 | ||||||
|  | @ -365,31 +373,27 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|         forceAttrs(vAttrs); |         forceAttrs(vAttrs); | ||||||
|          |          | ||||||
|         eval(env2, body, v); |         eval(env2, body, v); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchList(e, es)) { |     else if (matchList(e, es)) { | ||||||
|         mkList(v, ATgetLength(es)); |         mkList(v, ATgetLength(es)); | ||||||
|         for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es)) |         for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es)) | ||||||
|             mkThunk(v.list.elems[n], env, ATgetFirst(es)); |             mkThunk(v.list.elems[n], env, ATgetFirst(es)); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchOpEq(e, e1, e2)) { |     else if (matchOpEq(e, e1, e2)) { | ||||||
|         Value v1; eval(env, e1, v1); |         Value v1; eval(env, e1, v1); | ||||||
|         Value v2; eval(env, e2, v2); |         Value v2; eval(env, e2, v2); | ||||||
|         mkBool(v, eqValues(v1, v2)); |         mkBool(v, eqValues(v1, v2)); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchOpNEq(e, e1, e2)) { |     else if (matchOpNEq(e, e1, e2)) { | ||||||
|         Value v1; eval(env, e1, v1); |         Value v1; eval(env, e1, v1); | ||||||
|         Value v2; eval(env, e2, v2); |         Value v2; eval(env, e2, v2); | ||||||
|         mkBool(v, !eqValues(v1, v2)); |         mkBool(v, !eqValues(v1, v2)); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchOpConcat(e, e1, e2)) { |     else if (matchOpConcat(e, e1, e2)) { | ||||||
|         Value v1; eval(env, e1, v1); |         Value v1; eval(env, e1, v1); | ||||||
|         forceList(v1); |         forceList(v1); | ||||||
|         Value v2; eval(env, e2, v2); |         Value v2; eval(env, e2, v2); | ||||||
|  | @ -401,10 +405,9 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|             v.list.elems[n] = v1.list.elems[n]; |             v.list.elems[n] = v1.list.elems[n]; | ||||||
|         for (unsigned int n = 0; n < v2.list.length; ++n) |         for (unsigned int n = 0; n < v2.list.length; ++n) | ||||||
|             v.list.elems[n + v1.list.length] = v2.list.elems[n]; |             v.list.elems[n + v1.list.length] = v2.list.elems[n]; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchConcatStrings(e, es)) { |     else if (matchConcatStrings(e, es)) { | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         std::ostringstream s; |         std::ostringstream s; | ||||||
|          |          | ||||||
|  | @ -431,24 +434,62 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|                 % s.str()); |                 % s.str()); | ||||||
| 
 | 
 | ||||||
|         if (isPath) |         if (isPath) | ||||||
|             mkPath(v, strdup(s.str().c_str())); |             mkPath(v, s.str().c_str()); | ||||||
|         else |         else | ||||||
|             mkString(v, strdup(s.str().c_str())); // !!! context
 |             mkString(v, s.str().c_str()); // !!! context
 | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Expr e3; |     /* Conditionals. */ | ||||||
|     if (matchIf(e, e1, e2, e3)) { |     else if (matchIf(e, e1, e2, e3)) | ||||||
|         eval(env, evalBool(env, e1) ? e2 : e3, v); |         eval(env, evalBool(env, e1) ? e2 : e3, v); | ||||||
|         return; | 
 | ||||||
|  |     /* Assertions. */ | ||||||
|  |     else if (matchAssert(e, e1, e2, pos)) { | ||||||
|  |         if (!evalBool(env, e1)) | ||||||
|  |             throw AssertionError(format("assertion failed at %1%") % showPos(pos)); | ||||||
|  |         eval(env, e2, v); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchOpOr(e, e1, e2)) { |     /* Negation. */ | ||||||
|  |     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)); |         mkBool(v, evalBool(env, e1) || evalBool(env, e2)); | ||||||
|         return; | 
 | ||||||
|  |     /* Attribute set update (//). */ | ||||||
|  |     else if (matchOpUpdate(e, e1, e2)) { | ||||||
|  |         v.type = tAttrs; | ||||||
|  |         v.attrs = new Bindings; | ||||||
|  |          | ||||||
|  |         Value v2; | ||||||
|  |         eval(env, e2, v2); | ||||||
|  |         foreach (Bindings::iterator, i, *v2.attrs) | ||||||
|  |             (*v.attrs)[i->first] = i->second; | ||||||
|  |          | ||||||
|  |         eval(env, e1, v2); | ||||||
|  |         foreach (Bindings::iterator, i, *v2.attrs) | ||||||
|  |             if (v.attrs->find(i->first) == v.attrs->end()) | ||||||
|  |                 (*v.attrs)[i->first] = i->second; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     throw Error("unsupported term"); |     /* Attribute existence test (?). */ | ||||||
|  |     else if (matchOpHasAttr(e, e1, name)) { | ||||||
|  |         eval(env, e1, v); | ||||||
|  |         forceAttrs(v); | ||||||
|  |         mkBool(v, v.attrs->find(name) != v.attrs->end()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else throw Error("unsupported term"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -637,6 +678,18 @@ void EvalState::forceFunction(Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | string EvalState::forceStringNoCtx(Value & v) | ||||||
|  | { | ||||||
|  |     forceValue(v); | ||||||
|  |     if (v.type != tString) | ||||||
|  |         throw TypeError(format("value is %1% while a string was expected") % showType(v)); | ||||||
|  |     if (v.string.context) | ||||||
|  |         throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')") | ||||||
|  |             % v.string.s % v.string.context[0]); | ||||||
|  |     return string(v.string.s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| string EvalState::coerceToString(Value & v, PathSet & context, | string EvalState::coerceToString(Value & v, PathSet & context, | ||||||
|     bool coerceMore, bool copyToStore) |     bool coerceMore, bool copyToStore) | ||||||
| { | { | ||||||
|  | @ -901,68 +954,6 @@ LocalNoInline(ATerm expandRec(EvalState & state, ATerm e, ATermList rbnds, ATerm | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| LocalNoInline(Expr updateAttrs(Expr e1, Expr e2)) |  | ||||||
| { |  | ||||||
|     /* Note: e1 and e2 should be in normal form. */ |  | ||||||
| 
 |  | ||||||
|     ATermMap attrs; |  | ||||||
|     queryAllAttrs(e1, attrs, true); |  | ||||||
|     queryAllAttrs(e2, attrs, true); |  | ||||||
| 
 |  | ||||||
|     return makeAttrs(attrs); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| string evalString(EvalState & state, Expr e, PathSet & context) |  | ||||||
| { |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     string s; |  | ||||||
|     if (!matchStr(e, s, context)) |  | ||||||
|         throwTypeError("value is %1% while a string was expected", showType(e)); |  | ||||||
|     return s; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| string evalStringNoCtx(EvalState & state, Expr e) |  | ||||||
| { |  | ||||||
|     PathSet context; |  | ||||||
|     string s = evalString(state, e, context); |  | ||||||
|     if (!context.empty()) |  | ||||||
|         throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')") |  | ||||||
|             % s % *(context.begin())); |  | ||||||
|     return s; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| int evalInt(EvalState & state, Expr e) |  | ||||||
| { |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     int i; |  | ||||||
|     if (!matchInt(e, i)) |  | ||||||
|         throwTypeError("value is %1% while an integer was expected", showType(e)); |  | ||||||
|     return i; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| bool evalBool(EvalState & state, Expr e) |  | ||||||
| { |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     if (e == eTrue) return true; |  | ||||||
|     else if (e == eFalse) return false; |  | ||||||
|     else throwTypeError("value is %1% while a boolean was expected", showType(e)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ATermList evalList(EvalState & state, Expr e) |  | ||||||
| { |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     ATermList list; |  | ||||||
|     if (!matchList(e, list)) |  | ||||||
|         throwTypeError("value is %1% while a list was expected", showType(e)); |  | ||||||
|     return list; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static void flattenList(EvalState & state, Expr e, ATermList & result) | static void flattenList(EvalState & state, Expr e, ATermList & result) | ||||||
| { | { | ||||||
|     ATermList es; |     ATermList es; | ||||||
|  | @ -1078,14 +1069,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos)) |  | ||||||
| { |  | ||||||
|     if (!evalBool(state, cond)) |  | ||||||
|         throw AssertionError(format("assertion failed at %1%") % showPos(pos)); |  | ||||||
|     return evalExpr(state, body); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos)) | LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos)) | ||||||
| { | { | ||||||
|     ATermMap attrs; |     ATermMap attrs; | ||||||
|  | @ -1109,14 +1092,6 @@ LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| LocalNoInline(Expr evalHasAttr(EvalState & state, Expr e, ATerm name)) |  | ||||||
| { |  | ||||||
|     ATermMap attrs; |  | ||||||
|     queryAllAttrs(evalExpr(state, e), attrs); |  | ||||||
|     return makeBool(attrs.get(name) != 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e)) | LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e)) | ||||||
| { | { | ||||||
|     Expr e1, e2; |     Expr e1, e2; | ||||||
|  | @ -1177,19 +1152,6 @@ LocalNoInline(Expr evalSubPath(EvalState & state, Expr e1, Expr e2)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2)) |  | ||||||
| { |  | ||||||
|     try { |  | ||||||
|         ATermList l1 = evalList(state, e1); |  | ||||||
|         ATermList l2 = evalList(state, e2); |  | ||||||
|         return makeList(ATconcat(l1, l2)); |  | ||||||
|     } catch (Error & e) { |  | ||||||
|         addErrorPrefix(e, "in a list concatenation:\n"); |  | ||||||
|         throw; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Implementation of the `==' and `!=' operators. */ | /* Implementation of the `==' and `!=' operators. */ | ||||||
| LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2)) | LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2)) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -104,19 +104,9 @@ static inline void mkBool(Value & v, bool b) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static inline void mkString(Value & v, const char * s) | void mkString(Value & v, const char * s); | ||||||
| { | void mkString(Value & v, const string & s, const PathSet & context); | ||||||
|     v.type = tString; | void mkPath(Value & v, const char * s); | ||||||
|     v.string.s = s; |  | ||||||
|     v.string.context = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static inline void mkPath(Value & v, const char * s) |  | ||||||
| { |  | ||||||
|     v.type = tPath; |  | ||||||
|     v.path = s; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| typedef std::map<Path, PathSet> DrvRoots; | typedef std::map<Path, PathSet> DrvRoots; | ||||||
|  | @ -177,6 +167,7 @@ public: | ||||||
|     void forceAttrs(Value & v); |     void forceAttrs(Value & v); | ||||||
|     void forceList(Value & v); |     void forceList(Value & v); | ||||||
|     void forceFunction(Value & v); // either lambda or primop
 |     void forceFunction(Value & v); // either lambda or primop
 | ||||||
|  |     string forceStringNoCtx(Value & v); | ||||||
| 
 | 
 | ||||||
|     /* String coercion.  Converts strings, paths and derivations to a
 |     /* String coercion.  Converts strings, paths and derivations to a
 | ||||||
|        string.  If `coerceMore' is set, also converts nulls, integers, |        string.  If `coerceMore' is set, also converts nulls, integers, | ||||||
|  | @ -234,7 +225,6 @@ Expr strictEvalExpr(EvalState & state, Expr e); | ||||||
| 
 | 
 | ||||||
| /* Specific results. */ | /* Specific results. */ | ||||||
| string evalString(EvalState & state, Expr e, PathSet & context); | string evalString(EvalState & state, Expr e, PathSet & context); | ||||||
| string evalStringNoCtx(EvalState & state, Expr e); |  | ||||||
| int evalInt(EvalState & state, Expr e); | int evalInt(EvalState & state, Expr e); | ||||||
| bool evalBool(EvalState & state, Expr e); | bool evalBool(EvalState & state, Expr e); | ||||||
| ATermList evalList(EvalState & state, Expr e); | ATermList evalList(EvalState & state, Expr e); | ||||||
|  |  | ||||||
|  | @ -687,24 +687,32 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     return makeList(list); |     return makeList(list); | ||||||
| } | } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Dynamic version of the `.' operator. */ | /* Dynamic version of the `.' operator. */ | ||||||
| static void prim_getAttr(EvalState & state, Value * * args, Value & v) | static void prim_getAttr(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     string attr = evalStringNoCtx(state, args[0]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     return evalExpr(state, makeSelect(args[1], toATerm(attr))); |     state.forceAttrs(*args[1]); | ||||||
|  |     Bindings::iterator i = args[1]->attrs->find(toATerm(attr)); | ||||||
|  |     if (i == args[1]->attrs->end()) | ||||||
|  |         throw EvalError(format("attribute `%1%' missing") % attr); | ||||||
|  |     state.forceValue(i->second); | ||||||
|  |     v = i->second; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Dynamic version of the `?' operator. */ | /* Dynamic version of the `?' operator. */ | ||||||
| static void prim_hasAttr(EvalState & state, Value * * args, Value & v) | static void prim_hasAttr(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     string attr = evalStringNoCtx(state, args[0]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr))); |     state.forceAttrs(*args[1]); | ||||||
|  |     mkBool(v, args[1]->attrs->find(toATerm(attr)) != args[1]->attrs->end()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
| /* Builds an attribute set from a list specifying (name, value)
 | /* Builds an attribute set from a list specifying (name, value)
 | ||||||
|    pairs.  To be precise, a list [{name = "name1"; value = value1;} |    pairs.  To be precise, a list [{name = "name1"; value = value1;} | ||||||
|    ... {name = "nameN"; value = valueN;}] is transformed to {name1 = |    ... {name = "nameN"; value = valueN;}] is transformed to {name1 = | ||||||
|  | @ -896,31 +904,24 @@ static void prim_add(EvalState & state, Value * * args, Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| static void prim_sub(EvalState & state, Value * * args, Value & v) | static void prim_sub(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     int i1 = evalInt(state, args[0]); |     mkInt(v, state.forceInt(*args[0]) - state.forceInt(*args[1])); | ||||||
|     int i2 = evalInt(state, args[1]); |  | ||||||
|     return makeInt(i1 - i2); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void prim_mul(EvalState & state, Value * * args, Value & v) | static void prim_mul(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     int i1 = evalInt(state, args[0]); |     mkInt(v, state.forceInt(*args[0]) * state.forceInt(*args[1])); | ||||||
|     int i2 = evalInt(state, args[1]); |  | ||||||
|     return makeInt(i1 * i2); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void prim_div(EvalState & state, Value * * args, Value & v) | static void prim_div(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     int i1 = evalInt(state, args[0]); |     int i2 = state.forceInt(*args[1]); | ||||||
|     int i2 = evalInt(state, args[1]); |  | ||||||
|     if (i2 == 0) throw EvalError("division by zero"); |     if (i2 == 0) throw EvalError("division by zero"); | ||||||
|     return makeInt(i1 / i2); |     mkInt(v, state.forceInt(*args[0]) / i2); | ||||||
| } | } | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void prim_lessThan(EvalState & state, Value * * args, Value & v) | static void prim_lessThan(EvalState & state, Value * * args, Value & v) | ||||||
|  | @ -941,36 +942,36 @@ static void prim_toString(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     PathSet context; |     PathSet context; | ||||||
|     string s = state.coerceToString(*args[0], context, true, false); |     string s = state.coerceToString(*args[0], context, true, false); | ||||||
|     mkString(v, strdup(s.c_str())); // !!! context
 |     mkString(v, s.c_str()); // !!! context
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| /* `substring start len str' returns the substring of `str' starting
 | /* `substring start len str' returns the substring of `str' starting
 | ||||||
|    at character position `min(start, stringLength str)' inclusive and |    at character position `min(start, stringLength str)' inclusive and | ||||||
|    ending at `min(start + len, stringLength str)'.  `start' must be |    ending at `min(start + len, stringLength str)'.  `start' must be | ||||||
|    non-negative. */ |    non-negative. */ | ||||||
| static void prim_substring(EvalState & state, Value * * args, Value & v) | static void prim_substring(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     int start = evalInt(state, args[0]); |     int start = state.forceInt(*args[0]); | ||||||
|     int len = evalInt(state, args[1]); |     int len = state.forceInt(*args[1]); | ||||||
|     PathSet context; |     PathSet context; | ||||||
|     string s = coerceToString(state, args[2], context); |     string s = state.coerceToString(*args[2], context); | ||||||
| 
 | 
 | ||||||
|     if (start < 0) throw EvalError("negative start position in `substring'"); |     if (start < 0) throw EvalError("negative start position in `substring'"); | ||||||
| 
 | 
 | ||||||
|     return makeStr(string(s, start, len), context); |     mkString(v, string(s, start, len), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void prim_stringLength(EvalState & state, Value * * args, Value & v) | static void prim_stringLength(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     PathSet context; |     PathSet context; | ||||||
|     string s = coerceToString(state, args[0], context); |     string s = state.coerceToString(*args[0], context); | ||||||
|     return makeInt(s.size()); |     mkInt(v, s.size()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
| static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v) | static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     PathSet context; |     PathSet context; | ||||||
|  | @ -1078,7 +1079,7 @@ void EvalState::createBaseEnv() | ||||||
|     mkInt(v, time(0)); |     mkInt(v, time(0)); | ||||||
|     addConstant("__currentTime", v); |     addConstant("__currentTime", v); | ||||||
| 
 | 
 | ||||||
|     mkString(v, strdup(thisSystem.c_str())); |     mkString(v, thisSystem.c_str()); | ||||||
|     addConstant("__currentSystem", v); |     addConstant("__currentSystem", v); | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
|  | @ -1120,8 +1121,10 @@ void EvalState::createBaseEnv() | ||||||
| 
 | 
 | ||||||
|     // Attribute sets
 |     // Attribute sets
 | ||||||
|     addPrimOp("__attrNames", 1, prim_attrNames); |     addPrimOp("__attrNames", 1, prim_attrNames); | ||||||
|  | #endif | ||||||
|     addPrimOp("__getAttr", 2, prim_getAttr); |     addPrimOp("__getAttr", 2, prim_getAttr); | ||||||
|     addPrimOp("__hasAttr", 2, prim_hasAttr); |     addPrimOp("__hasAttr", 2, prim_hasAttr); | ||||||
|  | #if 0 | ||||||
|     addPrimOp("__isAttrs", 1, prim_isAttrs); |     addPrimOp("__isAttrs", 1, prim_isAttrs); | ||||||
|     addPrimOp("removeAttrs", 2, prim_removeAttrs); |     addPrimOp("removeAttrs", 2, prim_removeAttrs); | ||||||
|     addPrimOp("__listToAttrs", 1, prim_listToAttrs); |     addPrimOp("__listToAttrs", 1, prim_listToAttrs); | ||||||
|  | @ -1140,18 +1143,16 @@ void EvalState::createBaseEnv() | ||||||
|      |      | ||||||
|     // Integer arithmetic
 |     // Integer arithmetic
 | ||||||
|     addPrimOp("__add", 2, prim_add); |     addPrimOp("__add", 2, prim_add); | ||||||
| #if 0 |  | ||||||
|     addPrimOp("__sub", 2, prim_sub); |     addPrimOp("__sub", 2, prim_sub); | ||||||
|     addPrimOp("__mul", 2, prim_mul); |     addPrimOp("__mul", 2, prim_mul); | ||||||
|     addPrimOp("__div", 2, prim_div); |     addPrimOp("__div", 2, prim_div); | ||||||
| #endif |  | ||||||
|     addPrimOp("__lessThan", 2, prim_lessThan); |     addPrimOp("__lessThan", 2, prim_lessThan); | ||||||
| 
 | 
 | ||||||
|     // String manipulation
 |     // String manipulation
 | ||||||
|     addPrimOp("toString", 1, prim_toString); |     addPrimOp("toString", 1, prim_toString); | ||||||
| #if 0    
 |  | ||||||
|     addPrimOp("__substring", 3, prim_substring); |     addPrimOp("__substring", 3, prim_substring); | ||||||
|     addPrimOp("__stringLength", 1, prim_stringLength); |     addPrimOp("__stringLength", 1, prim_stringLength); | ||||||
|  | #if 0    
 | ||||||
|     addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); |     addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); | ||||||
|     addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); |     addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,9 +71,13 @@ void processExpr(EvalState & state, const Strings & attrPaths, | ||||||
|     bool parseOnly, bool strict, const ATermMap & autoArgs, |     bool parseOnly, bool strict, const ATermMap & autoArgs, | ||||||
|     bool evalOnly, bool xmlOutput, Expr e) |     bool evalOnly, bool xmlOutput, Expr e) | ||||||
| { | { | ||||||
|     Value v; |     if (parseOnly) | ||||||
|     state.strictEval(e, v); |         std::cout << format("%1%\n") % canonicaliseExpr(e); | ||||||
|     std::cout << v << std::endl; |     else { | ||||||
|  |         Value v; | ||||||
|  |         state.strictEval(e, v); | ||||||
|  |         std::cout << v << std::endl; | ||||||
|  |     } | ||||||
|      |      | ||||||
| #if 0 | #if 0 | ||||||
|     for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) { |     for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue