aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-04 17:53:52 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-04 18:59:29 +0200
commitb72c8d2e5b5bbdc218f7c00694027cdd75b6a584 (patch)
tree7173dfa3232031d57e12348d16e5255006f1f03d
parent3f8e1f56825f3ec2a9d99715609e362fe5e5a218 (diff)
Include position info in function application
This allows error messages like: error: the anonymous function at `/etc/nixos/configuration.nix:1:1' called without required argument `foo', at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/lib/modules.nix:77:59'
-rw-r--r--src/libexpr/eval-inline.hh2
-rw-r--r--src/libexpr/eval.cc31
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/nixexpr.cc2
-rw-r--r--src/libexpr/nixexpr.hh18
-rw-r--r--src/libexpr/parser.y6
-rw-r--r--src/libexpr/primops.cc6
7 files changed, 45 insertions, 22 deletions
diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh
index 5801a20c3..ffe8fa59c 100644
--- a/src/libexpr/eval-inline.hh
+++ b/src/libexpr/eval-inline.hh
@@ -35,7 +35,7 @@ void EvalState::forceValue(Value & v)
}
}
else if (v.type == tApp)
- callFunction(*v.app.left, *v.app.right, v);
+ callFunction(*v.app.left, *v.app.right, v, noPos);
else if (v.type == tBlackhole)
throwEvalError("infinite recursion encountered");
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index bbf494387..d26a0e258 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -130,12 +130,14 @@ string showType(const Value & v)
}
+#if HAVE_BOEHMGC
/* Called when the Boehm GC runs out of memory. */
static void * oomHandler(size_t requested)
{
/* Convert this to a proper C++ exception. */
throw std::bad_alloc();
}
+#endif
static Symbol getName(const AttrName & name, EvalState & state, Env & env) {
@@ -292,14 +294,19 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1))
throw TypeError(format(s) % s1);
}
+LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const Pos & pos))
+{
+ throw TypeError(format(s) % showType(v) % pos);
+}
+
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
{
throw TypeError(format(s) % s1 % s2);
}
-LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2))
+LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2, const Pos & pos))
{
- throw TypeError(format(s) % fun.showNamePos() % s2);
+ throw TypeError(format(s) % fun.showNamePos() % s2 % pos);
}
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
@@ -317,9 +324,9 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
e.addPrefix(format(s) % s2);
}
-LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun))
+LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun, const Pos & pos))
{
- e.addPrefix(format(s) % fun.showNamePos());
+ e.addPrefix(format(s) % fun.showNamePos() % pos);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos))
@@ -783,7 +790,7 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v)
/* FIXME: vFun prevents GCC from doing tail call optimisation. */
Value vFun;
e1->eval(state, env, vFun);
- state.callFunction(vFun, *(e2->maybeThunk(state, env)), v);
+ state.callFunction(vFun, *(e2->maybeThunk(state, env)), v, pos);
}
@@ -824,7 +831,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v)
}
-void EvalState::callFunction(Value & fun, Value & arg, Value & v)
+void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
{
if (fun.type == tPrimOp || fun.type == tPrimOpApp) {
callPrimOp(fun, arg, v);
@@ -832,7 +839,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
}
if (fun.type != tLambda)
- throwTypeError("attempt to call something which is not a function but %1%", fun);
+ throwTypeError("attempt to call something which is not a function but %1%, at %2%", fun, pos);
ExprLambda & lambda(*fun.lambda.fun);
@@ -860,8 +867,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
foreach (Formals::Formals_::iterator, i, lambda.formals->formals) {
Bindings::iterator j = arg.attrs->find(i->name);
if (j == arg.attrs->end()) {
- if (!i->def) throwTypeError("%1% called without required argument `%2%'",
- lambda, i->name);
+ if (!i->def) throwTypeError("%1% called without required argument `%2%', at %3%",
+ lambda, i->name, pos);
env2.values[displ++] = i->def->maybeThunk(*this, env2);
} else {
attrsUsed++;
@@ -876,7 +883,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
user. */
foreach (Bindings::iterator, i, *arg.attrs)
if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end())
- throwTypeError("%1% called with unexpected argument `%2%'", lambda, i->name);
+ throwTypeError("%1% called with unexpected argument `%2%', at %3%", lambda, i->name, pos);
abort(); // can't happen
}
}
@@ -890,7 +897,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
try {
lambda.body->eval(*this, env2, v);
} catch (Error & e) {
- addErrorPrefix(e, "while evaluating %1%:\n", lambda);
+ addErrorPrefix(e, "while evaluating %1%, called from %2%:\n", lambda, pos);
throw;
}
else
@@ -928,7 +935,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
actualArgs->attrs->sort();
- callFunction(fun, *actualArgs, res);
+ callFunction(fun, *actualArgs, res, noPos);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 58d1318c2..170b74079 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -226,7 +226,7 @@ public:
elements and attributes are compared recursively. */
bool eqValues(Value & v1, Value & v2);
- void callFunction(Value & fun, Value & arg, Value & v);
+ void callFunction(Value & fun, Value & arg, Value & v, const Pos & pos);
void callPrimOp(Value & fun, Value & arg, Value & v);
/* Automatically call a function for which each argument has a
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index bca2b7913..ba1f4f078 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -373,7 +373,7 @@ void ExprLambda::setName(Symbol & name)
string ExprLambda::showNamePos() const
{
- return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str();
+ return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "anonymous function") % pos).str();
}
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index a5c5d0533..527589147 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -273,6 +273,23 @@ struct ExprBuiltin : Expr
COMMON_METHODS
};
+struct ExprApp : Expr
+{
+ Pos pos;
+ Expr * e1, * e2;
+ ExprApp(Expr * e1, Expr * e2) : e1(e1), e2(e2) { };
+ ExprApp(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { };
+ void show(std::ostream & str)
+ {
+ str << *e1 << " " << *e2;
+ }
+ void bindVars(const StaticEnv & env)
+ {
+ e1->bindVars(env); e2->bindVars(env);
+ }
+ void eval(EvalState & state, Env & env, Value & v);
+};
+
#define MakeBinOp(name, s) \
struct Expr##name : Expr \
{ \
@@ -289,7 +306,6 @@ struct ExprBuiltin : Expr
void eval(EvalState & state, Env & env, Value & v); \
};
-MakeBinOp(App, "")
MakeBinOp(OpEq, "==")
MakeBinOp(OpNEq, "!=")
MakeBinOp(OpAnd, "&&")
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index ab0b86224..b8d4d7ca0 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -224,7 +224,7 @@ void backToString(yyscan_t scanner);
void backToIndString(yyscan_t scanner);
-static Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
+static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
{
return Pos(data->path, loc.first_line, loc.first_column);
}
@@ -355,7 +355,7 @@ expr_op
expr_app
: expr_app expr_select
- { $$ = new ExprApp($1, $2); }
+ { $$ = new ExprApp(CUR_POS, $1, $2); }
| expr_select { $$ = $1; }
;
@@ -367,7 +367,7 @@ expr_select
| /* Backwards compatibility: because Nixpkgs has a rarely used
function named ‘or’, allow stuff like ‘map or [...]’. */
expr_simple OR_KW
- { $$ = new ExprApp($1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
+ { $$ = new ExprApp(CUR_POS, $1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
| expr_simple { $$ = $1; }
;
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index ca316f08a..422d68f38 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -711,7 +711,7 @@ struct FilterFromExpr : PathFilter
mkString(arg1, path);
Value fun2;
- state.callFunction(filter, arg1, fun2);
+ state.callFunction(filter, arg1, fun2, noPos);
Value arg2;
mkString(arg2,
@@ -721,7 +721,7 @@ struct FilterFromExpr : PathFilter
"unknown" /* not supported, will fail! */);
Value res;
- state.callFunction(fun2, arg2, res);
+ state.callFunction(fun2, arg2, res, noPos);
return state.forceBool(res);
}
@@ -1008,7 +1008,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v)
bool same = true;
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
Value res;
- state.callFunction(*args[0], *args[1]->list.elems[n], res);
+ state.callFunction(*args[0], *args[1]->list.elems[n], res, noPos);
if (state.forceBool(res))
vs[k++] = args[1]->list.elems[n];
else