* When something goes wrong in the evaluation of a Nix expression,
print a nice backtrace of the stack, rather than vomiting a gigantic
  (and useless) aterm on the screen.  Example:
    error: while evaluating file `.../pkgs/system/test.nix':
    while evaluating attribute `subversion' at `.../pkgs/system/all-packages-generic.nix', line 533:
    while evaluating function at `.../pkgs/applications/version-management/subversion/default.nix', line 1:
    assertion failed at `.../pkgs/applications/version-management/subversion/default.nix', line 13
  Since the Nix expression language is lazy, the trace may be
  misleading.  The purpose is to provide a hint as to the location of
  the problem.
			
			
This commit is contained in:
		
							parent
							
								
									a520b1cbc3
								
							
						
					
					
						commit
						59b94ee18a
					
				
					 8 changed files with 201 additions and 90 deletions
				
			
		|  | @ -77,16 +77,16 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg) | |||
|         Expr key = *i; | ||||
|         Expr cur = subs.get(key); | ||||
|         if (!cur) | ||||
|             throw badTerm(format("function has no formal argument `%1%'") | ||||
|                 % aterm2String(key), arg); | ||||
|             throw Error(format("unexpected function argument `%1%'") | ||||
|                 % aterm2String(key)); | ||||
|         subs.set(key, args.get(key)); | ||||
|     } | ||||
| 
 | ||||
|     /* Check that all arguments are defined. */ | ||||
|     for (ATermIterator i(subs.keys()); i; ++i) | ||||
|         if (subs.get(*i) == undefined) | ||||
|             throw badTerm(format("formal argument `%1%' missing") | ||||
|                 % aterm2String(*i), arg); | ||||
|             throw Error(format("required function argument `%1%' missing") | ||||
|                 % aterm2String(*i)); | ||||
|      | ||||
|     return substitute(subs, body); | ||||
| } | ||||
|  | @ -119,16 +119,18 @@ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) | |||
|     /* Create the non-recursive set. */ | ||||
|     ATermMap as; | ||||
|     for (ATermIterator i(rbnds); i; ++i) { | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         as.set(name, substitute(subs, e2)); | ||||
|         as.set(name, ATmake("(<term>, <term>)", substitute(subs, e2), pos)); | ||||
|     } | ||||
| 
 | ||||
|     /* Copy the non-recursive bindings.  !!! inefficient */ | ||||
|     for (ATermIterator i(nrbnds); i; ++i) { | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         as.set(name, e2); | ||||
|         as.set(name, ATmake("(<term>, <term>)", e2, pos)); | ||||
|     } | ||||
| 
 | ||||
|     return makeAttrs(as); | ||||
|  | @ -140,8 +142,8 @@ static Expr updateAttrs(Expr e1, Expr e2) | |||
|     /* Note: e1 and e2 should be in normal form. */ | ||||
| 
 | ||||
|     ATermMap attrs; | ||||
|     queryAllAttrs(e1, attrs); | ||||
|     queryAllAttrs(e2, attrs); | ||||
|     queryAllAttrs(e1, attrs, true); | ||||
|     queryAllAttrs(e2, attrs, true); | ||||
| 
 | ||||
|     return makeAttrs(attrs); | ||||
| } | ||||
|  | @ -153,7 +155,7 @@ string evalString(EvalState & state, Expr e) | |||
|     ATMatcher m; | ||||
|     string s; | ||||
|     if (!(atMatch(m, e) >> "Str" >> s)) | ||||
|         throw badTerm("string expected", e); | ||||
|         throw Error("string expected"); | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
|  | @ -164,7 +166,7 @@ Path evalPath(EvalState & state, Expr e) | |||
|     ATMatcher m; | ||||
|     string s; | ||||
|     if (!(atMatch(m, e) >> "Path" >> s)) | ||||
|         throw badTerm("path expected", e); | ||||
|         throw Error("path expected"); | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
|  | @ -175,7 +177,7 @@ bool evalBool(EvalState & state, Expr e) | |||
|     ATMatcher m; | ||||
|     if (atMatch(m, e) >> "Bool" >> "True") return true; | ||||
|     else if (atMatch(m, e) >> "Bool" >> "False") return false; | ||||
|     else throw badTerm("expecting a boolean", e); | ||||
|     else throw Error("boolean expected"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -183,7 +185,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
| { | ||||
|     ATMatcher m; | ||||
|     Expr e1, e2, e3, e4; | ||||
|     ATerm name; | ||||
|     ATerm name, pos; | ||||
| 
 | ||||
|     /* Normal forms. */ | ||||
|     string cons; | ||||
|  | @ -219,6 +221,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|     if (atMatch(m, e) >> "Call" >> e1 >> e2) { | ||||
| 
 | ||||
|         ATermList formals; | ||||
|         ATerm pos; | ||||
|          | ||||
|         /* Evaluate the left-hand side. */ | ||||
|         e1 = evalExpr(state, e1); | ||||
|  | @ -229,25 +232,42 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|             if (primOp) return primOp(state, e2); else abort(); | ||||
|         } | ||||
| 
 | ||||
|         else if (atMatch(m, e1) >> "Function" >> formals >> e4) | ||||
|             return evalExpr(state,  | ||||
|                 substArgs(e4, formals, evalExpr(state, e2))); | ||||
|          | ||||
|         else if (atMatch(m, e1) >> "Function1" >> name >> e4) { | ||||
|             ATermMap subs; | ||||
|             subs.set(name, e2); | ||||
|             return evalExpr(state, substitute(subs, e4)); | ||||
|         else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { | ||||
|             e2 = evalExpr(state, e2); | ||||
|             try { | ||||
|                 return evalExpr(state, substArgs(e4, formals, e2)); | ||||
|             } catch (Error & e) { | ||||
|                 throw Error(format("while evaluating function at %1%:\n%2%") | ||||
|                     % showPos(pos) % e.msg()); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         else throw badTerm("expecting a function or primop", e1); | ||||
|         else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) { | ||||
|             try { | ||||
|                 ATermMap subs; | ||||
|                 subs.set(name, e2); | ||||
|                 return evalExpr(state, substitute(subs, e4)); | ||||
|             } catch (Error & e) { | ||||
|                 throw Error(format("while evaluating function at %1%:\n%2%") | ||||
|                     % showPos(pos) % e.msg()); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         else throw Error("function or primop expected in function call"); | ||||
|     } | ||||
| 
 | ||||
|     /* Attribute selection. */ | ||||
|     string s1; | ||||
|     if (atMatch(m, e) >> "Select" >> e1 >> s1) { | ||||
|         Expr a = queryAttr(evalExpr(state, e1), s1); | ||||
|         if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); | ||||
|         return evalExpr(state, a); | ||||
|         ATerm pos; | ||||
|         Expr a = queryAttr(evalExpr(state, e1), s1, pos); | ||||
|         if (!a) throw Error(format("attribute `%1%' missing") % s1); | ||||
|         try { | ||||
|             return evalExpr(state, a); | ||||
|         } catch (Error & e) { | ||||
|             throw Error(format("while evaluating attribute `%1%' at %2%:\n%3%") | ||||
|                 % s1 % showPos(pos) % e.msg()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Mutually recursive sets. */ | ||||
|  | @ -264,8 +284,9 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|     } | ||||
| 
 | ||||
|     /* Assertions. */ | ||||
|     if (atMatch(m, e) >> "Assert" >> e1 >> e2) { | ||||
|         if (!evalBool(state, e1)) throw badTerm("guard failed", e); | ||||
|     if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) { | ||||
|         if (!evalBool(state, e1)) | ||||
|             throw Error(format("assertion failed at %1%") % showPos(pos)); | ||||
|         return evalExpr(state, e2); | ||||
|     } | ||||
| 
 | ||||
|  | @ -323,7 +344,7 @@ Expr evalExpr(EvalState & state, Expr e) | |||
|     Expr nf = state.normalForms.get(e); | ||||
|     if (nf) { | ||||
|         if (nf == state.blackHole) | ||||
|             throw badTerm("infinite recursion", e); | ||||
|             throw Error("infinite recursion encountered"); | ||||
|         state.nrCached++; | ||||
|         return nf; | ||||
|     } | ||||
|  | @ -340,7 +361,12 @@ Expr evalFile(EvalState & state, const Path & path) | |||
| { | ||||
|     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); | ||||
|     Expr e = parseExprFromFile(state, path); | ||||
|     return evalExpr(state, e); | ||||
|     try { | ||||
|         return evalExpr(state, e); | ||||
|     } catch (Error & e) { | ||||
|         throw Error(format("while evaluating file `%1%':\n%2%") | ||||
|             % path % e.msg()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,6 +104,19 @@ string aterm2String(ATerm t) | |||
| { | ||||
|     return ATgetName(ATgetAFun(t)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| string showPos(ATerm pos) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     Path path; | ||||
|     int line, column; | ||||
|     if (atMatch(m, pos) >> "NoPos") | ||||
|         return "undefined position"; | ||||
|     if (!(atMatch(m, pos) >> "Pos" >> path >> line >> column)) | ||||
|         throw badTerm("position expected", pos); | ||||
|     return (format("`%1%', line %2%") % path % line).str(); | ||||
| } | ||||
|      | ||||
| 
 | ||||
| ATerm bottomupRewrite(TermFun & f, ATerm e) | ||||
|  | @ -135,37 +148,66 @@ ATerm bottomupRewrite(TermFun & f, ATerm e) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void queryAllAttrs(Expr e, ATermMap & attrs) | ||||
| void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     ATermList bnds; | ||||
|     if (!(atMatch(m, e) >> "Attrs" >> bnds)) | ||||
|         throw badTerm("expected attribute set", e); | ||||
|         throw Error("attribute set expected"); | ||||
| 
 | ||||
|     for (ATermIterator i(bnds); i; ++i) { | ||||
|         string s; | ||||
|         Expr e; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> s >> e)) | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         attrs.set(s, e); | ||||
|         attrs.set(s, withPos ? ATmake("(<term>, <term>)", e, pos) : e); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr queryAttr(Expr e, const string & name) | ||||
| { | ||||
|     ATermMap attrs; | ||||
|     queryAllAttrs(e, attrs); | ||||
|     return attrs.get(name); | ||||
|     ATerm dummy; | ||||
|     return queryAttr(e, name, dummy); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr queryAttr(Expr e, const string & name, ATerm & pos) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     ATermList bnds; | ||||
|     if (!(atMatch(m, e) >> "Attrs" >> bnds)) | ||||
|         throw Error("attribute set expected"); | ||||
| 
 | ||||
|     for (ATermIterator i(bnds); i; ++i) { | ||||
|         string s; | ||||
|         Expr e; | ||||
|         ATerm pos2; | ||||
|         if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos2)) | ||||
|             abort(); /* can't happen */ | ||||
|         if (s == name) { | ||||
|             pos = pos2; | ||||
|             return e; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr makeAttrs(const ATermMap & attrs) | ||||
| { | ||||
|     ATMatcher m; | ||||
|     ATermList bnds = ATempty; | ||||
|     for (ATermIterator i(attrs.keys()); i; ++i) | ||||
|     for (ATermIterator i(attrs.keys()); i; ++i) { | ||||
|         Expr e; | ||||
|         ATerm pos; | ||||
|         if (!(atMatch(m, attrs.get(*i)) >> "" >> e >> pos)) | ||||
|             abort(); /* can't happen */ | ||||
|         bnds = ATinsert(bnds,  | ||||
|             ATmake("Bind(<term>, <term>)", *i, attrs.get(*i))); | ||||
|             ATmake("Bind(<term>, <term>, <term>)", *i, e, pos)); | ||||
|     } | ||||
|     return ATmake("Attrs(<term>)", ATreverse(bnds)); | ||||
| } | ||||
| 
 | ||||
|  | @ -175,7 +217,7 @@ Expr substitute(const ATermMap & subs, Expr e) | |||
|     checkInterrupt(); | ||||
| 
 | ||||
|     ATMatcher m; | ||||
|     ATerm name; | ||||
|     ATerm name, pos; | ||||
| 
 | ||||
|     /* As an optimisation, don't substitute in subterms known to be
 | ||||
|        closed. */ | ||||
|  | @ -190,7 +232,7 @@ Expr substitute(const ATermMap & subs, Expr e) | |||
|        function. */ | ||||
|     ATermList formals; | ||||
|     ATerm body; | ||||
|     if (atMatch(m, e) >> "Function" >> formals >> body) { | ||||
|     if (atMatch(m, e) >> "Function" >> formals >> body >> pos) { | ||||
|         ATermMap subs2(subs); | ||||
|         for (ATermIterator i(formals); i; ++i) { | ||||
|             if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && | ||||
|  | @ -198,16 +240,16 @@ Expr substitute(const ATermMap & subs, Expr e) | |||
|                 abort(); | ||||
|             subs2.remove(name); | ||||
|         } | ||||
|         return ATmake("Function(<term>, <term>)", | ||||
|         return ATmake("Function(<term>, <term>, <term>)", | ||||
|             substitute(subs, (ATerm) formals), | ||||
|             substitute(subs2, body)); | ||||
|             substitute(subs2, body), pos); | ||||
|     } | ||||
| 
 | ||||
|     if (atMatch(m, e) >> "Function1" >> name >> body) { | ||||
|     if (atMatch(m, e) >> "Function1" >> name >> body >> pos) { | ||||
|         ATermMap subs2(subs); | ||||
|         subs2.remove(name); | ||||
|         return ATmake("Function1(<term>, <term>)", name, | ||||
|             substitute(subs2, body)); | ||||
|         return ATmake("Function1(<term>, <term>, <term>)", name, | ||||
|             substitute(subs2, body), pos); | ||||
|     } | ||||
|          | ||||
|     /* Idem for a mutually recursive attribute set. */ | ||||
|  |  | |||
|  | @ -52,6 +52,9 @@ private: | |||
| ATerm string2ATerm(const string & s); | ||||
| string aterm2String(ATerm t); | ||||
| 
 | ||||
| /* Show a position. */ | ||||
| string showPos(ATerm pos); | ||||
| 
 | ||||
| /* Generic bottomup traversal over ATerms.  The traversal first
 | ||||
|    recursively descends into subterms, and then applies the given term | ||||
|    function to the resulting term. */ | ||||
|  | @ -63,11 +66,12 @@ ATerm bottomupRewrite(TermFun & f, ATerm e); | |||
| 
 | ||||
| /* Query all attributes in an attribute set expression.  The
 | ||||
|    expression must be in normal form. */ | ||||
| void queryAllAttrs(Expr e, ATermMap & attrs); | ||||
| void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false); | ||||
| 
 | ||||
| /* Query a specific attribute from an attribute set expression.  The
 | ||||
|    expression must be in normal form. */ | ||||
| Expr queryAttr(Expr e, const string & name); | ||||
| Expr queryAttr(Expr e, const string & name, ATerm & pos); | ||||
| 
 | ||||
| /* Create an attribute set expression from an Attrs value. */ | ||||
| Expr makeAttrs(const ATermMap & attrs); | ||||
|  |  | |||
|  | @ -12,8 +12,8 @@ | |||
| struct ParseData  | ||||
| { | ||||
|     Expr result; | ||||
|     string basePath; | ||||
|     string location; | ||||
|     Path basePath; | ||||
|     Path path; | ||||
|     string error; | ||||
| }; | ||||
| 
 | ||||
|  | @ -39,8 +39,8 @@ ATerm absParsedPath(ParseData * data, ATerm t) | |||
|      | ||||
| void parseError(ParseData * data, char * error, int line, int column) | ||||
| { | ||||
|     data->error = (format("%1%, at line %2%, column %3%, of %4%") | ||||
|         % error % line % column % data->location).str(); | ||||
|     data->error = (format("%1%, at `%2%':%3%:%4%") | ||||
|         % error % data->path % line % column).str(); | ||||
| } | ||||
|          | ||||
| ATerm fixAttrs(int recursive, ATermList as) | ||||
|  | @ -51,13 +51,15 @@ ATerm fixAttrs(int recursive, ATermList as) | |||
|     for (ATermIterator i(as); i; ++i) { | ||||
|         ATermList names; | ||||
|         Expr src; | ||||
|         if (atMatch(m, *i) >> "Inherit" >> src >> names) { | ||||
|         ATerm pos; | ||||
|         if (atMatch(m, *i) >> "Inherit" >> src >> names >> pos) { | ||||
|             bool fromScope = atMatch(m, src) >> "Scope"; | ||||
|             for (ATermIterator j(names); j; ++j) { | ||||
|                 Expr rhs = fromScope | ||||
|                     ? ATmake("Var(<term>)", *j) | ||||
|                     : ATmake("Select(<term>, <term>)", src, *j); | ||||
|                 *is = ATinsert(*is, ATmake("Bind(<term>, <term>)", *j, rhs)); | ||||
|                 *is = ATinsert(*is, ATmake("Bind(<term>, <term>, <term>)", | ||||
|                                    *j, rhs, pos)); | ||||
|             } | ||||
|         } else bs = ATinsert(bs, *i); | ||||
|     } | ||||
|  | @ -67,18 +69,23 @@ ATerm fixAttrs(int recursive, ATermList as) | |||
|         return ATmake("Attrs(<term>)", bs); | ||||
| } | ||||
| 
 | ||||
| const char * getPath(ParseData * data) | ||||
| { | ||||
|     return data->path.c_str(); | ||||
| } | ||||
| 
 | ||||
| int yyparse(yyscan_t scanner, ParseData * data); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static Expr parse(EvalState & state, | ||||
|     const char * text, const string & location, | ||||
|     const char * text, const Path & path, | ||||
|     const Path & basePath) | ||||
| { | ||||
|     yyscan_t scanner; | ||||
|     ParseData data; | ||||
|     data.basePath = basePath; | ||||
|     data.location = location; | ||||
|     data.path = path; | ||||
| 
 | ||||
|     yylex_init(&scanner); | ||||
|     yy_scan_string(text, scanner); | ||||
|  | @ -90,7 +97,7 @@ static Expr parse(EvalState & state, | |||
|     try { | ||||
|         checkVarDefs(state.primOpsAll, data.result); | ||||
|     } catch (Error & e) { | ||||
|         throw Error(format("%1%, in %2%") % e.msg() % location); | ||||
|         throw Error(format("%1%, in `%2%'") % e.msg() % path); | ||||
|     } | ||||
| 
 | ||||
|     return data.result; | ||||
|  | @ -133,7 +140,7 @@ Expr parseExprFromFile(EvalState & state, Path path) | |||
|     readFull(fd, (unsigned char *) text, st.st_size); | ||||
|     text[st.st_size] = 0; | ||||
| 
 | ||||
|     return parse(state, text, "`" + path + "'", dirOf(path)); | ||||
|     return parse(state, text, path, dirOf(path)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,11 +19,20 @@ void setParseResult(void * data, ATerm t); | |||
| void parseError(void * data, char * error, int line, int column); | ||||
| ATerm absParsedPath(void * data, ATerm t); | ||||
| ATerm fixAttrs(int recursive, ATermList as); | ||||
| const char * getPath(void * data); | ||||
| 
 | ||||
| void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s) | ||||
| { | ||||
|     parseError(data, s, loc->first_line, loc->first_column); | ||||
| } | ||||
| 
 | ||||
| ATerm makePos(YYLTYPE * loc, void * data) | ||||
| { | ||||
|     return ATmake("Pos(<str>, <int>, <int>)", | ||||
|         getPath(data), loc->first_line, loc->first_column); | ||||
| } | ||||
| 
 | ||||
| #define CUR_POS makePos(yylocp, data) | ||||
|   | ||||
| %} | ||||
| 
 | ||||
|  | @ -55,15 +64,15 @@ expr: expr_function; | |||
| 
 | ||||
| expr_function | ||||
|   : '{' formals '}' ':' expr_function | ||||
|     { $$ = ATmake("Function(<term>, <term>)", $2, $5); } | ||||
|     { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } | ||||
|   | ID ':' expr_function | ||||
|     { $$ = ATmake("Function1(<term>, <term>)", $1, $3); } | ||||
|     { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } | ||||
|   | expr_assert | ||||
|   ; | ||||
| 
 | ||||
| expr_assert | ||||
|   : ASSERT expr ';' expr_assert | ||||
|     { $$ = ATmake("Assert(<term>, <term>)", $2, $4); } | ||||
|     { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } | ||||
|   | expr_if | ||||
|   ; | ||||
| 
 | ||||
|  | @ -123,9 +132,9 @@ binds | |||
| 
 | ||||
| bind | ||||
|   : ID '=' expr ';' | ||||
|     { $$ = ATmake("Bind(<term>, <term>)", $1, $3); } | ||||
|     { $$ = ATmake("Bind(<term>, <term>, <term>)", $1, $3, CUR_POS); } | ||||
|   | INHERIT inheritsrc ids ';' | ||||
|     { $$ = ATmake("Inherit(<term>, <term>)", $2, $3); } | ||||
|     { $$ = ATmake("Inherit(<term>, <term>, <term>)", $2, $3, CUR_POS); } | ||||
|   ; | ||||
| 
 | ||||
| inheritsrc | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ Expr primImport(EvalState & state, Expr arg) | |||
|     ATMatcher m; | ||||
|     string path; | ||||
|     if (!(atMatch(m, arg) >> "Path" >> path)) | ||||
|         throw badTerm("path expected", arg); | ||||
|         throw Error("path expected"); | ||||
|     return evalFile(state, path); | ||||
| } | ||||
| 
 | ||||
|  | @ -102,18 +102,18 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, | |||
|         Expr a = queryAttr(e, "type"); | ||||
|         if (a && evalString(state, a) == "derivation") { | ||||
|             a = queryAttr(e, "drvPath"); | ||||
|             if (!a) throw badTerm("derivation name missing", e); | ||||
|             if (!a) throw Error("derivation name missing"); | ||||
|             Path drvPath = evalPath(state, a); | ||||
| 
 | ||||
|             a = queryAttr(e, "drvHash"); | ||||
|             if (!a) throw badTerm("derivation hash missing", e); | ||||
|             if (!a) throw Error("derivation hash missing"); | ||||
|             Hash drvHash = parseHash(evalString(state, a)); | ||||
| 
 | ||||
|             state.drvHashes[drvPath] = drvHash; | ||||
|              | ||||
|             ss.push_back(addInput(state, drvPath, ne)); | ||||
|         } else | ||||
|             throw badTerm("invalid derivation binding", e); | ||||
|             throw Error("invalid derivation attribute"); | ||||
|     } | ||||
| 
 | ||||
|     else if (atMatch(m, e) >> "Path" >> s) { | ||||
|  | @ -142,7 +142,7 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, | |||
|         ss.push_back(canonPath(ss2.front() + "/" + s)); | ||||
|     } | ||||
|      | ||||
|     else throw badTerm("invalid derivation binding", e); | ||||
|     else throw Error("invalid derivation attribute"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -164,7 +164,7 @@ Expr primDerivation(EvalState & state, Expr args) | |||
| 
 | ||||
|     ATermMap attrs; | ||||
|     args = evalExpr(state, args); | ||||
|     queryAllAttrs(args, attrs); | ||||
|     queryAllAttrs(args, attrs, true); | ||||
| 
 | ||||
|     /* Build the derivation expression by processing the attributes. */ | ||||
|     StoreExpr ne; | ||||
|  | @ -177,15 +177,19 @@ Expr primDerivation(EvalState & state, Expr args) | |||
| 
 | ||||
|     for (ATermIterator i(attrs.keys()); i; ++i) { | ||||
|         string key = aterm2String(*i); | ||||
|         Expr value = attrs.get(key); | ||||
|         ATerm value; | ||||
|         Expr pos; | ||||
|         ATerm rhs = attrs.get(key); | ||||
|         ATMatcher m; | ||||
|         if (!(atMatch(m, rhs) >> "" >> value >> pos)) abort(); | ||||
|         startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); | ||||
| 
 | ||||
|         Strings ss; | ||||
|         try { | ||||
|             processBinding(state, value, ne, ss); | ||||
|         } catch (Error & e) { | ||||
|             throw Error(format("while processing derivation binding `%1%': %2%") | ||||
|                 % key % e.msg()); | ||||
|             throw Error(format("while processing derivation attribute `%1%' at %2%:\n%3%") | ||||
|                 % key % showPos(pos) % e.msg()); | ||||
|         } | ||||
| 
 | ||||
|         /* The `args' attribute is special: it supplies the
 | ||||
|  | @ -213,11 +217,11 @@ Expr primDerivation(EvalState & state, Expr args) | |||
|      | ||||
|     /* Do we have all required attributes? */ | ||||
|     if (ne.derivation.builder == "") | ||||
|         throw badTerm("required attribute `builder' missing", args); | ||||
|         throw Error("required attribute `builder' missing"); | ||||
|     if (ne.derivation.platform == "") | ||||
|         throw badTerm("required attribute `system' missing", args); | ||||
|         throw Error("required attribute `system' missing"); | ||||
|     if (drvName == "") | ||||
|         throw badTerm("required attribute `name' missing", args); | ||||
|         throw Error("required attribute `name' missing"); | ||||
|          | ||||
|     /* Determine the output path. */ | ||||
|     if (!outHashGiven) outHash = hashDerivation(state, ne); | ||||
|  | @ -238,10 +242,10 @@ Expr primDerivation(EvalState & state, Expr args) | |||
|     printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") | ||||
|         % drvName % drvPath); | ||||
| 
 | ||||
|     attrs.set("outPath", ATmake("Path(<str>)", outPath.c_str())); | ||||
|     attrs.set("drvPath", ATmake("Path(<str>)", drvPath.c_str())); | ||||
|     attrs.set("drvHash", ATmake("Str(<str>)", ((string) drvHash).c_str())); | ||||
|     attrs.set("type", ATmake("Str(\"derivation\")")); | ||||
|     attrs.set("outPath", ATmake("(Path(<str>), NoPos)", outPath.c_str())); | ||||
|     attrs.set("drvPath", ATmake("(Path(<str>), NoPos)", drvPath.c_str())); | ||||
|     attrs.set("drvHash", ATmake("(Str(<str>), NoPos)", ((string) drvHash).c_str())); | ||||
|     attrs.set("type", ATmake("(Str(\"derivation\"), NoPos)")); | ||||
| 
 | ||||
|     return makeAttrs(attrs); | ||||
| } | ||||
|  | @ -263,7 +267,7 @@ Expr primToString(EvalState & state, Expr arg) | |||
|         atMatch(m, arg) >> "Path" >> s || | ||||
|         atMatch(m, arg) >> "Uri" >> s) | ||||
|         return ATmake("Str(<str>)", s.c_str()); | ||||
|     else throw badTerm("cannot coerce to string", arg); | ||||
|     else throw Error("cannot coerce value to string"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -108,7 +108,7 @@ void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs) | |||
| { | ||||
|     Expr e = parseExprFromFile(state, absPath(nePath)); | ||||
|     if (!parseDerivations(state, e, drvs)) | ||||
|         throw badTerm("expected set of derivations", e); | ||||
|         throw Error("set of derivations expected"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -126,6 +126,21 @@ static Path getDefNixExprPath() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct AddPos : TermFun | ||||
| { | ||||
|     ATerm operator () (ATerm e) | ||||
|     { | ||||
|         ATMatcher m; | ||||
|         ATerm x, y, z; | ||||
|         if (atMatch(m, e) >> "Bind" >> x >> y >> z) | ||||
|             return e; | ||||
|         if (atMatch(m, e) >> "Bind" >> x >> y) | ||||
|             return ATmake("Bind(<term>, <term>, NoPos)", x, y); | ||||
|         return e; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void queryInstalled(EvalState & state, DrvInfos & drvs, | ||||
|     const Path & userEnv) | ||||
| { | ||||
|  | @ -136,8 +151,12 @@ void queryInstalled(EvalState & state, DrvInfos & drvs, | |||
|     Expr e = ATreadFromNamedFile(path.c_str()); | ||||
|     if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path); | ||||
| 
 | ||||
|     /* Compatibility: Bind(x, y) -> Bind(x, y, NoPos). */ | ||||
|     AddPos addPos; | ||||
|     e = bottomupRewrite(addPos, e); | ||||
| 
 | ||||
|     if (!parseDerivations(state, e, drvs)) | ||||
|         throw badTerm(format("expected set of derivations in `%1%'") % path, e); | ||||
|         throw badTerm(format("set of derivations expected in `%1%'") % path, e); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -155,11 +174,11 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, | |||
|     { | ||||
|         ATerm t = ATmake( | ||||
|             "Attrs([" | ||||
|             "Bind(\"type\", Str(\"derivation\")), " | ||||
|             "Bind(\"name\", Str(<str>)), " | ||||
|             "Bind(\"drvPath\", Path(<str>)), " | ||||
|             "Bind(\"drvHash\", Str(<str>)), " | ||||
|             "Bind(\"outPath\", Path(<str>))" | ||||
|             "Bind(\"type\", Str(\"derivation\"), NoPos), " | ||||
|             "Bind(\"name\", Str(<str>), NoPos), " | ||||
|             "Bind(\"drvPath\", Path(<str>), NoPos), " | ||||
|             "Bind(\"drvHash\", Str(<str>), NoPos), " | ||||
|             "Bind(\"outPath\", Path(<str>), NoPos)" | ||||
|             "])", | ||||
|             i->second.name.c_str(), | ||||
|             i->second.drvPath.c_str(), | ||||
|  | @ -176,9 +195,9 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, | |||
| 
 | ||||
|     Expr topLevel = ATmake( | ||||
|         "Call(<term>, Attrs([" | ||||
|         "Bind(\"system\", Str(<str>)), " | ||||
|         "Bind(\"derivations\", <term>), " // !!! redundant
 | ||||
|         "Bind(\"manifest\", Path(<str>))" | ||||
|         "Bind(\"system\", Str(<str>), NoPos), " | ||||
|         "Bind(\"derivations\", <term>, NoPos), " // !!! redundant
 | ||||
|         "Bind(\"manifest\", Path(<str>), NoPos)" | ||||
|         "]))", | ||||
|         envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ static void printNixExpr(EvalState & state, Expr e) | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     throw badTerm("top level does not evaluate to one or more Nix expressions", e); | ||||
|     throw Error("expression does not evaluate to one or more derivations"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue