LTP GCOV extension - code coverage report
Current view: directory - src/libexpr - eval.cc
Test: app.info
Date: 2004-12-21 Instrumented lines: 201
Code covered: 72.6 % Executed lines: 146

       1                 : #include "eval.hh"
       2                 : #include "parser.hh"
       3                 : #include "nixexpr-ast.hh"
       4                 : 
       5                 : 
       6                 : EvalState::EvalState()
       7              23 :     : normalForms(32768, 50)
       8              23 : {
       9              23 :     blackHole = makeBlackHole();
      10                 :     
      11              23 :     nrEvaluated = nrCached = 0;
      12                 : 
      13              23 :     initNixExprHelpers();
      14                 : 
      15              23 :     addPrimOps();
      16                 : }
      17                 : 
      18                 : 
      19                 : void EvalState::addPrimOp(const string & name,
      20                 :     unsigned int arity, PrimOp primOp)
      21             207 : {
      22             207 :     primOps.set(name, makePrimOpDef(arity, ATmakeBlob(0, (void *) primOp)));
      23                 : }
      24                 : 
      25                 : 
      26                 : /* Substitute an argument set into the body of a function. */
      27                 : static Expr substArgs(Expr body, ATermList formals, Expr arg)
      28               3 : {
      29               3 :     ATermMap subs;
      30               3 :     Expr undefined = makeUndefined();
      31                 : 
      32                 :     /* Get the formal arguments. */
      33               6 :     for (ATermIterator i(formals); i; ++i) {
      34               3 :         Expr name, def;
      35               3 :         if (matchNoDefFormal(*i, name))
      36               3 :             subs.set(name, undefined);
      37               0 :         else if (matchDefFormal(*i, name, def))
      38               0 :             subs.set(name, def);
      39               0 :         else abort(); /* can't happen */
      40                 :     }
      41                 : 
      42                 :     /* Get the actual arguments, and check that they match with the
      43                 :        formals. */
      44               3 :     ATermMap args;
      45               3 :     queryAllAttrs(arg, args);
      46               6 :     for (ATermIterator i(args.keys()); i; ++i) {
      47               3 :         Expr key = *i;
      48               3 :         Expr cur = subs.get(key);
      49               3 :         if (!cur)
      50               0 :             throw Error(format("unexpected function argument `%1%'")
      51               0 :                 % aterm2String(key));
      52               3 :         subs.set(key, args.get(key));
      53                 :     }
      54                 : 
      55                 :     /* Check that all arguments are defined. */
      56               6 :     for (ATermIterator i(subs.keys()); i; ++i)
      57               3 :         if (subs.get(*i) == undefined)
      58               0 :             throw Error(format("required function argument `%1%' missing")
      59                 :                 % aterm2String(*i));
      60                 :     
      61               3 :     return substitute(subs, body);
      62                 : }
      63                 : 
      64                 : 
      65                 : /* Transform a mutually recursive set into a non-recursive set.  Each
      66                 :    attribute is transformed into an expression that has all references
      67                 :    to attributes substituted with selection expressions on the
      68                 :    original set.  E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f
      69                 :    (e.x) (e.y); y = e.x;}'. */
      70                 : ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
      71               8 : {
      72               8 :     ATerm name;
      73               8 :     Expr e2;
      74               8 :     Pos pos;
      75                 : 
      76                 :     /* Create the substitution list. */
      77               8 :     ATermMap subs;
      78              37 :     for (ATermIterator i(rbnds); i; ++i) {
      79              29 :         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
      80              29 :         subs.set(name, makeSelect(e, name));
      81                 :     }
      82               9 :     for (ATermIterator i(nrbnds); i; ++i) {
      83               1 :         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
      84               1 :         subs.set(name, e2);
      85                 :     }
      86                 : 
      87                 :     /* Create the non-recursive set. */
      88               8 :     ATermMap as;
      89              37 :     for (ATermIterator i(rbnds); i; ++i) {
      90              29 :         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
      91              29 :         as.set(name, makeAttrRHS(substitute(subs, e2), pos));
      92                 :     }
      93                 : 
      94                 :     /* Copy the non-recursive bindings.  !!! inefficient */
      95               9 :     for (ATermIterator i(nrbnds); i; ++i) {
      96               1 :         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
      97               1 :         as.set(name, makeAttrRHS(e2, pos));
      98                 :     }
      99                 : 
     100               8 :     return makeAttrs(as);
     101                 : }
     102                 : 
     103                 : 
     104                 : static Expr updateAttrs(Expr e1, Expr e2)
     105               0 : {
     106                 :     /* Note: e1 and e2 should be in normal form. */
     107                 : 
     108               0 :     ATermMap attrs;
     109               0 :     queryAllAttrs(e1, attrs, true);
     110               0 :     queryAllAttrs(e2, attrs, true);
     111                 : 
     112               0 :     return makeAttrs(attrs);
     113                 : }
     114                 : 
     115                 : 
     116                 : string evalString(EvalState & state, Expr e)
     117              43 : {
     118              43 :     e = evalExpr(state, e);
     119              43 :     ATerm s;
     120              43 :     if (!matchStr(e, s)) throw Error("string expected");
     121              43 :     return aterm2String(s);
     122                 : }
     123                 : 
     124                 : 
     125                 : Path evalPath(EvalState & state, Expr e)
     126              43 : {
     127              43 :     e = evalExpr(state, e);
     128              43 :     ATerm s;
     129              43 :     if (!matchPath(e, s)) throw Error("path expected");
     130              43 :     return aterm2String(s);
     131                 : }
     132                 : 
     133                 : 
     134                 : bool evalBool(EvalState & state, Expr e)
     135               0 : {
     136               0 :     e = evalExpr(state, e);
     137               0 :     if (e == eTrue) return true;
     138               0 :     else if (e == eFalse) return false;
     139               0 :     else throw Error("boolean expected");
     140                 : }
     141                 : 
     142                 : 
     143                 : Expr evalExpr2(EvalState & state, Expr e)
     144             381 : {
     145             381 :     Expr e1, e2, e3, e4;
     146             381 :     ATerm name, pos;
     147             381 :     AFun sym = ATgetAFun(e);
     148                 : 
     149                 :     /* Normal forms. */
     150             381 :     if (sym == symStr ||
     151                 :         sym == symPath ||
     152                 :         sym == symSubPath ||
     153                 :         sym == symUri ||
     154                 :         sym == symNull ||
     155                 :         sym == symInt ||
     156                 :         sym == symBool ||
     157                 :         sym == symFunction ||
     158                 :         sym == symFunction1 ||
     159                 :         sym == symAttrs ||
     160                 :         sym == symList ||
     161                 :         sym == symPrimOp)
     162             231 :         return e;
     163                 :     
     164                 :     /* The `Closed' constructor is just a way to prevent substitutions
     165                 :        into expressions not containing free variables. */
     166             150 :     if (matchClosed(e, e1))
     167              41 :         return evalExpr(state, e1);
     168                 : 
     169                 :     /* Any encountered variables must be primops (since undefined
     170                 :        variables are detected after parsing). */
     171             109 :     if (matchVar(e, name)) {
     172              13 :         ATerm primOp = state.primOps.get(name);
     173              13 :         if (!primOp)
     174               0 :             throw Error(format("impossible: undefined variable `%1%'") % name);
     175              13 :         int arity;
     176              13 :         ATermBlob fun;
     177              13 :         if (!matchPrimOpDef(primOp, arity, fun)) abort();
     178              13 :         if (arity == 0)
     179               0 :             return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
     180                 :         else
     181              13 :             return makePrimOp(arity, fun, ATempty);
     182                 :     }
     183                 : 
     184                 :     /* Function application. */
     185              96 :     if (matchCall(e, e1, e2)) {
     186                 : 
     187              53 :         ATermList formals;
     188              53 :         ATerm pos;
     189                 :         
     190                 :         /* Evaluate the left-hand side. */
     191              53 :         e1 = evalExpr(state, e1);
     192                 : 
     193                 :         /* Is it a primop or a function? */
     194              53 :         int arity;
     195              53 :         ATermBlob fun;
     196              53 :         ATermList args;
     197              53 :         if (matchPrimOp(e1, arity, fun, args)) {
     198              26 :             args = ATinsert(args, e2);
     199              26 :             if (ATgetLength(args) == arity) {
     200                 :                 /* Put the arguments in a vector in reverse (i.e.,
     201                 :                    actual) order. */
     202              25 :                 ATermVector args2(arity);
     203              51 :                 for (ATermIterator i(args); i; ++i)
     204              26 :                     args2[--arity] = *i;
     205              25 :                 return ((PrimOp) ATgetBlobData((ATermBlob) fun))
     206                 :                     (state, args2);
     207                 :             } else
     208                 :                 /* Need more arguments, so propagate the primop. */
     209               1 :                 return makePrimOp(arity, fun, args);
     210                 :         }
     211                 : 
     212              27 :         else if (matchFunction(e1, formals, e4, pos)) {
     213               3 :             e2 = evalExpr(state, e2);
     214               3 :             try {
     215               3 :                 return evalExpr(state, substArgs(e4, formals, e2));
     216               0 :             } catch (Error & e) {
     217               0 :                 throw Error(format("while evaluating the function at %1%:\n%2%")
     218                 :                     % showPos(pos) % e.msg());
     219                 :             }
     220                 :         }
     221                 :         
     222              24 :         else if (matchFunction1(e1, name, e4, pos)) {
     223              24 :             try {
     224              24 :                 ATermMap subs;
     225              24 :                 subs.set(name, e2);
     226              24 :                 return evalExpr(state, substitute(subs, e4));
     227               0 :             } catch (Error & e) {
     228               0 :                 throw Error(format("while evaluating the function at %1%:\n%2%")
     229                 :                     % showPos(pos) % e.msg());
     230                 :             }
     231                 :         }
     232                 :         
     233               0 :         else throw Error("function or primop expected in function call");
     234                 :     }
     235                 : 
     236                 :     /* Attribute selection. */
     237              43 :     if (matchSelect(e, e1, name)) {
     238              31 :         ATerm pos;
     239              31 :         string s1 = aterm2String(name);
     240              31 :         Expr a = queryAttr(evalExpr(state, e1), s1, pos);
     241              31 :         if (!a) throw Error(format("attribute `%1%' missing") % s1);
     242              31 :         try {
     243              31 :             return evalExpr(state, a);
     244               3 :         } catch (Error & e) {
     245               3 :             throw Error(format("while evaluating the attribute `%1%' at %2%:\n%3%")
     246                 :                 % s1 % showPos(pos) % e.msg());
     247                 :         }
     248                 :     }
     249                 : 
     250                 :     /* Mutually recursive sets. */
     251              12 :     ATermList rbnds, nrbnds;
     252              12 :     if (matchRec(e, rbnds, nrbnds))
     253               8 :         return expandRec(e, rbnds, nrbnds);
     254                 : 
     255                 :     /* Conditionals. */
     256               4 :     if (matchIf(e, e1, e2, e3)) {
     257               0 :         if (evalBool(state, e1))
     258               0 :             return evalExpr(state, e2);
     259                 :         else
     260               0 :             return evalExpr(state, e3);
     261                 :     }
     262                 : 
     263                 :     /* Assertions. */
     264               4 :     if (matchAssert(e, e1, e2, pos)) {
     265               0 :         if (!evalBool(state, e1))
     266               0 :             throw Error(format("assertion failed at %1%") % showPos(pos));
     267               0 :         return evalExpr(state, e2);
     268                 :     }
     269                 : 
     270                 :     /* Withs. */
     271               4 :     if (matchWith(e, e1, e2, pos)) {
     272               0 :         ATermMap attrs;
     273               0 :         try {
     274               0 :             e1 = evalExpr(state, e1);
     275               0 :             queryAllAttrs(e1, attrs);
     276               0 :         } catch (Error & e) {
     277               0 :             throw Error(format("while evaluating the `with' definitions at %1%:\n%2%")
     278                 :                 % showPos(pos) % e.msg());
     279                 :         }
     280               0 :         try {
     281               0 :             e2 = substitute(attrs, e2);
     282               0 :             checkVarDefs(state.primOps, e2);
     283               0 :             return evalExpr(state, e2);
     284               0 :         } catch (Error & e) {
     285               0 :             throw Error(format("while evaluating the `with' body at %1%:\n%2%")
     286                 :                 % showPos(pos) % e.msg());
     287                 :         } 
     288                 :     }
     289                 : 
     290                 :     /* Generic equality. */
     291               4 :     if (matchOpEq(e, e1, e2))
     292               0 :         return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
     293                 : 
     294                 :     /* Generic inequality. */
     295               4 :     if (matchOpNEq(e, e1, e2))
     296               0 :         return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
     297                 : 
     298                 :     /* Negation. */
     299               4 :     if (matchOpNot(e, e1))
     300               0 :         return makeBool(!evalBool(state, e1));
     301                 : 
     302                 :     /* Implication. */
     303               4 :     if (matchOpImpl(e, e1, e2))
     304               0 :         return makeBool(!evalBool(state, e1) || evalBool(state, e2));
     305                 : 
     306                 :     /* Conjunction (logical AND). */
     307               4 :     if (matchOpAnd(e, e1, e2))
     308               0 :         return makeBool(evalBool(state, e1) && evalBool(state, e2));
     309                 : 
     310                 :     /* Disjunction (logical OR). */
     311               4 :     if (matchOpOr(e, e1, e2))
     312               0 :         return makeBool(evalBool(state, e1) || evalBool(state, e2));
     313                 : 
     314                 :     /* Attribute set update (//). */
     315               4 :     if (matchOpUpdate(e, e1, e2))
     316               0 :         return updateAttrs(evalExpr(state, e1), evalExpr(state, e2));
     317                 : 
     318                 :     /* Attribute existence test (?). */
     319               4 :     if (matchOpHasAttr(e, e1, name)) {
     320               0 :         ATermMap attrs;
     321               0 :         queryAllAttrs(evalExpr(state, e1), attrs);
     322               0 :         return makeBool(attrs.get(name) != 0);
     323                 :     }
     324                 : 
     325                 :     /* String or path concatenation. */
     326               4 :     if (matchOpPlus(e, e1, e2)) {
     327               4 :         e1 = evalExpr(state, e1);
     328               4 :         e2 = evalExpr(state, e2);
     329               4 :         ATerm s1, s2;
     330               4 :         if (matchStr(e1, s1) && matchStr(e2, s2))
     331               3 :             return makeStr(toATerm(
     332                 :                 (string) aterm2String(s1) + (string) aterm2String(s2)));
     333               1 :         else if (matchPath(e1, s1) && matchPath(e2, s2))
     334               1 :             return makePath(toATerm(canonPath(
     335                 :                 (string) aterm2String(s1) + "/" + (string) aterm2String(s2))));
     336               0 :         else throw Error("wrong argument types in `+' operator");
     337                 :     }
     338                 : 
     339                 :     /* Barf. */
     340               0 :     throw badTerm("invalid expression", e);
     341                 : }
     342                 : 
     343                 : 
     344                 : Expr evalExpr(EvalState & state, Expr e)
     345             607 : {
     346             607 :     checkInterrupt();
     347                 :     
     348             607 :     startNest(nest, lvlVomit,
     349                 :         format("evaluating expression: %1%") % e);
     350                 : 
     351             607 :     state.nrEvaluated++;
     352                 : 
     353                 :     /* Consult the memo table to quickly get the normal form of
     354                 :        previously evaluated expressions. */
     355             607 :     Expr nf = state.normalForms.get(e);
     356             607 :     if (nf) {
     357             226 :         if (nf == state.blackHole)
     358               1 :             throw Error("infinite recursion encountered");
     359             225 :         state.nrCached++;
     360             225 :         return nf;
     361                 :     }
     362                 : 
     363                 :     /* Otherwise, evaluate and memoize. */
     364             381 :     state.normalForms.set(e, state.blackHole);
     365             381 :     nf = evalExpr2(state, e);
     366             376 :     state.normalForms.set(e, nf);
     367             376 :     return nf;
     368                 : }
     369                 : 
     370                 : 
     371                 : Expr evalFile(EvalState & state, const Path & path)
     372              11 : {
     373              11 :     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
     374              11 :     Expr e = parseExprFromFile(state, path);
     375              11 :     try {
     376              11 :         return evalExpr(state, e);
     377               0 :     } catch (Error & e) {
     378               0 :         throw Error(format("while evaluating the file `%1%':\n%2%")
     379                 :             % path % e.msg());
     380                 :     }
     381                 : }
     382                 : 
     383                 : 
     384                 : void printEvalStats(EvalState & state)
     385              21 : {
     386              21 :     debug(format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency")
     387                 :         % state.nrEvaluated % state.nrCached
     388                 :         % ((float) state.nrCached / (float) state.nrEvaluated * 100));
     389                 : }

Generated by: LTP GCOV extension version 1.1