* 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:
Eelco Dolstra 2004-04-05 22:27:41 +00:00
parent a520b1cbc3
commit 59b94ee18a
8 changed files with 201 additions and 90 deletions

View file

@ -77,16 +77,16 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
Expr key = *i; Expr key = *i;
Expr cur = subs.get(key); Expr cur = subs.get(key);
if (!cur) if (!cur)
throw badTerm(format("function has no formal argument `%1%'") throw Error(format("unexpected function argument `%1%'")
% aterm2String(key), arg); % aterm2String(key));
subs.set(key, args.get(key)); subs.set(key, args.get(key));
} }
/* Check that all arguments are defined. */ /* Check that all arguments are defined. */
for (ATermIterator i(subs.keys()); i; ++i) for (ATermIterator i(subs.keys()); i; ++i)
if (subs.get(*i) == undefined) if (subs.get(*i) == undefined)
throw badTerm(format("formal argument `%1%' missing") throw Error(format("required function argument `%1%' missing")
% aterm2String(*i), arg); % aterm2String(*i));
return substitute(subs, body); return substitute(subs, body);
} }
@ -119,16 +119,18 @@ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
/* Create the non-recursive set. */ /* Create the non-recursive set. */
ATermMap as; ATermMap as;
for (ATermIterator i(rbnds); i; ++i) { 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 */ 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 */ /* Copy the non-recursive bindings. !!! inefficient */
for (ATermIterator i(nrbnds); i; ++i) { 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 */ abort(); /* can't happen */
as.set(name, e2); as.set(name, ATmake("(<term>, <term>)", e2, pos));
} }
return makeAttrs(as); return makeAttrs(as);
@ -140,8 +142,8 @@ static Expr updateAttrs(Expr e1, Expr e2)
/* Note: e1 and e2 should be in normal form. */ /* Note: e1 and e2 should be in normal form. */
ATermMap attrs; ATermMap attrs;
queryAllAttrs(e1, attrs); queryAllAttrs(e1, attrs, true);
queryAllAttrs(e2, attrs); queryAllAttrs(e2, attrs, true);
return makeAttrs(attrs); return makeAttrs(attrs);
} }
@ -153,7 +155,7 @@ string evalString(EvalState & state, Expr e)
ATMatcher m; ATMatcher m;
string s; string s;
if (!(atMatch(m, e) >> "Str" >> s)) if (!(atMatch(m, e) >> "Str" >> s))
throw badTerm("string expected", e); throw Error("string expected");
return s; return s;
} }
@ -164,7 +166,7 @@ Path evalPath(EvalState & state, Expr e)
ATMatcher m; ATMatcher m;
string s; string s;
if (!(atMatch(m, e) >> "Path" >> s)) if (!(atMatch(m, e) >> "Path" >> s))
throw badTerm("path expected", e); throw Error("path expected");
return s; return s;
} }
@ -175,7 +177,7 @@ bool evalBool(EvalState & state, Expr e)
ATMatcher m; ATMatcher m;
if (atMatch(m, e) >> "Bool" >> "True") return true; if (atMatch(m, e) >> "Bool" >> "True") return true;
else if (atMatch(m, e) >> "Bool" >> "False") return false; 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; ATMatcher m;
Expr e1, e2, e3, e4; Expr e1, e2, e3, e4;
ATerm name; ATerm name, pos;
/* Normal forms. */ /* Normal forms. */
string cons; string cons;
@ -219,6 +221,7 @@ Expr evalExpr2(EvalState & state, Expr e)
if (atMatch(m, e) >> "Call" >> e1 >> e2) { if (atMatch(m, e) >> "Call" >> e1 >> e2) {
ATermList formals; ATermList formals;
ATerm pos;
/* Evaluate the left-hand side. */ /* Evaluate the left-hand side. */
e1 = evalExpr(state, e1); e1 = evalExpr(state, e1);
@ -229,25 +232,42 @@ Expr evalExpr2(EvalState & state, Expr e)
if (primOp) return primOp(state, e2); else abort(); if (primOp) return primOp(state, e2); else abort();
} }
else if (atMatch(m, e1) >> "Function" >> formals >> e4) else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) {
return evalExpr(state, e2 = evalExpr(state, e2);
substArgs(e4, formals, evalExpr(state, e2))); try {
return evalExpr(state, substArgs(e4, formals, e2));
else if (atMatch(m, e1) >> "Function1" >> name >> e4) { } catch (Error & e) {
ATermMap subs; throw Error(format("while evaluating function at %1%:\n%2%")
subs.set(name, e2); % showPos(pos) % e.msg());
return evalExpr(state, substitute(subs, e4)); }
} }
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. */ /* Attribute selection. */
string s1; string s1;
if (atMatch(m, e) >> "Select" >> e1 >> s1) { if (atMatch(m, e) >> "Select" >> e1 >> s1) {
Expr a = queryAttr(evalExpr(state, e1), s1); ATerm pos;
if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); Expr a = queryAttr(evalExpr(state, e1), s1, pos);
return evalExpr(state, a); 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. */ /* Mutually recursive sets. */
@ -264,8 +284,9 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
/* Assertions. */ /* Assertions. */
if (atMatch(m, e) >> "Assert" >> e1 >> e2) { if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) {
if (!evalBool(state, e1)) throw badTerm("guard failed", e); if (!evalBool(state, e1))
throw Error(format("assertion failed at %1%") % showPos(pos));
return evalExpr(state, e2); return evalExpr(state, e2);
} }
@ -323,7 +344,7 @@ Expr evalExpr(EvalState & state, Expr e)
Expr nf = state.normalForms.get(e); Expr nf = state.normalForms.get(e);
if (nf) { if (nf) {
if (nf == state.blackHole) if (nf == state.blackHole)
throw badTerm("infinite recursion", e); throw Error("infinite recursion encountered");
state.nrCached++; state.nrCached++;
return nf; return nf;
} }
@ -340,7 +361,12 @@ Expr evalFile(EvalState & state, const Path & path)
{ {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr e = parseExprFromFile(state, 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());
}
} }

View file

@ -104,6 +104,19 @@ string aterm2String(ATerm t)
{ {
return ATgetName(ATgetAFun(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) 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; ATMatcher m;
ATermList bnds; ATermList bnds;
if (!(atMatch(m, e) >> "Attrs" >> bnds)) if (!(atMatch(m, e) >> "Attrs" >> bnds))
throw badTerm("expected attribute set", e); throw Error("attribute set expected");
for (ATermIterator i(bnds); i; ++i) { for (ATermIterator i(bnds); i; ++i) {
string s; string s;
Expr e; Expr e;
if (!(atMatch(m, *i) >> "Bind" >> s >> e)) ATerm pos;
if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos))
abort(); /* can't happen */ 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) Expr queryAttr(Expr e, const string & name)
{ {
ATermMap attrs; ATerm dummy;
queryAllAttrs(e, attrs); return queryAttr(e, name, dummy);
return attrs.get(name); }
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) Expr makeAttrs(const ATermMap & attrs)
{ {
ATMatcher m;
ATermList bnds = ATempty; 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, 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)); return ATmake("Attrs(<term>)", ATreverse(bnds));
} }
@ -175,7 +217,7 @@ Expr substitute(const ATermMap & subs, Expr e)
checkInterrupt(); checkInterrupt();
ATMatcher m; ATMatcher m;
ATerm name; ATerm name, pos;
/* As an optimisation, don't substitute in subterms known to be /* As an optimisation, don't substitute in subterms known to be
closed. */ closed. */
@ -190,7 +232,7 @@ Expr substitute(const ATermMap & subs, Expr e)
function. */ function. */
ATermList formals; ATermList formals;
ATerm body; ATerm body;
if (atMatch(m, e) >> "Function" >> formals >> body) { if (atMatch(m, e) >> "Function" >> formals >> body >> pos) {
ATermMap subs2(subs); ATermMap subs2(subs);
for (ATermIterator i(formals); i; ++i) { for (ATermIterator i(formals); i; ++i) {
if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && if (!(atMatch(m, *i) >> "NoDefFormal" >> name) &&
@ -198,16 +240,16 @@ Expr substitute(const ATermMap & subs, Expr e)
abort(); abort();
subs2.remove(name); subs2.remove(name);
} }
return ATmake("Function(<term>, <term>)", return ATmake("Function(<term>, <term>, <term>)",
substitute(subs, (ATerm) formals), 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); ATermMap subs2(subs);
subs2.remove(name); subs2.remove(name);
return ATmake("Function1(<term>, <term>)", name, return ATmake("Function1(<term>, <term>, <term>)", name,
substitute(subs2, body)); substitute(subs2, body), pos);
} }
/* Idem for a mutually recursive attribute set. */ /* Idem for a mutually recursive attribute set. */

View file

@ -52,6 +52,9 @@ private:
ATerm string2ATerm(const string & s); ATerm string2ATerm(const string & s);
string aterm2String(ATerm t); string aterm2String(ATerm t);
/* Show a position. */
string showPos(ATerm pos);
/* Generic bottomup traversal over ATerms. The traversal first /* Generic bottomup traversal over ATerms. The traversal first
recursively descends into subterms, and then applies the given term recursively descends into subterms, and then applies the given term
function to the resulting 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 /* Query all attributes in an attribute set expression. The
expression must be in normal form. */ 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 /* Query a specific attribute from an attribute set expression. The
expression must be in normal form. */ expression must be in normal form. */
Expr queryAttr(Expr e, const string & name); 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. */ /* Create an attribute set expression from an Attrs value. */
Expr makeAttrs(const ATermMap & attrs); Expr makeAttrs(const ATermMap & attrs);

View file

@ -12,8 +12,8 @@
struct ParseData struct ParseData
{ {
Expr result; Expr result;
string basePath; Path basePath;
string location; Path path;
string error; string error;
}; };
@ -39,8 +39,8 @@ ATerm absParsedPath(ParseData * data, ATerm t)
void parseError(ParseData * data, char * error, int line, int column) void parseError(ParseData * data, char * error, int line, int column)
{ {
data->error = (format("%1%, at line %2%, column %3%, of %4%") data->error = (format("%1%, at `%2%':%3%:%4%")
% error % line % column % data->location).str(); % error % data->path % line % column).str();
} }
ATerm fixAttrs(int recursive, ATermList as) ATerm fixAttrs(int recursive, ATermList as)
@ -51,13 +51,15 @@ ATerm fixAttrs(int recursive, ATermList as)
for (ATermIterator i(as); i; ++i) { for (ATermIterator i(as); i; ++i) {
ATermList names; ATermList names;
Expr src; 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"; bool fromScope = atMatch(m, src) >> "Scope";
for (ATermIterator j(names); j; ++j) { for (ATermIterator j(names); j; ++j) {
Expr rhs = fromScope Expr rhs = fromScope
? ATmake("Var(<term>)", *j) ? ATmake("Var(<term>)", *j)
: ATmake("Select(<term>, <term>)", src, *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); } else bs = ATinsert(bs, *i);
} }
@ -67,18 +69,23 @@ ATerm fixAttrs(int recursive, ATermList as)
return ATmake("Attrs(<term>)", bs); return ATmake("Attrs(<term>)", bs);
} }
const char * getPath(ParseData * data)
{
return data->path.c_str();
}
int yyparse(yyscan_t scanner, ParseData * data); int yyparse(yyscan_t scanner, ParseData * data);
} }
static Expr parse(EvalState & state, static Expr parse(EvalState & state,
const char * text, const string & location, const char * text, const Path & path,
const Path & basePath) const Path & basePath)
{ {
yyscan_t scanner; yyscan_t scanner;
ParseData data; ParseData data;
data.basePath = basePath; data.basePath = basePath;
data.location = location; data.path = path;
yylex_init(&scanner); yylex_init(&scanner);
yy_scan_string(text, scanner); yy_scan_string(text, scanner);
@ -90,7 +97,7 @@ static Expr parse(EvalState & state,
try { try {
checkVarDefs(state.primOpsAll, data.result); checkVarDefs(state.primOpsAll, data.result);
} catch (Error & e) { } catch (Error & e) {
throw Error(format("%1%, in %2%") % e.msg() % location); throw Error(format("%1%, in `%2%'") % e.msg() % path);
} }
return data.result; return data.result;
@ -133,7 +140,7 @@ Expr parseExprFromFile(EvalState & state, Path path)
readFull(fd, (unsigned char *) text, st.st_size); readFull(fd, (unsigned char *) text, st.st_size);
text[st.st_size] = 0; text[st.st_size] = 0;
return parse(state, text, "`" + path + "'", dirOf(path)); return parse(state, text, path, dirOf(path));
} }

View file

@ -19,11 +19,20 @@ void setParseResult(void * data, ATerm t);
void parseError(void * data, char * error, int line, int column); void parseError(void * data, char * error, int line, int column);
ATerm absParsedPath(void * data, ATerm t); ATerm absParsedPath(void * data, ATerm t);
ATerm fixAttrs(int recursive, ATermList as); ATerm fixAttrs(int recursive, ATermList as);
const char * getPath(void * data);
void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s) void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s)
{ {
parseError(data, s, loc->first_line, loc->first_column); 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 expr_function
: '{' formals '}' ':' expr_function : '{' formals '}' ':' expr_function
{ $$ = ATmake("Function(<term>, <term>)", $2, $5); } { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); }
| ID ':' expr_function | ID ':' expr_function
{ $$ = ATmake("Function1(<term>, <term>)", $1, $3); } { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); }
| expr_assert | expr_assert
; ;
expr_assert expr_assert
: ASSERT expr ';' expr_assert : ASSERT expr ';' expr_assert
{ $$ = ATmake("Assert(<term>, <term>)", $2, $4); } { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); }
| expr_if | expr_if
; ;
@ -123,9 +132,9 @@ binds
bind bind
: ID '=' expr ';' : ID '=' expr ';'
{ $$ = ATmake("Bind(<term>, <term>)", $1, $3); } { $$ = ATmake("Bind(<term>, <term>, <term>)", $1, $3, CUR_POS); }
| INHERIT inheritsrc ids ';' | INHERIT inheritsrc ids ';'
{ $$ = ATmake("Inherit(<term>, <term>)", $2, $3); } { $$ = ATmake("Inherit(<term>, <term>, <term>)", $2, $3, CUR_POS); }
; ;
inheritsrc inheritsrc

View file

@ -8,7 +8,7 @@ Expr primImport(EvalState & state, Expr arg)
ATMatcher m; ATMatcher m;
string path; string path;
if (!(atMatch(m, arg) >> "Path" >> path)) if (!(atMatch(m, arg) >> "Path" >> path))
throw badTerm("path expected", arg); throw Error("path expected");
return evalFile(state, path); return evalFile(state, path);
} }
@ -102,18 +102,18 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne,
Expr a = queryAttr(e, "type"); Expr a = queryAttr(e, "type");
if (a && evalString(state, a) == "derivation") { if (a && evalString(state, a) == "derivation") {
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
if (!a) throw badTerm("derivation name missing", e); if (!a) throw Error("derivation name missing");
Path drvPath = evalPath(state, a); Path drvPath = evalPath(state, a);
a = queryAttr(e, "drvHash"); 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)); Hash drvHash = parseHash(evalString(state, a));
state.drvHashes[drvPath] = drvHash; state.drvHashes[drvPath] = drvHash;
ss.push_back(addInput(state, drvPath, ne)); ss.push_back(addInput(state, drvPath, ne));
} else } else
throw badTerm("invalid derivation binding", e); throw Error("invalid derivation attribute");
} }
else if (atMatch(m, e) >> "Path" >> s) { 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)); 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; ATermMap attrs;
args = evalExpr(state, args); args = evalExpr(state, args);
queryAllAttrs(args, attrs); queryAllAttrs(args, attrs, true);
/* Build the derivation expression by processing the attributes. */ /* Build the derivation expression by processing the attributes. */
StoreExpr ne; StoreExpr ne;
@ -177,15 +177,19 @@ Expr primDerivation(EvalState & state, Expr args)
for (ATermIterator i(attrs.keys()); i; ++i) { for (ATermIterator i(attrs.keys()); i; ++i) {
string key = aterm2String(*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); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
Strings ss; Strings ss;
try { try {
processBinding(state, value, ne, ss); processBinding(state, value, ne, ss);
} catch (Error & e) { } catch (Error & e) {
throw Error(format("while processing derivation binding `%1%': %2%") throw Error(format("while processing derivation attribute `%1%' at %2%:\n%3%")
% key % e.msg()); % key % showPos(pos) % e.msg());
} }
/* The `args' attribute is special: it supplies the /* The `args' attribute is special: it supplies the
@ -213,11 +217,11 @@ Expr primDerivation(EvalState & state, Expr args)
/* Do we have all required attributes? */ /* Do we have all required attributes? */
if (ne.derivation.builder == "") if (ne.derivation.builder == "")
throw badTerm("required attribute `builder' missing", args); throw Error("required attribute `builder' missing");
if (ne.derivation.platform == "") if (ne.derivation.platform == "")
throw badTerm("required attribute `system' missing", args); throw Error("required attribute `system' missing");
if (drvName == "") if (drvName == "")
throw badTerm("required attribute `name' missing", args); throw Error("required attribute `name' missing");
/* Determine the output path. */ /* Determine the output path. */
if (!outHashGiven) outHash = hashDerivation(state, ne); if (!outHashGiven) outHash = hashDerivation(state, ne);
@ -238,10 +242,10 @@ Expr primDerivation(EvalState & state, Expr args)
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
% drvName % drvPath); % drvName % drvPath);
attrs.set("outPath", ATmake("Path(<str>)", outPath.c_str())); attrs.set("outPath", ATmake("(Path(<str>), NoPos)", outPath.c_str()));
attrs.set("drvPath", ATmake("Path(<str>)", drvPath.c_str())); attrs.set("drvPath", ATmake("(Path(<str>), NoPos)", drvPath.c_str()));
attrs.set("drvHash", ATmake("Str(<str>)", ((string) drvHash).c_str())); attrs.set("drvHash", ATmake("(Str(<str>), NoPos)", ((string) drvHash).c_str()));
attrs.set("type", ATmake("Str(\"derivation\")")); attrs.set("type", ATmake("(Str(\"derivation\"), NoPos)"));
return makeAttrs(attrs); return makeAttrs(attrs);
} }
@ -263,7 +267,7 @@ Expr primToString(EvalState & state, Expr arg)
atMatch(m, arg) >> "Path" >> s || atMatch(m, arg) >> "Path" >> s ||
atMatch(m, arg) >> "Uri" >> s) atMatch(m, arg) >> "Uri" >> s)
return ATmake("Str(<str>)", s.c_str()); return ATmake("Str(<str>)", s.c_str());
else throw badTerm("cannot coerce to string", arg); else throw Error("cannot coerce value to string");
} }

View file

@ -108,7 +108,7 @@ void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs)
{ {
Expr e = parseExprFromFile(state, absPath(nePath)); Expr e = parseExprFromFile(state, absPath(nePath));
if (!parseDerivations(state, e, drvs)) 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, void queryInstalled(EvalState & state, DrvInfos & drvs,
const Path & userEnv) const Path & userEnv)
{ {
@ -136,8 +151,12 @@ void queryInstalled(EvalState & state, DrvInfos & drvs,
Expr e = ATreadFromNamedFile(path.c_str()); Expr e = ATreadFromNamedFile(path.c_str());
if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path); 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)) 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( ATerm t = ATmake(
"Attrs([" "Attrs(["
"Bind(\"type\", Str(\"derivation\")), " "Bind(\"type\", Str(\"derivation\"), NoPos), "
"Bind(\"name\", Str(<str>)), " "Bind(\"name\", Str(<str>), NoPos), "
"Bind(\"drvPath\", Path(<str>)), " "Bind(\"drvPath\", Path(<str>), NoPos), "
"Bind(\"drvHash\", Str(<str>)), " "Bind(\"drvHash\", Str(<str>), NoPos), "
"Bind(\"outPath\", Path(<str>))" "Bind(\"outPath\", Path(<str>), NoPos)"
"])", "])",
i->second.name.c_str(), i->second.name.c_str(),
i->second.drvPath.c_str(), i->second.drvPath.c_str(),
@ -176,9 +195,9 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
Expr topLevel = ATmake( Expr topLevel = ATmake(
"Call(<term>, Attrs([" "Call(<term>, Attrs(["
"Bind(\"system\", Str(<str>)), " "Bind(\"system\", Str(<str>), NoPos), "
"Bind(\"derivations\", <term>), " // !!! redundant "Bind(\"derivations\", <term>, NoPos), " // !!! redundant
"Bind(\"manifest\", Path(<str>))" "Bind(\"manifest\", Path(<str>), NoPos)"
"]))", "]))",
envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str()); envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str());

View file

@ -47,7 +47,7 @@ static void printNixExpr(EvalState & state, Expr e)
return; 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");
} }