From 18a48d80a0686ba81959057e8becc6272acd6c46 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 16 May 2013 19:08:02 +0200 Subject: [PATCH] Show function names in error messages Functions in Nix are anonymous, but if they're assigned to a variable/attribute, we can use the variable/attribute name in error messages, e.g. while evaluating `concatMapStrings' at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/strings.nix:18:25': ... --- src/libexpr/eval.cc | 13 +++++++++---- src/libexpr/nixexpr.cc | 20 ++++++++++++++++++++ src/libexpr/nixexpr.hh | 4 ++++ src/libexpr/parser.y | 1 + src/libexpr/symbol-table.hh | 13 +++++++++---- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 551ed4ba5..c927db2c1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -247,6 +247,11 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const throw TypeError(format(s) % pos % s2); } +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 Pos & pos)) { throw TypeError(format(s) % pos); @@ -755,8 +760,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { Bindings::iterator j = arg.attrs->find(i->name); if (j == arg.attrs->end()) { - if (!i->def) throwTypeError("function at %1% called without required argument `%2%'", - fun.lambda.fun->pos, i->name); + if (!i->def) throwTypeError("%1% called without required argument `%2%'", + fun.lambda.fun->showNamePos(), i->name); env2.values[displ++] = i->def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -771,7 +776,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) user. */ foreach (Bindings::iterator, i, *arg.attrs) if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end()) - throwTypeError("function at %1% called with unexpected argument `%2%'", fun.lambda.fun->pos, i->name); + throwTypeError("%1% called with unexpected argument `%2%'", fun.lambda.fun->showNamePos(), i->name); abort(); // can't happen } } @@ -782,7 +787,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) try { fun.lambda.fun->body->eval(*this, env2, v); } catch (Error & e) { - addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos); + addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos()); throw; } } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index c52a41391..9b75bb644 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -324,4 +324,24 @@ void ExprConcatStrings::bindVars(const StaticEnv & env) } +/* Storing function names. */ + +void Expr::setName(Symbol & name) +{ +} + + +void ExprLambda::setName(Symbol & name) +{ + this->name = name; + body->setName(name); +} + + +string ExprLambda::showNamePos() +{ + return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str(); +} + + } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 86a7bfd50..8256605b5 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -63,6 +63,7 @@ struct Expr virtual void bindVars(const StaticEnv & env); virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); + virtual void setName(Symbol & name); }; std::ostream & operator << (std::ostream & str, Expr & e); @@ -197,6 +198,7 @@ struct Formals struct ExprLambda : Expr { Pos pos; + Symbol name; Symbol arg; bool matchAttrs; Formals * formals; @@ -208,6 +210,8 @@ struct ExprLambda : Expr throw ParseError(format("duplicate formal function argument `%1%' at %2%") % arg % pos); }; + void setName(Symbol & name); + string showNamePos(); COMMON_METHODS }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index f78780b1d..964527be6 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -104,6 +104,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, } } } + e->setName(attrPath.back()); } diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh index 143fc495b..ccdabb028 100644 --- a/src/libexpr/symbol-table.hh +++ b/src/libexpr/symbol-table.hh @@ -28,17 +28,17 @@ private: public: Symbol() : s(0) { }; - + bool operator == (const Symbol & s2) const { return s == s2.s; } - + bool operator != (const Symbol & s2) const { return s != s2.s; } - + bool operator < (const Symbol & s2) const { return s < s2.s; @@ -49,6 +49,11 @@ public: return *s; } + bool set() const + { + return s; + } + bool empty() const { return s->empty(); @@ -66,7 +71,7 @@ inline std::ostream & operator << (std::ostream & str, const Symbol & sym) class SymbolTable { private: -#if HAVE_TR1_UNORDERED_SET +#if HAVE_TR1_UNORDERED_SET typedef std::tr1::unordered_set Symbols; #else typedef std::set Symbols;