* Implemented withs.
This commit is contained in:
		
							parent
							
								
									9985230c00
								
							
						
					
					
						commit
						110d155778
					
				
					 4 changed files with 38 additions and 15 deletions
				
			
		|  | @ -72,7 +72,8 @@ void run(Strings args) | ||||||
|     doTest(state, "let { x = 1; body = x; }"); |     doTest(state, "let { x = 1; body = x; }"); | ||||||
|     doTest(state, "with { x = 1; }; x"); |     doTest(state, "with { x = 1; }; x"); | ||||||
|     doTest(state, "let x = 2; in with { x = 1; }; x"); // => 2
 |     doTest(state, "let x = 2; in with { x = 1; }; x"); // => 2
 | ||||||
|     doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 1
 |     doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 2
 | ||||||
|  |     doTest(state, "with { x = 1; }; with { y = 2; }; x"); // => 1
 | ||||||
|     doTest(state, "[ 1 2 3 ]"); |     doTest(state, "[ 1 2 3 ]"); | ||||||
|     doTest(state, "[ 1 2 ] ++ [ 3 4 5 ]"); |     doTest(state, "[ 1 2 ] ++ [ 3 4 5 ]"); | ||||||
|     doTest(state, "123 == 123"); |     doTest(state, "123 == 123"); | ||||||
|  |  | ||||||
|  | @ -253,8 +253,6 @@ Value * EvalState::lookupVar(Env * env, const Symbol & name) | ||||||
|         Bindings::iterator j = i->second.attrs->find(name); |         Bindings::iterator j = i->second.attrs->find(name); | ||||||
|         if (j != i->second.attrs->end()) return &j->second; |         if (j != i->second.attrs->end()) return &j->second; | ||||||
|     } |     } | ||||||
|      |  | ||||||
|     throwEvalError("urgh! undefined variable `%1%'", name); |  | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -483,13 +481,15 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
| void ExprVar::eval(EvalState & state, Env & env, Value & v) | void ExprVar::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     printMsg(lvlError, format("eval var %1% %2% %3%") % fromWith % level % displ); |  | ||||||
| 
 |  | ||||||
|     if (fromWith) { |  | ||||||
|         abort(); |  | ||||||
|     } else { |  | ||||||
|     Env * env2 = &env; |     Env * env2 = &env; | ||||||
|     for (unsigned int l = level; l; --l, env2 = env2->up) ; |     for (unsigned int l = level; l; --l, env2 = env2->up) ; | ||||||
|  |      | ||||||
|  |     if (fromWith) { | ||||||
|  |         Bindings::iterator j = env2->values[0].attrs->find(name); | ||||||
|  |         if (j == env2->values[0].attrs->end()) | ||||||
|  |             throwEvalError("undefined variable `%1%'", name); | ||||||
|  |         v = j->second; | ||||||
|  |     } else { | ||||||
|         state.forceValue(env2->values[displ]); |         state.forceValue(env2->values[displ]); | ||||||
|         v = env2->values[displ]; |         v = env2->values[displ]; | ||||||
|     } |     } | ||||||
|  | @ -655,17 +655,26 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res | ||||||
| 
 | 
 | ||||||
| void ExprWith::eval(EvalState & state, Env & env, Value & v) | void ExprWith::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     abort(); |     Env & env2(state.allocEnv(1)); | ||||||
| #if 0 |  | ||||||
|     Env & env2(state.allocEnv()); |  | ||||||
|     env2.up = &env; |     env2.up = &env; | ||||||
| 
 | 
 | ||||||
|     Value & vAttrs = env2.bindings[state.sWith]; |     state.eval(env, attrs, env2.values[0]); | ||||||
|     state.eval(env, attrs, vAttrs); |     state.forceAttrs(env2.values[0]); | ||||||
|     state.forceAttrs(vAttrs); | 
 | ||||||
|  |     /* If there is an enclosing `with', copy all attributes that don't
 | ||||||
|  |        appear in this `with'. */ | ||||||
|  |     if (prevWith != -1) { | ||||||
|  |         Env * env3 = &env; | ||||||
|  |         for (unsigned int l = prevWith; l; --l, env3 = env3->up) ; | ||||||
|  | 
 | ||||||
|  |         foreach (Bindings::iterator, i, *env3->values[0].attrs) { | ||||||
|  |             Bindings::iterator j = env2.values[0].attrs->find(i->first); | ||||||
|  |             if (j == env2.values[0].attrs->end()) | ||||||
|  |                 (*env2.values[0].attrs)[i->first] = i->second; // !!! sharing
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|          |          | ||||||
|     state.eval(env2, body, v); |     state.eval(env2, body, v); | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -264,6 +264,18 @@ void ExprLet::bindVars(const StaticEnv & env) | ||||||
| 
 | 
 | ||||||
| void ExprWith::bindVars(const StaticEnv & env) | void ExprWith::bindVars(const StaticEnv & env) | ||||||
| { | { | ||||||
|  |     /* Does this `with' have an enclosing `with'?  If so, record its
 | ||||||
|  |        level so that we can copy the attributes of the enclosing | ||||||
|  |        `with'. */ | ||||||
|  |     const StaticEnv * curEnv; | ||||||
|  |     unsigned int level; | ||||||
|  |     prevWith = -1; | ||||||
|  |     for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) | ||||||
|  |         if (curEnv->isWith) { | ||||||
|  |             prevWith = level; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |      | ||||||
|     attrs->bindVars(env);     |     attrs->bindVars(env);     | ||||||
|     StaticEnv newEnv(true, &env); |     StaticEnv newEnv(true, &env); | ||||||
|     body->bindVars(newEnv); |     body->bindVars(newEnv); | ||||||
|  |  | ||||||
|  | @ -170,6 +170,7 @@ struct ExprWith : Expr | ||||||
| { | { | ||||||
|     Pos pos; |     Pos pos; | ||||||
|     Expr * attrs, * body; |     Expr * attrs, * body; | ||||||
|  |     int prevWith; | ||||||
|     ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; |     ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue