mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
Add error context for most basic coercions
This commit is contained in:
parent
00e242feed
commit
be1f069746
21 changed files with 309 additions and 275 deletions
|
@ -195,9 +195,9 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
|||
, "/"), **state.vImportedDrvToDerivation);
|
||||
}
|
||||
|
||||
state.forceFunction(**state.vImportedDrvToDerivation, pos);
|
||||
state.forceFunction(**state.vImportedDrvToDerivation, pos, "While evaluating imported-drv-to-derivation.nix.gen.hh");
|
||||
v.mkApp(*state.vImportedDrvToDerivation, w);
|
||||
state.forceAttrs(v, pos);
|
||||
state.forceAttrs(v, pos, "While calling imported-drv-to-derivation.nix.gen.hh");
|
||||
}
|
||||
|
||||
else if (path == corepkgsPrefix + "fetchurl.nix") {
|
||||
|
@ -210,7 +210,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
|||
if (!vScope)
|
||||
state.evalFile(path, v);
|
||||
else {
|
||||
state.forceAttrs(*vScope, pos);
|
||||
state.forceAttrs(*vScope, pos, "While evaluating the first argument passed to builtins.scopedImport");
|
||||
|
||||
Env * env = &state.allocEnv(vScope->attrs->size());
|
||||
env->up = &state.baseEnv;
|
||||
|
@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
|
|||
{
|
||||
auto path = realisePath(state, pos, *args[0]);
|
||||
|
||||
std::string sym(state.forceStringNoCtx(*args[1], pos));
|
||||
std::string sym(state.forceStringNoCtx(*args[1], pos, "While evaluating the second argument passed to builtins.importNative"));
|
||||
|
||||
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle)
|
||||
|
@ -340,7 +340,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
|
|||
/* Execute a program and parse its output */
|
||||
void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.exec");
|
||||
auto elems = args[0]->listElems();
|
||||
auto count = args[0]->listSize();
|
||||
if (count == 0) {
|
||||
|
@ -381,7 +381,6 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return a string representing the type of the expression. */
|
||||
static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
|
@ -535,8 +534,10 @@ static RegisterPrimOp primop_isPath({
|
|||
struct CompareValues
|
||||
{
|
||||
EvalState & state;
|
||||
const Pos & pos;
|
||||
const std::string errorCtx;
|
||||
|
||||
CompareValues(EvalState & state) : state(state) { };
|
||||
CompareValues(EvalState & state, const Pos & pos, const std::string && errorCtx) : state(state), pos(pos), errorCtx(std::move(errorCtx)) { };
|
||||
|
||||
bool operator () (Value * v1, Value * v2) const
|
||||
{
|
||||
|
@ -545,7 +546,10 @@ struct CompareValues
|
|||
if (v1->type() == nInt && v2->type() == nFloat)
|
||||
return v1->integer < v2->fpoint;
|
||||
if (v1->type() != v2->type())
|
||||
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
|
||||
throw EvalError({
|
||||
.msg = hintfmt("%s: cannot compare %s with %s", errorCtx, showType(*v1), showType(*v2)),
|
||||
.errPos = pos,
|
||||
});
|
||||
switch (v1->type()) {
|
||||
case nInt:
|
||||
return v1->integer < v2->integer;
|
||||
|
@ -567,7 +571,10 @@ struct CompareValues
|
|||
}
|
||||
}
|
||||
default:
|
||||
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
|
||||
throw EvalError({
|
||||
.msg = hintfmt("%s: cannot compare %s with %s", errorCtx, showType(*v1), showType(*v2)),
|
||||
.errPos = pos,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -619,7 +626,7 @@ static Bindings::iterator getAttr(
|
|||
|
||||
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the first argument passed to builtins.genericClosure");
|
||||
|
||||
/* Get the start set. */
|
||||
Bindings::iterator startSet = getAttr(
|
||||
|
@ -630,7 +637,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||
pos
|
||||
);
|
||||
|
||||
state.forceList(*startSet->value, pos);
|
||||
state.forceList(*startSet->value, pos, "While evaluating the `startSet` attribute passed to builtins.genericClosure");
|
||||
|
||||
ValueList workSet;
|
||||
for (auto elem : startSet->value->listItems())
|
||||
|
@ -645,7 +652,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||
pos
|
||||
);
|
||||
|
||||
state.forceValue(*op->value, pos);
|
||||
state.forceFunction(*op->value, pos, "While evaluating the `operator` attribute passed to builtins.genericClosure");
|
||||
|
||||
/* Construct the closure by applying the operator to element of
|
||||
`workSet', adding the result to `workSet', continuing until
|
||||
|
@ -653,19 +660,19 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||
ValueList res;
|
||||
// `doneKeys' doesn't need to be a GC root, because its values are
|
||||
// reachable from res.
|
||||
auto cmp = CompareValues(state);
|
||||
auto cmp = CompareValues(state, pos, "While comparing the `key` attributes of two genericClosure elements");
|
||||
std::set<Value *, decltype(cmp)> doneKeys(cmp);
|
||||
while (!workSet.empty()) {
|
||||
Value * e = *(workSet.begin());
|
||||
workSet.pop_front();
|
||||
|
||||
state.forceAttrs(*e, pos);
|
||||
state.forceAttrs(*e, pos, "While evaluating one item to be part of the genericClosure");
|
||||
|
||||
Bindings::iterator key =
|
||||
e->attrs->find(state.sKey);
|
||||
if (key == e->attrs->end())
|
||||
throw EvalError({
|
||||
.msg = hintfmt("attribute 'key' required"),
|
||||
.msg = hintfmt("While evaluating one of the attribute sets to be part of the genericClosure: attribute `key` required"),
|
||||
.errPos = pos
|
||||
});
|
||||
state.forceValue(*key->value, pos);
|
||||
|
@ -676,7 +683,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||
/* Call the `operator' function with `e' as argument. */
|
||||
Value call;
|
||||
call.mkApp(op->value, e);
|
||||
state.forceList(call, pos);
|
||||
state.forceList(call, pos, "While evaluating the return value of the `operator` passed to builtins.genericClosure");
|
||||
|
||||
/* Add the values returned by the operator to the work set. */
|
||||
for (auto elem : call.listItems()) {
|
||||
|
@ -750,7 +757,7 @@ static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info {
|
|||
|
||||
static void prim_ceil(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos));
|
||||
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "While evaluating the first argument passed to builtins.ceil");
|
||||
v.mkInt(ceil(value));
|
||||
}
|
||||
|
||||
|
@ -769,7 +776,7 @@ static RegisterPrimOp primop_ceil({
|
|||
|
||||
static void prim_floor(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos));
|
||||
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "While evaluating the first argument passed to builtins.floor");
|
||||
v.mkInt(floor(value));
|
||||
}
|
||||
|
||||
|
@ -826,7 +833,7 @@ static RegisterPrimOp primop_tryEval({
|
|||
/* Return an environment variable. Use with care. */
|
||||
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
std::string name(state.forceStringNoCtx(*args[0], pos));
|
||||
std::string name(state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.getEnv"));
|
||||
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
|
||||
}
|
||||
|
||||
|
@ -924,7 +931,7 @@ static RegisterPrimOp primop_trace({
|
|||
derivation. */
|
||||
static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the argument passed to builtins.derivationStrict");
|
||||
|
||||
/* Figure out the name first (for stack backtraces). */
|
||||
Bindings::iterator attr = getAttr(
|
||||
|
@ -938,7 +945,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||
std::string drvName;
|
||||
Pos & posDrvName(*attr->pos);
|
||||
try {
|
||||
drvName = state.forceStringNoCtx(*attr->value, pos);
|
||||
drvName = state.forceStringNoCtx(*attr->value, pos, "While evaluating the `name` attribute passed to builtins.derivationStrict");
|
||||
} catch (Error & e) {
|
||||
e.addTrace(posDrvName, "while evaluating the derivation attribute 'name'");
|
||||
throw;
|
||||
|
@ -948,14 +955,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||
std::ostringstream jsonBuf;
|
||||
std::unique_ptr<JSONObject> jsonObject;
|
||||
attr = args[0]->attrs->find(state.sStructuredAttrs);
|
||||
if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos))
|
||||
if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos, "While evaluating the `__structuredAttrs` attribute passed to builtins.derivationStrict"))
|
||||
jsonObject = std::make_unique<JSONObject>(jsonBuf);
|
||||
|
||||
/* Check whether null attributes should be ignored. */
|
||||
bool ignoreNulls = false;
|
||||
attr = args[0]->attrs->find(state.sIgnoreNulls);
|
||||
if (attr != args[0]->attrs->end())
|
||||
ignoreNulls = state.forceBool(*attr->value, pos);
|
||||
ignoreNulls = state.forceBool(*attr->value, pos, "While evaluating the `__ignoreNulls` attribute passed to builtins.derivationStrict");
|
||||
|
||||
/* Build the derivation expression by processing the attributes. */
|
||||
Derivation drv;
|
||||
|
@ -1021,7 +1028,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||
}
|
||||
|
||||
if (i->name == state.sContentAddressed) {
|
||||
contentAddressed = state.forceBool(*i->value, pos);
|
||||
contentAddressed = state.forceBool(*i->value, pos, "While evaluating the `__contentAddressed` attribute passed to builtins.derivationStrict");
|
||||
if (contentAddressed)
|
||||
settings.requireExperimentalFeature(Xp::CaDerivations);
|
||||
}
|
||||
|
@ -1029,7 +1036,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||
/* The `args' attribute is special: it supplies the
|
||||
command-line arguments to the builder. */
|
||||
else if (i->name == state.sArgs) {
|
||||
state.forceList(*i->value, pos);
|
||||
state.forceList(*i->value, pos, "While evaluating the `args` attribute passed to builtins.derivationStrict");
|
||||
for (auto elem : i->value->listItems()) {
|
||||
auto s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
|
||||
drv.args.push_back(s);
|
||||
|
@ -1048,21 +1055,21 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||
printValueAsJSON(state, true, *i->value, pos, placeholder, context);
|
||||
|
||||
if (i->name == state.sBuilder)
|
||||
drv.builder = state.forceString(*i->value, context, posDrvName);
|
||||
drv.builder = state.forceString(*i->value, context, posDrvName, "While evaluating the `builder` attribute passed to builtins.derivationStrict");
|
||||
else if (i->name == state.sSystem)
|
||||
drv.platform = state.forceStringNoCtx(*i->value, posDrvName);
|
||||
drv.platform = state.forceStringNoCtx(*i->value, posDrvName, "While evaluating the `system` attribute passed to builtins.derivationStrict");
|
||||
else if (i->name == state.sOutputHash)
|
||||
outputHash = state.forceStringNoCtx(*i->value, posDrvName);
|
||||
outputHash = state.forceStringNoCtx(*i->value, posDrvName, "While evaluating the `outputHash` attribute passed to builtins.derivationStrict");
|
||||
else if (i->name == state.sOutputHashAlgo)
|
||||
outputHashAlgo = state.forceStringNoCtx(*i->value, posDrvName);
|
||||
outputHashAlgo = state.forceStringNoCtx(*i->value, posDrvName, "While evaluating the `outputHashAlgo` attribute passed to builtins.derivationStrict");
|
||||
else if (i->name == state.sOutputHashMode)
|
||||
handleHashMode(state.forceStringNoCtx(*i->value, posDrvName));
|
||||
handleHashMode(state.forceStringNoCtx(*i->value, posDrvName, "While evaluating the `outputHashMode` attribute passed to builtins.derivationStrict"));
|
||||
else if (i->name == state.sOutputs) {
|
||||
/* Require ‘outputs’ to be a list of strings. */
|
||||
state.forceList(*i->value, posDrvName);
|
||||
state.forceList(*i->value, posDrvName, "While evaluating the `outputs` attribute passed to builtins.derivationStrict");
|
||||
Strings ss;
|
||||
for (auto elem : i->value->listItems())
|
||||
ss.emplace_back(state.forceStringNoCtx(*elem, posDrvName));
|
||||
ss.emplace_back(state.forceStringNoCtx(*elem, posDrvName, "While evaluating an element of the `outputs` attribute passed to builtins.derivationStrict"));
|
||||
handleOutputs(ss);
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1282,7 @@ static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info {
|
|||
‘out’. */
|
||||
static void prim_placeholder(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkString(hashPlaceholder(state.forceStringNoCtx(*args[0], pos)));
|
||||
v.mkString(hashPlaceholder(state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.placeholder")));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_placeholder({
|
||||
|
@ -1467,17 +1474,17 @@ static RegisterPrimOp primop_readFile({
|
|||
which are desugared to 'findFile __nixPath "x"'. */
|
||||
static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.findFile");
|
||||
|
||||
SearchPath searchPath;
|
||||
|
||||
for (auto v2 : args[0]->listItems()) {
|
||||
state.forceAttrs(*v2, pos);
|
||||
state.forceAttrs(*v2, pos, "While evaluating an element of the list passed to builtins.findFile");
|
||||
|
||||
std::string prefix;
|
||||
Bindings::iterator i = v2->attrs->find(state.sPrefix);
|
||||
if (i != v2->attrs->end())
|
||||
prefix = state.forceStringNoCtx(*i->value, pos);
|
||||
prefix = state.forceStringNoCtx(*i->value, pos, "While evaluating the `prefix` attribute passed to an element of the list passed to builtins.findFile");
|
||||
|
||||
i = getAttr(
|
||||
state,
|
||||
|
@ -1504,7 +1511,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
searchPath.emplace_back(prefix, path);
|
||||
}
|
||||
|
||||
auto path = state.forceStringNoCtx(*args[1], pos);
|
||||
auto path = state.forceStringNoCtx(*args[1], pos, "While evaluating the second argument passed to builtins.findFile");
|
||||
|
||||
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
||||
}
|
||||
|
@ -1518,7 +1525,7 @@ static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
|
|||
/* Return the cryptographic hash of a file in base-16. */
|
||||
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto type = state.forceStringNoCtx(*args[0], pos);
|
||||
auto type = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.hashFile");
|
||||
std::optional<HashType> ht = parseHashType(type);
|
||||
if (!ht)
|
||||
throw Error({
|
||||
|
@ -1725,7 +1732,7 @@ static RegisterPrimOp primop_toJSON({
|
|||
/* Parse a JSON string to a value. */
|
||||
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto s = state.forceStringNoCtx(*args[0], pos);
|
||||
auto s = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.fromJSON");
|
||||
try {
|
||||
parseJSON(state, s, v);
|
||||
} catch (JSONParseError &e) {
|
||||
|
@ -1754,8 +1761,8 @@ static RegisterPrimOp primop_fromJSON({
|
|||
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
std::string name(state.forceStringNoCtx(*args[0], pos));
|
||||
std::string contents(state.forceString(*args[1], context, pos));
|
||||
std::string name(state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.toFile"));
|
||||
std::string contents(state.forceString(*args[1], context, pos, "While evaluating the second argument passed to builtins.toFile"));
|
||||
|
||||
StorePathSet refs;
|
||||
|
||||
|
@ -1912,7 +1919,7 @@ static void addPath(
|
|||
Value res;
|
||||
state.callFunction(*filterFun, 2, args, res, pos);
|
||||
|
||||
return state.forceBool(res, pos);
|
||||
return state.forceBool(res, pos, "While evaluating the return value of the path filter function");
|
||||
}) : defaultPathFilter;
|
||||
|
||||
std::optional<StorePath> expectedStorePath;
|
||||
|
@ -2009,7 +2016,7 @@ static RegisterPrimOp primop_filterSource({
|
|||
|
||||
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the argument passed to builtins.path");
|
||||
Path path;
|
||||
std::string name;
|
||||
Value * filterFun = nullptr;
|
||||
|
@ -2022,14 +2029,14 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
|
|||
if (n == "path")
|
||||
path = state.coerceToPath(*attr.pos, *attr.value, context);
|
||||
else if (attr.name == state.sName)
|
||||
name = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||
name = state.forceStringNoCtx(*attr.value, *attr.pos, "while evaluating the `name` attribute passed to builtins.path");
|
||||
else if (n == "filter") {
|
||||
state.forceValue(*attr.value, pos);
|
||||
filterFun = attr.value;
|
||||
} else if (n == "recursive")
|
||||
method = FileIngestionMethod { state.forceBool(*attr.value, *attr.pos) };
|
||||
method = FileIngestionMethod { state.forceBool(*attr.value, *attr.pos, "While evaluating the `recursive` attribute passed to builtins.path") };
|
||||
else if (n == "sha256")
|
||||
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
|
||||
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos, "While evaluating the `sha256` attribute passed to builtins.path"), htSHA256);
|
||||
else
|
||||
throw EvalError({
|
||||
.msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name),
|
||||
|
@ -2092,7 +2099,7 @@ static RegisterPrimOp primop_path({
|
|||
strings. */
|
||||
static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the argument passed to builtins.attrNames");
|
||||
|
||||
state.mkList(v, args[0]->attrs->size());
|
||||
|
||||
|
@ -2119,7 +2126,7 @@ static RegisterPrimOp primop_attrNames({
|
|||
order as attrNames. */
|
||||
static void prim_attrValues(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the argument passed to builtins.attrValues");
|
||||
|
||||
state.mkList(v, args[0]->attrs->size());
|
||||
|
||||
|
@ -2150,8 +2157,8 @@ static RegisterPrimOp primop_attrValues({
|
|||
/* Dynamic version of the `.' operator. */
|
||||
void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||
state.forceAttrs(*args[1], pos);
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.getAttr");
|
||||
state.forceAttrs(*args[1], pos, "While evaluating the second argument passed to builtins.getAttr");
|
||||
Bindings::iterator i = getAttr(
|
||||
state,
|
||||
"getAttr",
|
||||
|
@ -2180,8 +2187,8 @@ static RegisterPrimOp primop_getAttr({
|
|||
/* Return position information of the specified attribute. */
|
||||
static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||
state.forceAttrs(*args[1], pos);
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.unsafeGetAttrPos");
|
||||
state.forceAttrs(*args[1], pos, "While evaluating the second argument passed to builtins.unsafeGetAttrPos");
|
||||
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
|
||||
if (i == args[1]->attrs->end())
|
||||
v.mkNull();
|
||||
|
@ -2198,8 +2205,8 @@ static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
|
|||
/* Dynamic version of the `?' operator. */
|
||||
static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||
state.forceAttrs(*args[1], pos);
|
||||
auto attr = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.hasAttr");
|
||||
state.forceAttrs(*args[1], pos, "While evaluating the second argument passed to builtins.hasAttr");
|
||||
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
|
||||
}
|
||||
|
||||
|
@ -2232,8 +2239,8 @@ static RegisterPrimOp primop_isAttrs({
|
|||
|
||||
static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the first argument passed to builtins.removeAttrs");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.removeAttrs");
|
||||
|
||||
/* Get the attribute names to be removed.
|
||||
We keep them as Attrs instead of Symbols so std::set_difference
|
||||
|
@ -2241,7 +2248,7 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
|
|||
boost::container::small_vector<Attr, 64> names;
|
||||
names.reserve(args[1]->listSize());
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
state.forceStringNoCtx(*elem, pos);
|
||||
state.forceStringNoCtx(*elem, pos, "While evaluating the values of the second argument passed to builtins.removeAttrs");
|
||||
names.emplace_back(state.symbols.create(elem->string.s), nullptr);
|
||||
}
|
||||
std::sort(names.begin(), names.end());
|
||||
|
@ -2280,14 +2287,14 @@ static RegisterPrimOp primop_removeAttrs({
|
|||
name, the first takes precedence. */
|
||||
static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the argument passed to builtins.listToAttrs");
|
||||
|
||||
auto attrs = state.buildBindings(args[0]->listSize());
|
||||
|
||||
std::set<Symbol> seen;
|
||||
|
||||
for (auto v2 : args[0]->listItems()) {
|
||||
state.forceAttrs(*v2, pos);
|
||||
state.forceAttrs(*v2, pos, "While evaluating an element of the list passed to builtins.listToAttrs");
|
||||
|
||||
Bindings::iterator j = getAttr(
|
||||
state,
|
||||
|
@ -2297,7 +2304,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
|
|||
pos
|
||||
);
|
||||
|
||||
auto name = state.forceStringNoCtx(*j->value, *j->pos);
|
||||
auto name = state.forceStringNoCtx(*j->value, *j->pos, "While evaluating the `name` attribute of an element of the list passed to builtins.listToAttrs");
|
||||
|
||||
Symbol sym = state.symbols.create(name);
|
||||
if (seen.insert(sym).second) {
|
||||
|
@ -2342,8 +2349,8 @@ static RegisterPrimOp primop_listToAttrs({
|
|||
|
||||
static void prim_intersectAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos);
|
||||
state.forceAttrs(*args[1], pos);
|
||||
state.forceAttrs(*args[0], pos, "While evaluating the first argument passed to builtins.intersectAttrs");
|
||||
state.forceAttrs(*args[1], pos, "While evaluating the second argument passed to builtins.intersectAttrs");
|
||||
|
||||
auto attrs = state.buildBindings(std::min(args[0]->attrs->size(), args[1]->attrs->size()));
|
||||
|
||||
|
@ -2368,14 +2375,14 @@ static RegisterPrimOp primop_intersectAttrs({
|
|||
|
||||
static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos));
|
||||
state.forceList(*args[1], pos);
|
||||
Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.catAttrs"));
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.catAttrs");
|
||||
|
||||
Value * res[args[1]->listSize()];
|
||||
unsigned int found = 0;
|
||||
|
||||
for (auto v2 : args[1]->listItems()) {
|
||||
state.forceAttrs(*v2, pos);
|
||||
state.forceAttrs(*v2, pos, "While evaluating an element in the list passed as second argument to builtins.catAttrs");
|
||||
Bindings::iterator i = v2->attrs->find(attrName);
|
||||
if (i != v2->attrs->end())
|
||||
res[found++] = i->value;
|
||||
|
@ -2448,7 +2455,7 @@ static RegisterPrimOp primop_functionArgs({
|
|||
/* */
|
||||
static void prim_mapAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[1], pos);
|
||||
state.forceAttrs(*args[1], pos, "While evaluating the second argument passed to builtins.mapAttrs");
|
||||
|
||||
auto attrs = state.buildBindings(args[1]->attrs->size());
|
||||
|
||||
|
@ -2489,15 +2496,15 @@ static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args
|
|||
|
||||
std::map<Symbol, std::pair<size_t, Value * *>> attrsSeen;
|
||||
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.zipAttrsWith");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.zipAttrsWith");
|
||||
const auto listSize = args[1]->listSize();
|
||||
const auto listElems = args[1]->listElems();
|
||||
|
||||
for (unsigned int n = 0; n < listSize; ++n) {
|
||||
Value * vElem = listElems[n];
|
||||
try {
|
||||
state.forceAttrs(*vElem, noPos);
|
||||
state.forceAttrs(*vElem, noPos, "While evaluating a value of the list passed as second argument to builtins.zipAttrsWith");
|
||||
for (auto & attr : *vElem->attrs)
|
||||
attrsSeen[attr.name].first++;
|
||||
} catch (TypeError & e) {
|
||||
|
@ -2587,7 +2594,7 @@ static RegisterPrimOp primop_isList({
|
|||
|
||||
static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v)
|
||||
{
|
||||
state.forceList(list, pos);
|
||||
state.forceList(list, pos, "While evaluating the first argument passed to builtins.elemAt");
|
||||
if (n < 0 || (unsigned int) n >= list.listSize())
|
||||
throw Error({
|
||||
.msg = hintfmt("list index %1% is out of bounds", n),
|
||||
|
@ -2600,7 +2607,7 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu
|
|||
/* Return the n-1'th element of a list. */
|
||||
static void prim_elemAt(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
elemAt(state, pos, *args[0], state.forceInt(*args[1], pos), v);
|
||||
elemAt(state, pos, *args[0], state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.elemAt"), v);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_elemAt({
|
||||
|
@ -2635,7 +2642,7 @@ static RegisterPrimOp primop_head({
|
|||
don't want to use it! */
|
||||
static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.tail");
|
||||
if (args[0]->listSize() == 0)
|
||||
throw Error({
|
||||
.msg = hintfmt("'tail' called on an empty list"),
|
||||
|
@ -2666,13 +2673,17 @@ static RegisterPrimOp primop_tail({
|
|||
/* Apply a function to every element of a list. */
|
||||
static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.map");
|
||||
|
||||
state.mkList(v, args[1]->listSize());
|
||||
|
||||
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||
(v.listElems()[n] = state.allocValue())->mkApp(
|
||||
args[0], args[1]->listElems()[n]);
|
||||
if (args[1]->listSize() > 0) {
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.map");
|
||||
|
||||
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||
(v.listElems()[n] = state.allocValue())->mkApp(
|
||||
args[0], args[1]->listElems()[n]);
|
||||
};
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_map({
|
||||
|
@ -2696,8 +2707,14 @@ static RegisterPrimOp primop_map({
|
|||
returns true. */
|
||||
static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.filter");
|
||||
|
||||
if (args[1]->listSize() == 0) {
|
||||
v = *args[1];
|
||||
return;
|
||||
}
|
||||
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.filter");
|
||||
|
||||
// FIXME: putting this on the stack is risky.
|
||||
Value * vs[args[1]->listSize()];
|
||||
|
@ -2707,7 +2724,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
|
|||
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
||||
Value res;
|
||||
state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
|
||||
if (state.forceBool(res, pos))
|
||||
if (state.forceBool(res, pos, "While evaluating the return value of the filtering function passed to builtins.filter"))
|
||||
vs[k++] = args[1]->listElems()[n];
|
||||
else
|
||||
same = false;
|
||||
|
@ -2735,7 +2752,7 @@ static RegisterPrimOp primop_filter({
|
|||
static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
bool res = false;
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.elem");
|
||||
for (auto elem : args[1]->listItems())
|
||||
if (state.eqValues(*args[0], *elem)) {
|
||||
res = true;
|
||||
|
@ -2757,8 +2774,8 @@ static RegisterPrimOp primop_elem({
|
|||
/* Concatenate a list of lists. */
|
||||
static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.concatLists");
|
||||
state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos, "While evaluating a value of the list passed to builtins.concatLists");
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_concatLists({
|
||||
|
@ -2773,7 +2790,7 @@ static RegisterPrimOp primop_concatLists({
|
|||
/* Return the length of a list. This is an O(1) time operation. */
|
||||
static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.length");
|
||||
v.mkInt(args[0]->listSize());
|
||||
}
|
||||
|
||||
|
@ -2790,8 +2807,8 @@ static RegisterPrimOp primop_length({
|
|||
right. The operator is applied strictly. */
|
||||
static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[2], pos);
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.foldlStrict");
|
||||
state.forceList(*args[2], pos, "While evaluating the third argument passed to builtins.foldlStrict");
|
||||
|
||||
if (args[2]->listSize()) {
|
||||
Value * vCur = args[1];
|
||||
|
@ -2823,13 +2840,13 @@ static RegisterPrimOp primop_foldlStrict({
|
|||
|
||||
static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceFunction(*args[0], pos, std::string("While evaluating the first argument passed to builtins.") + (any ? "any" : "all"));
|
||||
state.forceList(*args[1], pos, std::string("While evaluating the second argument passed to builtins.") + (any ? "any" : "all"));
|
||||
|
||||
Value vTmp;
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
state.callFunction(*args[0], *elem, vTmp, pos);
|
||||
bool res = state.forceBool(vTmp, pos);
|
||||
bool res = state.forceBool(vTmp, pos, std::string("While evaluating the return value of the function passed to builtins.") + (any ? "any" : "all"));
|
||||
if (res == any) {
|
||||
v.mkBool(any);
|
||||
return;
|
||||
|
@ -2872,7 +2889,7 @@ static RegisterPrimOp primop_all({
|
|||
|
||||
static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto len = state.forceInt(*args[1], pos);
|
||||
auto len = state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.genList");
|
||||
|
||||
if (len < 0)
|
||||
throw EvalError({
|
||||
|
@ -2910,10 +2927,16 @@ static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
|
||||
static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.sort");
|
||||
|
||||
auto len = args[1]->listSize();
|
||||
if (len == 0) {
|
||||
v = *args[1];
|
||||
return;
|
||||
}
|
||||
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.sort");
|
||||
|
||||
state.mkList(v, len);
|
||||
for (unsigned int n = 0; n < len; ++n) {
|
||||
state.forceValue(*args[1]->listElems()[n], pos);
|
||||
|
@ -2924,12 +2947,12 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
|||
/* Optimization: if the comparator is lessThan, bypass
|
||||
callFunction. */
|
||||
if (args[0]->isPrimOp() && args[0]->primOp->fun == prim_lessThan)
|
||||
return CompareValues(state)(a, b);
|
||||
return CompareValues(state, pos, "While evaluating the ordering function passed to builtins.sort")(a, b);
|
||||
|
||||
Value * vs[] = {a, b};
|
||||
Value vBool;
|
||||
state.callFunction(*args[0], 2, vs, vBool, pos);
|
||||
return state.forceBool(vBool, pos);
|
||||
return state.forceBool(vBool, pos, "While evaluating the return value of the sorting function passed to builtins.sort");
|
||||
};
|
||||
|
||||
/* FIXME: std::sort can segfault if the comparator is not a strict
|
||||
|
@ -2961,8 +2984,8 @@ static RegisterPrimOp primop_sort({
|
|||
|
||||
static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.partition");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.partition");
|
||||
|
||||
auto len = args[1]->listSize();
|
||||
|
||||
|
@ -2973,7 +2996,7 @@ static void prim_partition(EvalState & state, const Pos & pos, Value * * args, V
|
|||
state.forceValue(*vElem, pos);
|
||||
Value res;
|
||||
state.callFunction(*args[0], *vElem, res, pos);
|
||||
if (state.forceBool(res, pos))
|
||||
if (state.forceBool(res, pos, "While evaluating the return value of the partition function passed to builtins.partition"))
|
||||
right.push_back(vElem);
|
||||
else
|
||||
wrong.push_back(vElem);
|
||||
|
@ -3021,15 +3044,15 @@ static RegisterPrimOp primop_partition({
|
|||
|
||||
static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.groupBy");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.groupBy");
|
||||
|
||||
ValueVectorMap attrs;
|
||||
|
||||
for (auto vElem : args[1]->listItems()) {
|
||||
Value res;
|
||||
state.callFunction(*args[0], *vElem, res, pos);
|
||||
auto name = state.forceStringNoCtx(res, pos);
|
||||
auto name = state.forceStringNoCtx(res, pos, "While evaluating the return value of the grouping function passed to builtins.groupBy");
|
||||
Symbol sym = state.symbols.create(name);
|
||||
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
||||
vector->second.push_back(vElem);
|
||||
|
@ -3073,8 +3096,8 @@ static RegisterPrimOp primop_groupBy({
|
|||
|
||||
static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceFunction(*args[0], pos, "While evaluating the first argument passed to builtins.concatMap");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.concatMap");
|
||||
auto nrLists = args[1]->listSize();
|
||||
|
||||
Value lists[nrLists];
|
||||
|
@ -3084,7 +3107,7 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
|
|||
Value * vElem = args[1]->listElems()[n];
|
||||
state.callFunction(*args[0], *vElem, lists[n], pos);
|
||||
try {
|
||||
state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos)));
|
||||
state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos)), "While evaluating the return value of the function passed to buitlins.concatMap");
|
||||
} catch (TypeError &e) {
|
||||
e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap"));
|
||||
throw;
|
||||
|
@ -3123,9 +3146,11 @@ static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value &
|
|||
state.forceValue(*args[0], pos);
|
||||
state.forceValue(*args[1], pos);
|
||||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos) + state.forceFloat(*args[1], pos));
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "While evaluating the first argument of the addition")
|
||||
+ state.forceFloat(*args[1], pos, "While evaluating the second argument of the addition"));
|
||||
else
|
||||
v.mkInt(state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos));
|
||||
v.mkInt( state.forceInt(*args[0], pos, "While evaluating the first argument of the addition")
|
||||
+ state.forceInt(*args[1], pos, "While evaluating the second argument of the addition"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_add({
|
||||
|
@ -3142,9 +3167,11 @@ static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value &
|
|||
state.forceValue(*args[0], pos);
|
||||
state.forceValue(*args[1], pos);
|
||||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos) - state.forceFloat(*args[1], pos));
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "While evaluating the first argument of the subtraction")
|
||||
- state.forceFloat(*args[1], pos, "While evaluating the second argument of the subtraction"));
|
||||
else
|
||||
v.mkInt(state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos));
|
||||
v.mkInt( state.forceInt(*args[0], pos, "While evaluating the first argument of the subtraction")
|
||||
- state.forceInt(*args[1], pos, "While evaluating the second argument of the subtraction"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_sub({
|
||||
|
@ -3161,9 +3188,11 @@ static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value &
|
|||
state.forceValue(*args[0], pos);
|
||||
state.forceValue(*args[1], pos);
|
||||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos) * state.forceFloat(*args[1], pos));
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "While evaluating the first of the multiplication")
|
||||
* state.forceFloat(*args[1], pos, "While evaluating the second argument of the multiplication"));
|
||||
else
|
||||
v.mkInt(state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos));
|
||||
v.mkInt( state.forceInt(*args[0], pos, "While evaluating the first argument of the multiplication")
|
||||
* state.forceInt(*args[1], pos, "While evaluating the second argument of the multiplication"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_mul({
|
||||
|
@ -3180,7 +3209,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
|
|||
state.forceValue(*args[0], pos);
|
||||
state.forceValue(*args[1], pos);
|
||||
|
||||
NixFloat f2 = state.forceFloat(*args[1], pos);
|
||||
NixFloat f2 = state.forceFloat(*args[1], pos, "While evaluating the second operand of the division");
|
||||
if (f2 == 0)
|
||||
throw EvalError({
|
||||
.msg = hintfmt("division by zero"),
|
||||
|
@ -3188,10 +3217,10 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
|
|||
});
|
||||
|
||||
if (args[0]->type() == nFloat || args[1]->type() == nFloat) {
|
||||
v.mkFloat(state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos));
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "While evaluating the first operand of the division") / f2);
|
||||
} else {
|
||||
NixInt i1 = state.forceInt(*args[0], pos);
|
||||
NixInt i2 = state.forceInt(*args[1], pos);
|
||||
NixInt i1 = state.forceInt(*args[0], pos, "While evaluating the first operand of the division");
|
||||
NixInt i2 = state.forceInt(*args[1], pos, "While evaluating the second operand of the division");
|
||||
/* Avoid division overflow as it might raise SIGFPE. */
|
||||
if (i1 == std::numeric_limits<NixInt>::min() && i2 == -1)
|
||||
throw EvalError({
|
||||
|
@ -3214,7 +3243,8 @@ static RegisterPrimOp primop_div({
|
|||
|
||||
static void prim_bitAnd(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos) & state.forceInt(*args[1], pos));
|
||||
v.mkInt(state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.bitAnd")
|
||||
& state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.bitAnd"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitAnd({
|
||||
|
@ -3228,7 +3258,8 @@ static RegisterPrimOp primop_bitAnd({
|
|||
|
||||
static void prim_bitOr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos) | state.forceInt(*args[1], pos));
|
||||
v.mkInt(state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.bitOr")
|
||||
| state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.bitOr"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitOr({
|
||||
|
@ -3242,7 +3273,8 @@ static RegisterPrimOp primop_bitOr({
|
|||
|
||||
static void prim_bitXor(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos) ^ state.forceInt(*args[1], pos));
|
||||
v.mkInt(state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.bitXor")
|
||||
^ state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.bitXor"));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitXor({
|
||||
|
@ -3258,7 +3290,8 @@ static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
{
|
||||
state.forceValue(*args[0], pos);
|
||||
state.forceValue(*args[1], pos);
|
||||
CompareValues comp{state};
|
||||
// pos is exact here, no need for a message.
|
||||
CompareValues comp(state, pos, "");
|
||||
v.mkBool(comp(args[0], args[1]));
|
||||
}
|
||||
|
||||
|
@ -3319,8 +3352,8 @@ static RegisterPrimOp primop_toString({
|
|||
non-negative. */
|
||||
static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
int start = state.forceInt(*args[0], pos);
|
||||
int len = state.forceInt(*args[1], pos);
|
||||
int start = state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.substring");
|
||||
int len = state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.substring");
|
||||
PathSet context;
|
||||
auto s = state.coerceToString(pos, *args[2], context);
|
||||
|
||||
|
@ -3373,7 +3406,7 @@ static RegisterPrimOp primop_stringLength({
|
|||
/* Return the cryptographic hash of a string in base-16. */
|
||||
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto type = state.forceStringNoCtx(*args[0], pos);
|
||||
auto type = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.hashString");
|
||||
std::optional<HashType> ht = parseHashType(type);
|
||||
if (!ht)
|
||||
throw Error({
|
||||
|
@ -3382,7 +3415,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
|
|||
});
|
||||
|
||||
PathSet context; // discarded
|
||||
auto s = state.forceString(*args[1], context, pos);
|
||||
auto s = state.forceString(*args[1], context, pos, "While evaluating the second argument passed to builtins.hashString");
|
||||
|
||||
v.mkString(hashString(*ht, s).to_string(Base16, false));
|
||||
}
|
||||
|
@ -3421,14 +3454,14 @@ std::shared_ptr<RegexCache> makeRegexCache()
|
|||
|
||||
void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto re = state.forceStringNoCtx(*args[0], pos);
|
||||
auto re = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.match");
|
||||
|
||||
try {
|
||||
|
||||
auto regex = state.regexCache->get(re);
|
||||
|
||||
PathSet context;
|
||||
const auto str = state.forceString(*args[1], context, pos);
|
||||
const auto str = state.forceString(*args[1], context, pos, "While evaluating the second argument passed to builtins.match");
|
||||
|
||||
std::cmatch match;
|
||||
if (!std::regex_match(str.begin(), str.end(), match, regex)) {
|
||||
|
@ -3502,14 +3535,14 @@ static RegisterPrimOp primop_match({
|
|||
non-matching parts interleaved by the lists of the matching groups. */
|
||||
void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto re = state.forceStringNoCtx(*args[0], pos);
|
||||
auto re = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.split");
|
||||
|
||||
try {
|
||||
|
||||
auto regex = state.regexCache->get(re);
|
||||
|
||||
PathSet context;
|
||||
const auto str = state.forceString(*args[1], context, pos);
|
||||
const auto str = state.forceString(*args[1], context, pos, "While evaluating the second argument passed to builtins.split");
|
||||
|
||||
auto begin = std::cregex_iterator(str.begin(), str.end(), regex);
|
||||
auto end = std::cregex_iterator();
|
||||
|
@ -3608,8 +3641,8 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
|
|||
{
|
||||
PathSet context;
|
||||
|
||||
auto sep = state.forceString(*args[0], context, pos);
|
||||
state.forceList(*args[1], pos);
|
||||
auto sep = state.forceString(*args[0], context, pos, "While evaluating the first argument passed to builtins.concatStringsSep");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.concatStringsSep");
|
||||
|
||||
std::string res;
|
||||
res.reserve((args[1]->listSize() + 32) * sep.size());
|
||||
|
@ -3636,8 +3669,8 @@ static RegisterPrimOp primop_concatStringsSep({
|
|||
|
||||
static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
state.forceList(*args[0], pos, "While evaluating the first argument passed to builtins.replaceStrings");
|
||||
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.replaceStrings");
|
||||
if (args[0]->listSize() != args[1]->listSize())
|
||||
throw EvalError({
|
||||
.msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"),
|
||||
|
@ -3647,18 +3680,18 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
|
|||
std::vector<std::string> from;
|
||||
from.reserve(args[0]->listSize());
|
||||
for (auto elem : args[0]->listItems())
|
||||
from.emplace_back(state.forceString(*elem, pos));
|
||||
from.emplace_back(state.forceString(*elem, pos, "While evaluating one of the strings to replace in builtins.replaceStrings"));
|
||||
|
||||
std::vector<std::pair<std::string, PathSet>> to;
|
||||
to.reserve(args[1]->listSize());
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
PathSet ctx;
|
||||
auto s = state.forceString(*elem, ctx, pos);
|
||||
auto s = state.forceString(*elem, ctx, pos, "While evaluating one of the replacement strings of builtins.replaceStrings");
|
||||
to.emplace_back(s, std::move(ctx));
|
||||
}
|
||||
|
||||
PathSet context;
|
||||
auto s = state.forceString(*args[2], context, pos);
|
||||
auto s = state.forceString(*args[2], context, pos, "While evaluating the third argument passed to builtins.replaceStrings");
|
||||
|
||||
std::string res;
|
||||
// Loops one past last character to handle the case where 'from' contains an empty string.
|
||||
|
@ -3716,7 +3749,7 @@ static RegisterPrimOp primop_replaceStrings({
|
|||
|
||||
static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto name = state.forceStringNoCtx(*args[0], pos);
|
||||
auto name = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.parseDrvName");
|
||||
DrvName parsed(name);
|
||||
auto attrs = state.buildBindings(2);
|
||||
attrs.alloc(state.sName).mkString(parsed.name);
|
||||
|
@ -3740,8 +3773,8 @@ static RegisterPrimOp primop_parseDrvName({
|
|||
|
||||
static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto version1 = state.forceStringNoCtx(*args[0], pos);
|
||||
auto version2 = state.forceStringNoCtx(*args[1], pos);
|
||||
auto version1 = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.compareVersions");
|
||||
auto version2 = state.forceStringNoCtx(*args[1], pos, "While evaluating the second argument passed to builtins.compareVersions");
|
||||
v.mkInt(compareVersions(version1, version2));
|
||||
}
|
||||
|
||||
|
@ -3760,7 +3793,7 @@ static RegisterPrimOp primop_compareVersions({
|
|||
|
||||
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto version = state.forceStringNoCtx(*args[0], pos);
|
||||
auto version = state.forceStringNoCtx(*args[0], pos, "While evaluating the first argument passed to builtins.splitVersion");
|
||||
auto iter = version.cbegin();
|
||||
Strings components;
|
||||
while (iter != version.cend()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue