This commit is contained in:
		
							parent
							
								
									392811eb8f
								
							
						
					
					
						commit
						807a67bc74
					
				
					 1 changed files with 55 additions and 12 deletions
				
			
		|  | @ -29,6 +29,8 @@ typedef enum { | |||
|     tInt = 1, | ||||
|     tBool, | ||||
|     tString, | ||||
|     tPath, | ||||
|     tNull, | ||||
|     tAttrs, | ||||
|     tList, | ||||
|     tThunk, | ||||
|  | @ -157,6 +159,23 @@ std::ostream & operator << (std::ostream & str, Value & v) | |||
| static void eval(Env & env, Expr e, Value & v); | ||||
| 
 | ||||
| 
 | ||||
| string showType(Value & v) | ||||
| { | ||||
|     switch (v.type) { | ||||
|         case tString: return "a string"; | ||||
|         case tPath: return "a path"; | ||||
|         case tNull: return "null"; | ||||
|         case tInt: return "an integer"; | ||||
|         case tBool: return "a boolean"; | ||||
|         case tLambda: return "a function"; | ||||
|         case tAttrs: return "an attribute set"; | ||||
|         case tList: return "a list"; | ||||
|         case tPrimOpApp: return "a partially applied built-in function"; | ||||
|         default: throw Error("unknown type"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void forceValue(Value & v) | ||||
| { | ||||
|     if (v.type == tThunk) { | ||||
|  | @ -172,6 +191,30 @@ static void forceValue(Value & v) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void forceInt(Value & v) | ||||
| { | ||||
|     forceValue(v); | ||||
|     if (v.type != tInt) | ||||
|         throw TypeError(format("value is %1% while an integer was expected") % showType(v)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void forceAttrs(Value & v) | ||||
| { | ||||
|     forceValue(v); | ||||
|     if (v.type != tAttrs) | ||||
|         throw TypeError(format("value is %1% while an attribute set was expected") % showType(v)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void forceList(Value & v) | ||||
| { | ||||
|     forceValue(v); | ||||
|     if (v.type != tList) | ||||
|         throw TypeError(format("value is %1% while a list was expected") % showType(v)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static Value * lookupWith(Env * env, Sym name) | ||||
| { | ||||
|     if (!env) return 0; | ||||
|  | @ -247,7 +290,7 @@ static bool eqValues(Value & v1, Value & v2) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| unsigned long nrValues = 0, nrEnvs = 0; | ||||
| unsigned long nrValues = 0, nrEnvs = 0, nrEvaluated = 0; | ||||
| 
 | ||||
| static Value * allocValues(unsigned int count) | ||||
| { | ||||
|  | @ -272,6 +315,8 @@ static void eval(Env & env, Expr e, Value & v) | |||
| 
 | ||||
|     printMsg(lvlError, format("eval: %1%") % e); | ||||
| 
 | ||||
|     nrEvaluated++; | ||||
| 
 | ||||
|     Sym name; | ||||
|     if (matchVar(e, name)) { | ||||
|         Value * v2 = lookupVar(&env, name); | ||||
|  | @ -328,7 +373,7 @@ static void eval(Env & env, Expr e, Value & v) | |||
|     Expr e1, e2; | ||||
|     if (matchSelect(e, e2, name)) { | ||||
|         eval(env, e2, v); | ||||
|         if (v.type != tAttrs) throw TypeError("expected attribute set"); | ||||
|         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 | ||||
|         Bindings::iterator i = v.attrs->find(name); | ||||
|         if (i == v.attrs->end()) throw TypeError("attribute not found"); | ||||
|         forceValue(i->second); | ||||
|  | @ -409,7 +454,7 @@ static void eval(Env & env, Expr e, Value & v) | |||
|             }                 | ||||
| 
 | ||||
|             eval(env, arg, *vArg); | ||||
|             if (vArg->type != tAttrs) throw TypeError("expected attribute set"); | ||||
|             forceAttrs(*vArg); | ||||
|              | ||||
|             /* For each formal argument, get the actual argument.  If
 | ||||
|                there is no matching actual argument but the formal | ||||
|  | @ -459,7 +504,7 @@ static void eval(Env & env, Expr e, Value & v) | |||
|         Value & vAttrs = env2.bindings[sWith]; | ||||
|         nrValues++; | ||||
|         eval(env, attrs, vAttrs); | ||||
|         if (vAttrs.type != tAttrs) throw TypeError("`with' should evaluate to an attribute set"); | ||||
|         forceAttrs(vAttrs); | ||||
|          | ||||
|         eval(env2, body, v); | ||||
|         return; | ||||
|  | @ -490,9 +535,9 @@ static void eval(Env & env, Expr e, Value & v) | |||
| 
 | ||||
|     if (matchOpConcat(e, e1, e2)) { | ||||
|         Value v1; eval(env, e1, v1); | ||||
|         if (v1.type != tList) throw TypeError("list expected"); | ||||
|         forceList(v1); | ||||
|         Value v2; eval(env, e2, v2); | ||||
|         if (v2.type != tList) throw TypeError("list expected"); | ||||
|         forceList(v2); | ||||
|         v.type = tList; | ||||
|         v.list.length = v1.list.length + v2.list.length; | ||||
|         v.list.elems = allocValues(v.list.length); | ||||
|  | @ -546,8 +591,7 @@ static void strictEval(Env & env, Expr e, Value & v) | |||
| 
 | ||||
| static void prim_head(Value * * args, Value & v) | ||||
| { | ||||
|     forceValue(*args[0]); | ||||
|     if (args[0]->type != tList) throw TypeError("list expected"); | ||||
|     forceList(*args[0]); | ||||
|     if (args[0]->list.length == 0) | ||||
|         throw Error("`head' called on an empty list"); | ||||
|     forceValue(args[0]->list.elems[0]); | ||||
|  | @ -557,10 +601,8 @@ static void prim_head(Value * * args, Value & v) | |||
| 
 | ||||
| static void prim_add(Value * * args, Value & v) | ||||
| { | ||||
|     forceValue(*args[0]); | ||||
|     if (args[0]->type != tInt) throw TypeError("integer expected"); | ||||
|     forceValue(*args[1]); | ||||
|     if (args[1]->type != tInt) throw TypeError("integer expected"); | ||||
|     forceInt(*args[0]); | ||||
|     forceInt(*args[1]); | ||||
|     mkInt(v, args[0]->integer + args[1]->integer); | ||||
| } | ||||
| 
 | ||||
|  | @ -649,6 +691,7 @@ void run(Strings args) | |||
|      | ||||
|     printMsg(lvlError, format("alloced %1% values") % nrValues); | ||||
|     printMsg(lvlError, format("alloced %1% environments") % nrEnvs); | ||||
|     printMsg(lvlError, format("evaluated %1% expressions") % nrEvaluated); | ||||
|     printMsg(lvlError, format("each eval() uses %1% bytes of stack space") % (p1 - p2)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue