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, |     tInt = 1, | ||||||
|     tBool, |     tBool, | ||||||
|     tString, |     tString, | ||||||
|  |     tPath, | ||||||
|  |     tNull, | ||||||
|     tAttrs, |     tAttrs, | ||||||
|     tList, |     tList, | ||||||
|     tThunk, |     tThunk, | ||||||
|  | @ -157,6 +159,23 @@ std::ostream & operator << (std::ostream & str, Value & v) | ||||||
| static void eval(Env & env, Expr e, 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) | static void forceValue(Value & v) | ||||||
| { | { | ||||||
|     if (v.type == tThunk) { |     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) | static Value * lookupWith(Env * env, Sym name) | ||||||
| { | { | ||||||
|     if (!env) return 0; |     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) | 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); |     printMsg(lvlError, format("eval: %1%") % e); | ||||||
| 
 | 
 | ||||||
|  |     nrEvaluated++; | ||||||
|  | 
 | ||||||
|     Sym name; |     Sym name; | ||||||
|     if (matchVar(e, name)) { |     if (matchVar(e, name)) { | ||||||
|         Value * v2 = lookupVar(&env, name); |         Value * v2 = lookupVar(&env, name); | ||||||
|  | @ -328,7 +373,7 @@ static void eval(Env & env, Expr e, Value & v) | ||||||
|     Expr e1, e2; |     Expr e1, e2; | ||||||
|     if (matchSelect(e, e2, name)) { |     if (matchSelect(e, e2, name)) { | ||||||
|         eval(env, e2, v); |         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); |         Bindings::iterator i = v.attrs->find(name); | ||||||
|         if (i == v.attrs->end()) throw TypeError("attribute not found"); |         if (i == v.attrs->end()) throw TypeError("attribute not found"); | ||||||
|         forceValue(i->second); |         forceValue(i->second); | ||||||
|  | @ -409,7 +454,7 @@ static void eval(Env & env, Expr e, Value & v) | ||||||
|             }                 |             }                 | ||||||
| 
 | 
 | ||||||
|             eval(env, arg, *vArg); |             eval(env, arg, *vArg); | ||||||
|             if (vArg->type != tAttrs) throw TypeError("expected attribute set"); |             forceAttrs(*vArg); | ||||||
|              |              | ||||||
|             /* For each formal argument, get the actual argument.  If
 |             /* For each formal argument, get the actual argument.  If
 | ||||||
|                there is no matching actual argument but the formal |                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]; |         Value & vAttrs = env2.bindings[sWith]; | ||||||
|         nrValues++; |         nrValues++; | ||||||
|         eval(env, attrs, vAttrs); |         eval(env, attrs, vAttrs); | ||||||
|         if (vAttrs.type != tAttrs) throw TypeError("`with' should evaluate to an attribute set"); |         forceAttrs(vAttrs); | ||||||
|          |          | ||||||
|         eval(env2, body, v); |         eval(env2, body, v); | ||||||
|         return; |         return; | ||||||
|  | @ -490,9 +535,9 @@ static void eval(Env & env, Expr e, Value & v) | ||||||
| 
 | 
 | ||||||
|     if (matchOpConcat(e, e1, e2)) { |     if (matchOpConcat(e, e1, e2)) { | ||||||
|         Value v1; eval(env, e1, v1); |         Value v1; eval(env, e1, v1); | ||||||
|         if (v1.type != tList) throw TypeError("list expected"); |         forceList(v1); | ||||||
|         Value v2; eval(env, e2, v2); |         Value v2; eval(env, e2, v2); | ||||||
|         if (v2.type != tList) throw TypeError("list expected"); |         forceList(v2); | ||||||
|         v.type = tList; |         v.type = tList; | ||||||
|         v.list.length = v1.list.length + v2.list.length; |         v.list.length = v1.list.length + v2.list.length; | ||||||
|         v.list.elems = allocValues(v.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) | static void prim_head(Value * * args, Value & v) | ||||||
| { | { | ||||||
|     forceValue(*args[0]); |     forceList(*args[0]); | ||||||
|     if (args[0]->type != tList) throw TypeError("list expected"); |  | ||||||
|     if (args[0]->list.length == 0) |     if (args[0]->list.length == 0) | ||||||
|         throw Error("`head' called on an empty list"); |         throw Error("`head' called on an empty list"); | ||||||
|     forceValue(args[0]->list.elems[0]); |     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) | static void prim_add(Value * * args, Value & v) | ||||||
| { | { | ||||||
|     forceValue(*args[0]); |     forceInt(*args[0]); | ||||||
|     if (args[0]->type != tInt) throw TypeError("integer expected"); |     forceInt(*args[1]); | ||||||
|     forceValue(*args[1]); |  | ||||||
|     if (args[1]->type != tInt) throw TypeError("integer expected"); |  | ||||||
|     mkInt(v, args[0]->integer + args[1]->integer); |     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% values") % nrValues); | ||||||
|     printMsg(lvlError, format("alloced %1% environments") % nrEnvs); |     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)); |     printMsg(lvlError, format("each eval() uses %1% bytes of stack space") % (p1 - p2)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue