* Implemented the ==' and !=' operators.  These now use a deep
				
					
				
			equality test, so they also work for (finite) attribute sets and lists.
This commit is contained in:
		
							parent
							
								
									8da118e4d0
								
							
						
					
					
						commit
						cad8726b2c
					
				
					 1 changed files with 67 additions and 0 deletions
				
			
		|  | @ -26,6 +26,7 @@ struct Env | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     tInt = 1, |     tInt = 1, | ||||||
|  |     tBool, | ||||||
|     tAttrs, |     tAttrs, | ||||||
|     tList, |     tList, | ||||||
|     tThunk, |     tThunk, | ||||||
|  | @ -41,6 +42,7 @@ struct Value | ||||||
|     union  |     union  | ||||||
|     { |     { | ||||||
|         int integer; |         int integer; | ||||||
|  |         bool boolean; | ||||||
|         Bindings * attrs; |         Bindings * attrs; | ||||||
|         struct { |         struct { | ||||||
|             unsigned int length; |             unsigned int length; | ||||||
|  | @ -66,6 +68,9 @@ std::ostream & operator << (std::ostream & str, Value & v) | ||||||
|     case tInt: |     case tInt: | ||||||
|         str << v.integer; |         str << v.integer; | ||||||
|         break; |         break; | ||||||
|  |     case tBool: | ||||||
|  |         str << (v.boolean ? "true" : "false"); | ||||||
|  |         break; | ||||||
|     case tAttrs: |     case tAttrs: | ||||||
|         str << "{ "; |         str << "{ "; | ||||||
|         foreach (Bindings::iterator, i, *v.attrs) |         foreach (Bindings::iterator, i, *v.attrs) | ||||||
|  | @ -152,6 +157,45 @@ static Value * lookupVar(Env * env, Sym name) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static void setBoolValue(Value & v, bool b) | ||||||
|  | { | ||||||
|  |     v.type = tBool; | ||||||
|  |     v.boolean = b; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static bool eqValues(Value & v1, Value & v2) | ||||||
|  | { | ||||||
|  |     forceValue(v1); | ||||||
|  |     forceValue(v2); | ||||||
|  |     switch (v1.type) { | ||||||
|  | 
 | ||||||
|  |         case tInt: | ||||||
|  |             return v2.type == tInt && v1.integer == v2.integer; | ||||||
|  | 
 | ||||||
|  |         case tBool: | ||||||
|  |             return v2.type == tBool && v1.boolean == v2.boolean; | ||||||
|  | 
 | ||||||
|  |         case tList: | ||||||
|  |             if (v2.type != tList || v1.list.length != v2.list.length) return false; | ||||||
|  |             for (unsigned int n = 0; n < v1.list.length; ++n) | ||||||
|  |                 if (!eqValues(v1.list.elems[n], v2.list.elems[n])) return false; | ||||||
|  |             return true; | ||||||
|  | 
 | ||||||
|  |         case tAttrs: { | ||||||
|  |             if (v2.type != tAttrs || v1.attrs->size() != v2.attrs->size()) return false; | ||||||
|  |             Bindings::iterator i, j; | ||||||
|  |             for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) | ||||||
|  |                 if (!eqValues(i->second, j->second)) return false; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             throw Error("cannot compare given values"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| unsigned long nrValues = 0, nrEnvs = 0; | unsigned long nrValues = 0, nrEnvs = 0; | ||||||
| 
 | 
 | ||||||
| static Env * allocEnv() | static Env * allocEnv() | ||||||
|  | @ -337,6 +381,20 @@ static void eval(Env * env, Expr e, Value & v) | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (matchOpEq(e, e1, e2)) { | ||||||
|  |         Value v1; eval(env, e1, v1); | ||||||
|  |         Value v2; eval(env, e2, v2); | ||||||
|  |         setBoolValue(v, eqValues(v1, v2)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (matchOpNEq(e, e1, e2)) { | ||||||
|  |         Value v1; eval(env, e1, v1); | ||||||
|  |         Value v2; eval(env, e2, v2); | ||||||
|  |         setBoolValue(v, !eqValues(v1, v2)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     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"); |         if (v1.type != tList) throw TypeError("list expected"); | ||||||
|  | @ -411,6 +469,15 @@ void run(Strings args) | ||||||
|     doTest("with { x = 1; }; with { x = 2; }; x"); // => 1
 |     doTest("with { x = 1; }; with { x = 2; }; x"); // => 1
 | ||||||
|     doTest("[ 1 2 3 ]"); |     doTest("[ 1 2 3 ]"); | ||||||
|     doTest("[ 1 2 ] ++ [ 3 4 5 ]"); |     doTest("[ 1 2 ] ++ [ 3 4 5 ]"); | ||||||
|  |     doTest("123 == 123"); | ||||||
|  |     doTest("123 == 456"); | ||||||
|  |     doTest("let id = x: x; in [1 2] == [(id 1) (id 2)]"); | ||||||
|  |     doTest("let id = x: x; in [1 2] == [(id 1) (id 3)]"); | ||||||
|  |     doTest("[1 2] == [3 (let x = x; in x)]"); | ||||||
|  |     doTest("{ x = 1; y.z = 2; } == { y = { z = 2; }; x = 1; }"); | ||||||
|  |     doTest("{ x = 1; y = 2; } == { x = 2; }"); | ||||||
|  |     doTest("{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }"); | ||||||
|  |     doTest("1 != 1"); | ||||||
|      |      | ||||||
|     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); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue