forked from lix-project/lix
Refactor to use more traces and less string manipulations
This commit is contained in:
parent
13c4dc6532
commit
e6d07e0d89
|
@ -15,10 +15,10 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, const std::string & s2))
|
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v))
|
||||||
{
|
{
|
||||||
throw TypeError({
|
throw TypeError({
|
||||||
.msg = hintfmt(s, showType(v), s2),
|
.msg = hintfmt(s, showType(v)),
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -52,26 +52,39 @@ void EvalState::forceValue(Value & v, Callable getPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void EvalState::forceAttrs(Value & v, const Pos & pos, const std::string & errorCtx)
|
inline void EvalState::forceAttrs(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceAttrs(v, [&]() { return pos; }, errorCtx);
|
forceAttrs(v, [&]() { return pos; }, errorCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Callable>
|
template <typename Callable>
|
||||||
inline void EvalState::forceAttrs(Value & v, Callable getPos, const std::string & errorCtx)
|
inline void EvalState::forceAttrs(Value & v, Callable getPos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, getPos);
|
try {
|
||||||
if (v.type() != nAttrs)
|
forceValue(v, noPos);
|
||||||
throwTypeError(getPos(), "%2%value is %1% while a set was expected", v, errorCtx);
|
if (v.type() != nAttrs) {
|
||||||
|
throwTypeError(noPos, "value is %1% while a set was expected", v);
|
||||||
|
}
|
||||||
|
} catch (Error & e) {
|
||||||
|
Pos pos = getPos();
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void EvalState::forceList(Value & v, const Pos & pos, const std::string & errorCtx)
|
inline void EvalState::forceList(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
try {
|
||||||
if (!v.isList())
|
forceValue(v, noPos);
|
||||||
throwTypeError(pos, "%2%value is %1% while a list was expected", v, errorCtx);
|
if (!v.isList()) {
|
||||||
|
throwTypeError(noPos, "value is %1% while a list was expected", v);
|
||||||
|
}
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: Various places expect the allocated memory to be zeroed. */
|
/* Note: Various places expect the allocated memory to be zeroed. */
|
||||||
|
|
|
@ -694,9 +694,12 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||||
evaluator. So here are some helper functions for throwing
|
evaluator. So here are some helper functions for throwing
|
||||||
exceptions. */
|
exceptions. */
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2))
|
LocalNoInlineNoReturn(void throwTypeErrorWithTrace(const Pos & pos, const char * s, const std::string & s2, const Symbol & sym, const Pos & p2, const std::string & s3))
|
||||||
{
|
{
|
||||||
throw EvalError(s, s2);
|
throw EvalError({
|
||||||
|
.msg = hintfmt(s, s2, sym),
|
||||||
|
.errPos = pos
|
||||||
|
}).addTrace(p2, s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
|
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
|
||||||
|
@ -707,23 +710,10 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2, const std::string & s3))
|
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const Value & v))
|
||||||
{
|
{
|
||||||
throw EvalError(s, s2, s3);
|
throw AssertionError({
|
||||||
}
|
.msg = hintfmt(s, showType(v)),
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3))
|
|
||||||
{
|
|
||||||
throw EvalError({
|
|
||||||
.msg = hintfmt(s, s2, s3),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3, const std::string & s4))
|
|
||||||
{
|
|
||||||
throw EvalError({
|
|
||||||
.msg = hintfmt(s, s2, s3, s4),
|
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -737,22 +727,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2))
|
|
||||||
{
|
|
||||||
throw TypeError({
|
|
||||||
.msg = hintfmt(s, fun.showNamePos(), s2),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v))
|
|
||||||
{
|
|
||||||
throw AssertionError({
|
|
||||||
.msg = hintfmt(s, showType(v)),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const std::string & s1))
|
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const std::string & s1))
|
||||||
{
|
{
|
||||||
throw AssertionError({
|
throw AssertionError({
|
||||||
|
@ -1040,21 +1014,31 @@ void EvalState::eval(Expr * e, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos, const std::string & errorCtx)
|
inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
Value v;
|
try {
|
||||||
e->eval(*this, env, v);
|
Value v;
|
||||||
if (v.type() != nBool)
|
e->eval(*this, env, v);
|
||||||
throwTypeError(pos, "%2%value is %1% while a Boolean was expected", v, errorCtx);
|
if (v.type() != nBool)
|
||||||
return v.boolean;
|
throw TypeError("value is %1% while a Boolean was expected", showType(v));
|
||||||
|
return v.boolean;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const Pos & pos, const std::string & errorCtx)
|
inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
e->eval(*this, env, v);
|
try {
|
||||||
if (v.type() != nAttrs)
|
e->eval(*this, env, v);
|
||||||
throwTypeError(pos, "%2%value is %1% while a set was expected", v, errorCtx);
|
if (v.type() != nAttrs)
|
||||||
|
throw TypeError("value is %1% while a set was expected", showType(v));
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1297,6 +1281,10 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||||
v.mkLambda(&env, this);
|
v.mkLambda(&env, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string prettyLambdaName(const ExprLambda & e)
|
||||||
|
{
|
||||||
|
return e.name.set() ? std::string(e.name): "anonymous lambda";
|
||||||
|
}
|
||||||
|
|
||||||
void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos)
|
void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos)
|
||||||
{
|
{
|
||||||
|
@ -1336,7 +1324,12 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
env2.values[displ++] = args[0];
|
env2.values[displ++] = args[0];
|
||||||
|
|
||||||
else {
|
else {
|
||||||
forceAttrs(*args[0], pos, "While evaluating the value passed as argument to a function expecting an attribute set: ");
|
try {
|
||||||
|
forceAttrs(*args[0], lambda.pos, "While evaluating the value passed for this lambda parameter");
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, "from call site");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lambda.arg.empty())
|
if (!lambda.arg.empty())
|
||||||
env2.values[displ++] = args[0];
|
env2.values[displ++] = args[0];
|
||||||
|
@ -1348,8 +1341,11 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
for (auto & i : lambda.formals->formals) {
|
for (auto & i : lambda.formals->formals) {
|
||||||
auto j = args[0]->attrs->get(i.name);
|
auto j = args[0]->attrs->get(i.name);
|
||||||
if (!j) {
|
if (!j) {
|
||||||
if (!i.def) throwTypeError(pos, "Function %1% called without required argument '%2%'",
|
if (!i.def) {
|
||||||
lambda, i.name);
|
throwTypeErrorWithTrace(lambda.pos,
|
||||||
|
"Function '%1%' called without required argument '%2%'", prettyLambdaName(lambda), i.name,
|
||||||
|
pos, "from call site");
|
||||||
|
}
|
||||||
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
|
@ -1363,8 +1359,11 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
/* Nope, so show the first unexpected argument to the
|
/* Nope, so show the first unexpected argument to the
|
||||||
user. */
|
user. */
|
||||||
for (auto & i : *args[0]->attrs)
|
for (auto & i : *args[0]->attrs)
|
||||||
if (!lambda.formals->has(i.name))
|
if (!lambda.formals->has(i.name)) {
|
||||||
throwTypeError(pos, "Function %1% called with unexpected argument '%2%'", lambda, i.name);
|
throwTypeErrorWithTrace(lambda.pos,
|
||||||
|
"Function '%1%' called with unexpected argument '%2%'", prettyLambdaName(lambda), i.name,
|
||||||
|
pos, "from call site");
|
||||||
|
}
|
||||||
abort(); // can't happen
|
abort(); // can't happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1377,11 +1376,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
lambda.body->eval(*this, env2, vCur);
|
lambda.body->eval(*this, env2, vCur);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (loggerSettings.showTrace.get()) {
|
if (loggerSettings.showTrace.get()) {
|
||||||
addErrorTrace(e, lambda.pos, "while evaluating %s",
|
addErrorTrace(e, lambda.pos, "While evaluating the '%s' function", prettyLambdaName(lambda));
|
||||||
(lambda.name.set()
|
if (pos) e.addTrace(pos, "from call site");
|
||||||
? "'" + (const std::string &) lambda.name + "'"
|
|
||||||
: "anonymous lambda"));
|
|
||||||
addErrorTrace(e, pos, "from call site%s", "");
|
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -1400,9 +1396,17 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
/* We have all the arguments, so call the primop. */
|
/* We have all the arguments, so call the primop. */
|
||||||
|
Symbol name = vCur.primOp->name;
|
||||||
|
|
||||||
nrPrimOpCalls++;
|
nrPrimOpCalls++;
|
||||||
if (countCalls) primOpCalls[vCur.primOp->name]++;
|
if (countCalls) primOpCalls[name]++;
|
||||||
vCur.primOp->fun(*this, pos, args, vCur);
|
|
||||||
|
try {
|
||||||
|
vCur.primOp->fun(*this, pos, args, vCur);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorTrace(e, pos, "While calling the '%1%' builtin", name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
nrArgs -= argsLeft;
|
nrArgs -= argsLeft;
|
||||||
args += argsLeft;
|
args += argsLeft;
|
||||||
|
@ -1437,9 +1441,16 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
for (size_t i = 0; i < argsLeft; ++i)
|
for (size_t i = 0; i < argsLeft; ++i)
|
||||||
vArgs[argsDone + i] = args[i];
|
vArgs[argsDone + i] = args[i];
|
||||||
|
|
||||||
|
Symbol name = primOp->primOp->name;
|
||||||
nrPrimOpCalls++;
|
nrPrimOpCalls++;
|
||||||
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
if (countCalls) primOpCalls[name]++;
|
||||||
primOp->primOp->fun(*this, pos, vArgs, vCur);
|
|
||||||
|
try {
|
||||||
|
primOp->primOp->fun(*this, noPos, vArgs, vCur);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorTrace(e, pos, "While calling the '%1%' builtin", name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
nrArgs -= argsLeft;
|
nrArgs -= argsLeft;
|
||||||
args += argsLeft;
|
args += argsLeft;
|
||||||
|
@ -1452,8 +1463,12 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
heap-allocate a copy and use that instead. */
|
heap-allocate a copy and use that instead. */
|
||||||
Value * args2[] = {allocValue(), args[0]};
|
Value * args2[] = {allocValue(), args[0]};
|
||||||
*args2[0] = vCur;
|
*args2[0] = vCur;
|
||||||
/* !!! Should we use the attr pos here? */
|
try {
|
||||||
callFunction(*functor->value, 2, args2, vCur, pos);
|
callFunction(*functor->value, 2, args2, vCur, *functor->pos);
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, "While calling a functor (an attribute set with a 'functor' attribute)");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
nrArgs--;
|
nrArgs--;
|
||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
|
@ -1553,7 +1568,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
// We cheat in the parser, an pass the position of the condition as the position of the if itself.
|
// We cheat in the parser, an pass the position of the condition as the position of the if itself.
|
||||||
(state.evalBool(env, cond, pos, "") ? then : else_)->eval(state, env, v);
|
(state.evalBool(env, cond, pos, "While evaluating a branch condition") ? then : else_)->eval(state, env, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1578,7 +1593,7 @@ void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Value v1; e1->eval(state, env, v1);
|
||||||
Value v2; e2->eval(state, env, v2);
|
Value v2; e2->eval(state, env, v2);
|
||||||
v.mkBool(state.eqValues(v1, v2, pos, ""));
|
v.mkBool(state.eqValues(v1, v2, pos, "While testing two values for equality"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1586,7 +1601,7 @@ void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Value v1; e1->eval(state, env, v1);
|
||||||
Value v2; e2->eval(state, env, v2);
|
Value v2; e2->eval(state, env, v2);
|
||||||
v.mkBool(!state.eqValues(v1, v2, pos, ""));
|
v.mkBool(!state.eqValues(v1, v2, pos, "While testing two values for inequality"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1655,7 +1670,7 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos, const std::string & errorCtx)
|
void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
nrListConcats++;
|
nrListConcats++;
|
||||||
|
|
||||||
|
@ -1739,20 +1754,20 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
nf = n;
|
nf = n;
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp.fpoint;
|
||||||
} else
|
} else
|
||||||
throwEvalError(i_pos, "cannot add %1% to an integer", showType(vTmp));
|
throwEvalError(i_pos, "cannot add %1% to an integer", vTmp);
|
||||||
} else if (firstType == nFloat) {
|
} else if (firstType == nFloat) {
|
||||||
if (vTmp.type() == nInt) {
|
if (vTmp.type() == nInt) {
|
||||||
nf += vTmp.integer;
|
nf += vTmp.integer;
|
||||||
} else if (vTmp.type() == nFloat) {
|
} else if (vTmp.type() == nFloat) {
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp.fpoint;
|
||||||
} else
|
} else
|
||||||
throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp));
|
throwEvalError(i_pos, "cannot add %1% to a float", vTmp);
|
||||||
} else {
|
} else {
|
||||||
if (s.empty()) s.reserve(es->size());
|
if (s.empty()) s.reserve(es->size());
|
||||||
/* skip canonization of first path, which would only be not
|
/* skip canonization of first path, which would only be not
|
||||||
canonized in the first place if it's coming from a ./${foo} type
|
canonized in the first place if it's coming from a ./${foo} type
|
||||||
path */
|
path */
|
||||||
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first, "");
|
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first, "While evaluating a path segment");
|
||||||
sSize += part->size();
|
sSize += part->size();
|
||||||
s.emplace_back(std::move(part));
|
s.emplace_back(std::move(part));
|
||||||
}
|
}
|
||||||
|
@ -1810,32 +1825,47 @@ void EvalState::forceValueDeep(Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NixInt EvalState::forceInt(Value & v, const Pos & pos, const std::string & errorCtx)
|
NixInt EvalState::forceInt(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
try {
|
||||||
if (v.type() != nInt)
|
forceValue(v, pos);
|
||||||
throwTypeError(pos, "%2%value is %1% while an integer was expected", v, errorCtx);
|
if (v.type() != nInt)
|
||||||
return v.integer;
|
throw TypeError("value is %1% while an integer was expected", showType(v));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NixFloat EvalState::forceFloat(Value & v, const Pos & pos, const std::string & errorCtx)
|
|
||||||
{
|
|
||||||
forceValue(v, pos);
|
|
||||||
if (v.type() == nInt)
|
|
||||||
return v.integer;
|
return v.integer;
|
||||||
else if (v.type() != nFloat)
|
} catch (Error & e) {
|
||||||
throwTypeError(pos, "%2%value is %1% while a float was expected", v, errorCtx);
|
e.addTrace(pos, errorCtx);
|
||||||
return v.fpoint;
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EvalState::forceBool(Value & v, const Pos & pos, const std::string & errorCtx)
|
NixFloat EvalState::forceFloat(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
try {
|
||||||
if (v.type() != nBool)
|
forceValue(v, pos);
|
||||||
throwTypeError(pos, "%2%value is %1% while a Boolean was expected", v, errorCtx);
|
if (v.type() == nInt)
|
||||||
return v.boolean;
|
return v.integer;
|
||||||
|
else if (v.type() != nFloat)
|
||||||
|
throw TypeError("value is %1% while a float was expected", showType(v));
|
||||||
|
return v.fpoint;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool EvalState::forceBool(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
forceValue(v, pos);
|
||||||
|
if (v.type() != nBool)
|
||||||
|
throw TypeError("value is %1% while a Boolean was expected", showType(v));
|
||||||
|
return v.boolean;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1845,21 +1875,30 @@ bool EvalState::isFunctor(Value & fun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::forceFunction(Value & v, const Pos & pos, const std::string & errorCtx)
|
void EvalState::forceFunction(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
try {
|
||||||
if (v.type() != nFunction && !isFunctor(v))
|
forceValue(v, pos);
|
||||||
throwTypeError(pos, "%2%value is %1% while a function was expected", v, errorCtx);
|
if (v.type() != nFunction && !isFunctor(v))
|
||||||
|
throw TypeError("value is %1% while a function was expected", showType(v));
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string_view EvalState::forceString(Value & v, const Pos & pos, const std::string & errorCtx)
|
std::string_view EvalState::forceString(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
try {
|
||||||
if (v.type() != nString) {
|
forceValue(v, pos);
|
||||||
throwTypeError(pos, "%2%value is %1% while a string was expected", v, errorCtx);
|
if (v.type() != nString)
|
||||||
|
throw TypeError("value is %1% while a string was expected", showType(v));
|
||||||
|
return v.string.s;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
return v.string.s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1894,7 +1933,7 @@ std::vector<std::pair<Path, std::string>> Value::getContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos & pos, const std::string & errorCtx)
|
std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
auto s = forceString(v, pos, errorCtx);
|
auto s = forceString(v, pos, errorCtx);
|
||||||
copyContext(v, context);
|
copyContext(v, context);
|
||||||
|
@ -1902,18 +1941,21 @@ std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos, const std::string & errorCtx)
|
std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
auto s = forceString(v, pos, errorCtx);
|
try {
|
||||||
if (v.string.context) {
|
auto s = forceString(v, pos, errorCtx);
|
||||||
if (pos)
|
if (v.string.context) {
|
||||||
throwEvalError(pos, (errorCtx + ": the string '%1%' is not allowed to refer to a store path (such as '%2%')").c_str(),
|
if (pos)
|
||||||
v.string.s, v.string.context[0]);
|
throw EvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0]);
|
||||||
else
|
else
|
||||||
throwEvalError((errorCtx + ": the string '%1%' is not allowed to refer to a store path (such as '%2%')").c_str(),
|
throw EvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0]);
|
||||||
v.string.s, v.string.context[0]);
|
}
|
||||||
|
return s;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1943,7 +1985,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value &
|
||||||
}
|
}
|
||||||
|
|
||||||
BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore, bool copyToStore, bool canonicalizePath, const std::string & errorCtx)
|
bool coerceMore, bool copyToStore, bool canonicalizePath, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
|
|
||||||
|
@ -1966,7 +2008,9 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
|
||||||
if (maybeString)
|
if (maybeString)
|
||||||
return std::move(*maybeString);
|
return std::move(*maybeString);
|
||||||
auto i = v.attrs->find(sOutPath);
|
auto i = v.attrs->find(sOutPath);
|
||||||
if (i == v.attrs->end()) throwTypeError(pos, "%2%cannot coerce %1% to a string", v, errorCtx);
|
if (i == v.attrs->end()) {
|
||||||
|
throw TypeError("cannot coerce %1% to a string", showType(v)).addTrace(pos, errorCtx);
|
||||||
|
}
|
||||||
return coerceToString(pos, *i->value, context, coerceMore, copyToStore, canonicalizePath, errorCtx);
|
return coerceToString(pos, *i->value, context, coerceMore, copyToStore, canonicalizePath, errorCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1986,8 +2030,13 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
|
||||||
if (v.isList()) {
|
if (v.isList()) {
|
||||||
std::string result;
|
std::string result;
|
||||||
for (auto [n, v2] : enumerate(v.listItems())) {
|
for (auto [n, v2] : enumerate(v.listItems())) {
|
||||||
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore, canonicalizePath,
|
try {
|
||||||
errorCtx + ": While evaluating one element of the list");
|
result += *coerceToString(noPos, *v2, context, coerceMore, copyToStore, canonicalizePath,
|
||||||
|
"While evaluating one element of the list");
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, errorCtx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
if (n < v.listSize() - 1
|
if (n < v.listSize() - 1
|
||||||
/* !!! not quite correct */
|
/* !!! not quite correct */
|
||||||
&& (!v2->isList() || v2->listSize() != 0))
|
&& (!v2->isList() || v2->listSize() != 0))
|
||||||
|
@ -1997,14 +2046,14 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throwTypeError(pos, "%2%cannot coerce %1% to a string", v, errorCtx);
|
throw TypeError("cannot coerce %1% to a string", showType(v)).addTrace(pos, errorCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||||
{
|
{
|
||||||
if (nix::isDerivation(path))
|
if (nix::isDerivation(path))
|
||||||
throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
|
throw EvalError("file names are not allowed to end in '%1%'", drvExtension);
|
||||||
|
|
||||||
Path dstPath;
|
Path dstPath;
|
||||||
auto i = srcToStore.find(path);
|
auto i = srcToStore.find(path);
|
||||||
|
@ -2025,28 +2074,25 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx)
|
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned();
|
auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned();
|
||||||
if (path == "" || path[0] != '/')
|
if (path == "" || path[0] != '/')
|
||||||
throwEvalError(pos, "%2%string '%1%' doesn't represent an absolute path", path, errorCtx);
|
throw EvalError("string '%1%' doesn't represent an absolute path", path).addTrace(pos, errorCtx);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx)
|
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned();
|
auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned();
|
||||||
if (auto storePath = store->maybeParseStorePath(path))
|
if (auto storePath = store->maybeParseStorePath(path))
|
||||||
return *storePath;
|
return *storePath;
|
||||||
throw EvalError({
|
throw EvalError("path '%1%' is not in the Nix store", path).addTrace(pos, errorCtx);
|
||||||
.msg = hintfmt("%2%path '%1%' is not in the Nix store", path, errorCtx),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EvalState::eqValues(Value & v1, Value & v2, const Pos & pos, const std::string & errorCtx)
|
bool EvalState::eqValues(Value & v1, Value & v2, const Pos & pos, const std::string_view & errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v1, noPos);
|
forceValue(v1, noPos);
|
||||||
forceValue(v2, noPos);
|
forceValue(v2, noPos);
|
||||||
|
@ -2120,7 +2166,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const Pos & pos, const std::str
|
||||||
return v1.fpoint == v2.fpoint;
|
return v1.fpoint == v2.fpoint;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throwEvalError(pos, "%3%cannot compare %1% with %2%", showType(v1), showType(v2), errorCtx);
|
throw EvalError("cannot compare %1% with %2%", showType(v1), showType(v2)).addTrace(pos, errorCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2242,12 +2288,9 @@ void EvalState::printStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const
|
std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string_view & errorCtx) const
|
||||||
{
|
{
|
||||||
throw TypeError({
|
throw TypeError("cannot coerce %1% to a string", showType()).addTrace(pos, errorCtx);
|
||||||
.msg = hintfmt("%2%cannot coerce %1% to a string", showType(), errorCtx),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -217,8 +217,8 @@ public:
|
||||||
|
|
||||||
/* Evaluation the expression, then verify that it has the expected
|
/* Evaluation the expression, then verify that it has the expected
|
||||||
type. */
|
type. */
|
||||||
inline bool evalBool(Env & env, Expr * e, const Pos & pos, const std::string & errorCtx);
|
inline bool evalBool(Env & env, Expr * e, const Pos & pos, const std::string_view & errorCtx);
|
||||||
inline void evalAttrs(Env & env, Expr * e, Value & v, const Pos & pos, const std::string & errorCtx);
|
inline void evalAttrs(Env & env, Expr * e, Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
||||||
of the evaluation of the thunk. If `v' is a delayed function
|
of the evaluation of the thunk. If `v' is a delayed function
|
||||||
|
@ -234,20 +234,20 @@ public:
|
||||||
void forceValueDeep(Value & v);
|
void forceValueDeep(Value & v);
|
||||||
|
|
||||||
/* Force `v', and then verify that it has the expected type. */
|
/* Force `v', and then verify that it has the expected type. */
|
||||||
NixInt forceInt(Value & v, const Pos & pos, const std::string & errorCtx);
|
NixInt forceInt(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
NixFloat forceFloat(Value & v, const Pos & pos, const std::string & errorCtx);
|
NixFloat forceFloat(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
bool forceBool(Value & v, const Pos & pos, const std::string & errorCtx);
|
bool forceBool(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
void forceAttrs(Value & v, const Pos & pos, const std::string & errorCtx);
|
void forceAttrs(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
template <typename Callable>
|
template <typename Callable>
|
||||||
inline void forceAttrs(Value & v, Callable getPos, const std::string & errorCtx);
|
inline void forceAttrs(Value & v, Callable getPos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
inline void forceList(Value & v, const Pos & pos, const std::string & errorCtx);
|
inline void forceList(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
void forceFunction(Value & v, const Pos & pos, const std::string & errorCtx); // either lambda or primop
|
void forceFunction(Value & v, const Pos & pos, const std::string_view & errorCtx); // either lambda or primop
|
||||||
std::string_view forceString(Value & v, const Pos & pos, const std::string & errorCtx);
|
std::string_view forceString(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
std::string_view forceString(Value & v, PathSet & context, const Pos & pos, const std::string & errorCtx);
|
std::string_view forceString(Value & v, PathSet & context, const Pos & pos, const std::string_view & errorCtx);
|
||||||
std::string_view forceStringNoCtx(Value & v, const Pos & pos, const std::string & errorCtx);
|
std::string_view forceStringNoCtx(Value & v, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
/* Return true iff the value `v' denotes a derivation (i.e. a
|
/* Return true iff the value `v' denotes a derivation (i.e. a
|
||||||
set with attribute `type = "derivation"'). */
|
set with attribute `type = "derivation"'). */
|
||||||
|
@ -263,17 +263,17 @@ public:
|
||||||
BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
|
BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore = false, bool copyToStore = true,
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
bool canonicalizePath = true,
|
bool canonicalizePath = true,
|
||||||
const std::string & errorCtx = "");
|
const std::string_view & errorCtx = "");
|
||||||
|
|
||||||
std::string copyPathToStore(PathSet & context, const Path & path);
|
std::string copyPathToStore(PathSet & context, const Path & path);
|
||||||
|
|
||||||
/* Path coercion. Converts strings, paths and derivations to a
|
/* Path coercion. Converts strings, paths and derivations to a
|
||||||
path. The result is guaranteed to be a canonicalised, absolute
|
path. The result is guaranteed to be a canonicalised, absolute
|
||||||
path. Nothing is copied to the store. */
|
path. Nothing is copied to the store. */
|
||||||
Path coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx);
|
Path coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string_view & errorCtx);
|
||||||
|
|
||||||
/* Like coerceToPath, but the result must be a store path. */
|
/* Like coerceToPath, but the result must be a store path. */
|
||||||
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx);
|
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string_view & errorCtx);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ public:
|
||||||
|
|
||||||
/* Do a deep equality test between two values. That is, list
|
/* Do a deep equality test between two values. That is, list
|
||||||
elements and attributes are compared recursively. */
|
elements and attributes are compared recursively. */
|
||||||
bool eqValues(Value & v1, Value & v2, const Pos & pos, const std::string & errorCtx);
|
bool eqValues(Value & v1, Value & v2, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
bool isFunctor(Value & fun);
|
bool isFunctor(Value & fun);
|
||||||
|
|
||||||
|
@ -364,7 +364,7 @@ public:
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
void mkPos(Value & v, ptr<Pos> pos);
|
void mkPos(Value & v, ptr<Pos> pos);
|
||||||
|
|
||||||
void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos, const std::string & errorCtx);
|
void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos, const std::string_view & errorCtx);
|
||||||
|
|
||||||
/* Print statistics. */
|
/* Print statistics. */
|
||||||
void printStats();
|
void printStats();
|
||||||
|
|
|
@ -396,7 +396,7 @@ expr_function
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_if
|
expr_if
|
||||||
: IF expr THEN expr ELSE expr { $$ = new ExprIf(makeCurPos(@2, data), $2, $4, $6); }
|
: IF expr THEN expr ELSE expr { $$ = new ExprIf(CUR_POS, $2, $4, $6); }
|
||||||
| expr_op
|
| expr_op
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -85,7 +85,7 @@ class ExternalValueBase
|
||||||
/* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
|
/* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const;
|
virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string_view & errorCtx) const;
|
||||||
|
|
||||||
/* Compare to another value of the same type. Defaults to uncomparable,
|
/* Compare to another value of the same type. Defaults to uncomparable,
|
||||||
* i.e. always false.
|
* i.e. always false.
|
||||||
|
|
|
@ -185,15 +185,15 @@ void printAtPos(const ErrPos & pos, std::ostream & out)
|
||||||
if (pos) {
|
if (pos) {
|
||||||
switch (pos.origin) {
|
switch (pos.origin) {
|
||||||
case foFile: {
|
case foFile: {
|
||||||
out << fmt(ANSI_BLUE "at " ANSI_WARNING "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos));
|
out << fmt(ANSI_BLUE " at " ANSI_WARNING "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case foString: {
|
case foString: {
|
||||||
out << fmt(ANSI_BLUE "at " ANSI_WARNING "«string»:%s" ANSI_NORMAL ":", showErrPos(pos));
|
out << fmt(ANSI_BLUE " at " ANSI_WARNING "«string»:%s" ANSI_NORMAL ":", showErrPos(pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case foStdin: {
|
case foStdin: {
|
||||||
out << fmt(ANSI_BLUE "at " ANSI_WARNING "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos));
|
out << fmt(ANSI_BLUE " at " ANSI_WARNING "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -269,7 +269,6 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
|
||||||
oss << einfo.msg << "\n";
|
oss << einfo.msg << "\n";
|
||||||
|
|
||||||
if (einfo.errPos.has_value() && *einfo.errPos) {
|
if (einfo.errPos.has_value() && *einfo.errPos) {
|
||||||
oss << "\n";
|
|
||||||
printAtPos(*einfo.errPos, oss);
|
printAtPos(*einfo.errPos, oss);
|
||||||
|
|
||||||
auto loc = getCodeLines(*einfo.errPos);
|
auto loc = getCodeLines(*einfo.errPos);
|
||||||
|
@ -278,26 +277,34 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
|
||||||
if (loc.has_value()) {
|
if (loc.has_value()) {
|
||||||
oss << "\n";
|
oss << "\n";
|
||||||
printCodeLines(oss, "", *einfo.errPos, *loc);
|
printCodeLines(oss, "", *einfo.errPos, *loc);
|
||||||
oss << "\n";
|
|
||||||
}
|
}
|
||||||
|
oss << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// traces
|
// traces
|
||||||
if (showTrace && !einfo.traces.empty()) {
|
if (!einfo.traces.empty()) {
|
||||||
|
unsigned int count = 0;
|
||||||
for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) {
|
for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) {
|
||||||
|
if (!showTrace && count > 3) {
|
||||||
|
oss << "\n" << "(truncated)" << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iter->hint.str().empty()) continue;
|
||||||
|
count++;
|
||||||
oss << "\n" << "… " << iter->hint.str() << "\n";
|
oss << "\n" << "… " << iter->hint.str() << "\n";
|
||||||
|
|
||||||
if (iter->pos.has_value() && (*iter->pos)) {
|
if (iter->pos.has_value() && (*iter->pos)) {
|
||||||
|
count++;
|
||||||
auto pos = iter->pos.value();
|
auto pos = iter->pos.value();
|
||||||
oss << "\n";
|
|
||||||
printAtPos(pos, oss);
|
printAtPos(pos, oss);
|
||||||
|
|
||||||
auto loc = getCodeLines(pos);
|
auto loc = getCodeLines(pos);
|
||||||
if (loc.has_value()) {
|
if (loc.has_value()) {
|
||||||
oss << "\n";
|
oss << "\n";
|
||||||
printCodeLines(oss, "", pos, *loc);
|
printCodeLines(oss, "", pos, *loc);
|
||||||
oss << "\n";
|
|
||||||
}
|
}
|
||||||
|
oss << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,8 @@ protected:
|
||||||
public:
|
public:
|
||||||
unsigned int status = 1; // exit status
|
unsigned int status = 1; // exit status
|
||||||
|
|
||||||
|
BaseError(const BaseError &) = default;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
BaseError(unsigned int status, const Args & ... args)
|
BaseError(unsigned int status, const Args & ... args)
|
||||||
: err { .level = lvlError, .msg = hintfmt(args...) }
|
: err { .level = lvlError, .msg = hintfmt(args...) }
|
||||||
|
@ -165,10 +167,14 @@ public:
|
||||||
const std::string & msg() const { return calcWhat(); }
|
const std::string & msg() const { return calcWhat(); }
|
||||||
const ErrorInfo & info() const { calcWhat(); return err; }
|
const ErrorInfo & info() const { calcWhat(); return err; }
|
||||||
|
|
||||||
|
void pushTrace(Trace trace) {
|
||||||
|
err.traces.push_front(trace);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
BaseError & addTrace(std::optional<ErrPos> e, const std::string & fs, const Args & ... args)
|
BaseError & addTrace(std::optional<ErrPos> e, const std::string_view & fs, const Args & ... args)
|
||||||
{
|
{
|
||||||
return addTrace(e, hintfmt(fs, args...));
|
return addTrace(e, hintfmt(std::string(fs), args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseError & addTrace(std::optional<ErrPos> e, hintformat hint);
|
BaseError & addTrace(std::optional<ErrPos> e, hintformat hint);
|
||||||
|
|
Loading…
Reference in a new issue