forked from lix-project/lix
* 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
|
@ -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));
|
||||||
|
} catch (Error & e) {
|
||||||
|
throw Error(format("while evaluating function at %1%:\n%2%")
|
||||||
|
% showPos(pos) % e.msg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (atMatch(m, e1) >> "Function1" >> name >> e4) {
|
else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) {
|
||||||
|
try {
|
||||||
ATermMap subs;
|
ATermMap subs;
|
||||||
subs.set(name, e2);
|
subs.set(name, e2);
|
||||||
return evalExpr(state, substitute(subs, e4));
|
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 badTerm("expecting a function or primop", e1);
|
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);
|
||||||
|
if (!a) throw Error(format("attribute `%1%' missing") % s1);
|
||||||
|
try {
|
||||||
return evalExpr(state, a);
|
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);
|
||||||
|
try {
|
||||||
return evalExpr(state, e);
|
return evalExpr(state, e);
|
||||||
|
} catch (Error & e) {
|
||||||
|
throw Error(format("while evaluating file `%1%':\n%2%")
|
||||||
|
% path % e.msg());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,19 @@ string aterm2String(ATerm 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)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,21 @@ 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)
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue