* Don't use ATmake / ATmatch anymore, nor the ATMatcher class.
Instead we generate data bindings (build and match functions) for the constructors specified in `constructors.def'. In particular this removes the conversions between AFuns and strings, and Nix expression evaluation now seems 3 to 4 times faster.
This commit is contained in:
		
							parent
							
								
									eb8284ddaa
								
							
						
					
					
						commit
						5fe9222b36
					
				
					 11 changed files with 410 additions and 304 deletions
				
			
		|  | @ -1,15 +1,17 @@ | |||
| #include "eval.hh" | ||||
| #include "parser.hh" | ||||
| #include "constructors.hh" | ||||
| 
 | ||||
| 
 | ||||
| EvalState::EvalState() | ||||
|     : normalForms(32768, 50) | ||||
| { | ||||
|     blackHole = ATmake("BlackHole()"); | ||||
|     if (!blackHole) throw Error("cannot build black hole"); | ||||
|     blackHole = makeBlackHole(); | ||||
|      | ||||
|     nrEvaluated = nrCached = 0; | ||||
| 
 | ||||
|     initSyms(); | ||||
| 
 | ||||
|     addPrimOps(); | ||||
| } | ||||
| 
 | ||||
|  | @ -17,24 +19,22 @@ EvalState::EvalState() | |||
| void EvalState::addPrimOp(const string & name, | ||||
|     unsigned int arity, PrimOp primOp) | ||||
| { | ||||
|     primOps.set(name, ATmake("(<int>, <term>)", | ||||
|         arity, ATmakeBlob(0, (void *) primOp))); | ||||
|     primOps.set(name, makePrimOpDef(arity, ATmakeBlob(0, (void *) primOp))); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Substitute an argument set into the body of a function. */ | ||||
| static Expr substArgs(Expr body, ATermList formals, Expr arg) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     ATermMap subs; | ||||
|     Expr undefined = ATmake("Undefined"); | ||||
|     Expr undefined = makeUndefined(); | ||||
| 
 | ||||
|     /* Get the formal arguments. */ | ||||
|     for (ATermIterator i(formals); i; ++i) { | ||||
|         Expr name, def; | ||||
|         if (atMatch(m, *i) >> "NoDefFormal" >> name) | ||||
|         if (matchNoDefFormal(*i, name)) | ||||
|             subs.set(name, undefined); | ||||
|         else if (atMatch(m, *i) >> "DefFormal" >> name >> def) | ||||
|         else if (matchDefFormal(*i, name, def)) | ||||
|             subs.set(name, def); | ||||
|         else abort(); /* can't happen */ | ||||
|     } | ||||
|  | @ -69,38 +69,32 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg) | |||
|    (e.x) (e.y); y = e.x;}'. */ | ||||
| ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     ATerm name; | ||||
|     Expr e2; | ||||
|     Pos pos; | ||||
| 
 | ||||
|     /* Create the substitution list. */ | ||||
|     ATermMap subs; | ||||
|     for (ATermIterator i(rbnds); i; ++i) { | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) | ||||
|             abort(); /* can't happen */ | ||||
|         subs.set(name, ATmake("Select(<term>, <term>)", e, name)); | ||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||
|         subs.set(name, makeSelect(e, name)); | ||||
|     } | ||||
|     for (ATermIterator i(nrbnds); i; ++i) { | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) | ||||
|             abort(); /* can't happen */ | ||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||
|         subs.set(name, e2); | ||||
|     } | ||||
| 
 | ||||
|     /* Create the non-recursive set. */ | ||||
|     ATermMap as; | ||||
|     for (ATermIterator i(rbnds); i; ++i) { | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         as.set(name, ATmake("(<term>, <term>)", substitute(subs, e2), pos)); | ||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||
|         as.set(name, makeAttrRHS(substitute(subs, e2), pos)); | ||||
|     } | ||||
| 
 | ||||
|     /* Copy the non-recursive bindings.  !!! inefficient */ | ||||
|     for (ATermIterator i(nrbnds); i; ++i) { | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         as.set(name, ATmake("(<term>, <term>)", e2, pos)); | ||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||
|         as.set(name, makeAttrRHS(e2, pos)); | ||||
|     } | ||||
| 
 | ||||
|     return makeAttrs(as); | ||||
|  | @ -122,82 +116,73 @@ static Expr updateAttrs(Expr e1, Expr e2) | |||
| string evalString(EvalState & state, Expr e) | ||||
| { | ||||
|     e = evalExpr(state, e); | ||||
|     ATMatcher m; | ||||
|     string s; | ||||
|     if (!(atMatch(m, e) >> "Str" >> s)) | ||||
|         throw Error("string expected"); | ||||
|     return s; | ||||
|     ATerm s; | ||||
|     if (!matchStr(e, s)) throw Error("string expected"); | ||||
|     return aterm2String(s); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Path evalPath(EvalState & state, Expr e) | ||||
| { | ||||
|     e = evalExpr(state, e); | ||||
|     ATMatcher m; | ||||
|     string s; | ||||
|     if (!(atMatch(m, e) >> "Path" >> s)) | ||||
|         throw Error("path expected"); | ||||
|     return s; | ||||
|     ATerm s; | ||||
|     if (!matchPath(e, s)) throw Error("path expected"); | ||||
|     return aterm2String(s); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool evalBool(EvalState & state, Expr e) | ||||
| { | ||||
|     e = evalExpr(state, e); | ||||
|     ATMatcher m; | ||||
|     if (atMatch(m, e) >> "Bool" >> "True") return true; | ||||
|     else if (atMatch(m, e) >> "Bool" >> "False") return false; | ||||
|     if (e == eTrue) return true; | ||||
|     else if (e == eFalse) return false; | ||||
|     else throw Error("boolean expected"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr evalExpr2(EvalState & state, Expr e) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     Expr e1, e2, e3, e4; | ||||
|     ATerm name, pos; | ||||
|     AFun sym = ATgetAFun(e); | ||||
| 
 | ||||
|     /* Normal forms. */ | ||||
|     string cons; | ||||
|     if (atMatch(m, e) >> cons && | ||||
|         (cons == "Str" || | ||||
|          cons == "Path" || | ||||
|          cons == "SubPath" || | ||||
|          cons == "Uri" || | ||||
|          cons == "Null" || | ||||
|          cons == "Int" || | ||||
|          cons == "Bool" || | ||||
|          cons == "Function" || | ||||
|          cons == "Function1" || | ||||
|          cons == "Attrs" || | ||||
|          cons == "List" || | ||||
|          cons == "PrimOp")) | ||||
|     if (sym == symStr || | ||||
|         sym == symPath || | ||||
|         sym == symSubPath || | ||||
|         sym == symUri || | ||||
|         sym == symNull || | ||||
|         sym == symInt || | ||||
|         sym == symBool || | ||||
|         sym == symFunction || | ||||
|         sym == symFunction1 || | ||||
|         sym == symAttrs || | ||||
|         sym == symList || | ||||
|         sym == symPrimOp) | ||||
|         return e; | ||||
| 
 | ||||
|      | ||||
|     /* The `Closed' constructor is just a way to prevent substitutions
 | ||||
|        into expressions not containing free variables. */ | ||||
|     if (atMatch(m, e) >> "Closed" >> e1) | ||||
|     if (matchClosed(e, e1)) | ||||
|         return evalExpr(state, e1); | ||||
| 
 | ||||
|     /* Any encountered variables must be primops (since undefined
 | ||||
|        variables are detected after parsing). */ | ||||
|     if (atMatch(m, e) >> "Var" >> name) { | ||||
|     if (matchVar(e, name)) { | ||||
|         ATerm primOp = state.primOps.get(name); | ||||
|         if (!primOp) | ||||
|             throw Error(format("impossible: undefined variable `%1%'") % name); | ||||
|         int arity; | ||||
|         ATerm fun; | ||||
|         if (!(atMatch(m, primOp) >> "" >> arity >> fun)) abort(); | ||||
|         ATermBlob fun; | ||||
|         if (!matchPrimOpDef(primOp, arity, fun)) abort(); | ||||
|         if (arity == 0) | ||||
|             return ((PrimOp) ATgetBlobData((ATermBlob) fun)) | ||||
|                 (state, ATermVector()); | ||||
|             return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector()); | ||||
|         else | ||||
|             return ATmake("PrimOp(<int>, <term>, <term>)", | ||||
|                 arity, fun, ATempty); | ||||
|             return makePrimOp(arity, fun, ATempty); | ||||
|     } | ||||
| 
 | ||||
|     /* Function application. */ | ||||
|     if (atMatch(m, e) >> "Call" >> e1 >> e2) { | ||||
|     if (matchCall(e, e1, e2)) { | ||||
| 
 | ||||
|         ATermList formals; | ||||
|         ATerm pos; | ||||
|  | @ -207,9 +192,9 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
| 
 | ||||
|         /* Is it a primop or a function? */ | ||||
|         int arity; | ||||
|         ATerm fun; | ||||
|         ATermBlob fun; | ||||
|         ATermList args; | ||||
|         if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) { | ||||
|         if (matchPrimOp(e1, arity, fun, args)) { | ||||
|             args = ATinsert(args, e2); | ||||
|             if (ATgetLength(args) == arity) { | ||||
|                 /* Put the arguments in a vector in reverse (i.e.,
 | ||||
|  | @ -221,11 +206,10 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|                     (state, args2); | ||||
|             } else | ||||
|                 /* Need more arguments, so propagate the primop. */ | ||||
|                 return ATmake("PrimOp(<int>, <term>, <term>)", | ||||
|                     arity, fun, args); | ||||
|                 return makePrimOp(arity, fun, args); | ||||
|         } | ||||
| 
 | ||||
|         else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { | ||||
|         else if (matchFunction(e1, formals, e4, pos)) { | ||||
|             e2 = evalExpr(state, e2); | ||||
|             try { | ||||
|                 return evalExpr(state, substArgs(e4, formals, e2)); | ||||
|  | @ -235,7 +219,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|             } | ||||
|         } | ||||
|          | ||||
|         else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) { | ||||
|         else if (matchFunction1(e1, name, e4, pos)) { | ||||
|             try { | ||||
|                 ATermMap subs; | ||||
|                 subs.set(name, e2); | ||||
|  | @ -250,9 +234,9 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|     } | ||||
| 
 | ||||
|     /* Attribute selection. */ | ||||
|     string s1; | ||||
|     if (atMatch(m, e) >> "Select" >> e1 >> s1) { | ||||
|     if (matchSelect(e, e1, name)) { | ||||
|         ATerm pos; | ||||
|         string s1 = aterm2String(name); | ||||
|         Expr a = queryAttr(evalExpr(state, e1), s1, pos); | ||||
|         if (!a) throw Error(format("attribute `%1%' missing") % s1); | ||||
|         try { | ||||
|  | @ -265,11 +249,11 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
| 
 | ||||
|     /* Mutually recursive sets. */ | ||||
|     ATermList rbnds, nrbnds; | ||||
|     if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) | ||||
|     if (matchRec(e, rbnds, nrbnds)) | ||||
|         return expandRec(e, rbnds, nrbnds); | ||||
| 
 | ||||
|     /* Conditionals. */ | ||||
|     if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { | ||||
|     if (matchIf(e, e1, e2, e3)) { | ||||
|         if (evalBool(state, e1)) | ||||
|             return evalExpr(state, e2); | ||||
|         else | ||||
|  | @ -277,14 +261,14 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|     } | ||||
| 
 | ||||
|     /* Assertions. */ | ||||
|     if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) { | ||||
|     if (matchAssert(e, e1, e2, pos)) { | ||||
|         if (!evalBool(state, e1)) | ||||
|             throw Error(format("assertion failed at %1%") % showPos(pos)); | ||||
|         return evalExpr(state, e2); | ||||
|     } | ||||
| 
 | ||||
|     /* Withs. */ | ||||
|     if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) { | ||||
|     if (matchWith(e, e1, e2, pos)) { | ||||
|         ATermMap attrs; | ||||
|         try { | ||||
|             e1 = evalExpr(state, e1); | ||||
|  | @ -304,51 +288,51 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|     } | ||||
| 
 | ||||
|     /* Generic equality. */ | ||||
|     if (atMatch(m, e) >> "OpEq" >> e1 >> e2) | ||||
|     if (matchOpEq(e, e1, e2)) | ||||
|         return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); | ||||
| 
 | ||||
|     /* Generic inequality. */ | ||||
|     if (atMatch(m, e) >> "OpNEq" >> e1 >> e2) | ||||
|     if (matchOpNEq(e, e1, e2)) | ||||
|         return makeBool(evalExpr(state, e1) != evalExpr(state, e2)); | ||||
| 
 | ||||
|     /* Negation. */ | ||||
|     if (atMatch(m, e) >> "OpNot" >> e1) | ||||
|     if (matchOpNot(e, e1)) | ||||
|         return makeBool(!evalBool(state, e1)); | ||||
| 
 | ||||
|     /* Implication. */ | ||||
|     if (atMatch(m, e) >> "OpImpl" >> e1 >> e2) | ||||
|     if (matchOpImpl(e, e1, e2)) | ||||
|         return makeBool(!evalBool(state, e1) || evalBool(state, e2)); | ||||
| 
 | ||||
|     /* Conjunction (logical AND). */ | ||||
|     if (atMatch(m, e) >> "OpAnd" >> e1 >> e2) | ||||
|     if (matchOpAnd(e, e1, e2)) | ||||
|         return makeBool(evalBool(state, e1) && evalBool(state, e2)); | ||||
| 
 | ||||
|     /* Disjunction (logical OR). */ | ||||
|     if (atMatch(m, e) >> "OpOr" >> e1 >> e2) | ||||
|     if (matchOpOr(e, e1, e2)) | ||||
|         return makeBool(evalBool(state, e1) || evalBool(state, e2)); | ||||
| 
 | ||||
|     /* Attribute set update (//). */ | ||||
|     if (atMatch(m, e) >> "OpUpdate" >> e1 >> e2) | ||||
|     if (matchOpUpdate(e, e1, e2)) | ||||
|         return updateAttrs(evalExpr(state, e1), evalExpr(state, e2)); | ||||
| 
 | ||||
|     /* Attribute existence test (?). */ | ||||
|     if (atMatch(m, e) >> "OpHasAttr" >> e1 >> name) { | ||||
|     if (matchOpHasAttr(e, e1, name)) { | ||||
|         ATermMap attrs; | ||||
|         queryAllAttrs(evalExpr(state, e1), attrs); | ||||
|         return makeBool(attrs.get(name) != 0); | ||||
|     } | ||||
| 
 | ||||
|     /* String or path concatenation. */ | ||||
|     if (atMatch(m, e) >> "OpPlus" >> e1 >> e2) { | ||||
|     if (matchOpPlus(e, e1, e2)) { | ||||
|         e1 = evalExpr(state, e1); | ||||
|         e2 = evalExpr(state, e2); | ||||
|         string s1, s2; | ||||
|         if (atMatch(m, e1) >> "Str" >> s1 && | ||||
|             atMatch(m, e2) >> "Str" >> s2) | ||||
|             return makeString(s1 + s2); | ||||
|         else if (atMatch(m, e1) >> "Path" >> s1 && | ||||
|             atMatch(m, e2) >> "Path" >> s2) | ||||
|             return makePath(canonPath(s1 + "/" + s2)); | ||||
|         ATerm s1, s2; | ||||
|         if (matchStr(e1, s1) && matchStr(e2, s2)) | ||||
|             return makeStr(string2ATerm(( | ||||
|                 (string) aterm2String(s1) + (string) aterm2String(s2)).c_str())); | ||||
|         else if (matchPath(e1, s1) && matchPath(e2, s2)) | ||||
|             return makePath(string2ATerm(canonPath( | ||||
|                 (string) aterm2String(s1) + "/" + (string) aterm2String(s2)).c_str())); | ||||
|         else throw Error("wrong argument types in `+' operator"); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue