From a5fe73094016973a50741db0c5d51ca96c14147b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 21:14:11 +0200 Subject: [PATCH] forceString: Show position info --- src/libexpr/eval.cc | 33 ++++++++++++++++++++++++--------- src/libexpr/eval.hh | 4 ++-- src/libexpr/get-drvs.cc | 9 +++------ src/libexpr/nixexpr.cc | 2 +- src/libexpr/nixexpr.hh | 4 ++++ src/libexpr/primops.cc | 24 ++++++++++++------------ 6 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5c88a34a92..30a8793ee7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -140,7 +140,8 @@ static void * oomHandler(size_t requested) #endif -static Symbol getName(const AttrName & name, EvalState & state, Env & env) { +static Symbol getName(const AttrName & name, EvalState & state, Env & env) +{ if (name.symbol.set()) { return name.symbol; } else { @@ -279,6 +280,11 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con throw EvalError(format(s) % s2 % s3); } +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, const Pos & pos)) +{ + throw EvalError(format(s) % s2 % s3 % pos); +} + LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, const Pos & p1, const Pos & p2)) { throw EvalError(format(s) % sym % p1 % p2); @@ -1172,11 +1178,15 @@ void EvalState::forceFunction(Value & v, const Pos & pos) } -string EvalState::forceString(Value & v) +string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v); - if (v.type != tString) - throwTypeError("value is %1% while a string was expected", v); + if (v.type != tString) { + if (pos) + throwTypeError("value is %1% while a string was expected, at %2%", v, pos); + else + throwTypeError("value is %1% while a string was expected", v); + } return string(v.string.s); } @@ -1197,12 +1207,17 @@ string EvalState::forceString(Value & v, PathSet & context) } -string EvalState::forceStringNoCtx(Value & v) +string EvalState::forceStringNoCtx(Value & v, const Pos & pos) { - string s = forceString(v); - if (v.string.context) - throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%')", - v.string.s, v.string.context[0]); + string s = forceString(v, pos); + if (v.string.context) { + if (pos) + throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%'), at %3%", + v.string.s, v.string.context[0], pos); + else + throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%')", + v.string.s, v.string.context[0]); + } return s; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 248805004c..1d53f49821 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -165,9 +165,9 @@ public: inline void forceList(Value & v); inline void forceList(Value & v, const Pos & pos); void forceFunction(Value & v, const Pos & pos); // either lambda or primop - string forceString(Value & v); + string forceString(Value & v, const Pos & pos = noPos); string forceString(Value & v, PathSet & context); - string forceStringNoCtx(Value & v); + string forceStringNoCtx(Value & v, const Pos & pos = noPos); /* Return true iff the value `v' denotes a derivation (i.e. a set with attribute `type = "derivation"'). */ diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 4e7690063a..88ea68a5f0 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -41,7 +41,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs() /* For each output... */ for (unsigned int j = 0; j < i->value->list.length; ++j) { /* Evaluate the corresponding set. */ - string name = state->forceStringNoCtx(*i->value->list.elems[j]); + string name = state->forceStringNoCtx(*i->value->list.elems[j], *i->pos); Bindings::iterator out = attrs->find(state->symbols.create(name)); if (out == attrs->end()) continue; // FIXME: throw error? state->forceAttrs(*out->value); @@ -199,11 +199,8 @@ static bool getDerivation(EvalState & state, Value & v, Bindings::iterator i2 = v.attrs->find(state.sSystem); - DrvInfo drv( - state, - state.forceStringNoCtx(*i->value), - attrPath, - i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value), + DrvInfo drv(state, state.forceStringNoCtx(*i->value), attrPath, + i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value, *i2->pos), v.attrs); drvs.push_back(drv); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 92f46b30a3..d40250d877 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -145,7 +145,7 @@ void ExprPos::show(std::ostream & str) std::ostream & operator << (std::ostream & str, const Pos & pos) { - if (!pos.line) + if (!pos) str << "undefined position"; else str << (format("%1%:%2%:%3%") % pos.file % pos.line % pos.column).str(); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 527589147e..9234e2970f 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -28,6 +28,10 @@ struct Pos Pos() : line(0), column(0) { }; Pos(const Symbol & file, unsigned int line, unsigned int column) : file(file), line(line), column(column) { }; + operator bool() const + { + return line != 0; + } bool operator < (const Pos & p2) const { if (!line) return p2.line; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 2aa45525e6..00833403d7 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -299,7 +299,7 @@ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Val /* Return an environment variable. Use with care. */ static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); mkString(v, getEnv(name)); } @@ -343,7 +343,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * string drvName; Pos & posDrvName(*attr->pos); try { - drvName = state.forceStringNoCtx(*attr->value); + drvName = state.forceStringNoCtx(*attr->value, pos); } catch (Error & e) { e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName); throw; @@ -664,7 +664,7 @@ static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Valu static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); string contents = state.forceString(*args[1], context); PathSet refs; @@ -775,7 +775,7 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V /* Dynamic version of the `.' operator. */ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); // !!! Should we create a symbol here or just do a lookup? Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); @@ -791,7 +791,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) /* Return position information of the specified attribute. */ void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) @@ -804,7 +804,7 @@ void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, V /* Dynamic version of the `?' operator. */ static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); mkBool(v, args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); } @@ -826,7 +826,7 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, /* Get the attribute names to be removed. */ std::set names; for (unsigned int i = 0; i < args[1]->list.length; ++i) { - state.forceStringNoCtx(*args[1]->list.elems[i]); + state.forceStringNoCtx(*args[1]->list.elems[i], pos); names.insert(state.symbols.create(args[1]->list.elems[i]->string.s)); } @@ -861,7 +861,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) throw TypeError(format("`name' attribute missing in a call to `listToAttrs', at %1%") % pos); - string name = state.forceStringNoCtx(*j->value); + string name = state.forceStringNoCtx(*j->value, pos); Symbol sym = state.symbols.create(name); if (seen.find(sym) == seen.end()) { @@ -1168,7 +1168,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po /* Return the cryptographic hash of a string in base-16. */ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string type = state.forceStringNoCtx(*args[0]); + string type = state.forceStringNoCtx(*args[0], pos); HashType ht = parseHashType(type); if (ht == htUnknown) throw Error(format("unknown hash type `%1%', at %2%") % type % pos); @@ -1187,7 +1187,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); DrvName parsed(name); state.mkAttrs(v, 2); mkString(*state.allocAttr(v, state.sName), parsed.name); @@ -1198,8 +1198,8 @@ static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string version1 = state.forceStringNoCtx(*args[0]); - string version2 = state.forceStringNoCtx(*args[1]); + string version1 = state.forceStringNoCtx(*args[0], pos); + string version2 = state.forceStringNoCtx(*args[1], pos); mkInt(v, compareVersions(version1, version2)); }