forked from lix-project/lix
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'
This commit is contained in:
parent
3f8e1f5682
commit
b72c8d2e5b
|
@ -35,7 +35,7 @@ void EvalState::forceValue(Value & v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v.type == tApp)
|
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)
|
else if (v.type == tBlackhole)
|
||||||
throwEvalError("infinite recursion encountered");
|
throwEvalError("infinite recursion encountered");
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,12 +130,14 @@ string showType(const Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if HAVE_BOEHMGC
|
||||||
/* Called when the Boehm GC runs out of memory. */
|
/* Called when the Boehm GC runs out of memory. */
|
||||||
static void * oomHandler(size_t requested)
|
static void * oomHandler(size_t requested)
|
||||||
{
|
{
|
||||||
/* Convert this to a proper C++ exception. */
|
/* Convert this to a proper C++ exception. */
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static Symbol getName(const AttrName & name, EvalState & state, Env & env) {
|
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);
|
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))
|
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
|
||||||
{
|
{
|
||||||
throw TypeError(format(s) % s1 % 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))
|
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);
|
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))
|
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. */
|
/* FIXME: vFun prevents GCC from doing tail call optimisation. */
|
||||||
Value vFun;
|
Value vFun;
|
||||||
e1->eval(state, env, 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) {
|
if (fun.type == tPrimOp || fun.type == tPrimOpApp) {
|
||||||
callPrimOp(fun, arg, v);
|
callPrimOp(fun, arg, v);
|
||||||
|
@ -832,7 +839,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fun.type != tLambda)
|
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);
|
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) {
|
foreach (Formals::Formals_::iterator, i, lambda.formals->formals) {
|
||||||
Bindings::iterator j = arg.attrs->find(i->name);
|
Bindings::iterator j = arg.attrs->find(i->name);
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
|
if (!i->def) throwTypeError("%1% called without required argument `%2%', at %3%",
|
||||||
lambda, i->name);
|
lambda, i->name, pos);
|
||||||
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
|
@ -876,7 +883,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
user. */
|
user. */
|
||||||
foreach (Bindings::iterator, i, *arg.attrs)
|
foreach (Bindings::iterator, i, *arg.attrs)
|
||||||
if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end())
|
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
|
abort(); // can't happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -890,7 +897,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
try {
|
try {
|
||||||
lambda.body->eval(*this, env2, v);
|
lambda.body->eval(*this, env2, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
addErrorPrefix(e, "while evaluating %1%:\n", lambda);
|
addErrorPrefix(e, "while evaluating %1%, called from %2%:\n", lambda, pos);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -928,7 +935,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
|
|
||||||
actualArgs->attrs->sort();
|
actualArgs->attrs->sort();
|
||||||
|
|
||||||
callFunction(fun, *actualArgs, res);
|
callFunction(fun, *actualArgs, res, noPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ public:
|
||||||
elements and attributes are compared recursively. */
|
elements and attributes are compared recursively. */
|
||||||
bool eqValues(Value & v1, Value & v2);
|
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);
|
void callPrimOp(Value & fun, Value & arg, Value & v);
|
||||||
|
|
||||||
/* Automatically call a function for which each argument has a
|
/* Automatically call a function for which each argument has a
|
||||||
|
|
|
@ -373,7 +373,7 @@ void ExprLambda::setName(Symbol & name)
|
||||||
|
|
||||||
string ExprLambda::showNamePos() const
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -273,6 +273,23 @@ struct ExprBuiltin : Expr
|
||||||
COMMON_METHODS
|
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) \
|
#define MakeBinOp(name, s) \
|
||||||
struct Expr##name : Expr \
|
struct Expr##name : Expr \
|
||||||
{ \
|
{ \
|
||||||
|
@ -289,7 +306,6 @@ struct ExprBuiltin : Expr
|
||||||
void eval(EvalState & state, Env & env, Value & v); \
|
void eval(EvalState & state, Env & env, Value & v); \
|
||||||
};
|
};
|
||||||
|
|
||||||
MakeBinOp(App, "")
|
|
||||||
MakeBinOp(OpEq, "==")
|
MakeBinOp(OpEq, "==")
|
||||||
MakeBinOp(OpNEq, "!=")
|
MakeBinOp(OpNEq, "!=")
|
||||||
MakeBinOp(OpAnd, "&&")
|
MakeBinOp(OpAnd, "&&")
|
||||||
|
|
|
@ -224,7 +224,7 @@ void backToString(yyscan_t scanner);
|
||||||
void backToIndString(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);
|
return Pos(data->path, loc.first_line, loc.first_column);
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ expr_op
|
||||||
|
|
||||||
expr_app
|
expr_app
|
||||||
: expr_app expr_select
|
: expr_app expr_select
|
||||||
{ $$ = new ExprApp($1, $2); }
|
{ $$ = new ExprApp(CUR_POS, $1, $2); }
|
||||||
| expr_select { $$ = $1; }
|
| expr_select { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ expr_select
|
||||||
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
||||||
function named ‘or’, allow stuff like ‘map or [...]’. */
|
function named ‘or’, allow stuff like ‘map or [...]’. */
|
||||||
expr_simple OR_KW
|
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; }
|
| expr_simple { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -711,7 +711,7 @@ struct FilterFromExpr : PathFilter
|
||||||
mkString(arg1, path);
|
mkString(arg1, path);
|
||||||
|
|
||||||
Value fun2;
|
Value fun2;
|
||||||
state.callFunction(filter, arg1, fun2);
|
state.callFunction(filter, arg1, fun2, noPos);
|
||||||
|
|
||||||
Value arg2;
|
Value arg2;
|
||||||
mkString(arg2,
|
mkString(arg2,
|
||||||
|
@ -721,7 +721,7 @@ struct FilterFromExpr : PathFilter
|
||||||
"unknown" /* not supported, will fail! */);
|
"unknown" /* not supported, will fail! */);
|
||||||
|
|
||||||
Value res;
|
Value res;
|
||||||
state.callFunction(fun2, arg2, res);
|
state.callFunction(fun2, arg2, res, noPos);
|
||||||
|
|
||||||
return state.forceBool(res);
|
return state.forceBool(res);
|
||||||
}
|
}
|
||||||
|
@ -1008,7 +1008,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v)
|
||||||
bool same = true;
|
bool same = true;
|
||||||
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
|
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
|
||||||
Value res;
|
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))
|
if (state.forceBool(res))
|
||||||
vs[k++] = args[1]->list.elems[n];
|
vs[k++] = args[1]->list.elems[n];
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue