* More primops.
This commit is contained in:
		
							parent
							
								
									5b72d8a749
								
							
						
					
					
						commit
						c3aa615a5f
					
				
					 4 changed files with 56 additions and 97 deletions
				
			
		|  | @ -56,10 +56,12 @@ void run(Strings args) | ||||||
|     doTest("{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }"); |     doTest("{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }"); | ||||||
|     doTest("1 != 1"); |     doTest("1 != 1"); | ||||||
|     doTest("true"); |     doTest("true"); | ||||||
|  |     doTest("builtins.true"); | ||||||
|     doTest("true == false"); |     doTest("true == false"); | ||||||
|     doTest("__head [ 1 2 3 ]"); |     doTest("__head [ 1 2 3 ]"); | ||||||
|     doTest("__add 1 2"); |     doTest("__add 1 2"); | ||||||
|     doTest("null"); |     doTest("null"); | ||||||
|  |     doTest("null"); | ||||||
|     doTest("\"foo\""); |     doTest("\"foo\""); | ||||||
|     doTest("let s = \"bar\"; in \"foo${s}\""); |     doTest("let s = \"bar\"; in \"foo${s}\""); | ||||||
|     doTest("if true then 1 else 2"); |     doTest("if true then 1 else 2"); | ||||||
|  | @ -67,9 +69,9 @@ void run(Strings args) | ||||||
|     doTest("if false || true then 1 else 2"); |     doTest("if false || true then 1 else 2"); | ||||||
|     doTest("let x = x; in if true || x then 1 else 2"); |     doTest("let x = x; in if true || x then 1 else 2"); | ||||||
|     doTest("/etc/passwd"); |     doTest("/etc/passwd"); | ||||||
|     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 (__add 1) [ 1 2 3 ]"); |     doTest("map (builtins.add 1) [ 1 2 3 ]"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -95,14 +95,26 @@ EvalState::EvalState() : baseEnv(allocEnv()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | void EvalState::addConstant(const string & name, Value & v) | ||||||
|  | { | ||||||
|  |     baseEnv.bindings[toATerm(name)] = v; | ||||||
|  |     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; | ||||||
|  |     (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v; | ||||||
|  |     nrValues += 2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void EvalState::addPrimOp(const string & name, | void EvalState::addPrimOp(const string & name, | ||||||
|     unsigned int arity, PrimOp primOp) |     unsigned int arity, PrimOp primOp) | ||||||
| { | { | ||||||
|     Value & v = baseEnv.bindings[toATerm(name)]; |     Value v; | ||||||
|     nrValues++; |  | ||||||
|     v.type = tPrimOp; |     v.type = tPrimOp; | ||||||
|     v.primOp.arity = arity; |     v.primOp.arity = arity; | ||||||
|     v.primOp.fun = primOp; |     v.primOp.fun = primOp; | ||||||
|  |     baseEnv.bindings[toATerm(name)] = v; | ||||||
|  |     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; | ||||||
|  |     (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v; | ||||||
|  |     nrValues += 2; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -212,6 +224,14 @@ Env & EvalState::allocEnv() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | void EvalState::mkList(Value & v, unsigned int length) | ||||||
|  | { | ||||||
|  |     v.type = tList; | ||||||
|  |     v.list.length = length; | ||||||
|  |     v.list.elems = allocValues(length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void EvalState::evalFile(const Path & path, Value & v) | void EvalState::evalFile(const Path & path, Value & v) | ||||||
| { | { | ||||||
|     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); |     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); | ||||||
|  | @ -349,9 +369,7 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (matchList(e, es)) { |     if (matchList(e, es)) { | ||||||
|         v.type = tList; |         mkList(v, ATgetLength(es)); | ||||||
|         v.list.length = ATgetLength(es); |  | ||||||
|         v.list.elems = allocValues(v.list.length); |  | ||||||
|         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; |         return; | ||||||
|  | @ -376,9 +394,7 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|         forceList(v1); |         forceList(v1); | ||||||
|         Value v2; eval(env, e2, v2); |         Value v2; eval(env, e2, v2); | ||||||
|         forceList(v2); |         forceList(v2); | ||||||
|         v.type = tList; |         mkList(v, v1.list.length + v2.list.length); | ||||||
|         v.list.length = v1.list.length + v2.list.length; |  | ||||||
|         v.list.elems = allocValues(v.list.length); |  | ||||||
|         /* !!! This loses sharing with the original lists.  We could
 |         /* !!! This loses sharing with the original lists.  We could
 | ||||||
|            use a tCopy node, but that would use more memory. */ |            use a tCopy node, but that would use more memory. */ | ||||||
|         for (unsigned int n = 0; n < v1.list.length; ++n) |         for (unsigned int n = 0; n < v1.list.length; ++n) | ||||||
|  |  | ||||||
|  | @ -196,6 +196,8 @@ private: | ||||||
| 
 | 
 | ||||||
|     void createBaseEnv(); |     void createBaseEnv(); | ||||||
|      |      | ||||||
|  |     void addConstant(const string & name, Value & v); | ||||||
|  | 
 | ||||||
|     void addPrimOp(const string & name, |     void addPrimOp(const string & name, | ||||||
|         unsigned int arity, PrimOp primOp); |         unsigned int arity, PrimOp primOp); | ||||||
| 
 | 
 | ||||||
|  | @ -210,6 +212,8 @@ public: | ||||||
|     /* Allocation primitives. */ |     /* Allocation primitives. */ | ||||||
|     Value * allocValues(unsigned int count); |     Value * allocValues(unsigned int count); | ||||||
|     Env & allocEnv(); |     Env & allocEnv(); | ||||||
|  | 
 | ||||||
|  |     void mkList(Value & v, unsigned int length); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,63 +20,6 @@ | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| /*************************************************************
 |  | ||||||
|  * Constants |  | ||||||
|  *************************************************************/ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr prim_builtins(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     /* Return an attribute set containing all primops.  This allows
 |  | ||||||
|        Nix expressions to test for new primops and take appropriate |  | ||||||
|        action if they're not available.  For instance, rather than |  | ||||||
|        calling a primop `foo' directly, they could say `if builtins ? |  | ||||||
|        foo then builtins.foo ... else ...'. */ |  | ||||||
| 
 |  | ||||||
|     ATermMap builtins(state.primOps.size()); |  | ||||||
| 
 |  | ||||||
|     for (ATermMap::const_iterator i = state.primOps.begin(); |  | ||||||
|          i != state.primOps.end(); ++i) |  | ||||||
|     { |  | ||||||
|         string name = aterm2String(i->key); |  | ||||||
|         if (string(name, 0, 2) == "__") |  | ||||||
|             name = string(name, 2); |  | ||||||
|         /* !!! should use makePrimOp here, I guess. */ |  | ||||||
|         builtins.set(toATerm(name), makeAttrRHS(makeVar(i->key), makeNoPos())); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return makeAttrs(builtins); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Boolean constructors. */ |  | ||||||
| static Expr prim_true(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     return eTrue; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr prim_false(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     return eFalse; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Return the null value. */ |  | ||||||
| static Expr prim_null(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     return makeNull(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr prim_currentTime(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     return ATmake("Int(<int>)", time(0)); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /*************************************************************
 | /*************************************************************
 | ||||||
|  * Miscellaneous |  * Miscellaneous | ||||||
|  *************************************************************/ |  *************************************************************/ | ||||||
|  | @ -903,17 +846,17 @@ static void prim_head(EvalState & state, Value * * args, Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| /* Return a list consisting of everything but the the first element of
 | /* Return a list consisting of everything but the the first element of
 | ||||||
|    a list. */ |    a list. */ | ||||||
| static Expr prim_tail(EvalState & state, const ATermVector & args) | static void prim_tail(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     ATermList list = evalList(state, args[0]); |     state.forceList(*args[0]); | ||||||
|     if (ATisEmpty(list)) |     if (args[0]->list.length == 0) | ||||||
|         throw Error("`tail' called on an empty list"); |         throw Error("`tail' called on an empty list"); | ||||||
|     return makeList(ATgetNext(list)); |     state.mkList(v, args[0]->list.length - 1); | ||||||
|  |     for (unsigned int n = 0; n < v.list.length; ++n) | ||||||
|  |         v.list.elems[n] = args[0]->list.elems[n + 1]; | ||||||
| } | } | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Apply a function to every element of a list. */ | /* Apply a function to every element of a list. */ | ||||||
|  | @ -922,9 +865,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v) | ||||||
|     state.forceFunction(*args[0]); |     state.forceFunction(*args[0]); | ||||||
|     state.forceList(*args[1]); |     state.forceList(*args[1]); | ||||||
| 
 | 
 | ||||||
|     v.type = tList; |     state.mkList(v, args[1]->list.length); | ||||||
|     v.list.length = args[1]->list.length; |  | ||||||
|     v.list.elems = state.allocValues(v.list.length); |  | ||||||
| 
 | 
 | ||||||
|     for (unsigned int n = 0; n < v.list.length; ++n) { |     for (unsigned int n = 0; n < v.list.length; ++n) { | ||||||
|         v.list.elems[n].type = tApp; |         v.list.elems[n].type = tApp; | ||||||
|  | @ -1123,26 +1064,24 @@ void EvalState::createBaseEnv() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Add global constants such as `true' to the base environment. */ |     /* Add global constants such as `true' to the base environment. */ | ||||||
|     {   Value & v = baseEnv.bindings[toATerm("true")]; |     Value v; | ||||||
|         mkBool(v, true); |  | ||||||
|     } |  | ||||||
|     {   Value & v = baseEnv.bindings[toATerm("false")]; |  | ||||||
|         mkBool(v, false); |  | ||||||
|     } |  | ||||||
|     {   Value & v = baseEnv.bindings[toATerm("null")]; |  | ||||||
|         v.type = tNull; |  | ||||||
|     } |  | ||||||
|     {   Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")]; |  | ||||||
|         mkString(v, strdup(thisSystem.c_str())); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
| #if 0    
 |     mkBool(v, true); | ||||||
|     // Constants
 |     addConstant("true", v); | ||||||
|     addPrimOp("__currentSystem", 0, prim_currentSystem); |      | ||||||
|     addPrimOp("__currentTime", 0, prim_currentTime); |     mkBool(v, false); | ||||||
|  |     addConstant("false", v); | ||||||
|  |      | ||||||
|  |     v.type = tNull; | ||||||
|  |     addConstant("null", v); | ||||||
|  | 
 | ||||||
|  |     mkInt(v, time(0)); | ||||||
|  |     addConstant("__currentTime", v); | ||||||
|  | 
 | ||||||
|  |     mkString(v, strdup(thisSystem.c_str())); | ||||||
|  |     addConstant("__currentSystem", v); | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
| #endif |  | ||||||
|     addPrimOp("import", 1, prim_import); |     addPrimOp("import", 1, prim_import); | ||||||
| #if 0 | #if 0 | ||||||
|     addPrimOp("isNull", 1, prim_isNull); |     addPrimOp("isNull", 1, prim_isNull); | ||||||
|  | @ -1193,9 +1132,7 @@ void EvalState::createBaseEnv() | ||||||
|     addPrimOp("__isList", 1, prim_isList); |     addPrimOp("__isList", 1, prim_isList); | ||||||
| #endif | #endif | ||||||
|     addPrimOp("__head", 1, prim_head); |     addPrimOp("__head", 1, prim_head); | ||||||
| #if 0 |  | ||||||
|     addPrimOp("__tail", 1, prim_tail); |     addPrimOp("__tail", 1, prim_tail); | ||||||
| #endif |  | ||||||
|     addPrimOp("map", 2, prim_map); |     addPrimOp("map", 2, prim_map); | ||||||
| #if 0 | #if 0 | ||||||
|     addPrimOp("__length", 1, prim_length); |     addPrimOp("__length", 1, prim_length); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue