libexpr: de-ptr-ize Value references
thunk values are shareable, and we can represent invalid/uninitialized values with a special bit pattern that makes no sense otherwise. there is no need to keep allocating values on the heap, instead we can treat values like reference-counted smart pointers to heap objects, which in turn lets us save a lot of allocations and, ultimately, gc heap space. compared to our baseline (main of 2025-09-27) we save 15%+ memory on a system rebuild and 17% on nix search. eval time regresses by ~3% for a system rebuild, while nix search is 7% faster. further optimization is probably possible (but for now this will just have to be good enough). Change-Id: Ib6c47acdbe2fac4f76a83c2269f16f30ef66b2e1
This commit is contained in:
+11
-11
@@ -151,12 +151,12 @@ static void getAllExprs(Evaluator & state,
|
||||
continue;
|
||||
}
|
||||
/* Load the expression on demand. */
|
||||
auto vArg = state.mem.allocValue();
|
||||
vArg->mkString(path2.canonical().abs());
|
||||
Value vArg;
|
||||
vArg.mkString(path2.canonical().abs());
|
||||
if (seen.size() == maxAttrs)
|
||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
||||
attrs.alloc(attrName
|
||||
) = {NewValueAs::app, state.mem, state.builtins.get("import"), *vArg};
|
||||
) = {NewValueAs::app, state.mem, state.builtins.get("import"), vArg};
|
||||
}
|
||||
else if (st.type == InputAccessor::tDirectory)
|
||||
/* `path2' is a directory (with no default.nix in it);
|
||||
@@ -517,9 +517,9 @@ static bool keep(EvalState & state, DrvInfo & drv)
|
||||
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
||||
const std::string & name, const std::string & value)
|
||||
{
|
||||
auto v = state.ctx.mem.allocValue();
|
||||
v->mkString(value);
|
||||
drv.setMeta(state, name, *v);
|
||||
Value v;
|
||||
v.mkString(value);
|
||||
drv.setMeta(state, name, v);
|
||||
}
|
||||
|
||||
static void installDerivations(Globals & globals,
|
||||
@@ -1290,12 +1290,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
} else if (v->type() == nList) {
|
||||
attrs2["type"] = "strings";
|
||||
XMLOpenElement m(xml, "meta", attrs2);
|
||||
for (auto elem : v->listItems()) {
|
||||
if (elem->type() != nString) {
|
||||
for (auto & elem : v->listItems()) {
|
||||
if (elem.type() != nString) {
|
||||
continue;
|
||||
}
|
||||
XMLAttrs attrs3;
|
||||
attrs3["value"] = elem->str();
|
||||
attrs3["value"] = elem.str();
|
||||
xml.writeEmptyElement("string", attrs3);
|
||||
}
|
||||
} else if (v->type() == nAttrs) {
|
||||
@@ -1304,12 +1304,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
Bindings & attrs = *v->attrs();
|
||||
for (auto &i : attrs) {
|
||||
const Attr & a(*attrs.get(i.name));
|
||||
if (a.value->type() != nString) {
|
||||
if (a.value.type() != nString) {
|
||||
continue;
|
||||
}
|
||||
XMLAttrs attrs3;
|
||||
attrs3["type"] = globals.state->symbols[i.name];
|
||||
attrs3["value"] = a.value->str();
|
||||
attrs3["value"] = a.value.str();
|
||||
xml.writeEmptyElement("string", attrs3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
auto outputsList = state.ctx.mem.newList(outputs.size());
|
||||
vOutputs = {NewValueAs::list, outputsList};
|
||||
for (const auto & [m, j] : enumerate(outputs)) {
|
||||
(outputsList->elems[m] = state.ctx.mem.allocValue())->mkString(j.first);
|
||||
outputsList->elems[m].mkString(j.first);
|
||||
auto outputAttrs = state.ctx.buildBindings(2);
|
||||
outputAttrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(*j.second));
|
||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||
@@ -78,12 +78,12 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
for (auto & j : metaNames) {
|
||||
Value * v = i.queryMeta(state, j);
|
||||
if (!v) continue;
|
||||
meta.insert(state.ctx.symbols.create(j), v);
|
||||
meta.insert(state.ctx.symbols.create(j), *v);
|
||||
}
|
||||
|
||||
attrs.alloc(state.ctx.s.meta).mkAttrs(meta);
|
||||
|
||||
(manifest->elems[n++] = state.ctx.mem.allocValue())->mkAttrs(attrs);
|
||||
manifest->elems[n++].mkAttrs(attrs);
|
||||
|
||||
if (drvPath) references.insert(*drvPath);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
builder with the manifest as argument. */
|
||||
auto attrs = state.ctx.buildBindings(3);
|
||||
state.ctx.paths.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||
attrs.insert(state.ctx.symbols.create("derivations"), &vManifest);
|
||||
attrs.insert(state.ctx.symbols.create("derivations"), vManifest);
|
||||
Value args;
|
||||
args.mkAttrs(attrs);
|
||||
|
||||
@@ -117,9 +117,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
state.forceValue(topLevel, noPos);
|
||||
NixStringContext context;
|
||||
const Attr & aDrvPath(*topLevel.attrs()->get(state.ctx.s.drvPath));
|
||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, aDrvPath.value, context, "");
|
||||
const Attr & aOutPath(*topLevel.attrs()->get(state.ctx.s.outPath));
|
||||
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
|
||||
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, aOutPath.value, context, "");
|
||||
|
||||
/* Realise the resulting store expression. */
|
||||
debug("building user environment");
|
||||
|
||||
@@ -183,13 +183,13 @@ Bindings * MixEvalArgs::getAutoArgs(Evaluator & state)
|
||||
{
|
||||
auto res = state.buildBindings(autoArgs.size());
|
||||
for (auto & i : autoArgs) {
|
||||
auto v = state.mem.allocValue();
|
||||
Value v;
|
||||
if (i.second[0] == 'E')
|
||||
state.evalLazily(
|
||||
state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), *v
|
||||
state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), v
|
||||
);
|
||||
else
|
||||
v->mkString(((std::string_view) i.second).substr(1));
|
||||
v.mkString(((std::string_view) i.second).substr(1));
|
||||
res.insert(state.symbols.create(i.first), v);
|
||||
}
|
||||
return res.finish();
|
||||
|
||||
@@ -419,7 +419,7 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||
auto aOutputs = vFlake.attrs()->get(state.ctx.symbols.create("outputs"));
|
||||
assert(aOutputs);
|
||||
|
||||
return *aOutputs->value;
|
||||
return aOutputs->value;
|
||||
};
|
||||
|
||||
if (fingerprint) {
|
||||
@@ -449,23 +449,23 @@ Installables SourceExprCommand::parseInstallables(
|
||||
throw UsageError("'--file' and '--expr' are exclusive");
|
||||
|
||||
auto evaluator = getEvaluator();
|
||||
auto vFile = evaluator->mem.allocValue();
|
||||
Value vFile;
|
||||
|
||||
if (file == "-") {
|
||||
auto & e = evaluator->parseStdin();
|
||||
state.eval(e, *vFile);
|
||||
state.eval(e, vFile);
|
||||
}
|
||||
else if (file)
|
||||
state.evalFile(state.aio.blockOn(lookupFileArg(*evaluator, *file)).unwrap(), *vFile);
|
||||
state.evalFile(state.aio.blockOn(lookupFileArg(*evaluator, *file)).unwrap(), vFile);
|
||||
else {
|
||||
auto & e = evaluator->parseExprFromString(*expr, CanonPath::fromCwd());
|
||||
state.eval(e, *vFile);
|
||||
state.eval(e, vFile);
|
||||
}
|
||||
|
||||
for (auto & s : ss) {
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
|
||||
result.push_back(make_ref<InstallableAttrPath>(InstallableAttrPath::parse(
|
||||
evaluator, *this, *vFile, std::move(prefix), std::move(extendedOutputsSpec)
|
||||
evaluator, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec)
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
+40
-38
@@ -174,35 +174,37 @@ struct NixRepl
|
||||
/**
|
||||
* Get a list of each of the `repl-overlays` (parsed and evaluated).
|
||||
*/
|
||||
Value * replOverlays();
|
||||
Value replOverlays();
|
||||
|
||||
/**
|
||||
* Get the Nix function that composes the `repl-overlays` together.
|
||||
*/
|
||||
Value * getReplOverlaysEvalFunction();
|
||||
Value getReplOverlaysEvalFunction();
|
||||
|
||||
/**
|
||||
* Cached return value of `getReplOverlaysEvalFunction`.
|
||||
*
|
||||
* Note: This is `shared_ptr` to avoid garbage collection.
|
||||
*/
|
||||
std::shared_ptr<Value *> replOverlaysEvalFunction =
|
||||
std::allocate_shared<Value *>(TraceableAllocator<Value *>(), nullptr);
|
||||
std::shared_ptr<std::optional<Value>> replOverlaysEvalFunction =
|
||||
std::allocate_shared<std::optional<Value>>(
|
||||
TraceableAllocator<std::optional<Value>>(), std::nullopt
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the `info` AttrSet that's passed as the first argument to each
|
||||
* of the `repl-overlays`.
|
||||
*/
|
||||
Value * replInitInfo();
|
||||
Value replInitInfo();
|
||||
|
||||
/**
|
||||
* Get the current top-level bindings as an AttrSet.
|
||||
*/
|
||||
Value * bindingsToAttrs();
|
||||
Value bindingsToAttrs();
|
||||
/**
|
||||
* Parse a file, evaluate its result, and force the resulting value.
|
||||
*/
|
||||
Value * evalFile(SourcePath & path);
|
||||
Value evalFile(SourcePath & path);
|
||||
|
||||
void printValue(std::ostream & str,
|
||||
Value & v,
|
||||
@@ -863,10 +865,10 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
std::visit(overloaded {
|
||||
[&](ExprReplBindings & b) {
|
||||
for (auto & [name, e] : b.symbols) {
|
||||
Value * v = state.ctx.mem.allocValue();
|
||||
e->eval(state, *env, *v);
|
||||
Value v;
|
||||
e->eval(state, *env, v);
|
||||
(void) e.release(); // NOLINT(bugprone-unused-return-value): leak because of thunk references
|
||||
addVarToScope(name, *v);
|
||||
addVarToScope(name, v);
|
||||
}
|
||||
},
|
||||
[&](std::unique_ptr<Expr> & e) {
|
||||
@@ -964,9 +966,9 @@ void NixRepl::loadReplOverlays()
|
||||
notice("Loading '%1%'...", "repl-overlays");
|
||||
auto replInitFilesFunction = getReplOverlaysEvalFunction();
|
||||
|
||||
Value &newAttrs(*evaluator.mem.allocValue());
|
||||
SmallValueVector<3> args = {replInitInfo(), bindingsToAttrs(), replOverlays()};
|
||||
state.callFunction(*replInitFilesFunction, args, newAttrs, noPos);
|
||||
Value newAttrs;
|
||||
Value args[] = {replInitInfo(), bindingsToAttrs(), replOverlays()};
|
||||
state.callFunction(replInitFilesFunction, args, newAttrs, noPos);
|
||||
|
||||
// n.b. this does in fact load the stuff into the environment twice (once
|
||||
// from the superset of the environment returned by repl-overlays and once
|
||||
@@ -976,14 +978,14 @@ void NixRepl::loadReplOverlays()
|
||||
addAttrsToScope(newAttrs);
|
||||
}
|
||||
|
||||
Value * NixRepl::getReplOverlaysEvalFunction()
|
||||
Value NixRepl::getReplOverlaysEvalFunction()
|
||||
{
|
||||
if (replOverlaysEvalFunction && *replOverlaysEvalFunction) {
|
||||
return *replOverlaysEvalFunction;
|
||||
return **replOverlaysEvalFunction;
|
||||
}
|
||||
|
||||
auto evalReplInitFilesPath = CanonPath::root + "repl-overlays.nix";
|
||||
*replOverlaysEvalFunction = evaluator.mem.allocValue();
|
||||
*replOverlaysEvalFunction = Value{};
|
||||
auto code =
|
||||
#include "repl-overlays.nix.gen.hh"
|
||||
;
|
||||
@@ -995,14 +997,14 @@ Value * NixRepl::getReplOverlaysEvalFunction()
|
||||
|
||||
state.eval(expr, **replOverlaysEvalFunction);
|
||||
|
||||
return *replOverlaysEvalFunction;
|
||||
return **replOverlaysEvalFunction;
|
||||
}
|
||||
|
||||
Value * NixRepl::replOverlays()
|
||||
Value NixRepl::replOverlays()
|
||||
{
|
||||
Value * replInits(evaluator.mem.allocValue());
|
||||
Value replInits;
|
||||
auto replInitStorage = evaluator.mem.newList(evalSettings.replOverlays.get().size());
|
||||
*replInits = {NewValueAs::list, replInitStorage};
|
||||
replInits = {NewValueAs::list, replInitStorage};
|
||||
|
||||
size_t i = 0;
|
||||
for (auto path : evalSettings.replOverlays.get()) {
|
||||
@@ -1018,18 +1020,18 @@ Value * NixRepl::replOverlays()
|
||||
auto replInit = evalFile(sourcePath);
|
||||
evalSettings.pureEval.setDefault(prevPureEval);
|
||||
|
||||
if (!replInit->isLambda()) {
|
||||
if (!replInit.isLambda()) {
|
||||
evaluator.errors
|
||||
.make<TypeError>(
|
||||
"Expected `repl-overlays` entry %s to be a lambda but found %s: %s",
|
||||
path,
|
||||
showType(*replInit),
|
||||
ValuePrinter(state, *replInit, errorPrintOptions)
|
||||
showType(replInit),
|
||||
ValuePrinter(state, replInit, errorPrintOptions)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
|
||||
if (auto attrs = dynamic_cast<AttrsPattern *>(replInit->lambda().fun->pattern.get());
|
||||
if (auto attrs = dynamic_cast<AttrsPattern *>(replInit.lambda().fun->pattern.get());
|
||||
attrs && !attrs->ellipsis)
|
||||
{
|
||||
evaluator.errors
|
||||
@@ -1039,7 +1041,7 @@ Value * NixRepl::replOverlays()
|
||||
"repl-overlays",
|
||||
"..."
|
||||
)
|
||||
.atPos(replInit->lambda().fun->pos)
|
||||
.atPos(replInit.lambda().fun->pos)
|
||||
.debugThrow();
|
||||
}
|
||||
|
||||
@@ -1051,16 +1053,16 @@ Value * NixRepl::replOverlays()
|
||||
return replInits;
|
||||
}
|
||||
|
||||
Value * NixRepl::replInitInfo()
|
||||
Value NixRepl::replInitInfo()
|
||||
{
|
||||
auto builder = evaluator.buildBindings(2);
|
||||
|
||||
Value * currentSystem(evaluator.mem.allocValue());
|
||||
currentSystem->mkString(evalSettings.getCurrentSystem());
|
||||
Value currentSystem;
|
||||
currentSystem.mkString(evalSettings.getCurrentSystem());
|
||||
builder.insert(evaluator.symbols.create("currentSystem"), currentSystem);
|
||||
|
||||
Value * info(evaluator.mem.allocValue());
|
||||
info->mkAttrs(builder.finish());
|
||||
Value info;
|
||||
info.mkAttrs(builder.finish());
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -1118,19 +1120,19 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
|
||||
} else {
|
||||
notice("Added %s.", evaluator.symbols[name]);
|
||||
}
|
||||
env->values[displ++] = &v;
|
||||
env->values[displ++] = v;
|
||||
varNames.emplace(evaluator.symbols[name]);
|
||||
}
|
||||
|
||||
Value * NixRepl::bindingsToAttrs()
|
||||
Value NixRepl::bindingsToAttrs()
|
||||
{
|
||||
auto builder = evaluator.buildBindings(staticEnv->vars.size());
|
||||
for (auto & [symbol, displacement] : staticEnv->vars) {
|
||||
builder.insert(symbol, env->values[displacement]);
|
||||
}
|
||||
|
||||
Value * attrs(evaluator.mem.allocValue());
|
||||
attrs->mkAttrs(builder.finish());
|
||||
Value attrs;
|
||||
attrs.mkAttrs(builder.finish());
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@@ -1153,12 +1155,12 @@ void NixRepl::evalString(std::string s, Value & v)
|
||||
state.forceValue(v, noPos);
|
||||
}
|
||||
|
||||
Value * NixRepl::evalFile(SourcePath & path)
|
||||
Value NixRepl::evalFile(SourcePath & path)
|
||||
{
|
||||
auto & expr = evaluator.parseExprFromFile(evaluator.paths.checkSourcePath(path), staticEnv);
|
||||
Value * result(evaluator.mem.allocValue());
|
||||
expr.eval(state, *env, *result);
|
||||
state.forceValue(*result, noPos);
|
||||
Value result;
|
||||
expr.eval(state, *env, result);
|
||||
state.forceValue(result, noPos);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & au
|
||||
ValuePrinter(state, v, errorPrintOptions)
|
||||
);
|
||||
}
|
||||
v = *a->value;
|
||||
v = a->value;
|
||||
pos = a->pos;
|
||||
} else {
|
||||
if (!v.isList()) {
|
||||
@@ -153,7 +153,7 @@ findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & au
|
||||
);
|
||||
}
|
||||
|
||||
v = *v.listElems()[*attrIndex];
|
||||
v = v.listElems()[*attrIndex];
|
||||
pos = noPos;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@ Bindings * EvalMemory::allocBindings(size_t capacity)
|
||||
|
||||
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
|
||||
{
|
||||
auto value = mem.allocValue();
|
||||
bindings->push_back(Attr(name, value, pos));
|
||||
return *value;
|
||||
bindings->push_back(Attr(name, {}, pos));
|
||||
return (bindings->end() - 1)->value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ struct Attr
|
||||
way we keep Attr size at two words with no wasted space. */
|
||||
Symbol name;
|
||||
PosIdx pos;
|
||||
Value * value;
|
||||
Attr(Symbol name, Value * value, PosIdx pos = noPos) : name(name), pos(pos), value(value) {}
|
||||
mutable Value value;
|
||||
Attr(Symbol name, Value value, PosIdx pos = noPos) : name(name), pos(pos), value(value) {}
|
||||
Attr() { };
|
||||
bool operator < (const Attr & a) const
|
||||
{
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
const Attr * get(Symbol name)
|
||||
{
|
||||
Attr key(name, 0);
|
||||
Attr key(name, {});
|
||||
iterator i = std::lower_bound(begin(), end(), key);
|
||||
if (i != end() && i->name == name) return &*i;
|
||||
return nullptr;
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void insert(Symbol name, Value * value, PosIdx pos = noPos)
|
||||
void insert(Symbol name, Value value, PosIdx pos = noPos)
|
||||
{
|
||||
insert(Attr(name, value, pos));
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ Value & AttrCursor::getValue(EvalState & state)
|
||||
auto attr = vParent.attrs()->get(state.ctx.symbols.create(parent->second));
|
||||
if (!attr)
|
||||
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr(state));
|
||||
_value = allocRootValue(*attr->value);
|
||||
_value = allocRootValue(attr->value);
|
||||
} else
|
||||
_value = allocRootValue(root->getRootValue(state));
|
||||
}
|
||||
@@ -520,7 +520,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(EvalState & state, const st
|
||||
}
|
||||
|
||||
return make_ref<AttrCursor>(
|
||||
root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2)
|
||||
root, std::make_pair(shared_from_this(), name), &attr->value, std::move(cachedValue2)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -686,7 +686,7 @@ std::vector<std::string> AttrCursor::getListOfStrings(EvalState & state)
|
||||
|
||||
for (auto & elem : v.listItems()) {
|
||||
res.push_back(std::string(
|
||||
state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching")
|
||||
state.forceStringNoCtx(elem, noPos, "while evaluating an attribute for caching")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
+14
-21
@@ -13,18 +13,18 @@ namespace nix {
|
||||
inline Value::Value(app_t, EvalMemory & mem, Value & lhs, Value & rhs)
|
||||
{
|
||||
auto app = static_cast<Value::App *>(mem.allocBytes(sizeof(Value::App) + sizeof(Value *)));
|
||||
app->_left = reinterpret_cast<uintptr_t>(&lhs);
|
||||
app->_left = lhs;
|
||||
app->_n = 1;
|
||||
app->_args[0] = &rhs;
|
||||
app->_args[0] = rhs;
|
||||
raw = tag(tApp, app);
|
||||
}
|
||||
|
||||
inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span<Value *> args)
|
||||
inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span<Value> args)
|
||||
{
|
||||
auto app = static_cast<Value::App *>(mem.allocBytes(sizeof(Value::App) + args.size_bytes()));
|
||||
app->_left = reinterpret_cast<uintptr_t>(&lhs);
|
||||
app->_left = lhs;
|
||||
app->_n = args.size();
|
||||
memcpy(app->_args, args.data(), args.size_bytes());
|
||||
std::copy(args.begin(), args.end(), app->_args);
|
||||
raw = tag(tApp, app);
|
||||
}
|
||||
|
||||
@@ -85,14 +85,6 @@ T * EvalMemory::allocType(size_t n)
|
||||
return static_cast<T *>(allocBytes(checkedArrayAllocSize(sizeof(T), n)));
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
Value * EvalMemory::allocValue()
|
||||
{
|
||||
static_assert(CACHES * CACHE_INCREMENT >= sizeof(Value));
|
||||
stats.nrValues++;
|
||||
return static_cast<Value *>(allocBytes(sizeof(Value)));
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
Env & EvalMemory::allocEnv(size_t size)
|
||||
{
|
||||
@@ -117,15 +109,15 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||
if (thunk.resolved()) {
|
||||
v = thunk.result();
|
||||
} else {
|
||||
const auto backup = v;
|
||||
Env * env = v.thunk().env();
|
||||
Expr & expr = *v.thunk().expr;
|
||||
v = Value{NewValueAs::blackhole};
|
||||
const auto backup = thunk;
|
||||
Env * env = thunk.env();
|
||||
Expr & expr = *thunk.expr;
|
||||
thunk = Value::blackHole;
|
||||
try {
|
||||
expr.eval(*this, *env, v);
|
||||
backup.thunk().resolve(v);
|
||||
thunk.resolve(v);
|
||||
} catch (...) {
|
||||
v = backup;
|
||||
thunk = backup;
|
||||
tryFixupBlackHolePos(v, pos);
|
||||
throw;
|
||||
}
|
||||
@@ -136,8 +128,9 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||
v = app.result();
|
||||
} else {
|
||||
auto target = app.target();
|
||||
if (!target->isPrimOp() || target->primOp()->arity <= app.totalArgs()) {
|
||||
callFunction(*v.app().left(), v.app().args(), v, pos);
|
||||
if (!target.isPrimOp() || target.primOp()->arity <= app.totalArgs()) {
|
||||
auto tmp = v.app().left();
|
||||
callFunction(tmp, v.app().args(), v, pos);
|
||||
app.resolve(v);
|
||||
}
|
||||
}
|
||||
|
||||
+104
-113
@@ -135,7 +135,7 @@ std::string showType(const Value & v)
|
||||
case tApp:
|
||||
if (v.isPrimOpApp()) {
|
||||
return fmt(
|
||||
"the partially applied built-in function '%s'", v.app().target()->primOp()->name
|
||||
"the partially applied built-in function '%s'", v.app().target().primOp()->name
|
||||
);
|
||||
} else {
|
||||
return "a function application";
|
||||
@@ -563,11 +563,8 @@ Path EvalPaths::toRealPath(const Path & path, const NixStringContext & context)
|
||||
: path;
|
||||
}
|
||||
|
||||
void EvalBuiltins::addConstant(const std::string & name, const Value & v2, Constant info)
|
||||
void EvalBuiltins::addConstant(const std::string & name, const Value & v, Constant info)
|
||||
{
|
||||
Value * v = mem.allocValue();
|
||||
*v = v2;
|
||||
|
||||
auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
|
||||
|
||||
constantInfos.push_back({name2, info});
|
||||
@@ -577,14 +574,14 @@ void EvalBuiltins::addConstant(const std::string & name, const Value & v2, Const
|
||||
|
||||
We might know the type of a thunk in advance, so be allowed
|
||||
to just write it down in that case. */
|
||||
if (auto gotType = v->type(true); gotType != nThunk) {
|
||||
if (auto gotType = v.type(true); gotType != nThunk) {
|
||||
assert(info.type == gotType);
|
||||
}
|
||||
|
||||
/* Install value the base environment. */
|
||||
staticEnv->vars.insert_or_assign(symbols.create(name), baseEnvDispl);
|
||||
env.values[baseEnvDispl++] = v;
|
||||
env.values[0]->attrs()->push_back(Attr(symbols.create(name2), v));
|
||||
env.values[0].attrs()->push_back(Attr(symbols.create(name2), v));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,15 +597,14 @@ void EvalBuiltins::addPrimOp(PrimOpDetails primOp)
|
||||
the primop to a dummy value. */
|
||||
if (primOp.arity == 0) {
|
||||
primOp.arity = 1;
|
||||
auto vPrimOp = mem.allocValue();
|
||||
vPrimOp->mkPrimOp(new PrimOp(primOp));
|
||||
Value v{NewValueAs::app, mem, *vPrimOp, *vPrimOp};
|
||||
Value vPrimOp{NewValueAs::primop, *new PrimOp(primOp)};
|
||||
Value v{NewValueAs::app, mem, vPrimOp, vPrimOp};
|
||||
addConstant(
|
||||
primOp.name,
|
||||
vPrimOp.primOp()->name,
|
||||
v,
|
||||
{
|
||||
.type = nFunction,
|
||||
.doc = vPrimOp->primOp()->doc,
|
||||
.doc = vPrimOp.primOp()->doc,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -617,17 +613,16 @@ void EvalBuiltins::addPrimOp(PrimOpDetails primOp)
|
||||
if (primOp.name.starts_with("__"))
|
||||
primOp.name = primOp.name.substr(2);
|
||||
|
||||
Value * v = mem.allocValue();
|
||||
v->mkPrimOp(new PrimOp(std::move(primOp)));
|
||||
Value v{NewValueAs::primop, *new PrimOp(std::move(primOp))};
|
||||
staticEnv->vars.insert_or_assign(auto(envName), baseEnvDispl);
|
||||
env.values[baseEnvDispl++] = v;
|
||||
env.values[0]->attrs()->push_back(Attr(symbols.create(v->primOp()->name), v));
|
||||
env.values[0].attrs()->push_back(Attr(symbols.create(v.primOp()->name), v));
|
||||
}
|
||||
|
||||
|
||||
Value & EvalBuiltins::get(const std::string & name)
|
||||
{
|
||||
return *env.values[0]->attrs()->get(symbols.create(name))->value;
|
||||
return env.values[0].attrs()->get(symbols.create(name))->value;
|
||||
}
|
||||
|
||||
|
||||
@@ -670,9 +665,9 @@ void printStaticEnvBindings(const SymbolTable & st, const StaticEnv & se)
|
||||
// just for the current level of Env, not the whole chain.
|
||||
void printWithBindings(const SymbolTable & st, const Env & env)
|
||||
{
|
||||
if (env.values[0]->type() == nAttrs) {
|
||||
if (env.values[0].type() == nAttrs) {
|
||||
std::set<std::string_view> bindings;
|
||||
for (const auto & attr : *env.values[0]->attrs()) {
|
||||
for (const auto & attr : *env.values[0].attrs()) {
|
||||
bindings.emplace(st[attr.name]);
|
||||
}
|
||||
|
||||
@@ -728,10 +723,10 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En
|
||||
if (env.up && se.up) {
|
||||
mapStaticEnvBindings(st, *se.up, *env.up, vm);
|
||||
|
||||
if (se.isWith && env.values[0]->type() == nAttrs) {
|
||||
if (se.isWith && env.values[0].type() == nAttrs) {
|
||||
// add 'with' bindings.
|
||||
Bindings::iterator j = env.values[0]->attrs()->begin();
|
||||
while (j != env.values[0]->attrs()->end()) {
|
||||
Bindings::iterator j = env.values[0].attrs()->begin();
|
||||
while (j != env.values[0].attrs()->end()) {
|
||||
vm[std::string(st[j->name])] = j->value;
|
||||
++j;
|
||||
}
|
||||
@@ -860,7 +855,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
for (auto l = var.level; l; --l, env = env->up) ;
|
||||
|
||||
if (!var.fromWith) {
|
||||
return env->values[var.displ];
|
||||
return &env->values[var.displ];
|
||||
}
|
||||
|
||||
// This early exit defeats the `maybeThunk` optimization for variables from `with`,
|
||||
@@ -871,14 +866,14 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
auto * fromWith = var.fromWith;
|
||||
while (1) {
|
||||
forceAttrs(
|
||||
*env->values[0],
|
||||
env->values[0],
|
||||
fromWith->pos,
|
||||
"while evaluating the first subexpression of a with expression"
|
||||
);
|
||||
auto j = env->values[0]->attrs()->get(var.name);
|
||||
auto j = env->values[0].attrs()->get(var.name);
|
||||
if (j) {
|
||||
if (ctx.stats.countCalls) ctx.stats.attrSelects[j->pos]++;
|
||||
return j->value;
|
||||
return &j->value;
|
||||
}
|
||||
if (!fromWith->parentWith)
|
||||
ctx.errors.make<UndefinedVarError>("undefined variable '%1%'", ctx.symbols[var.name]).atPos(var.pos).withFrame(*env, var).debugThrow();
|
||||
@@ -978,31 +973,28 @@ void EvalState::mkSingleDerivedPathString(
|
||||
in the given environment. But if the expression is a variable,
|
||||
then look it up right away. This significantly reduces the number
|
||||
of thunks allocated. */
|
||||
Value * Expr::maybeThunk(EvalState & state, Env & env)
|
||||
Value Expr::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
Value * v = state.ctx.mem.allocValue();
|
||||
*v = {NewValueAs::thunk, state.ctx.mem, env, *this};
|
||||
state.ctx.stats.nrThunks++;
|
||||
return v;
|
||||
return {NewValueAs::thunk, state.ctx.mem, env, *this};
|
||||
}
|
||||
|
||||
|
||||
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||
Value ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
Value * v = state.lookupVar(&env, *this, true);
|
||||
/* The value might not be initialised in the environment yet.
|
||||
In that case, ignore it. */
|
||||
if (v) {
|
||||
if (v && !v->isInvalid()) {
|
||||
state.ctx.stats.nrAvoided++;
|
||||
return v;
|
||||
return *v;
|
||||
}
|
||||
return Expr::maybeThunk(state, env);
|
||||
}
|
||||
|
||||
Value * ExprLiteral::maybeThunk(EvalState & state, Env & env)
|
||||
Value ExprLiteral::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
state.ctx.stats.nrAvoided++;
|
||||
return &v;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -1140,10 +1132,9 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v)
|
||||
in the original environment. */
|
||||
Displacement displ = 0;
|
||||
for (auto & i : attrs) {
|
||||
Value * vAttr;
|
||||
Value vAttr;
|
||||
if (hasOverrides && i.second.kind != ExprAttrs::AttrDef::Kind::Inherited) {
|
||||
vAttr = state.ctx.mem.allocValue();
|
||||
*vAttr = {
|
||||
vAttr = {
|
||||
NewValueAs::thunk,
|
||||
state.ctx.mem,
|
||||
*i.second.chooseByKind(&env2, &env, inheritEnv),
|
||||
@@ -1167,7 +1158,7 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v)
|
||||
been substituted into the bodies of the other attributes.
|
||||
Hence we need __overrides.) */
|
||||
if (hasOverrides) {
|
||||
Value & vOverrides = *(*v.attrs())[overrides->second.displ].value;
|
||||
Value & vOverrides = (*v.attrs())[overrides->second.displ].value;
|
||||
state.forceAttrs(vOverrides, noPos, "while evaluating the `__overrides` attribute");
|
||||
Bindings * newBnds = state.ctx.mem.allocBindings(capacity + vOverrides.attrs()->size());
|
||||
for (auto & i : *v.attrs())
|
||||
@@ -1254,16 +1245,15 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
auto result = state.ctx.mem.newList(elems.size());
|
||||
v = {NewValueAs::list, result};
|
||||
for (auto [n, v2] : enumerate(result->span())) {
|
||||
const_cast<Value *&>(v2) = elems[n]->maybeThunk(state, env);
|
||||
for (auto && [n, v2] : enumerate(result->span())) {
|
||||
v2 = elems[n]->maybeThunk(state, env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Value * ExprList::maybeThunk(EvalState & state, Env & env)
|
||||
Value ExprList::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
if (elems.empty()) {
|
||||
return &Value::EMPTY_LIST;
|
||||
return Value::EMPTY_LIST;
|
||||
}
|
||||
return Expr::maybeThunk(state, env);
|
||||
}
|
||||
@@ -1291,9 +1281,9 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
void ExprInheritFrom::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
Value * v2 = env.values[displ];
|
||||
state.forceValue(*v2, pos);
|
||||
v = *v2;
|
||||
Value & v2 = env.values[displ];
|
||||
state.forceValue(v2, pos);
|
||||
v = v2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1400,7 +1390,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
// If we're here, then we successfully found the attribute.
|
||||
// Set our currently operated-on attrset to this one, and keep going.
|
||||
vCurrent = attrIt->value;
|
||||
vCurrent = &attrIt->value;
|
||||
posCurrent = attrIt->pos;
|
||||
posCurrentSyntax = currentAttrName.pos;
|
||||
if (state.ctx.stats.countCalls) state.ctx.stats.attrSelects[posCurrent]++;
|
||||
@@ -1435,7 +1425,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||
v.mkBool(false);
|
||||
return;
|
||||
} else {
|
||||
vAttrs = j->value;
|
||||
vAttrs = &j->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1523,7 +1513,7 @@ Env & SimplePattern::match(
|
||||
{
|
||||
Env & env2(state.ctx.mem.allocEnv(1));
|
||||
env2.up = &up;
|
||||
env2.values[0] = &arg;
|
||||
env2.values[0] = arg;
|
||||
return env2;
|
||||
}
|
||||
|
||||
@@ -1547,7 +1537,7 @@ Env & AttrsPattern::match(
|
||||
}
|
||||
|
||||
if (name) {
|
||||
env2.values[displ++] = &arg;
|
||||
env2.values[displ++] = arg;
|
||||
}
|
||||
|
||||
///* For each formal argument, get the actual argument. If
|
||||
@@ -1598,7 +1588,7 @@ Env & AttrsPattern::match(
|
||||
return env2;
|
||||
}
|
||||
|
||||
void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes, const PosIdx pos)
|
||||
void EvalState::callFunction(Value & fun, std::span<Value> args, Value & vRes, const PosIdx pos)
|
||||
{
|
||||
if (callDepth > evalSettings.maxCallDepth)
|
||||
ctx.errors.make<EvalError>("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow();
|
||||
@@ -1612,11 +1602,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
|
||||
Value vCur(fun);
|
||||
|
||||
auto makeAppChain = [&]() {
|
||||
auto fun2 = ctx.mem.allocValue();
|
||||
*fun2 = vCur;
|
||||
vRes = {NewValueAs::app, ctx.mem, *fun2, args};
|
||||
};
|
||||
auto makeAppChain = [&]() { vRes = {NewValueAs::app, ctx.mem, vCur, args}; };
|
||||
|
||||
const Attr * functor;
|
||||
|
||||
@@ -1626,7 +1612,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
|
||||
ExprLambda & lambda(*vCur.lambda().fun);
|
||||
|
||||
Env & env2 = lambda.pattern->match(lambda, *this, *vCur.lambda().env(), *args[0], pos);
|
||||
Env & env2 = lambda.pattern->match(lambda, *this, *vCur.lambda().env(), args[0], pos);
|
||||
|
||||
ctx.stats.nrFunctionCalls++;
|
||||
if (ctx.stats.countCalls) ctx.stats.addCall(lambda);
|
||||
@@ -1664,7 +1650,11 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
if (ctx.stats.countCalls) ctx.stats.primOpCalls[fn->name]++;
|
||||
|
||||
try {
|
||||
fn->fun(*this, args.data(), vCur);
|
||||
SmallVector<Value *, 4> pargs(argsLeft);
|
||||
for (unsigned i = 0; i < argsLeft; i++) {
|
||||
pargs[i] = &args[i];
|
||||
}
|
||||
fn->fun(*this, pargs.data(), vCur);
|
||||
} catch (ThrownError & e) {
|
||||
// Distinguish between an error that simply happened while "throw"
|
||||
// was being evaluated and an explicit thrown error.
|
||||
@@ -1684,13 +1674,16 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
}
|
||||
|
||||
else if (vCur.isPrimOpApp()) {
|
||||
/* Figure out the number of arguments still needed. */
|
||||
size_t argsDone = vCur.app().totalArgs();
|
||||
Value * primOp = vCur.app().target();
|
||||
auto arity = primOp->primOp()->arity;
|
||||
auto argsLeft = arity - argsDone;
|
||||
auto & app = vCur.app();
|
||||
auto prevArgs = app.args();
|
||||
|
||||
if (args.size() < argsLeft) {
|
||||
assert(!vCur.app().left().isApp());
|
||||
|
||||
/* Figure out the number of arguments still needed. */
|
||||
Value primOp = app.target();
|
||||
auto arity = primOp.primOp()->arity;
|
||||
|
||||
if (args.size() < arity - prevArgs.size()) {
|
||||
/* We still don't have enough arguments, so extend the tPrimOpApp chain. */
|
||||
makeAppChain();
|
||||
return;
|
||||
@@ -1699,18 +1692,16 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
the previous and new arguments. */
|
||||
|
||||
// max arity as of writing is 3. even 4 seems excessive though.
|
||||
SmallVector<Value *, 4> vArgs(arity);
|
||||
auto n = argsDone;
|
||||
for (Value * arg = &vCur; arg->isApp(); arg = arg->app().left()) {
|
||||
auto curArgs = arg->app().args();
|
||||
memcpy(&vArgs[n] - curArgs.size(), curArgs.data(), curArgs.size_bytes());
|
||||
n -= curArgs.size();
|
||||
SmallVector<Value *, 4> vArgs;
|
||||
for (auto & arg : prevArgs) {
|
||||
vArgs.push_back(&arg);
|
||||
}
|
||||
while (vArgs.size() < arity) {
|
||||
vArgs.push_back(&args[0]);
|
||||
args = args.subspan(1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < argsLeft; ++i)
|
||||
vArgs[argsDone + i] = args[i];
|
||||
|
||||
auto fn = primOp->primOp();
|
||||
auto fn = primOp.primOp();
|
||||
ctx.stats.nrPrimOpCalls++;
|
||||
if (ctx.stats.countCalls) ctx.stats.primOpCalls[fn->name]++;
|
||||
|
||||
@@ -1724,8 +1715,6 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
e.addTrace(ctx.positions[pos], "while calling the '%1%' builtin", fn->name);
|
||||
throw;
|
||||
}
|
||||
|
||||
args = args.subspan(argsLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1733,10 +1722,9 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
/* 'vCur' may be allocated on the stack of the calling
|
||||
function, but for functors we may keep a reference, so
|
||||
heap-allocate a copy and use that instead. */
|
||||
Value * args2[] = {ctx.mem.allocValue(), args[0]};
|
||||
*args2[0] = vCur;
|
||||
Value args2[] = {vCur, args[0]};
|
||||
try {
|
||||
callFunction(*functor->value, args2, vCur, functor->pos);
|
||||
callFunction(functor->value, args2, vCur, functor->pos);
|
||||
} catch (Error & e) {
|
||||
e.addTrace(ctx.positions[pos], "while calling a functor (an attribute set with a '__functor' attribute)");
|
||||
throw;
|
||||
@@ -1792,7 +1780,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res, PosI
|
||||
auto found = fun.attrs()->get(ctx.s.functor);
|
||||
if (found) {
|
||||
Value v;
|
||||
callFunction(*found->value, fun, v, pos);
|
||||
callFunction(found->value, fun, v, pos);
|
||||
forceValue(v, pos);
|
||||
return autoCallFunction(args, v, res, pos);
|
||||
}
|
||||
@@ -1975,19 +1963,19 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
|
||||
void EvalState::concatLists(
|
||||
Value & v, size_t nrLists, Value * const * lists, const PosIdx pos, std::string_view errorCtx
|
||||
Value & v, std::span<Value> lists, const PosIdx pos, std::string_view errorCtx
|
||||
)
|
||||
{
|
||||
ctx.stats.nrListConcats++;
|
||||
|
||||
Value * nonEmpty = 0;
|
||||
size_t len = 0;
|
||||
for (size_t n = 0; n < nrLists; ++n) {
|
||||
forceList(*lists[n], pos, errorCtx);
|
||||
auto l = lists[n]->listSize();
|
||||
for (size_t n = 0; n < lists.size(); ++n) {
|
||||
forceList(lists[n], pos, errorCtx);
|
||||
auto l = lists[n].listSize();
|
||||
len += l;
|
||||
if (l) {
|
||||
nonEmpty = lists[n];
|
||||
nonEmpty = &lists[n];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,10 +1987,10 @@ void EvalState::concatLists(
|
||||
auto list = ctx.mem.newList(len);
|
||||
v = {NewValueAs::list, list};
|
||||
auto out = list->elems;
|
||||
for (size_t n = 0, pos = 0; n < nrLists; ++n) {
|
||||
auto l = lists[n]->listSize();
|
||||
for (size_t n = 0, pos = 0; n < lists.size(); ++n) {
|
||||
auto l = lists[n].listSize();
|
||||
if (l) {
|
||||
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
|
||||
std::copy(lists[n].listItems().begin(), lists[n].listItems().end(), out + pos);
|
||||
}
|
||||
pos += l;
|
||||
}
|
||||
@@ -2165,18 +2153,18 @@ void EvalState::forceValueDeep(Value & v)
|
||||
for (auto & i : *v.attrs())
|
||||
try {
|
||||
// If the value is a thunk, we're evaling. Otherwise no trace necessary.
|
||||
auto dts = ctx.debug && i.value->isThunk()
|
||||
auto dts = ctx.debug && i.value.isThunk()
|
||||
? makeDebugTraceStacker(
|
||||
*this,
|
||||
*i.value->thunk().expr,
|
||||
*i.value->thunk().env(),
|
||||
*i.value.thunk().expr,
|
||||
*i.value.thunk().env(),
|
||||
ctx.positions[i.pos],
|
||||
"while evaluating the attribute '%1%'",
|
||||
ctx.symbols[i.name]
|
||||
)
|
||||
: nullptr;
|
||||
|
||||
recurse(*i.value);
|
||||
recurse(i.value);
|
||||
} catch (Error & e) {
|
||||
e.addTrace(ctx.positions[i.pos], "while evaluating the attribute '%1%'", ctx.symbols[i.name]);
|
||||
throw;
|
||||
@@ -2184,8 +2172,8 @@ void EvalState::forceValueDeep(Value & v)
|
||||
}
|
||||
|
||||
else if (v.isList()) {
|
||||
for (auto v2 : v.listItems()) {
|
||||
recurse(*v2);
|
||||
for (auto & v2 : v.listItems()) {
|
||||
recurse(v2);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2335,11 +2323,11 @@ bool EvalState::isDerivation(Value & v)
|
||||
if (!i) {
|
||||
return false;
|
||||
}
|
||||
forceValue(*i->value, i->pos);
|
||||
if (i->value->type() != nString) {
|
||||
forceValue(i->value, i->pos);
|
||||
if (i->value.type() != nString) {
|
||||
return false;
|
||||
}
|
||||
return i->value->str() == "derivation";
|
||||
return i->value.str() == "derivation";
|
||||
}
|
||||
|
||||
|
||||
@@ -2350,7 +2338,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value &
|
||||
if (i) {
|
||||
Value v1;
|
||||
try {
|
||||
callFunction(*i->value, v, v1, i->pos);
|
||||
callFunction(i->value, v, v1, i->pos);
|
||||
return coerceToString(pos, v1, context,
|
||||
"while evaluating the result of the `__toString` attribute",
|
||||
mode, copyToStore).toOwned();
|
||||
@@ -2406,7 +2394,7 @@ BackedStringView EvalState::coerceToString(
|
||||
.debugThrow();
|
||||
}
|
||||
return coerceToString(
|
||||
pos, *i->value, context, errorCtx, mode, copyToStore, canonicalizePath
|
||||
pos, i->value, context, errorCtx, mode, copyToStore, canonicalizePath
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2445,7 +2433,7 @@ BackedStringView EvalState::coerceToString(
|
||||
try {
|
||||
result += *coerceToString(
|
||||
pos,
|
||||
*v2,
|
||||
v2,
|
||||
context,
|
||||
"while evaluating one element of the list",
|
||||
mode,
|
||||
@@ -2458,7 +2446,7 @@ BackedStringView EvalState::coerceToString(
|
||||
}
|
||||
if (n < v.listSize() - 1
|
||||
/* !!! not quite correct */
|
||||
&& (!v2->isList() || v2->listSize() != 0))
|
||||
&& (!v2.isList() || v2.listSize() != 0))
|
||||
{
|
||||
result += " ";
|
||||
}
|
||||
@@ -2588,11 +2576,6 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
forceValue(v1, pos);
|
||||
forceValue(v2, pos);
|
||||
|
||||
/* !!! Hack to support some old broken code that relies on pointer
|
||||
equality tests between sets. (Specifically, builderDefs calls
|
||||
uniqList on a list of sets.) Will remove this eventually. */
|
||||
if (&v1 == &v2) return true;
|
||||
|
||||
// Special case type-compatibility between float and int
|
||||
if (v1.type() == nInt && v2.type() == nFloat) {
|
||||
return v1.integer().value == v2.fpoint();
|
||||
@@ -2604,6 +2587,11 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
// All other types are not compatible with each other.
|
||||
if (v1.type() != v2.type()) return false;
|
||||
|
||||
/* !!! Hack to support some old broken code that relies on pointer
|
||||
equality tests between sets. (Specifically, builderDefs calls
|
||||
uniqList on a list of sets.) Will remove this eventually. */
|
||||
auto pointerEq = [&] { return v1.pointerEqProxy() == v2.pointerEqProxy(); };
|
||||
|
||||
switch (v1.type()) {
|
||||
case nInt:
|
||||
return v1.integer() == v2.integer();
|
||||
@@ -2621,22 +2609,24 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
return true;
|
||||
|
||||
case nList:
|
||||
if (pointerEq()) return true;
|
||||
if (v1.listSize() != v2.listSize()) return false;
|
||||
for (size_t n = 0; n < v1.listSize(); ++n) {
|
||||
if (!eqValues(*v1.listElems()[n], *v2.listElems()[n], pos, errorCtx)) {
|
||||
if (!eqValues(v1.listElems()[n], v2.listElems()[n], pos, errorCtx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case nAttrs: {
|
||||
if (pointerEq()) return true;
|
||||
/* If both sets denote a derivation (type = "derivation"),
|
||||
then compare their outPaths. */
|
||||
if (isDerivation(v1) && isDerivation(v2)) {
|
||||
auto i = v1.attrs()->get(ctx.s.outPath);
|
||||
auto j = v2.attrs()->get(ctx.s.outPath);
|
||||
if (i && j) {
|
||||
return eqValues(*i->value, *j->value, pos, errorCtx);
|
||||
return eqValues(i->value, j->value, pos, errorCtx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2646,7 +2636,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
Bindings::iterator i, j;
|
||||
for (i = v1.attrs()->begin(), j = v2.attrs()->begin(); i != v1.attrs()->end(); ++i, ++j)
|
||||
{
|
||||
if (i->name != j->name || !eqValues(*i->value, *j->value, pos, errorCtx)) {
|
||||
if (i->name != j->name || !eqValues(i->value, j->value, pos, errorCtx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2659,6 +2649,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
return false;
|
||||
|
||||
case nExternal:
|
||||
if (pointerEq()) return true;
|
||||
return *v1.external() == *v2.external();
|
||||
|
||||
case nFloat:
|
||||
@@ -2708,7 +2699,6 @@ void Evaluator::printStatistics()
|
||||
|
||||
uint64_t bEnvs = mem.nrEnvs * sizeof(Env) + mem.nrValuesInEnvs * sizeof(Value *);
|
||||
uint64_t bLists = mem.nrListElems * sizeof(Value *);
|
||||
uint64_t bValues = mem.nrValues * sizeof(Value);
|
||||
uint64_t bAttrsets = mem.nrAttrsets * sizeof(Bindings) + mem.nrAttrsInAttrsets * sizeof(Attr);
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
@@ -2732,9 +2722,10 @@ void Evaluator::printStatistics()
|
||||
{"bytes", bLists},
|
||||
{"concats", stats.nrListConcats},
|
||||
};
|
||||
// reported for compatibility, even though we no longer allocate these on the heap
|
||||
topObj["values"] = {
|
||||
{"number", mem.nrValues},
|
||||
{"bytes", bValues},
|
||||
{"number", 0},
|
||||
{"bytes", 0},
|
||||
};
|
||||
topObj["symbols"] = {
|
||||
{"number", symbols.size()},
|
||||
|
||||
+6
-14
@@ -61,12 +61,12 @@ struct Constant
|
||||
bool impureOnly = false;
|
||||
};
|
||||
|
||||
using ValMap = GcMap<std::string, Value *>;
|
||||
using ValMap = GcMap<std::string, Value>;
|
||||
|
||||
struct alignas(Value::Acb::TAG_ALIGN) Env
|
||||
{
|
||||
Env * up;
|
||||
Value * values[0];
|
||||
Value values[0];
|
||||
};
|
||||
|
||||
void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env);
|
||||
@@ -192,7 +192,6 @@ public:
|
||||
{
|
||||
unsigned long nrEnvs = 0;
|
||||
unsigned long nrValuesInEnvs = 0;
|
||||
unsigned long nrValues = 0;
|
||||
unsigned long nrAttrsets = 0;
|
||||
unsigned long nrAttrsInAttrsets = 0;
|
||||
unsigned long nrListElems = 0;
|
||||
@@ -210,7 +209,6 @@ public:
|
||||
template<typename T>
|
||||
inline T * allocType(size_t n = 1);
|
||||
|
||||
inline Value * allocValue();
|
||||
inline Env & allocEnv(size_t size);
|
||||
|
||||
Bindings * allocBindings(size_t capacity);
|
||||
@@ -795,12 +793,11 @@ public:
|
||||
|
||||
bool isFunctor(Value & fun);
|
||||
|
||||
void callFunction(Value & fun, std::span<Value *> args, Value & vRes, const PosIdx pos);
|
||||
void callFunction(Value & fun, std::span<Value> args, Value & vRes, const PosIdx pos);
|
||||
|
||||
void callFunction(Value & fun, Value & arg, Value & vRes, const PosIdx pos)
|
||||
{
|
||||
Value * args[] = {&arg};
|
||||
callFunction(fun, args, vRes, pos);
|
||||
callFunction(fun, {&arg, 1}, vRes, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -840,13 +837,8 @@ public:
|
||||
const SingleDerivedPath & p,
|
||||
Value & v);
|
||||
|
||||
void concatLists(
|
||||
Value & v,
|
||||
size_t nrLists,
|
||||
Value * const * lists,
|
||||
const PosIdx pos,
|
||||
std::string_view errorCtx
|
||||
);
|
||||
void
|
||||
concatLists(Value & v, std::span<Value> lists, const PosIdx pos, std::string_view errorCtx);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
+54
-54
@@ -109,15 +109,15 @@ static void parseFlakeInputAttr(EvalState & state, const Attr & attr, fetchers::
|
||||
// Allow selecting a subset of enum values
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
switch (attr.value->type()) {
|
||||
switch (attr.value.type()) {
|
||||
case nString:
|
||||
attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value->str()));
|
||||
attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value.str()));
|
||||
break;
|
||||
case nBool:
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value.boolean()});
|
||||
break;
|
||||
case nInt: {
|
||||
auto intValue = attr.value->integer().value;
|
||||
auto intValue = attr.value.integer().value;
|
||||
|
||||
if (intValue < 0) {
|
||||
state.ctx.errors
|
||||
@@ -137,7 +137,7 @@ static void parseFlakeInputAttr(EvalState & state, const Attr & attr, fetchers::
|
||||
.make<TypeError>(
|
||||
"flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
|
||||
state.ctx.symbols[attr.name],
|
||||
showType(*attr.value)
|
||||
showType(attr.value)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
@@ -169,21 +169,21 @@ static FlakeInput parseFlakeInput(
|
||||
for (nix::Attr attr : *(value.attrs())) {
|
||||
try {
|
||||
if (attr.name == sUrl) {
|
||||
expectType(state, nString, *attr.value, attr.pos);
|
||||
url = attr.value->str();
|
||||
expectType(state, nString, attr.value, attr.pos);
|
||||
url = attr.value.str();
|
||||
attrs.emplace("url", *url);
|
||||
} else if (attr.name == sFlake) {
|
||||
expectType(state, nBool, *attr.value, attr.pos);
|
||||
input.isFlake = attr.value->boolean();
|
||||
expectType(state, nBool, attr.value, attr.pos);
|
||||
input.isFlake = attr.value.boolean();
|
||||
} else if (attr.name == sInputs) {
|
||||
input.overrides =
|
||||
parseFlakeInputs(
|
||||
state, *attr.value, attr.pos, baseDir, lockRootPath, depth + 1, false
|
||||
state, attr.value, attr.pos, baseDir, lockRootPath, depth + 1, false
|
||||
)
|
||||
.first;
|
||||
} else if (attr.name == sFollows) {
|
||||
expectType(state, nString, *attr.value, attr.pos);
|
||||
auto follows(parseInputPath(attr.value->str()));
|
||||
expectType(state, nString, attr.value, attr.pos);
|
||||
auto follows(parseInputPath(attr.value.str()));
|
||||
follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end());
|
||||
input.follows = follows;
|
||||
} else {
|
||||
@@ -247,17 +247,17 @@ static std::pair<std::map<FlakeId, FlakeInput>, std::optional<fetchers::Attrs>>
|
||||
"'self' input attributes not allowed at %s", state.ctx.positions[inputAttr.pos]
|
||||
);
|
||||
}
|
||||
expectType(state, nAttrs, *inputAttr.value, inputAttr.pos);
|
||||
expectType(state, nAttrs, inputAttr.value, inputAttr.pos);
|
||||
|
||||
selfAttrs = selfAttrs.value_or(fetchers::Attrs{});
|
||||
for (auto & attr : *inputAttr.value->attrs()) {
|
||||
for (auto & attr : *inputAttr.value.attrs()) {
|
||||
parseFlakeInputAttr(state, attr, *selfAttrs);
|
||||
}
|
||||
} else {
|
||||
inputs.emplace(
|
||||
inputName,
|
||||
parseFlakeInput(
|
||||
state, inputName, *inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth
|
||||
state, inputName, inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -335,15 +335,15 @@ static Flake getFlake(
|
||||
state.eval(flakeExpr, vInfo);
|
||||
|
||||
if (auto description = vInfo.attrs()->get(state.ctx.s.description)) {
|
||||
expectType(state, nString, *description->value, description->pos);
|
||||
flake.description = description->value->str();
|
||||
expectType(state, nString, description->value, description->pos);
|
||||
flake.description = description->value.str();
|
||||
}
|
||||
|
||||
auto sInputs = state.ctx.symbols.create("inputs");
|
||||
|
||||
if (auto inputs = vInfo.attrs()->get(sInputs)) {
|
||||
auto [flakeInputs, selfAttrs] =
|
||||
parseFlakeInputs(state, *inputs->value, inputs->pos, flakeDir, lockRootPath, 0, true);
|
||||
parseFlakeInputs(state, inputs->value, inputs->pos, flakeDir, lockRootPath, 0, true);
|
||||
flake.inputs = std::move(flakeInputs);
|
||||
flake.selfAttrs = std::move(selfAttrs);
|
||||
}
|
||||
@@ -368,11 +368,11 @@ static Flake getFlake(
|
||||
}
|
||||
|
||||
if (auto outputs = vInfo.attrs()->get(state.ctx.s.outputs)) {
|
||||
expectType(state, nFunction, *outputs->value, outputs->pos);
|
||||
expectType(state, nFunction, outputs->value, outputs->pos);
|
||||
|
||||
if (outputs->value->isLambda()) {
|
||||
if (outputs->value.isLambda()) {
|
||||
if (auto pattern =
|
||||
dynamic_cast<AttrsPattern *>(outputs->value->lambda().fun->pattern.get());
|
||||
dynamic_cast<AttrsPattern *>(outputs->value.lambda().fun->pattern.get());
|
||||
pattern)
|
||||
{
|
||||
for (auto & formal : pattern->formals) {
|
||||
@@ -393,23 +393,23 @@ static Flake getFlake(
|
||||
auto sNixConfig = state.ctx.symbols.create("nixConfig");
|
||||
|
||||
if (auto nixConfig = vInfo.attrs()->get(sNixConfig)) {
|
||||
expectType(state, nAttrs, *nixConfig->value, nixConfig->pos);
|
||||
expectType(state, nAttrs, nixConfig->value, nixConfig->pos);
|
||||
|
||||
for (auto & setting : *nixConfig->value->attrs()) {
|
||||
forceTrivialValue(state, *setting.value, setting.pos);
|
||||
if (setting.value->type() == nString) {
|
||||
for (auto & setting : *nixConfig->value.attrs()) {
|
||||
forceTrivialValue(state, setting.value, setting.pos);
|
||||
if (setting.value.type() == nString) {
|
||||
flake.config.settings.emplace(
|
||||
state.ctx.symbols[setting.name],
|
||||
std::string(state.forceStringNoCtx(*setting.value, setting.pos, ""))
|
||||
std::string(state.forceStringNoCtx(setting.value, setting.pos, ""))
|
||||
);
|
||||
} else if (setting.value->type() == nPath) {
|
||||
} else if (setting.value.type() == nPath) {
|
||||
NixStringContext emptyContext = {};
|
||||
flake.config.settings.emplace(
|
||||
state.ctx.symbols[setting.name],
|
||||
state
|
||||
.coerceToString(
|
||||
setting.pos,
|
||||
*setting.value,
|
||||
setting.value,
|
||||
emptyContext,
|
||||
"",
|
||||
StringCoercionMode::Strict,
|
||||
@@ -418,30 +418,30 @@ static Flake getFlake(
|
||||
)
|
||||
.toOwned()
|
||||
);
|
||||
} else if (setting.value->type() == nInt) {
|
||||
} else if (setting.value.type() == nInt) {
|
||||
flake.config.settings.emplace(
|
||||
state.ctx.symbols[setting.name],
|
||||
state.forceInt(*setting.value, setting.pos, "").value
|
||||
state.forceInt(setting.value, setting.pos, "").value
|
||||
);
|
||||
} else if (setting.value->type() == nBool) {
|
||||
} else if (setting.value.type() == nBool) {
|
||||
flake.config.settings.emplace(
|
||||
state.ctx.symbols[setting.name],
|
||||
Explicit<bool>{state.forceBool(*setting.value, setting.pos, "")}
|
||||
Explicit<bool>{state.forceBool(setting.value, setting.pos, "")}
|
||||
);
|
||||
} else if (setting.value->type() == nList) {
|
||||
} else if (setting.value.type() == nList) {
|
||||
std::vector<std::string> ss;
|
||||
for (auto elem : setting.value->listItems()) {
|
||||
if (elem->type() != nString) {
|
||||
for (auto & elem : setting.value.listItems()) {
|
||||
if (elem.type() != nString) {
|
||||
state.ctx.errors
|
||||
.make<TypeError>(
|
||||
"list element in flake configuration setting '%s' is %s while a "
|
||||
"string is expected",
|
||||
state.ctx.symbols[setting.name],
|
||||
showType(*setting.value)
|
||||
showType(setting.value)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos, ""));
|
||||
ss.emplace_back(state.forceStringNoCtx(elem, setting.pos, ""));
|
||||
}
|
||||
flake.config.settings.emplace(state.ctx.symbols[setting.name], ss);
|
||||
} else {
|
||||
@@ -449,7 +449,7 @@ static Flake getFlake(
|
||||
.make<TypeError>(
|
||||
"flake configuration setting '%s' is %s",
|
||||
state.ctx.symbols[setting.name],
|
||||
showType(*setting.value)
|
||||
showType(setting.value)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
@@ -941,24 +941,24 @@ void callFlake(EvalState & state,
|
||||
const LockedFlake & lockedFlake,
|
||||
Value & vRes)
|
||||
{
|
||||
auto vLocks = state.ctx.mem.allocValue();
|
||||
auto vRootSrc = state.ctx.mem.allocValue();
|
||||
auto vRootSubdir = state.ctx.mem.allocValue();
|
||||
auto vTmp1 = state.ctx.mem.allocValue();
|
||||
auto vTmp2 = state.ctx.mem.allocValue();
|
||||
Value vLocks;
|
||||
Value vRootSrc;
|
||||
Value vRootSubdir;
|
||||
Value vTmp1;
|
||||
Value vTmp2;
|
||||
|
||||
vLocks->mkString(lockedFlake.lockFile.to_string());
|
||||
vLocks.mkString(lockedFlake.lockFile.to_string());
|
||||
|
||||
emitTreeAttrs(
|
||||
state.ctx,
|
||||
*lockedFlake.flake.sourceInfo,
|
||||
lockedFlake.flake.lockedRef.input,
|
||||
*vRootSrc,
|
||||
vRootSrc,
|
||||
false,
|
||||
lockedFlake.flake.forceDirty
|
||||
);
|
||||
|
||||
vRootSubdir->mkString(lockedFlake.flake.lockedRef.subdir);
|
||||
vRootSubdir.mkString(lockedFlake.flake.lockedRef.subdir);
|
||||
|
||||
if (!state.ctx.caches.vCallFlake) {
|
||||
state.ctx.caches.vCallFlake = allocRootValue({});
|
||||
@@ -971,9 +971,9 @@ void callFlake(EvalState & state,
|
||||
);
|
||||
}
|
||||
|
||||
state.callFunction(*state.ctx.caches.vCallFlake, *vLocks, *vTmp1, noPos);
|
||||
state.callFunction(*vTmp1, *vRootSrc, *vTmp2, noPos);
|
||||
state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos);
|
||||
state.callFunction(*state.ctx.caches.vCallFlake, vLocks, vTmp1, noPos);
|
||||
state.callFunction(vTmp1, vRootSrc, vTmp2, noPos);
|
||||
state.callFunction(vTmp2, vRootSubdir, vRes, noPos);
|
||||
}
|
||||
|
||||
void prim_getFlake(EvalState & state, Value * * args, Value & v)
|
||||
@@ -1024,9 +1024,9 @@ void prim_flakeRefToString(
|
||||
"while evaluating the argument passed to builtins.flakeRefToString");
|
||||
fetchers::Attrs attrs;
|
||||
for (const auto & attr : *args[0]->attrs()) {
|
||||
auto t = attr.value->type();
|
||||
auto t = attr.value.type();
|
||||
if (t == nInt) {
|
||||
auto intValue = attr.value->integer().value;
|
||||
auto intValue = attr.value.integer().value;
|
||||
|
||||
if (intValue < 0) {
|
||||
state.ctx.errors.make<EvalError>("negative value given for flake ref attr %1%: %2%", state.ctx.symbols[attr.name], intValue).debugThrow();
|
||||
@@ -1035,16 +1035,16 @@ void prim_flakeRefToString(
|
||||
|
||||
attrs.emplace(state.ctx.symbols[attr.name], asUnsigned);
|
||||
} else if (t == nBool) {
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value.boolean()});
|
||||
} else if (t == nString) {
|
||||
attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value->str()));
|
||||
attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value.str()));
|
||||
} else {
|
||||
state.ctx.errors
|
||||
.make<EvalError>(
|
||||
"flake reference attribute sets may only contain integers, Booleans, "
|
||||
"and strings, but attribute '%s' is %s",
|
||||
state.ctx.symbols[attr.name],
|
||||
showType(*attr.value)
|
||||
showType(attr.value)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ using SmallVector = boost::container::small_vector<T, nItems, TraceableAllocator
|
||||
/**
|
||||
* A vector of value pointers. See `SmallVector`.
|
||||
*/
|
||||
template <size_t nItems>
|
||||
using SmallValueVector = SmallVector<Value *, nItems>;
|
||||
template<size_t nItems>
|
||||
using SmallValueVector = SmallVector<Value, nItems>;
|
||||
|
||||
/**
|
||||
* A vector of values that must not be referenced after the vector is destroyed.
|
||||
|
||||
+35
-35
@@ -69,7 +69,7 @@ std::string DrvInfo::queryName(EvalState & state)
|
||||
state.ctx.errors.make<TypeError>("derivation name missing").debugThrow();
|
||||
}
|
||||
name = state.forceStringNoCtx(
|
||||
*i->value, noPos, "while evaluating the 'name' attribute of a derivation"
|
||||
i->value, noPos, "while evaluating the 'name' attribute of a derivation"
|
||||
);
|
||||
}
|
||||
return name;
|
||||
@@ -83,7 +83,7 @@ std::string DrvInfo::querySystem(EvalState & state)
|
||||
system = !i
|
||||
? "unknown"
|
||||
: state.forceStringNoCtx(
|
||||
*i->value, i->pos, "while evaluating the 'system' attribute of a derivation"
|
||||
i->value, i->pos, "while evaluating the 'system' attribute of a derivation"
|
||||
);
|
||||
}
|
||||
return system;
|
||||
@@ -100,7 +100,7 @@ std::optional<StorePath> DrvInfo::queryDrvPath(EvalState & state)
|
||||
} else {
|
||||
drvPath = {state.coerceToStorePath(
|
||||
i->pos,
|
||||
*i->value,
|
||||
i->value,
|
||||
context,
|
||||
"while evaluating the 'drvPath' attribute of a derivation"
|
||||
)};
|
||||
@@ -125,7 +125,7 @@ StorePath DrvInfo::queryOutPath(EvalState & state)
|
||||
NixStringContext context;
|
||||
if (i) {
|
||||
outPath = state.coerceToStorePath(
|
||||
i->pos, *i->value, context, "while evaluating the output path of a derivation"
|
||||
i->pos, i->value, context, "while evaluating the output path of a derivation"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -158,17 +158,17 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths)
|
||||
|
||||
// NOTE(Qyriad): I don't think there is any codepath that can cause this to error.
|
||||
state.forceList(
|
||||
*outputs->value, outputs->pos, "while evaluating the 'outputs' attribute of a derivation"
|
||||
outputs->value, outputs->pos, "while evaluating the 'outputs' attribute of a derivation"
|
||||
);
|
||||
|
||||
for (auto [idx, elem] : enumerate(outputs->value->listItems())) {
|
||||
for (auto && [idx, elem] : enumerate(outputs->value.listItems())) {
|
||||
// NOTE(Qyriad): This error should be *extremely* rare in practice.
|
||||
// It is impossible to construct with `stdenv.mkDerivation`,
|
||||
// `builtins.derivation`, or even `derivationStrict`. As far as we can tell,
|
||||
// it is only possible by overriding a derivation attrset already created by
|
||||
// one of those with `//` to introduce the failing `outputs` entry.
|
||||
auto errMsg = fmt("while evaluating output %d of a derivation", idx);
|
||||
std::string_view outputName = state.forceStringNoCtx(*elem, outputs->pos, errMsg);
|
||||
std::string_view outputName = state.forceStringNoCtx(elem, outputs->pos, errMsg);
|
||||
|
||||
if (withPaths) {
|
||||
// Find the attr with this output's name...
|
||||
@@ -180,10 +180,10 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths)
|
||||
|
||||
// Meanwhile we couldn't figure out any circumstances
|
||||
// that cause this to error.
|
||||
state.forceAttrs(*out->value, outputs->pos, errMsg);
|
||||
state.forceAttrs(out->value, outputs->pos, errMsg);
|
||||
|
||||
// ...and evaluate its `outPath` attribute.
|
||||
const Attr * outPath = out->value->attrs()->get(state.ctx.s.outPath);
|
||||
const Attr * outPath = out->value.attrs()->get(state.ctx.s.outPath);
|
||||
if (outPath == nullptr) {
|
||||
continue;
|
||||
// FIXME: throw error?
|
||||
@@ -192,8 +192,7 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths)
|
||||
NixStringContext context;
|
||||
// And idk what could possibly cause this one to error
|
||||
// that wouldn't error before here.
|
||||
auto storePath =
|
||||
state.coerceToStorePath(outPath->pos, *outPath->value, context, errMsg);
|
||||
auto storePath = state.coerceToStorePath(outPath->pos, outPath->value, context, errMsg);
|
||||
this->outputs.emplace(outputName, storePath);
|
||||
} else {
|
||||
this->outputs.emplace(outputName, std::nullopt);
|
||||
@@ -225,7 +224,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state, bool withPaths, bool o
|
||||
// explicitly selected-into output.
|
||||
if (const Attr * outSpecAttr = attrs->get(state.ctx.s.outputSpecified)) {
|
||||
bool outputSpecified = state.forceBool(
|
||||
*outSpecAttr->value,
|
||||
outSpecAttr->value,
|
||||
outSpecAttr->pos,
|
||||
"while evaluating the 'outputSpecified' attribute of a derivation"
|
||||
);
|
||||
@@ -245,16 +244,16 @@ DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state, bool withPaths, bool o
|
||||
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
||||
if (!outTI->isList()) throw Error(errMsg + "expected a list but got %s", Uncolored(showType(outTI->type())));
|
||||
Outputs result;
|
||||
for (auto elem : outTI->listItems()) {
|
||||
if (elem->type() != nString) {
|
||||
for (auto & elem : outTI->listItems()) {
|
||||
if (elem.type() != nString) {
|
||||
throw Error(
|
||||
errMsg + "element is %s where a string was expected",
|
||||
Uncolored(showType(elem->type()))
|
||||
Uncolored(showType(elem.type()))
|
||||
);
|
||||
}
|
||||
auto out = outputs.find(std::string(elem->str()));
|
||||
auto out = outputs.find(std::string(elem.str()));
|
||||
if (out == outputs.end()) {
|
||||
throw Error(errMsg + "output '%s' does not exist", elem->str());
|
||||
throw Error(errMsg + "output '%s' does not exist", elem.str());
|
||||
}
|
||||
result.insert(*out);
|
||||
}
|
||||
@@ -267,7 +266,7 @@ std::string DrvInfo::queryOutputName(EvalState & state)
|
||||
if (outputName == "" && attrs) {
|
||||
auto i = attrs->get(state.ctx.s.outputName);
|
||||
outputName = i ? state.forceStringNoCtx(
|
||||
*i->value, noPos, "while evaluating the output name of a derivation"
|
||||
i->value, noPos, "while evaluating the output name of a derivation"
|
||||
)
|
||||
: "";
|
||||
}
|
||||
@@ -283,8 +282,8 @@ Bindings * DrvInfo::getMeta(EvalState & state)
|
||||
if (!a) {
|
||||
return 0;
|
||||
}
|
||||
state.forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
|
||||
meta = a->value->attrs();
|
||||
state.forceAttrs(a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
|
||||
meta = a->value.attrs();
|
||||
return meta;
|
||||
}
|
||||
|
||||
@@ -303,8 +302,8 @@ bool DrvInfo::checkMeta(EvalState & state, Value & v)
|
||||
{
|
||||
state.forceValue(v, noPos);
|
||||
if (v.type() == nList) {
|
||||
for (auto elem : v.listItems()) {
|
||||
if (!checkMeta(state, *elem)) {
|
||||
for (auto & elem : v.listItems()) {
|
||||
if (!checkMeta(state, elem)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -316,7 +315,7 @@ bool DrvInfo::checkMeta(EvalState & state, Value & v)
|
||||
return false;
|
||||
}
|
||||
for (auto & i : *v.attrs()) {
|
||||
if (!checkMeta(state, *i.value)) {
|
||||
if (!checkMeta(state, i.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -331,10 +330,10 @@ Value * DrvInfo::queryMeta(EvalState & state, const std::string & name)
|
||||
{
|
||||
if (!getMeta(state)) return 0;
|
||||
auto a = meta->get(state.ctx.symbols.create(name));
|
||||
if (!a || !checkMeta(state, *a->value)) {
|
||||
if (!a || !checkMeta(state, a->value)) {
|
||||
return 0;
|
||||
}
|
||||
return a->value;
|
||||
return &a->value;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,7 +391,7 @@ void DrvInfo::setMeta(EvalState & state, const std::string & name, Value & v)
|
||||
for (auto i : *meta)
|
||||
if (i.name != sym)
|
||||
attrs.insert(i);
|
||||
attrs.insert(sym, &v);
|
||||
attrs.insert(sym, v);
|
||||
meta = attrs.finish();
|
||||
}
|
||||
|
||||
@@ -464,13 +463,13 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos,
|
||||
if (v.type() == nList) {
|
||||
// NOTE we can't really deduplicate here because small lists don't have stable addresses
|
||||
// and can cause spurious duplicate detections due to v being on the stack.
|
||||
for (auto [n, elem] : enumerate(v.listItems())) {
|
||||
for (auto && [n, elem] : enumerate(v.listItems())) {
|
||||
std::string joinedAttrPath = addToPath(pathPrefix, fmt("%d", n));
|
||||
bool shouldRecurse =
|
||||
getDerivation(state, *elem, joinedAttrPath, drvs, ignoreAssertionFailures);
|
||||
getDerivation(state, elem, joinedAttrPath, drvs, ignoreAssertionFailures);
|
||||
if (shouldRecurse) {
|
||||
getDerivations(
|
||||
state, *elem, pos, joinedAttrPath, autoArgs, drvs, done, ignoreAssertionFailures
|
||||
state, elem, pos, joinedAttrPath, autoArgs, drvs, done, ignoreAssertionFailures
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -510,7 +509,7 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos,
|
||||
if (combineChannels) {
|
||||
getDerivations(
|
||||
state,
|
||||
*attr->value,
|
||||
attr->value,
|
||||
attr->pos,
|
||||
joinedAttrPath,
|
||||
autoArgs,
|
||||
@@ -518,18 +517,19 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos,
|
||||
done,
|
||||
ignoreAssertionFailures
|
||||
);
|
||||
} else if (getDerivation(state, *attr->value, joinedAttrPath, drvs, ignoreAssertionFailures)) {
|
||||
} else if (getDerivation(state, attr->value, joinedAttrPath, drvs, ignoreAssertionFailures))
|
||||
{
|
||||
/* If the value of this attribute is itself a set,
|
||||
should we recurse into it? => Only if it has a
|
||||
`recurseForDerivations = true' attribute. */
|
||||
if (attr->value->type() == nAttrs) {
|
||||
if (attr->value.type() == nAttrs) {
|
||||
const Attr * recurseForDrvs =
|
||||
attr->value->attrs()->get(state.ctx.s.recurseForDerivations);
|
||||
attr->value.attrs()->get(state.ctx.s.recurseForDerivations);
|
||||
if (recurseForDrvs == nullptr) {
|
||||
continue;
|
||||
}
|
||||
bool shouldRecurse = state.forceBool(
|
||||
*recurseForDrvs->value,
|
||||
recurseForDrvs->value,
|
||||
attr->pos,
|
||||
fmt("while evaluating the '%s' attribute", Magenta("recurseForDerivations"))
|
||||
);
|
||||
@@ -539,7 +539,7 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos,
|
||||
|
||||
getDerivations(
|
||||
state,
|
||||
*attr->value,
|
||||
attr->value,
|
||||
attr->pos,
|
||||
joinedAttrPath,
|
||||
autoArgs,
|
||||
|
||||
@@ -23,7 +23,7 @@ class JSONSax : nlohmann::json_sax<JSON> {
|
||||
explicit JSONState(std::unique_ptr<JSONState> && p) : parent(std::move(p)) {}
|
||||
JSONState() = default;
|
||||
JSONState(JSONState & p) = delete;
|
||||
Value & value(EvalState & state)
|
||||
Value & value()
|
||||
{
|
||||
if (!v) {
|
||||
v = allocRootValue({});
|
||||
@@ -31,7 +31,7 @@ class JSONSax : nlohmann::json_sax<JSON> {
|
||||
return *v;
|
||||
}
|
||||
virtual ~JSONState() {}
|
||||
virtual void add(EvalState & state) {}
|
||||
virtual void add() {}
|
||||
};
|
||||
|
||||
class JSONObjectState : public JSONState {
|
||||
@@ -41,17 +41,14 @@ class JSONSax : nlohmann::json_sax<JSON> {
|
||||
std::unique_ptr<JSONState> resolve(EvalState & state) override
|
||||
{
|
||||
auto attrs2 = state.ctx.buildBindings(attrs.size());
|
||||
for (auto & i : attrs) {
|
||||
auto v = state.ctx.mem.allocValue();
|
||||
*v = i.second;
|
||||
attrs2.insert(i.first, v);
|
||||
}
|
||||
parent->value(state).mkAttrs(attrs2.alreadySorted());
|
||||
for (auto & i : attrs)
|
||||
attrs2.insert(i.first, i.second);
|
||||
parent->value().mkAttrs(attrs2.alreadySorted());
|
||||
return std::move(parent);
|
||||
}
|
||||
void add(EvalState & state) override
|
||||
void add() override
|
||||
{
|
||||
attrs.insert_or_assign(_key, value(state));
|
||||
attrs.insert_or_assign(_key, value());
|
||||
v = nullptr;
|
||||
}
|
||||
public:
|
||||
@@ -66,13 +63,13 @@ class JSONSax : nlohmann::json_sax<JSON> {
|
||||
std::unique_ptr<JSONState> resolve(EvalState & state) override
|
||||
{
|
||||
auto list = state.ctx.mem.newList(values.size());
|
||||
parent->value(state) = {NewValueAs::list, list};
|
||||
parent->value() = {NewValueAs::list, list};
|
||||
for (size_t n = 0; n < values.size(); ++n) {
|
||||
*(list->elems[n] = state.ctx.mem.allocValue()) = values[n];
|
||||
list->elems[n] = values[n];
|
||||
}
|
||||
return std::move(parent);
|
||||
}
|
||||
void add(EvalState & state) override
|
||||
void add() override
|
||||
{
|
||||
values.push_back(*v);
|
||||
v = nullptr;
|
||||
@@ -92,27 +89,27 @@ public:
|
||||
|
||||
Value result()
|
||||
{
|
||||
return rs->value(state);
|
||||
return rs->value();
|
||||
}
|
||||
|
||||
bool null() override
|
||||
{
|
||||
rs->value(state).mkNull();
|
||||
rs->add(state);
|
||||
rs->value().mkNull();
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool val) override
|
||||
{
|
||||
rs->value(state).mkBool(val);
|
||||
rs->add(state);
|
||||
rs->value().mkBool(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t val) override
|
||||
{
|
||||
rs->value(state).mkInt(val);
|
||||
rs->add(state);
|
||||
rs->value().mkInt(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -124,22 +121,22 @@ public:
|
||||
return number_float(static_cast<number_float_t>(val_), "");
|
||||
}
|
||||
NixInt::Inner val = val_;
|
||||
rs->value(state).mkInt(val);
|
||||
rs->add(state);
|
||||
rs->value().mkInt(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t & s) override
|
||||
{
|
||||
rs->value(state).mkFloat(val);
|
||||
rs->add(state);
|
||||
rs->value().mkFloat(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t & val) override
|
||||
{
|
||||
rs->value(state).mkString(val);
|
||||
rs->add(state);
|
||||
rs->value().mkString(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -166,7 +163,7 @@ public:
|
||||
|
||||
bool end_object() override {
|
||||
rs = rs->resolve(state);
|
||||
rs->add(state);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
virtual JSON toJSON(const SymbolTable & symbols) const;
|
||||
virtual void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) = 0;
|
||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||
virtual Value * maybeThunk(EvalState & state, Env & env);
|
||||
virtual Value maybeThunk(EvalState & state, Env & env);
|
||||
virtual void setName(Symbol name);
|
||||
PosIdx getPos() const { return pos; }
|
||||
|
||||
@@ -175,7 +175,7 @@ protected:
|
||||
Value v;
|
||||
ExprLiteral(const PosIdx pos) : Expr(pos) {};
|
||||
public:
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
@@ -253,7 +253,7 @@ struct ExprVar : Expr
|
||||
|
||||
ExprVar(Symbol name) : name(name), needsRoot(false) { };
|
||||
ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : Expr(pos), name(name), needsRoot(needsRoot) { };
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
@@ -395,7 +395,7 @@ struct ExprList : Expr
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
};
|
||||
|
||||
struct Pattern {
|
||||
|
||||
+133
-141
@@ -189,11 +189,10 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v)
|
||||
|
||||
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
||||
mkOutputString(state, attrs, *storePath, o);
|
||||
(outputsList->elems[i] = state.ctx.mem.allocValue())->mkString(o.first);
|
||||
outputsList->elems[i].mkString(o.first);
|
||||
}
|
||||
|
||||
auto w = state.ctx.mem.allocValue();
|
||||
w->mkAttrs(attrs);
|
||||
Value w{NewValueAs::attrs, attrs.finish()};
|
||||
|
||||
if (!state.ctx.caches.vImportedDrvToDerivation) {
|
||||
state.ctx.caches.vImportedDrvToDerivation = allocRootValue({});
|
||||
@@ -211,7 +210,7 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v)
|
||||
noPos,
|
||||
"while evaluating imported-drv-to-derivation.nix.gen.hh"
|
||||
);
|
||||
v = {NewValueAs::app, state.ctx.mem, *state.ctx.caches.vImportedDrvToDerivation, *w};
|
||||
v = {NewValueAs::app, state.ctx.mem, *state.ctx.caches.vImportedDrvToDerivation, w};
|
||||
state.forceAttrs(v, noPos, "while calling imported-drv-to-derivation.nix.gen.hh");
|
||||
}
|
||||
|
||||
@@ -307,7 +306,7 @@ void prim_exec(EvalState & state, Value * * args, Value & v)
|
||||
state
|
||||
.coerceToString(
|
||||
noPos,
|
||||
*elems[0],
|
||||
elems[0],
|
||||
context,
|
||||
"while evaluating the first element of the argument passed to builtins.exec",
|
||||
StringCoercionMode::Strict,
|
||||
@@ -320,7 +319,7 @@ void prim_exec(EvalState & state, Value * * args, Value & v)
|
||||
state
|
||||
.coerceToString(
|
||||
noPos,
|
||||
*elems[i],
|
||||
elems[i],
|
||||
context,
|
||||
"while evaluating an element of the argument passed to builtins.exec",
|
||||
StringCoercionMode::Strict,
|
||||
@@ -489,12 +488,12 @@ struct CompareValues : NeverAsync
|
||||
} else if (i == v1.listSize()) {
|
||||
return true;
|
||||
} else if (!state.eqValues(
|
||||
*v1.listElems()[i], *v2.listElems()[i], noPos, errorCtx
|
||||
v1.listElems()[i], v2.listElems()[i], noPos, errorCtx
|
||||
))
|
||||
{
|
||||
return (*this)(
|
||||
*v1.listElems()[i],
|
||||
*v2.listElems()[i],
|
||||
v1.listElems()[i],
|
||||
v2.listElems()[i],
|
||||
"while comparing two list elements"
|
||||
);
|
||||
}
|
||||
@@ -547,18 +546,18 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
);
|
||||
|
||||
state.forceList(
|
||||
*startSet->value,
|
||||
startSet->value,
|
||||
noPos,
|
||||
"while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure"
|
||||
);
|
||||
|
||||
UnsafeValueList workSet;
|
||||
for (auto elem : startSet->value->listItems()) {
|
||||
workSet.push_back(elem);
|
||||
for (auto & elem : startSet->value.listItems()) {
|
||||
workSet.push_back(&elem);
|
||||
}
|
||||
|
||||
if (startSet->value->listSize() == 0) {
|
||||
v = *startSet->value;
|
||||
if (startSet->value.listSize() == 0) {
|
||||
v = startSet->value;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -570,7 +569,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
"in the attrset passed as argument to builtins.genericClosure"
|
||||
);
|
||||
state.forceFunction(
|
||||
*op->value,
|
||||
op->value,
|
||||
noPos,
|
||||
"while evaluating the 'operator' attribute passed as argument to builtins.genericClosure"
|
||||
);
|
||||
@@ -595,22 +594,23 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
e->attrs(),
|
||||
"in one of the attrsets generated by (or initially passed to) builtins.genericClosure"
|
||||
);
|
||||
state.forceValue(*key->value, noPos);
|
||||
state.forceValue(key->value, noPos);
|
||||
|
||||
if (!doneKeys.insert(key->value).second) {
|
||||
if (!doneKeys.insert(&key->value).second) {
|
||||
continue;
|
||||
}
|
||||
res.push_back(e);
|
||||
|
||||
/* Call the `operator' function with `e' as argument. */
|
||||
Value newElements;
|
||||
state.callFunction(*op->value, {&e, 1}, newElements, noPos);
|
||||
state.callFunction(op->value, {e, 1}, newElements, noPos);
|
||||
state.forceList(newElements, noPos, "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 : newElements.listItems()) {
|
||||
state.forceValue(*elem, noPos); // "while evaluating one one of the elements returned by the `operator` passed to builtins.genericClosure");
|
||||
workSet.push_back(elem);
|
||||
for (auto & elem : newElements.listItems()) {
|
||||
state.forceValue(elem, noPos); // "while evaluating one one of the elements returned by
|
||||
// the `operator` passed to builtins.genericClosure");
|
||||
workSet.push_back(&elem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
v = {NewValueAs::list, result};
|
||||
unsigned int n = 0;
|
||||
for (auto & i : res)
|
||||
result->elems[n++] = i;
|
||||
result->elems[n++] = *i;
|
||||
}
|
||||
|
||||
|
||||
@@ -719,7 +719,7 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v)
|
||||
return true;
|
||||
}();
|
||||
if (success)
|
||||
attrs.insert(state.ctx.s.value, args[0]);
|
||||
attrs.insert(state.ctx.s.value, *args[0]);
|
||||
else
|
||||
attrs.alloc(state.ctx.s.value).mkBool(false);
|
||||
attrs.alloc("success").mkBool(success);
|
||||
@@ -810,7 +810,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
std::string drvName;
|
||||
try {
|
||||
drvName = state.forceStringNoCtx(
|
||||
*nameAttr->value,
|
||||
nameAttr->value,
|
||||
noPos,
|
||||
"while evaluating the `name` attribute passed to builtins.derivationStrict"
|
||||
);
|
||||
@@ -858,7 +858,7 @@ drvName, Bindings * attrs, Value & v)
|
||||
auto attr = attrs->get(state.ctx.s.structuredAttrs);
|
||||
if (attr
|
||||
&& state.forceBool(
|
||||
*attr->value,
|
||||
attr->value,
|
||||
attr->pos,
|
||||
"while evaluating the `__structuredAttrs` "
|
||||
"attribute passed to builtins.derivationStrict"
|
||||
@@ -872,7 +872,7 @@ drvName, Bindings * attrs, Value & v)
|
||||
attr = attrs->get(state.ctx.s.ignoreNulls);
|
||||
if (attr) {
|
||||
ignoreNulls = state.forceBool(
|
||||
*attr->value,
|
||||
attr->value,
|
||||
attr->pos,
|
||||
"while evaluating the `__ignoreNulls` attribute "
|
||||
"passed to builtins.derivationStrict"
|
||||
@@ -933,21 +933,21 @@ drvName, Bindings * attrs, Value & v)
|
||||
const std::string_view context_below("");
|
||||
|
||||
if (ignoreNulls) {
|
||||
state.forceValue(*i->value, noPos);
|
||||
if (i->value->type() == nNull) {
|
||||
state.forceValue(i->value, noPos);
|
||||
if (i->value.type() == nNull) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (i->name == state.ctx.s.contentAddressed
|
||||
&& state.forceBool(*i->value, noPos, context_below))
|
||||
&& state.forceBool(i->value, noPos, context_below))
|
||||
{
|
||||
state.ctx.errors.make<EvalError>("ca derivations are not supported in Lix")
|
||||
.debugThrow();
|
||||
}
|
||||
|
||||
else if (i->name == state.ctx.s.impure
|
||||
&& state.forceBool(*i->value, noPos, context_below))
|
||||
&& state.forceBool(i->value, noPos, context_below))
|
||||
{
|
||||
state.ctx.errors.make<EvalError>("impure derivations are not supported in Lix")
|
||||
.debugThrow();
|
||||
@@ -957,12 +957,12 @@ drvName, Bindings * attrs, Value & v)
|
||||
command-line arguments to the builder. */
|
||||
else if (i->name == state.ctx.s.args)
|
||||
{
|
||||
state.forceList(*i->value, noPos, context_below);
|
||||
for (auto elem : i->value->listItems()) {
|
||||
state.forceList(i->value, noPos, context_below);
|
||||
for (auto & elem : i->value.listItems()) {
|
||||
auto s = state
|
||||
.coerceToString(
|
||||
noPos,
|
||||
*elem,
|
||||
elem,
|
||||
context,
|
||||
"while evaluating an element of the argument list",
|
||||
StringCoercionMode::ToString
|
||||
@@ -982,24 +982,24 @@ drvName, Bindings * attrs, Value & v)
|
||||
if (i->name == state.ctx.s.structuredAttrs) continue;
|
||||
|
||||
(*jsonObject)[std::string(key)] =
|
||||
printValueAsJSON(state, true, *i->value, noPos, context);
|
||||
printValueAsJSON(state, true, i->value, noPos, context);
|
||||
|
||||
if (i->name == state.ctx.s.builder)
|
||||
drv.builder = state.forceString(*i->value, context, noPos, context_below);
|
||||
drv.builder = state.forceString(i->value, context, noPos, context_below);
|
||||
else if (i->name == state.ctx.s.system)
|
||||
drv.platform = state.forceStringNoCtx(*i->value, noPos, context_below);
|
||||
drv.platform = state.forceStringNoCtx(i->value, noPos, context_below);
|
||||
else if (i->name == state.ctx.s.outputHash)
|
||||
outputHash = state.forceStringNoCtx(*i->value, noPos, context_below);
|
||||
outputHash = state.forceStringNoCtx(i->value, noPos, context_below);
|
||||
else if (i->name == state.ctx.s.outputHashAlgo)
|
||||
outputHashAlgo = state.forceStringNoCtx(*i->value, noPos, context_below);
|
||||
outputHashAlgo = state.forceStringNoCtx(i->value, noPos, context_below);
|
||||
else if (i->name == state.ctx.s.outputHashMode)
|
||||
handleHashMode(state.forceStringNoCtx(*i->value, noPos, context_below));
|
||||
handleHashMode(state.forceStringNoCtx(i->value, noPos, context_below));
|
||||
else if (i->name == state.ctx.s.outputs) {
|
||||
/* Require ‘outputs’ to be a list of strings. */
|
||||
state.forceList(*i->value, noPos, context_below);
|
||||
state.forceList(i->value, noPos, context_below);
|
||||
Strings ss;
|
||||
for (auto elem : i->value->listItems()) {
|
||||
ss.emplace_back(state.forceStringNoCtx(*elem, noPos, context_below));
|
||||
for (auto & elem : i->value.listItems()) {
|
||||
ss.emplace_back(state.forceStringNoCtx(elem, noPos, context_below));
|
||||
}
|
||||
handleOutputs(ss);
|
||||
}
|
||||
@@ -1051,7 +1051,7 @@ drvName, Bindings * attrs, Value & v)
|
||||
auto s = state
|
||||
.coerceToString(
|
||||
noPos,
|
||||
*i->value,
|
||||
i->value,
|
||||
context,
|
||||
context_below,
|
||||
StringCoercionMode::ToString
|
||||
@@ -1381,29 +1381,29 @@ static void prim_findFile(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
SearchPath searchPath;
|
||||
|
||||
for (auto v2 : args[0]->listItems()) {
|
||||
for (auto & v2 : args[0]->listItems()) {
|
||||
state.forceAttrs(
|
||||
*v2, noPos, "while evaluating an element of the list passed to builtins.findFile"
|
||||
v2, noPos, "while evaluating an element of the list passed to builtins.findFile"
|
||||
);
|
||||
|
||||
std::string prefix;
|
||||
auto i = v2->attrs()->get(state.ctx.s.prefix);
|
||||
auto i = v2.attrs()->get(state.ctx.s.prefix);
|
||||
if (i) {
|
||||
prefix = state.forceStringNoCtx(
|
||||
*i->value,
|
||||
i->value,
|
||||
noPos,
|
||||
"while evaluating the `prefix` attribute of an element of the list passed to "
|
||||
"builtins.findFile"
|
||||
);
|
||||
}
|
||||
|
||||
i = getAttr(state, state.ctx.s.path, v2->attrs(), "in an element of the __nixPath");
|
||||
i = getAttr(state, state.ctx.s.path, v2.attrs(), "in an element of the __nixPath");
|
||||
|
||||
NixStringContext context;
|
||||
auto path = state
|
||||
.coerceToString(
|
||||
noPos,
|
||||
*i->value,
|
||||
i->value,
|
||||
context,
|
||||
"while evaluating the `path` attribute of an element of the list "
|
||||
"passed to builtins.findFile",
|
||||
@@ -1488,11 +1488,11 @@ static void prim_readDir(EvalState & state, Value * * args, Value & v)
|
||||
// Some filesystems or operating systems may not be able to return
|
||||
// detailed node info quickly in this case we produce a thunk to
|
||||
// query the file type lazily.
|
||||
auto epath = state.ctx.mem.allocValue();
|
||||
epath->mkPath(path + name);
|
||||
Value epath;
|
||||
epath.mkPath(path + name);
|
||||
if (!readFileType)
|
||||
readFileType = &state.ctx.builtins.get("readFileType");
|
||||
attr = {NewValueAs::app, state.ctx.mem, *readFileType, *epath};
|
||||
attr = {NewValueAs::app, state.ctx.mem, *readFileType, epath};
|
||||
} else {
|
||||
// This branch of the conditional is much more likely.
|
||||
// Here we just stringize the directory entry type.
|
||||
@@ -1630,7 +1630,7 @@ static void addPath(
|
||||
S_ISLNK(st.st_mode) ? "symlink" :
|
||||
"unknown" /* not supported, will fail! */);
|
||||
|
||||
Value * args []{&arg1, &arg2};
|
||||
Value args[]{arg1, arg2};
|
||||
Value res;
|
||||
state.callFunction(*filterFun, args, res, noPos);
|
||||
|
||||
@@ -1697,32 +1697,32 @@ static void prim_path(EvalState & state, Value * * args, Value & v)
|
||||
if (n == "path") {
|
||||
path.emplace(state.coerceToPath(
|
||||
attr.pos,
|
||||
*attr.value,
|
||||
attr.value,
|
||||
context,
|
||||
"while evaluating the 'path' attribute passed to 'builtins.path'"
|
||||
));
|
||||
} else if (attr.name == state.ctx.s.name) {
|
||||
name = state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the `name` attribute passed to builtins.path"
|
||||
);
|
||||
} else if (n == "filter") {
|
||||
state.forceFunction(
|
||||
*(filterFun = attr.value),
|
||||
*(filterFun = &attr.value),
|
||||
attr.pos,
|
||||
"while evaluating the `filter` parameter passed to builtins.path"
|
||||
);
|
||||
} else if (n == "recursive") {
|
||||
method = FileIngestionMethod{state.forceBool(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the `recursive` attribute passed to builtins.path"
|
||||
)};
|
||||
} else if (n == "sha256") {
|
||||
expectedHash = newHashAllowEmpty(
|
||||
state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the `sha256` attribute passed to builtins.path"
|
||||
),
|
||||
@@ -1764,10 +1764,10 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
size_t n = 0;
|
||||
for (auto & i : *args[0]->attrs())
|
||||
result->elems[n++] = const_cast<Value *>(state.ctx.symbols[i.name].toValuePtr());
|
||||
result->elems[n++] = state.ctx.symbols[i.name].toValue();
|
||||
|
||||
std::sort(result->elems, result->elems + n, [](Value * v1, Value * v2) {
|
||||
return v1->str() < v2->str();
|
||||
std::sort(result->elems, result->elems + n, [](Value & v1, Value & v2) {
|
||||
return v1.str() < v2.str();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1809,8 +1809,8 @@ void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
||||
);
|
||||
// !!! add to stack trace?
|
||||
if (state.ctx.stats.countCalls && i->pos) state.ctx.stats.attrSelects[i->pos]++;
|
||||
state.forceValue(*i->value, noPos);
|
||||
v = *i->value;
|
||||
state.forceValue(i->value, noPos);
|
||||
v = i->value;
|
||||
}
|
||||
|
||||
/* Return position information of the specified attribute. */
|
||||
@@ -1859,10 +1859,9 @@ static struct LazyPosAcessors {
|
||||
|
||||
void operator()(EvalState & state, const PosIdx pos, Value & line, Value & column)
|
||||
{
|
||||
Value * posV = state.ctx.mem.allocValue();
|
||||
posV->mkInt(pos.id);
|
||||
line = {NewValueAs::app, state.ctx.mem, lineOfPos, *posV};
|
||||
column = {NewValueAs::app, state.ctx.mem, columnOfPos, *posV};
|
||||
Value posV{NewValueAs::integer, NixInt{pos.id}};
|
||||
line = {NewValueAs::app, state.ctx.mem, lineOfPos, posV};
|
||||
column = {NewValueAs::app, state.ctx.mem, columnOfPos, posV};
|
||||
}
|
||||
} makeLazyPosAccessors;
|
||||
|
||||
@@ -1897,13 +1896,13 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
|
||||
// 64: large enough to fit the attributes of a derivation
|
||||
boost::container::small_vector<Attr, 64> names;
|
||||
names.reserve(args[1]->listSize());
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
for (auto & elem : args[1]->listItems()) {
|
||||
state.forceStringNoCtx(
|
||||
*elem,
|
||||
elem,
|
||||
noPos,
|
||||
"while evaluating the values of the second argument passed to builtins.removeAttrs"
|
||||
);
|
||||
names.emplace_back(state.ctx.symbols.create(elem->str()), nullptr);
|
||||
names.emplace_back(state.ctx.symbols.create(elem.str()), Value());
|
||||
}
|
||||
std::sort(names.begin(), names.end());
|
||||
|
||||
@@ -1931,15 +1930,15 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
std::set<Symbol> seen;
|
||||
|
||||
for (auto v2 : args[0]->listItems()) {
|
||||
for (auto & v2 : args[0]->listItems()) {
|
||||
state.forceAttrs(
|
||||
*v2, noPos, "while evaluating an element of the list passed to builtins.listToAttrs"
|
||||
v2, noPos, "while evaluating an element of the list passed to builtins.listToAttrs"
|
||||
);
|
||||
|
||||
auto j = getAttr(state, state.ctx.s.name, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
auto j = getAttr(state, state.ctx.s.name, v2.attrs(), "in a {name=...; value=...;} pair");
|
||||
|
||||
auto name = state.forceStringNoCtx(
|
||||
*j->value,
|
||||
j->value,
|
||||
j->pos,
|
||||
"while evaluating the `name` attribute of an element of the list passed to "
|
||||
"builtins.listToAttrs"
|
||||
@@ -1948,7 +1947,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
||||
auto sym = state.ctx.symbols.create(name);
|
||||
if (seen.insert(sym).second) {
|
||||
auto j2 =
|
||||
getAttr(state, state.ctx.s.value, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
getAttr(state, state.ctx.s.value, v2.attrs(), "in a {name=...; value=...;} pair");
|
||||
attrs.insert(sym, j2->value, j2->pos);
|
||||
}
|
||||
}
|
||||
@@ -2032,13 +2031,13 @@ static void prim_catAttrs(EvalState & state, Value * * args, Value & v)
|
||||
SmallValueVector<nonRecursiveStackReservation> res(args[1]->listSize());
|
||||
size_t found = 0;
|
||||
|
||||
for (auto v2 : args[1]->listItems()) {
|
||||
for (auto & v2 : args[1]->listItems()) {
|
||||
state.forceAttrs(
|
||||
*v2,
|
||||
v2,
|
||||
noPos,
|
||||
"while evaluating an element in the list passed as second argument to builtins.catAttrs"
|
||||
);
|
||||
auto i = v2->attrs()->get(attrName);
|
||||
auto i = v2.attrs()->get(attrName);
|
||||
if (i) {
|
||||
res[found++] = i->value;
|
||||
}
|
||||
@@ -2082,8 +2081,8 @@ static void prim_mapAttrs(EvalState & state, Value * * args, Value & v)
|
||||
auto attrs = state.ctx.buildBindings(args[1]->attrs()->size());
|
||||
|
||||
for (auto & i : *args[1]->attrs()) {
|
||||
auto vName = const_cast<Value *>(state.ctx.symbols[i.name].toValuePtr());
|
||||
Value * appArgs[] = {vName, i.value};
|
||||
auto vName = state.ctx.symbols[i.name].toValue();
|
||||
Value appArgs[] = {vName, i.value};
|
||||
attrs.alloc(i.name) = {NewValueAs::app, state.ctx.mem, *args[0], appArgs};
|
||||
}
|
||||
|
||||
@@ -2099,7 +2098,7 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v)
|
||||
// attribute with the merge function application. this way we need not
|
||||
// use (slightly slower) temporary storage the GC does not know about.
|
||||
|
||||
std::map<Symbol, std::pair<size_t, Value * *>> attrsSeen;
|
||||
std::map<Symbol, std::pair<size_t, Value *>> attrsSeen;
|
||||
|
||||
state.forceFunction(*args[0], noPos, "while evaluating the first argument passed to builtins.zipAttrsWith");
|
||||
state.forceList(*args[1], noPos, "while evaluating the second argument passed to builtins.zipAttrsWith");
|
||||
@@ -2107,14 +2106,14 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v)
|
||||
const auto listElems = args[1]->listElems();
|
||||
|
||||
for (unsigned int n = 0; n < listSize; ++n) {
|
||||
Value * vElem = listElems[n];
|
||||
Value & vElem = listElems[n];
|
||||
state.forceAttrs(
|
||||
*vElem,
|
||||
vElem,
|
||||
noPos,
|
||||
"while evaluating a value of the list passed as second argument to "
|
||||
"builtins.zipAttrsWith"
|
||||
);
|
||||
for (auto & attr : *vElem->attrs()) {
|
||||
for (auto & attr : *vElem.attrs()) {
|
||||
attrsSeen[attr.name].first++;
|
||||
}
|
||||
}
|
||||
@@ -2122,16 +2121,14 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v)
|
||||
auto attrs = state.ctx.buildBindings(attrsSeen.size());
|
||||
for (auto & [sym, elem] : attrsSeen) {
|
||||
/* Take care of the returned lists. */
|
||||
auto list = state.ctx.mem.allocValue();
|
||||
auto content = state.ctx.mem.newList(elem.first);
|
||||
*list = {NewValueAs::list, content};
|
||||
Value list{NewValueAs::list, content};
|
||||
elem.second = content->elems;
|
||||
|
||||
/* Construct a `fn name list` function call value. */
|
||||
auto name = const_cast<Value *>(state.ctx.symbols[sym].toValuePtr());
|
||||
Value * callArgs[] = {name, list};
|
||||
auto call = state.ctx.mem.allocValue();
|
||||
*call = {NewValueAs::app, state.ctx.mem, *args[0], callArgs};
|
||||
auto name = state.ctx.symbols[sym].toValue();
|
||||
Value callArgs[] = {name, list};
|
||||
Value call{NewValueAs::app, state.ctx.mem, *args[0], callArgs};
|
||||
|
||||
/* Insert it inside the returned attribute set. */
|
||||
attrs.insert(sym, call);
|
||||
@@ -2139,8 +2136,8 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
/* Populate the lists inside the attribute set */
|
||||
for (unsigned int n = 0; n < listSize; ++n) {
|
||||
Value * vElem = listElems[n];
|
||||
for (auto & attr : *vElem->attrs()) {
|
||||
Value & vElem = listElems[n];
|
||||
for (auto & attr : *vElem.attrs()) {
|
||||
*attrsSeen[attr.name].second++ = attr.value;
|
||||
}
|
||||
}
|
||||
@@ -2167,8 +2164,8 @@ static void elemAt(EvalState & state, Value & list, NixInt::Inner n, Value & v)
|
||||
if (n < 0 || std::make_unsigned_t<NixInt::Inner>(n) >= list.listSize()) {
|
||||
state.ctx.errors.make<EvalError>("list index %1% is out of bounds", n).debugThrow();
|
||||
}
|
||||
state.forceValue(*list.listElems()[n], noPos);
|
||||
v = *list.listElems()[n];
|
||||
state.forceValue(list.listElems()[n], noPos);
|
||||
v = list.listElems()[n];
|
||||
}
|
||||
|
||||
/* Return the n-1'th element of a list. */
|
||||
@@ -2214,8 +2211,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
|
||||
auto result = state.ctx.mem.newList(args[1]->listSize());
|
||||
v = {NewValueAs::list, result};
|
||||
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||
result->elems[n] = state.ctx.mem.allocValue();
|
||||
*result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], *args[1]->listElems()[n]};
|
||||
result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], args[1]->listElems()[n]};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2240,7 +2236,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v)
|
||||
bool same = true;
|
||||
for (size_t n = 0; n < len; ++n) {
|
||||
Value res;
|
||||
state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
|
||||
state.callFunction(*args[0], args[1]->listElems()[n], res, noPos);
|
||||
if (state.forceBool(res, noPos, "while evaluating the return value of the filtering function passed to builtins.filter"))
|
||||
vs[k++] = args[1]->listElems()[n];
|
||||
else
|
||||
@@ -2263,10 +2259,10 @@ static void prim_elem(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
bool res = false;
|
||||
state.forceList(*args[1], noPos, "while evaluating the second argument passed to builtins.elem");
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
for (auto & elem : args[1]->listItems()) {
|
||||
if (state.eqValues(
|
||||
*args[0],
|
||||
*elem,
|
||||
elem,
|
||||
noPos,
|
||||
"while searching for the presence of the given element in the list"
|
||||
))
|
||||
@@ -2284,8 +2280,7 @@ static void prim_concatLists(EvalState & state, Value * * args, Value & v)
|
||||
state.forceList(*args[0], noPos, "while evaluating the first argument passed to builtins.concatLists");
|
||||
state.concatLists(
|
||||
v,
|
||||
args[0]->listSize(),
|
||||
args[0]->listElems(),
|
||||
std::span{args[0]->listElems(), args[0]->listSize()},
|
||||
noPos,
|
||||
"while evaluating a value of the list passed to builtins.concatLists"
|
||||
);
|
||||
@@ -2306,13 +2301,13 @@ static void prim_foldlStrict(EvalState & state, Value * * args, Value & v)
|
||||
state.forceList(*args[2], noPos, "while evaluating the third argument passed to builtins.foldlStrict");
|
||||
|
||||
if (args[2]->listSize()) {
|
||||
Value * vCur = args[1];
|
||||
Value vCur = *args[1];
|
||||
|
||||
for (auto [n, elem] : enumerate(args[2]->listItems())) {
|
||||
Value * vs []{vCur, elem};
|
||||
vCur = n == args[2]->listSize() - 1 ? &v : state.ctx.mem.allocValue();
|
||||
state.callFunction(*args[0], vs, *vCur, noPos);
|
||||
for (auto && [n, elem] : enumerate(args[2]->listItems())) {
|
||||
Value vs[]{vCur, elem};
|
||||
state.callFunction(*args[0], vs, vCur, noPos);
|
||||
}
|
||||
v = vCur;
|
||||
state.forceValue(v, noPos);
|
||||
} else {
|
||||
state.forceValue(*args[1], noPos);
|
||||
@@ -2330,8 +2325,8 @@ static void anyOrAll(bool any, EvalState & state, Value * * args, Value & v)
|
||||
: "while evaluating the return value of the function passed to builtins.all";
|
||||
|
||||
Value vTmp;
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
state.callFunction(*args[0], *elem, vTmp, noPos);
|
||||
for (auto & elem : args[1]->listItems()) {
|
||||
state.callFunction(*args[0], elem, vTmp, noPos);
|
||||
bool res = state.forceBool(vTmp, noPos, errorCtx);
|
||||
if (res == any) {
|
||||
v.mkBool(any);
|
||||
@@ -2371,10 +2366,8 @@ static void prim_genList(EvalState & state, Value * * args, Value & v)
|
||||
auto result = state.ctx.mem.newList(len);
|
||||
v = {NewValueAs::list, result};
|
||||
for (size_t n = 0; n < len; ++n) {
|
||||
auto arg = state.ctx.mem.allocValue();
|
||||
arg->mkInt(n);
|
||||
result->elems[n] = state.ctx.mem.allocValue();
|
||||
*result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], *arg};
|
||||
Value arg{NewValueAs::integer, NixInt{ssize_t(n)}};
|
||||
result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], arg};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2396,11 +2389,11 @@ static void prim_sort(EvalState & state, Value * * args, Value & v)
|
||||
auto list = state.ctx.mem.newList(len);
|
||||
v = {NewValueAs::list, list};
|
||||
for (unsigned int n = 0; n < len; ++n) {
|
||||
state.forceValue(*args[1]->listElems()[n], noPos);
|
||||
state.forceValue(args[1]->listElems()[n], noPos);
|
||||
list->elems[n] = args[1]->listElems()[n];
|
||||
}
|
||||
|
||||
auto comparator = [&](Value * a, Value * b) {
|
||||
auto comparator = [&](Value a, Value b) {
|
||||
/* Optimization: if the comparator is lessThan, bypass
|
||||
callFunction. */
|
||||
/* TODO: (layus) this is absurd. An optimisation like this
|
||||
@@ -2408,10 +2401,10 @@ static void prim_sort(EvalState & state, Value * * args, Value & v)
|
||||
if (args[0]->isPrimOp()) {
|
||||
auto ptr = args[0]->primOp()->fun.target<decltype(&prim_lessThan)>();
|
||||
if (ptr && *ptr == prim_lessThan)
|
||||
return CompareValues(state, "while evaluating the ordering function passed to builtins.sort")(*a, *b);
|
||||
return CompareValues(state, "while evaluating the ordering function passed to builtins.sort")(a, b);
|
||||
}
|
||||
|
||||
Value * vs[] = {a, b};
|
||||
Value vs[] = {a, b};
|
||||
Value vBool;
|
||||
state.callFunction(*args[0], vs, vBool, noPos);
|
||||
return state.forceBool(vBool, noPos, "while evaluating the return value of the sorting function passed to builtins.sort");
|
||||
@@ -2434,10 +2427,10 @@ static void prim_partition(EvalState & state, Value * * args, Value & v)
|
||||
std::vector<size_t> right, wrong;
|
||||
|
||||
for (size_t n = 0; n < len; ++n) {
|
||||
auto vElem = elems[n];
|
||||
state.forceValue(*vElem, noPos);
|
||||
auto & vElem = args[1]->listElems()[n];
|
||||
state.forceValue(vElem, noPos);
|
||||
Value res;
|
||||
state.callFunction(*args[0], *vElem, res, noPos);
|
||||
state.callFunction(*args[0], vElem, res, noPos);
|
||||
if (state.forceBool(res, noPos, "while evaluating the return value of the partition function passed to builtins.partition"))
|
||||
right.push_back(n);
|
||||
else
|
||||
@@ -2476,7 +2469,7 @@ static void prim_groupBy(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
for (auto [i, vElem] : enumerate(args[1]->listItems())) {
|
||||
Value res;
|
||||
state.callFunction(*args[0], *vElem, res, noPos);
|
||||
state.callFunction(*args[0], vElem, res, noPos);
|
||||
auto name = state.forceStringNoCtx(res, noPos, "while evaluating the return value of the grouping function passed to builtins.groupBy");
|
||||
auto sym = state.ctx.symbols.create(name);
|
||||
auto vector = attrs.try_emplace(sym, std::vector<size_t>()).first;
|
||||
@@ -2509,8 +2502,8 @@ static void prim_concatMap(EvalState & state, Value * * args, Value & v)
|
||||
size_t len = 0;
|
||||
|
||||
for (size_t n = 0; n < nrLists; ++n) {
|
||||
Value * vElem = args[1]->listElems()[n];
|
||||
state.callFunction(*args[0], *vElem, lists[n], noPos);
|
||||
Value & vElem = args[1]->listElems()[n];
|
||||
state.callFunction(*args[0], vElem, lists[n], noPos);
|
||||
state.forceList(lists[n], noPos, "while evaluating the return value of the function passed to builtins.concatMap");
|
||||
len += lists[n].listSize();
|
||||
}
|
||||
@@ -2521,7 +2514,7 @@ static void prim_concatMap(EvalState & state, Value * * args, Value & v)
|
||||
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
||||
auto l = lists[n].listSize();
|
||||
if (l) {
|
||||
memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *));
|
||||
std::copy(lists[n].listItems().begin(), lists[n].listItems().end(), out + pos);
|
||||
}
|
||||
pos += l;
|
||||
}
|
||||
@@ -2785,9 +2778,9 @@ void prim_match(EvalState & state, Value * * args, Value & v)
|
||||
v = {NewValueAs::list, result};
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (!match[i+1].matched)
|
||||
(result->elems[i] = state.ctx.mem.allocValue())->mkNull();
|
||||
result->elems[i].mkNull();
|
||||
else
|
||||
(result->elems[i] = state.ctx.mem.allocValue())->mkString(match[i + 1].str());
|
||||
result->elems[i].mkString(match[i + 1].str());
|
||||
}
|
||||
|
||||
} catch (regex::Error & e) {
|
||||
@@ -2818,7 +2811,7 @@ void prim_split(EvalState & state, Value * * args, Value & v)
|
||||
size_t idx = 0;
|
||||
|
||||
if (len == 0) {
|
||||
result->elems[idx++] = args[1];
|
||||
result->elems[idx++] = *args[1];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2827,26 +2820,25 @@ void prim_split(EvalState & state, Value * * args, Value & v)
|
||||
auto match = *i;
|
||||
|
||||
// Add a string for non-matched characters.
|
||||
(result->elems[idx++] = state.ctx.mem.allocValue())->mkString(match.prefix().str());
|
||||
result->elems[idx++].mkString(match.prefix().str());
|
||||
|
||||
// Add a list for matched substrings.
|
||||
const size_t slen = match.size() - 1;
|
||||
auto elem = result->elems[idx++] = state.ctx.mem.allocValue();
|
||||
auto & elem = result->elems[idx++];
|
||||
|
||||
// Start at 1, beacause the first match is the whole string.
|
||||
auto content = state.ctx.mem.newList(slen);
|
||||
*elem = {NewValueAs::list, content};
|
||||
elem = {NewValueAs::list, content};
|
||||
for (size_t si = 0; si < slen; ++si) {
|
||||
if (!match[si + 1].matched)
|
||||
(content->elems[si] = state.ctx.mem.allocValue())->mkNull();
|
||||
content->elems[si].mkNull();
|
||||
else
|
||||
(content->elems[si] = state.ctx.mem.allocValue())
|
||||
->mkString(match[si + 1].str());
|
||||
content->elems[si].mkString(match[si + 1].str());
|
||||
}
|
||||
|
||||
// Add a string for non-matched suffix characters.
|
||||
if (idx == 2 * len) {
|
||||
(result->elems[idx++] = state.ctx.mem.allocValue())->mkString(match.suffix().str());
|
||||
result->elems[idx++].mkString(match.suffix().str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2868,11 +2860,11 @@ static void prim_concatStringsSep(EvalState & state, Value * * args, Value & v)
|
||||
res.reserve((args[1]->listSize() + 32) * sep.size());
|
||||
bool first = true;
|
||||
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
for (auto & elem : args[1]->listItems()) {
|
||||
if (first) first = false; else res += sep;
|
||||
res += *state.coerceToString(
|
||||
noPos,
|
||||
*elem,
|
||||
elem,
|
||||
context,
|
||||
"while evaluating one element of the list of strings to concat passed to "
|
||||
"builtins.concatStringsSep"
|
||||
@@ -2893,9 +2885,9 @@ static void prim_replaceStrings(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
std::vector<std::string> from;
|
||||
from.reserve(args[0]->listSize());
|
||||
for (auto elem : args[0]->listItems()) {
|
||||
for (auto & elem : args[0]->listItems()) {
|
||||
from.emplace_back(state.forceString(
|
||||
*elem,
|
||||
elem,
|
||||
noPos,
|
||||
"while evaluating one of the strings to replace passed to builtins.replaceStrings"
|
||||
));
|
||||
@@ -2921,7 +2913,7 @@ static void prim_replaceStrings(EvalState & state, Value * * args, Value & v)
|
||||
if (v == cache.end()) {
|
||||
NixStringContext ctx;
|
||||
auto ts = state.forceString(
|
||||
**j,
|
||||
*j,
|
||||
ctx,
|
||||
noPos,
|
||||
"while evaluating one of the replacement strings passed to "
|
||||
@@ -2990,7 +2982,7 @@ static void prim_splitVersion(EvalState & state, Value * * args, Value & v)
|
||||
auto result = state.ctx.mem.newList(components.size());
|
||||
v = {NewValueAs::list, result};
|
||||
for (const auto & [n, component] : enumerate(components))
|
||||
(result->elems[n] = state.ctx.mem.allocValue())->mkString(std::move(component));
|
||||
result->elems[n].mkString(std::move(component));
|
||||
}
|
||||
|
||||
|
||||
@@ -3016,7 +3008,7 @@ Value EvalBuiltins::prepareNixPath(const SearchPath & searchPath)
|
||||
auto attrs = mem.buildBindings(symbols, 2);
|
||||
attrs.alloc("path").mkString(i.path.s);
|
||||
attrs.alloc("prefix").mkString(i.prefix.s);
|
||||
(v->elems[n++] = mem.allocValue())->mkAttrs(attrs);
|
||||
v->elems[n++].mkAttrs(attrs);
|
||||
}
|
||||
return {NewValueAs::list, v};
|
||||
}
|
||||
@@ -3081,7 +3073,7 @@ void EvalBuiltins::createBaseEnv(const SearchPath & searchPath, const Path & sto
|
||||
|
||||
/* Now that we've added all primops, sort the `builtins' set,
|
||||
because attribute lookups expect it to be sorted. */
|
||||
env.values[0]->attrs()->sort();
|
||||
env.values[0].attrs()->sort();
|
||||
|
||||
staticEnv->isRoot = true;
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ void prim_getContext(EvalState & state, Value * * args, Value & v)
|
||||
auto content = state.ctx.mem.newList(info.second.outputs.size());
|
||||
outputsVal = {NewValueAs::list, content};
|
||||
for (const auto & [i, output] : enumerate(info.second.outputs))
|
||||
(content->elems[i] = state.ctx.mem.allocValue())->mkString(output);
|
||||
content->elems[i].mkString(output);
|
||||
}
|
||||
attrs.alloc(state.ctx.store->printStorePath(info.first)).mkAttrs(infoAttrs);
|
||||
}
|
||||
@@ -183,11 +183,11 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v)
|
||||
auto namePath = state.ctx.store->parseStorePath(name);
|
||||
if (!settings.readOnlyMode)
|
||||
state.aio.blockOn(state.ctx.store->ensurePath(namePath));
|
||||
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
||||
auto a = i.value->attrs()->get(state.ctx.s.path);
|
||||
state.forceAttrs(i.value, i.pos, "while evaluating the value of a string context");
|
||||
auto a = i.value.attrs()->get(state.ctx.s.path);
|
||||
if (a) {
|
||||
if (state.forceBool(
|
||||
*a->value, a->pos, "while evaluating the `path` attribute of a string context"
|
||||
a->value, a->pos, "while evaluating the `path` attribute of a string context"
|
||||
))
|
||||
{
|
||||
context.emplace(NixStringContextElem::Opaque{
|
||||
@@ -196,10 +196,10 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
}
|
||||
|
||||
a = i.value->attrs()->get(sAllOutputs);
|
||||
a = i.value.attrs()->get(sAllOutputs);
|
||||
if (a) {
|
||||
if (state.forceBool(
|
||||
*a->value,
|
||||
a->value,
|
||||
a->pos,
|
||||
"while evaluating the `allOutputs` attribute of a string context"
|
||||
))
|
||||
@@ -216,20 +216,20 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
}
|
||||
|
||||
a = i.value->attrs()->get(state.ctx.s.outputs);
|
||||
a = i.value.attrs()->get(state.ctx.s.outputs);
|
||||
if (a) {
|
||||
state.forceList(
|
||||
*a->value, a->pos, "while evaluating the `outputs` attribute of a string context"
|
||||
a->value, a->pos, "while evaluating the `outputs` attribute of a string context"
|
||||
);
|
||||
if (a->value->listSize() && !isDerivation(name)) {
|
||||
if (a->value.listSize() && !isDerivation(name)) {
|
||||
state.ctx.errors.make<EvalError>(
|
||||
"tried to add derivation output context of %s, which is not a derivation, to a string",
|
||||
name
|
||||
).atPos(i.pos).debugThrow();
|
||||
}
|
||||
for (auto elem : a->value->listItems()) {
|
||||
for (auto & elem : a->value.listItems()) {
|
||||
auto outputName = state.forceStringNoCtx(
|
||||
*elem, a->pos, "while evaluating an output name within a string context"
|
||||
elem, a->pos, "while evaluating an output name within a string context"
|
||||
);
|
||||
context.emplace(NixStringContextElem::Built {
|
||||
.drvPath = makeConstantStorePath(namePath),
|
||||
|
||||
@@ -126,26 +126,26 @@ void prim_fetchClosure(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
if (attrName == "fromPath") {
|
||||
NixStringContext context;
|
||||
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint());
|
||||
fromPath = state.coerceToStorePath(attr.pos, attr.value, context, attrHint());
|
||||
}
|
||||
|
||||
else if (attrName == "toPath") {
|
||||
state.forceValue(*attr.value, attr.pos);
|
||||
bool isEmptyString = attr.value->type() == nString && attr.value->str().empty();
|
||||
state.forceValue(attr.value, attr.pos);
|
||||
bool isEmptyString = attr.value.type() == nString && attr.value.str().empty();
|
||||
if (isEmptyString) {
|
||||
toPath = StorePathOrGap {};
|
||||
}
|
||||
else {
|
||||
NixStringContext context;
|
||||
toPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint());
|
||||
toPath = state.coerceToStorePath(attr.pos, attr.value, context, attrHint());
|
||||
}
|
||||
}
|
||||
|
||||
else if (attrName == "fromStore")
|
||||
fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos, attrHint());
|
||||
fromStoreUrl = state.forceStringNoCtx(attr.value, attr.pos, attrHint());
|
||||
|
||||
else if (attrName == "inputAddressed")
|
||||
inputAddressedMaybe = state.forceBool(*attr.value, attr.pos, attrHint());
|
||||
inputAddressedMaybe = state.forceBool(attr.value, attr.pos, attrHint());
|
||||
|
||||
else
|
||||
throw Error({
|
||||
|
||||
@@ -23,7 +23,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v)
|
||||
url = state
|
||||
.coerceToString(
|
||||
attr.pos,
|
||||
*attr.value,
|
||||
attr.value,
|
||||
context,
|
||||
"while evaluating the `url` attribute passed to "
|
||||
"builtins.fetchMercurial",
|
||||
@@ -35,7 +35,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v)
|
||||
// Ugly: unlike fetchGit, here the "rev" attribute can
|
||||
// be both a revision or a branch/tag name.
|
||||
auto value = state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the `rev` attribute passed to builtins.fetchMercurial"
|
||||
);
|
||||
@@ -46,7 +46,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
else if (n == "name")
|
||||
name = state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the `name` attribute passed to builtins.fetchMercurial"
|
||||
);
|
||||
|
||||
@@ -128,7 +128,7 @@ static void fetchTree(
|
||||
"unexpected attribute 'type'"
|
||||
).atPos(pos).debugThrow();
|
||||
type = state.forceStringNoCtx(
|
||||
*aType->value,
|
||||
aType->value,
|
||||
aType->pos,
|
||||
"while evaluating the `type` attribute passed to builtins.fetchTree"
|
||||
);
|
||||
@@ -142,12 +142,12 @@ static void fetchTree(
|
||||
|
||||
for (auto & attr : *args[0]->attrs()) {
|
||||
if (attr.name == state.ctx.s.type) continue;
|
||||
state.forceValue(*attr.value, attr.pos);
|
||||
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
||||
state.forceValue(attr.value, attr.pos);
|
||||
if (attr.value.type() == nPath || attr.value.type() == nString) {
|
||||
auto s =
|
||||
state
|
||||
.coerceToString(
|
||||
attr.pos, *attr.value, context, "", StringCoercionMode::Strict, false
|
||||
attr.pos, attr.value, context, "", StringCoercionMode::Strict, false
|
||||
)
|
||||
.toOwned();
|
||||
attrs.emplace(state.ctx.symbols[attr.name],
|
||||
@@ -156,10 +156,10 @@ static void fetchTree(
|
||||
? fixURIForGit(s, state)
|
||||
: fixURI(s, state)
|
||||
: s);
|
||||
} else if (attr.value->type() == nBool) {
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||
} else if (attr.value->type() == nInt) {
|
||||
auto intValue = attr.value->integer().value;
|
||||
} else if (attr.value.type() == nBool) {
|
||||
attrs.emplace(state.ctx.symbols[attr.name], Explicit<bool>{attr.value.boolean()});
|
||||
} else if (attr.value.type() == nInt) {
|
||||
auto intValue = attr.value.integer().value;
|
||||
|
||||
if (intValue < 0) {
|
||||
state.ctx.errors.make<EvalError>("negative value given for fetchTree attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow();
|
||||
@@ -173,7 +173,7 @@ static void fetchTree(
|
||||
"fetchTree argument '%s' is %s while a string, Boolean or integer is "
|
||||
"expected",
|
||||
state.ctx.symbols[attr.name],
|
||||
showType(*attr.value)
|
||||
showType(attr.value)
|
||||
)
|
||||
.debugThrow();
|
||||
}
|
||||
@@ -241,12 +241,12 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||
std::string_view n(state.ctx.symbols[attr.name]);
|
||||
if (n == "url")
|
||||
url = state.forceStringNoCtx(
|
||||
*attr.value, attr.pos, "while evaluating the url we should fetch"
|
||||
attr.value, attr.pos, "while evaluating the url we should fetch"
|
||||
);
|
||||
else if (n == "sha256") {
|
||||
expectedHash = newHashAllowEmpty(
|
||||
state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the sha256 of the content we should fetch"
|
||||
),
|
||||
@@ -254,7 +254,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||
);
|
||||
} else if (n == "name")
|
||||
name = state.forceStringNoCtx(
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos,
|
||||
"while evaluating the name of the content we should fetch"
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ void prim_fromTOML(EvalState & state, Value ** args, Value & val)
|
||||
auto list = state.ctx.mem.newList(size);
|
||||
v = {NewValueAs::list, list};
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
self(*(list->elems[i] = state.ctx.mem.allocValue()), array[i]);
|
||||
self(list->elems[i], array[i]);
|
||||
}
|
||||
} break;
|
||||
case toml::value_t::boolean:
|
||||
|
||||
@@ -9,11 +9,12 @@ namespace nix {
|
||||
|
||||
// See: https://github.com/NixOS/nix/issues/9730
|
||||
void printAmbiguous(
|
||||
Value &v,
|
||||
const SymbolTable &symbols,
|
||||
std::ostream &str,
|
||||
std::set<const void *> *seen,
|
||||
int depth)
|
||||
const Value & v,
|
||||
const SymbolTable & symbols,
|
||||
std::ostream & str,
|
||||
std::set<const void *> * seen,
|
||||
int depth
|
||||
)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
@@ -21,6 +22,10 @@ void printAmbiguous(
|
||||
str << "«too deep»";
|
||||
return;
|
||||
}
|
||||
if (v.isInvalid()) {
|
||||
str << "<INVALID>";
|
||||
return;
|
||||
}
|
||||
switch (v.type()) {
|
||||
case nInt:
|
||||
str << v.integer();
|
||||
@@ -44,7 +49,7 @@ void printAmbiguous(
|
||||
str << "{ ";
|
||||
for (auto & i : v.attrs()->lexicographicOrder(symbols)) {
|
||||
str << symbols[i->name] << " = ";
|
||||
printAmbiguous(*i->value, symbols, str, seen, depth - 1);
|
||||
printAmbiguous(i->value, symbols, str, seen, depth - 1);
|
||||
str << "; ";
|
||||
}
|
||||
str << "}";
|
||||
@@ -56,11 +61,8 @@ void printAmbiguous(
|
||||
str << "«repeated»";
|
||||
else {
|
||||
str << "[ ";
|
||||
for (auto v2 : v.listItems()) {
|
||||
if (v2)
|
||||
printAmbiguous(*v2, symbols, str, seen, depth - 1);
|
||||
else
|
||||
str << "(nullptr)";
|
||||
for (auto & v2 : v.listItems()) {
|
||||
printAmbiguous(v2, symbols, str, seen, depth - 1);
|
||||
str << " ";
|
||||
}
|
||||
str << "]";
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace nix {
|
||||
* See: https://github.com/NixOS/nix/issues/9730
|
||||
*/
|
||||
void printAmbiguous(
|
||||
Value &v,
|
||||
const SymbolTable &symbols,
|
||||
std::ostream &str,
|
||||
std::set<const void *> *seen,
|
||||
int depth);
|
||||
|
||||
const Value & v,
|
||||
const SymbolTable & symbols,
|
||||
std::ostream & str,
|
||||
std::set<const void *> * seen,
|
||||
int depth
|
||||
);
|
||||
}
|
||||
|
||||
+25
-18
@@ -237,7 +237,7 @@ private:
|
||||
std::string storePath;
|
||||
if (i) {
|
||||
storePath = state.ctx.store->printStorePath(state.coerceToStorePath(
|
||||
i->pos, *i->value, context, "while evaluating the drvPath of a derivation"
|
||||
i->pos, i->value, context, "while evaluating the drvPath of a derivation"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -264,18 +264,18 @@ private:
|
||||
}
|
||||
|
||||
auto item = v[0].second;
|
||||
if (!item->value) {
|
||||
if (item->value.isInvalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (options.force) {
|
||||
// The item is going to be forced during printing anyway, but we need its type now.
|
||||
state.forceValue(*item->value, noPos);
|
||||
state.forceValue(item->value, noPos);
|
||||
}
|
||||
|
||||
// Pretty-print single-item attrsets only if they contain nested
|
||||
// structures.
|
||||
auto itemType = item->value->type();
|
||||
auto itemType = item->value.type();
|
||||
return itemType == nList || itemType == nAttrs;
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ private:
|
||||
}
|
||||
|
||||
output << " = ";
|
||||
print(*i.second->value, depth + 1);
|
||||
print(i.second->value, depth + 1);
|
||||
output << ";";
|
||||
attrsPrinted++;
|
||||
printedHere++;
|
||||
@@ -338,7 +338,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldPrettyPrintList(std::span<Value * const> list)
|
||||
bool shouldPrettyPrintList(std::span<Value> list)
|
||||
{
|
||||
if (!options.shouldPrettyPrint() || list.empty()) {
|
||||
return false;
|
||||
@@ -349,19 +349,19 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
auto item = list[0];
|
||||
if (!item) {
|
||||
auto & item = list[0];
|
||||
if (item.isInvalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (options.force) {
|
||||
// The item is going to be forced during printing anyway, but we need its type now.
|
||||
state.forceValue(*item, noPos);
|
||||
state.forceValue(item, noPos);
|
||||
}
|
||||
|
||||
// Pretty-print single-item lists only if they contain nested
|
||||
// structures.
|
||||
auto itemType = item->type();
|
||||
auto itemType = item.type();
|
||||
return itemType == nList || itemType == nAttrs;
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ private:
|
||||
auto listItems = v.listItems();
|
||||
auto prettyPrint = shouldPrettyPrintList(listItems);
|
||||
size_t printedHere = 0;
|
||||
for (auto elem : listItems) {
|
||||
for (auto & elem : listItems) {
|
||||
printSpace(prettyPrint);
|
||||
|
||||
if (listItemsPrinted >= options.maxListItems) {
|
||||
@@ -386,11 +386,7 @@ private:
|
||||
break;
|
||||
}
|
||||
|
||||
if (elem) {
|
||||
print(*elem, depth + 1);
|
||||
} else {
|
||||
printNullptr();
|
||||
}
|
||||
print(elem, depth + 1);
|
||||
listItemsPrinted++;
|
||||
printedHere++;
|
||||
}
|
||||
@@ -427,7 +423,7 @@ private:
|
||||
output << "primop";
|
||||
} else if (v.isPrimOpApp()) {
|
||||
output << "partially applied ";
|
||||
auto primOp = v.app().target()->primOp();
|
||||
auto primOp = v.app().target().primOp();
|
||||
if (primOp)
|
||||
output << *primOp;
|
||||
else
|
||||
@@ -495,11 +491,22 @@ private:
|
||||
checkInterrupt();
|
||||
|
||||
try {
|
||||
if (v.isInvalid()) {
|
||||
if (options.ansiColors) {
|
||||
output << ANSI_MAGENTA;
|
||||
}
|
||||
output << "«invalid»";
|
||||
if (options.ansiColors) {
|
||||
output << ANSI_NORMAL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.force) {
|
||||
state.forceValue(v, noPos);
|
||||
}
|
||||
|
||||
switch (v.type()) {
|
||||
switch (v.type(true)) {
|
||||
|
||||
case nInt:
|
||||
printInt(v);
|
||||
|
||||
@@ -82,9 +82,9 @@ public:
|
||||
return contents;
|
||||
}
|
||||
|
||||
const Value * toValuePtr() const
|
||||
Value toValue() const
|
||||
{
|
||||
return &underlyingValue;
|
||||
return underlyingValue;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & os, const InternedSymbol & symbol);
|
||||
|
||||
@@ -61,7 +61,7 @@ JSON printValueAsJSON(EvalState & state, bool strict,
|
||||
const Attr & a(*v.attrs()->get(state.ctx.symbols.create(j)));
|
||||
try {
|
||||
out[j] =
|
||||
printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore);
|
||||
printValueAsJSON(state, strict, a.value, a.pos, context, copyToStore);
|
||||
} catch (Error & e) {
|
||||
e.addTrace(
|
||||
state.ctx.positions[a.pos],
|
||||
@@ -71,7 +71,7 @@ JSON printValueAsJSON(EvalState & state, bool strict,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
|
||||
return printValueAsJSON(state, strict, i->value, i->pos, context, copyToStore);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ JSON printValueAsJSON(EvalState & state, bool strict,
|
||||
int i = 0;
|
||||
for (auto elem : v.listItems()) {
|
||||
try {
|
||||
out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore));
|
||||
out.push_back(printValueAsJSON(state, strict, elem, pos, context, copyToStore));
|
||||
} catch (Error & e) {
|
||||
e.addTrace(state.ctx.positions[pos],
|
||||
HintFmt("while evaluating list element at index %1%", i));
|
||||
|
||||
@@ -43,7 +43,7 @@ static void showAttrs(EvalState & state, bool strict, bool location,
|
||||
if (location && a.pos) posToXML(state, xmlAttrs, state.ctx.positions[a.pos]);
|
||||
|
||||
XMLOpenElement _(doc, "attr", xmlAttrs);
|
||||
printValueAsXML(state, strict, location, *a.value, doc, context, drvsSeen, a.pos);
|
||||
printValueAsXML(state, strict, location, a.value, doc, context, drvsSeen, a.pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,20 +90,20 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
a = v.attrs()->get(state.ctx.s.drvPath);
|
||||
if (a) {
|
||||
if (strict) {
|
||||
state.forceValue(*a->value, a->pos);
|
||||
state.forceValue(a->value, a->pos);
|
||||
}
|
||||
if (a->value->type() == nString) {
|
||||
xmlAttrs["drvPath"] = drvPath = a->value->str();
|
||||
if (a->value.type() == nString) {
|
||||
xmlAttrs["drvPath"] = drvPath = a->value.str();
|
||||
}
|
||||
}
|
||||
|
||||
a = v.attrs()->get(state.ctx.s.outPath);
|
||||
if (a) {
|
||||
if (strict) {
|
||||
state.forceValue(*a->value, a->pos);
|
||||
state.forceValue(a->value, a->pos);
|
||||
}
|
||||
if (a->value->type() == nString) {
|
||||
xmlAttrs["outPath"] = a->value->str();
|
||||
if (a->value.type() == nString) {
|
||||
xmlAttrs["outPath"] = a->value.str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +124,8 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
|
||||
case nList: {
|
||||
XMLOpenElement _(doc, "list");
|
||||
for (auto v2 : v.listItems()) {
|
||||
printValueAsXML(state, strict, location, *v2, doc, context, drvsSeen, pos);
|
||||
for (auto & v2 : v.listItems()) {
|
||||
printValueAsXML(state, strict, location, v2, doc, context, drvsSeen, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+101
-117
@@ -75,13 +75,15 @@ struct PrimOpDetails
|
||||
// NOTE value.cc contains alignment assertions for pointers tagged thusly.
|
||||
// *always* ensure that these assertions match the tag types declared here
|
||||
typedef enum {
|
||||
// NOTE: tThunk *must* be 0, otherwise invalid value detection breaks
|
||||
// since invalid values are encoded as thunks with a null thunk state
|
||||
tThunk = 0,
|
||||
tApp,
|
||||
tInt,
|
||||
tBool,
|
||||
tString,
|
||||
tAttrs,
|
||||
tList,
|
||||
tThunk,
|
||||
tApp,
|
||||
tAuxiliary,
|
||||
} InternalType;
|
||||
|
||||
@@ -483,29 +485,6 @@ public:
|
||||
/// allocating memory.
|
||||
Value(list_t, const List * items) : raw(tag(tList, items)) {}
|
||||
|
||||
/// Constructs a nix language value of type "list", with an element array
|
||||
/// initialized by applying @ref transformer to each element in @ref items.
|
||||
///
|
||||
/// This allows "in-place" construction of a nix list when some logic is
|
||||
/// needed to get each Value pointer. This constructor dynamically (GC)
|
||||
/// allocates memory for the size of @ref items, and the Value pointers
|
||||
/// returned by @ref transformer are shallow copied into it.
|
||||
template<
|
||||
std::ranges::sized_range SizedIterableT,
|
||||
InvocableR<Value *, typename SizedIterableT::value_type const &> TransformerT
|
||||
>
|
||||
Value(list_t, SizedIterableT & items, TransformerT const & transformer)
|
||||
{
|
||||
auto list =
|
||||
reinterpret_cast<List *>(gcAllocBytes(sizeof(List) + items.size() * sizeof(Value *)));
|
||||
list->size = items.size();
|
||||
auto it = items.begin();
|
||||
for (size_t i = 0; i < items.size(); i++, it++) {
|
||||
list->elems[i] = transformer(*it);
|
||||
}
|
||||
raw = tag(tList, list);
|
||||
}
|
||||
|
||||
/// Constructs a nix language value of the singleton type "null".
|
||||
Value(null_t) : raw(tag(tAuxiliary, &NULL_ACB)) {}
|
||||
|
||||
@@ -533,7 +512,7 @@ public:
|
||||
|
||||
/// Constructs a nix language value of type "lambda", which represents a
|
||||
/// lazy and/or partial application of a function.
|
||||
Value(app_t, EvalMemory & mem, Value & lhs, std::span<Value *> args);
|
||||
Value(app_t, EvalMemory & mem, Value & lhs, std::span<Value> args);
|
||||
|
||||
/// Constructs a nix language value of type "external", which is only used
|
||||
/// by plugins. Do any existing plugins even use this mechanism?
|
||||
@@ -597,9 +576,10 @@ public:
|
||||
{
|
||||
return internalType() == tApp;
|
||||
}
|
||||
inline bool isBlackhole() const
|
||||
inline bool isBlackhole() const;
|
||||
inline bool isInvalid() const
|
||||
{
|
||||
return internalType() == tThunk && untag<const Thunk *>() == &blackHole;
|
||||
return raw == 0;
|
||||
}
|
||||
|
||||
// type() == nFunction
|
||||
@@ -611,21 +591,7 @@ public:
|
||||
{
|
||||
return internalType() == tAuxiliary && auxiliary()->type() == Acb::tPrimOp;
|
||||
}
|
||||
inline bool isPrimOpApp() const
|
||||
{
|
||||
return internalType() == tApp && !app().resolved() && app().target()->isPrimOp();
|
||||
}
|
||||
|
||||
struct alignas(TAG_ALIGN) List
|
||||
{
|
||||
size_t size;
|
||||
Value * elems[0];
|
||||
|
||||
std::span<Value *> span()
|
||||
{
|
||||
return {elems, elems + size};
|
||||
}
|
||||
};
|
||||
inline bool isPrimOpApp() const;
|
||||
|
||||
/**
|
||||
* Strings in the evaluator carry a so-called `context` which
|
||||
@@ -663,50 +629,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(TAG_ALIGN) App
|
||||
{
|
||||
uintptr_t _left;
|
||||
size_t _n;
|
||||
Value * _args[0];
|
||||
|
||||
bool resolved() const
|
||||
{
|
||||
return _n == 0;
|
||||
}
|
||||
|
||||
void resolve(Value v)
|
||||
{
|
||||
_left = v.raw;
|
||||
_n = 0;
|
||||
}
|
||||
|
||||
Value * left() const
|
||||
{
|
||||
return reinterpret_cast<Value *>(_left);
|
||||
}
|
||||
|
||||
Value result() const
|
||||
{
|
||||
Value v;
|
||||
v.raw = _left;
|
||||
return v;
|
||||
}
|
||||
|
||||
Value * target() const
|
||||
{
|
||||
return left()->isApp() ? left()->app().target() : left();
|
||||
}
|
||||
|
||||
std::span<Value *> args()
|
||||
{
|
||||
return std::span{_args, _n};
|
||||
}
|
||||
|
||||
size_t totalArgs() const
|
||||
{
|
||||
return _n + (left()->isApp() ? left()->app().totalArgs() : 0);
|
||||
}
|
||||
};
|
||||
struct App;
|
||||
|
||||
/// auxiliary control block for values that require more space.
|
||||
/// these blocks are usually heap-allocated in GC memory space.
|
||||
@@ -861,15 +784,9 @@ public:
|
||||
return internalType() == tList;
|
||||
}
|
||||
|
||||
Value * const * listElems() const
|
||||
{
|
||||
return untag<const List *>()->elems;
|
||||
}
|
||||
Value * listElems() const;
|
||||
|
||||
size_t listSize() const
|
||||
{
|
||||
return untag<const List *>()->size;
|
||||
}
|
||||
size_t listSize() const;
|
||||
|
||||
/**
|
||||
* Check whether forcing this value requires a trivial amount of
|
||||
@@ -878,11 +795,11 @@ public:
|
||||
*/
|
||||
bool isTrivial() const;
|
||||
|
||||
auto listItems()
|
||||
auto listItems() const
|
||||
{
|
||||
struct ListIterable
|
||||
{
|
||||
typedef Value * const * iterator;
|
||||
typedef Value * iterator;
|
||||
iterator _begin, _end;
|
||||
iterator begin() const { return _begin; }
|
||||
iterator end() const { return _end; }
|
||||
@@ -892,20 +809,6 @@ public:
|
||||
return ListIterable { begin, begin + listSize() };
|
||||
}
|
||||
|
||||
auto listItems() const
|
||||
{
|
||||
struct ConstListIterable
|
||||
{
|
||||
typedef const Value * const * iterator;
|
||||
iterator _begin, _end;
|
||||
iterator begin() const { return _begin; }
|
||||
iterator end() const { return _end; }
|
||||
};
|
||||
assert(isList());
|
||||
auto begin = listElems();
|
||||
return ConstListIterable { begin, begin + listSize() };
|
||||
}
|
||||
|
||||
SourcePath path() const
|
||||
{
|
||||
assert(internalType() == tString && untag<const String *>()->isPath());
|
||||
@@ -982,6 +885,11 @@ public:
|
||||
{
|
||||
return untag<const Acb *>();
|
||||
}
|
||||
|
||||
uintptr_t pointerEqProxy() const
|
||||
{
|
||||
return raw;
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(Value::TAG_ALIGN) Value::Thunk
|
||||
@@ -1014,6 +922,60 @@ struct alignas(Value::TAG_ALIGN) Value::Thunk
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(Value::TAG_ALIGN) Value::List
|
||||
{
|
||||
size_t size;
|
||||
Value elems[0];
|
||||
|
||||
std::span<Value> span()
|
||||
{
|
||||
return {elems, elems + size};
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(Value::TAG_ALIGN) Value::App
|
||||
{
|
||||
Value _left;
|
||||
size_t _n;
|
||||
Value _args[0];
|
||||
|
||||
bool resolved() const
|
||||
{
|
||||
return _n == ~size_t(0);
|
||||
}
|
||||
|
||||
void resolve(Value v)
|
||||
{
|
||||
_left = v;
|
||||
_n = ~size_t(0);
|
||||
}
|
||||
|
||||
Value left() const
|
||||
{
|
||||
return _left;
|
||||
}
|
||||
|
||||
Value result() const
|
||||
{
|
||||
return left();
|
||||
}
|
||||
|
||||
Value target() const
|
||||
{
|
||||
return left().isApp() ? left().app().target() : left();
|
||||
}
|
||||
|
||||
std::span<Value> args()
|
||||
{
|
||||
return std::span{_args, _n};
|
||||
}
|
||||
|
||||
size_t totalArgs() const
|
||||
{
|
||||
return _n + (left().isApp() ? left().app().totalArgs() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
inline ValueType Value::type(bool invalidIsThunk) const
|
||||
{
|
||||
again:
|
||||
@@ -1043,7 +1005,13 @@ again:
|
||||
return nInt;
|
||||
}
|
||||
case tThunk:
|
||||
if (thunk().resolved()) {
|
||||
if (isInvalid()) {
|
||||
if (invalidIsThunk) {
|
||||
return nThunk;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
} else if (thunk().resolved()) {
|
||||
raw = thunk().result().raw;
|
||||
goto again;
|
||||
}
|
||||
@@ -1053,12 +1021,28 @@ again:
|
||||
raw = app().result().raw;
|
||||
goto again;
|
||||
}
|
||||
return app().target()->isPrimOp() ? nFunction : nThunk;
|
||||
return app().target().isPrimOp() ? nFunction : nThunk;
|
||||
}
|
||||
if (invalidIsThunk)
|
||||
return nThunk;
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
inline bool Value::isBlackhole() const
|
||||
{
|
||||
return internalType() == tThunk && untag<const Thunk *>()->expr == blackHole.expr;
|
||||
}
|
||||
|
||||
inline bool Value::isPrimOpApp() const
|
||||
{
|
||||
return internalType() == tApp && !app().resolved() && app().target().isPrimOp();
|
||||
}
|
||||
|
||||
inline Value * Value::listElems() const
|
||||
{
|
||||
return untag<List *>()->elems;
|
||||
}
|
||||
|
||||
inline size_t Value::listSize() const
|
||||
{
|
||||
return untag<const List *>()->size;
|
||||
}
|
||||
|
||||
using PrimOp = Value::PrimOp;
|
||||
|
||||
+3
-3
@@ -109,13 +109,13 @@ struct CmdBundle : InstallableCommand
|
||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||
|
||||
NixStringContext context2;
|
||||
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
|
||||
auto drvPath = evalState->coerceToStorePath(attr1->pos, attr1->value, context2, "");
|
||||
|
||||
auto attr2 = vRes.attrs()->get(evaluator->s.outPath);
|
||||
if (!attr2)
|
||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||
|
||||
auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2, "");
|
||||
auto outPath = evalState->coerceToStorePath(attr2->pos, attr2->value, context2, "");
|
||||
|
||||
aio().blockOn(store->buildPaths({
|
||||
DerivedPath::Built {
|
||||
@@ -128,7 +128,7 @@ struct CmdBundle : InstallableCommand
|
||||
auto * attr = vRes.attrs()->get(evaluator->s.name);
|
||||
if (!attr)
|
||||
throw Error("attribute 'name' missing");
|
||||
outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, "");
|
||||
outLink = evalState->forceStringNoCtx(attr->value, attr->pos, "");
|
||||
}
|
||||
|
||||
// TODO: will crash if not a localFSStore?
|
||||
|
||||
+32
-33
@@ -185,20 +185,20 @@ static void enumerateOutputs(
|
||||
auto aOutputs = vFlake.attrs()->get(state.ctx.symbols.create("outputs"));
|
||||
assert(aOutputs);
|
||||
|
||||
state.forceAttrs(*aOutputs->value, noPos, "while evaluating the outputs of a flake");
|
||||
state.forceAttrs(aOutputs->value, noPos, "while evaluating the outputs of a flake");
|
||||
|
||||
auto sHydraJobs = state.ctx.symbols.create("hydraJobs");
|
||||
|
||||
/* Hack: ensure that hydraJobs is evaluated before anything
|
||||
else. This way we can disable IFD for hydraJobs and then enable
|
||||
it for other outputs. */
|
||||
if (auto attr = aOutputs->value->attrs()->get(sHydraJobs)) {
|
||||
callback(state.ctx.symbols[attr->name], *attr->value, attr->pos);
|
||||
if (auto attr = aOutputs->value.attrs()->get(sHydraJobs)) {
|
||||
callback(state.ctx.symbols[attr->name], attr->value, attr->pos);
|
||||
}
|
||||
|
||||
for (auto & attr : *aOutputs->value->attrs()) {
|
||||
for (auto & attr : *aOutputs->value.attrs()) {
|
||||
if (attr.name != sHydraJobs) {
|
||||
callback(state.ctx.symbols[attr.name], *attr.value, attr.pos);
|
||||
callback(state.ctx.symbols[attr.name], attr.value, attr.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -502,14 +502,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
throw Error("jobset should not be a derivation at top-level");
|
||||
|
||||
for (auto & attr : *v.attrs()) {
|
||||
state->forceAttrs(*attr.value, attr.pos, "");
|
||||
state->forceAttrs(attr.value, attr.pos, "");
|
||||
auto attrPath2 = concatStrings(attrPath, ".", evaluator->symbols[attr.name]);
|
||||
if (state->isDerivation(*attr.value)) {
|
||||
if (state->isDerivation(attr.value)) {
|
||||
Activity act(*logger, lvlInfo, actUnknown,
|
||||
fmt("checking Hydra job '%s'", attrPath2));
|
||||
checkDerivation(attrPath2, *attr.value, attr.pos);
|
||||
checkDerivation(attrPath2, attr.value, attr.pos);
|
||||
} else {
|
||||
checkHydraJobs(attrPath2, *attr.value, attr.pos);
|
||||
checkHydraJobs(attrPath2, attr.value, attr.pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
if (attr->name == evaluator->symbols.create("path")) {
|
||||
NixStringContext context;
|
||||
auto path = state->ctx.paths.checkSourcePath(
|
||||
state->coerceToPath(attr->pos, *attr->value, context, "")
|
||||
state->coerceToPath(attr->pos, attr->value, context, "")
|
||||
);
|
||||
if (!path.pathExists())
|
||||
throw Error("template '%s' refers to a non-existent path '%s'", attrPath, path);
|
||||
@@ -556,7 +556,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
throw Error("template '%s' lacks attribute 'path'", attrPath);
|
||||
|
||||
if (auto attr = v.attrs()->get(evaluator->symbols.create("description")))
|
||||
state->forceStringNoCtx(*attr->value, attr->pos, "");
|
||||
state->forceStringNoCtx(attr->value, attr->pos, "");
|
||||
else
|
||||
throw Error("template '%s' lacks attribute 'description'", attrPath);
|
||||
|
||||
@@ -625,18 +625,17 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
state->forceAttrs(*attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value->attrs()) {
|
||||
state->forceAttrs(attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value.attrs()) {
|
||||
auto drvPath = checkDerivation(
|
||||
fmt("%s.%s.%s",
|
||||
name,
|
||||
attr_name,
|
||||
evaluator->symbols[attr2.name]),
|
||||
*attr2.value,
|
||||
attr2.value,
|
||||
attr2.pos
|
||||
);
|
||||
if (drvPath && attr_name == evalSettings.getCurrentSystem())
|
||||
{
|
||||
if (drvPath && attr_name == evalSettings.getCurrentSystem()) {
|
||||
drvPaths.push_back(DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePath(*drvPath),
|
||||
.outputs = OutputsSpec::All { },
|
||||
@@ -654,7 +653,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos);
|
||||
checkApp(fmt("%s.%s", name, attr_name), attr.value, attr.pos);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -666,14 +665,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
state->forceAttrs(*attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value->attrs()) {
|
||||
state->forceAttrs(attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value.attrs()) {
|
||||
checkDerivation(
|
||||
fmt("%s.%s.%s",
|
||||
name,
|
||||
attr_name,
|
||||
evaluator->symbols[attr2.name]),
|
||||
*attr2.value,
|
||||
attr2.value,
|
||||
attr2.pos
|
||||
);
|
||||
}
|
||||
@@ -688,14 +687,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
state->forceAttrs(*attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value->attrs()) {
|
||||
state->forceAttrs(attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value.attrs()) {
|
||||
checkApp(
|
||||
fmt("%s.%s.%s",
|
||||
name,
|
||||
attr_name,
|
||||
evaluator->symbols[attr2.name]),
|
||||
*attr2.value,
|
||||
attr2.value,
|
||||
attr2.pos
|
||||
);
|
||||
}
|
||||
@@ -711,7 +710,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
checkDerivation(
|
||||
fmt("%s.%s", name, attr_name), *attr.value, attr.pos
|
||||
fmt("%s.%s", name, attr_name), attr.value, attr.pos
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -724,7 +723,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos) ) {
|
||||
checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos);
|
||||
checkApp(fmt("%s.%s", name, attr_name), attr.value, attr.pos);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -750,7 +749,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
for (auto & attr : *vOutput.attrs())
|
||||
checkOverlay(
|
||||
fmt("%s.%s", name, evaluator->symbols[attr.name]),
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos
|
||||
);
|
||||
}
|
||||
@@ -766,7 +765,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
for (auto & attr : *vOutput.attrs())
|
||||
checkModule(
|
||||
fmt("%s.%s", name, evaluator->symbols[attr.name]),
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos
|
||||
);
|
||||
}
|
||||
@@ -777,7 +776,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
for (auto & attr : *vOutput.attrs())
|
||||
checkNixOSConfiguration(
|
||||
fmt("%s.%s", name, evaluator->symbols[attr.name]),
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos
|
||||
);
|
||||
}
|
||||
@@ -798,7 +797,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
for (auto & attr : *vOutput.attrs())
|
||||
checkTemplate(
|
||||
fmt("%s.%s", name, evaluator->symbols[attr.name]),
|
||||
*attr.value,
|
||||
attr.value,
|
||||
attr.pos
|
||||
);
|
||||
}
|
||||
@@ -811,7 +810,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
checkBundler(
|
||||
fmt("%s.%s", name, attr_name), *attr.value, attr.pos
|
||||
fmt("%s.%s", name, attr_name), attr.value, attr.pos
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -824,14 +823,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
const auto & attr_name = evaluator->symbols[attr.name];
|
||||
checkSystemName(attr_name, attr.pos);
|
||||
if (checkSystemType(attr_name, attr.pos)) {
|
||||
state->forceAttrs(*attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value->attrs()) {
|
||||
state->forceAttrs(attr.value, attr.pos, "");
|
||||
for (auto & attr2 : *attr.value.attrs()) {
|
||||
checkBundler(
|
||||
fmt("%s.%s.%s",
|
||||
name,
|
||||
attr_name,
|
||||
evaluator->symbols[attr2.name]),
|
||||
*attr2.value,
|
||||
attr2.value,
|
||||
attr2.pos
|
||||
);
|
||||
}
|
||||
|
||||
+4
-4
@@ -378,7 +378,7 @@ static void showHelp(AsyncIoRoot & aio, std::vector<std::string> subcommand, Nix
|
||||
throw UsageError("`nix` has no subcommand '%s'", concatStringsSep("", subcommand));
|
||||
|
||||
auto markdown =
|
||||
state->forceString(*attr->value, noPos, "while evaluating the lowdown help text");
|
||||
state->forceString(attr->value, noPos, "while evaluating the lowdown help text");
|
||||
|
||||
RunPager pager;
|
||||
std::cout << renderMarkdownToTerminal(markdown) << "\n";
|
||||
@@ -528,13 +528,13 @@ void mainWrapped(AsyncIoRoot & aio, int argc, char * * argv)
|
||||
auto res = JSON::object();
|
||||
res["builtins"] = ({
|
||||
auto builtinsJson = JSON::object();
|
||||
auto builtins = state.builtins.env.values[0]->attrs();
|
||||
auto builtins = state.builtins.env.values[0].attrs();
|
||||
for (auto & builtin : *builtins) {
|
||||
auto b = JSON::object();
|
||||
if (!builtin.value->isPrimOp()) {
|
||||
if (!builtin.value.isPrimOp()) {
|
||||
continue;
|
||||
}
|
||||
auto primOp = builtin.value->primOp();
|
||||
auto primOp = builtin.value.primOp();
|
||||
if (!primOp->doc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+8
-8
@@ -39,14 +39,14 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url)
|
||||
if (!mirrorList) {
|
||||
throw Error("unknown mirror name '%s'", mirrorName);
|
||||
}
|
||||
state.forceList(*mirrorList->value, noPos, "while evaluating one mirror configuration");
|
||||
state.forceList(mirrorList->value, noPos, "while evaluating one mirror configuration");
|
||||
|
||||
if (mirrorList->value->listSize() < 1) {
|
||||
if (mirrorList->value.listSize() < 1) {
|
||||
throw Error("mirror URL '%s' did not expand to anything", url);
|
||||
}
|
||||
|
||||
std::string mirror(state.forceString(
|
||||
*mirrorList->value->listElems()[0], noPos, "while evaluating the first available mirror"
|
||||
mirrorList->value.listElems()[0], noPos, "while evaluating the first available mirror"
|
||||
));
|
||||
return mirror + (mirror.ends_with("/") ? "" : "/") + s.substr(p + 1);
|
||||
}
|
||||
@@ -217,12 +217,12 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str
|
||||
auto * attr = v.attrs()->get(evaluator->symbols.create("urls"));
|
||||
if (!attr)
|
||||
throw Error("attribute 'urls' missing");
|
||||
state->forceList(*attr->value, noPos, "while evaluating the urls to prefetch");
|
||||
if (attr->value->listSize() < 1) {
|
||||
state->forceList(attr->value, noPos, "while evaluating the urls to prefetch");
|
||||
if (attr->value.listSize() < 1) {
|
||||
throw Error("'urls' list is empty");
|
||||
}
|
||||
url = state->forceString(
|
||||
*attr->value->listElems()[0],
|
||||
attr->value.listElems()[0],
|
||||
noPos,
|
||||
"while evaluating the first url from the urls list"
|
||||
);
|
||||
@@ -233,7 +233,7 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str
|
||||
printInfo("warning: this does not look like a fetchurl call");
|
||||
else
|
||||
unpack = state->forceString(
|
||||
*attr2->value,
|
||||
attr2->value,
|
||||
noPos,
|
||||
"while evaluating the outputHashMode of the source to prefetch"
|
||||
)
|
||||
@@ -244,7 +244,7 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str
|
||||
auto attr3 = v.attrs()->get(evaluator->symbols.create("name"));
|
||||
if (!attr3)
|
||||
name = state->forceString(
|
||||
*attr3->value, noPos, "while evaluating the name of the source to prefetch"
|
||||
attr3->value, noPos, "while evaluating the name of the source to prefetch"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -68,10 +68,10 @@ struct CmdRepl : RawInstallablesCommand
|
||||
auto what = installable.what();
|
||||
state->forceValue(val, pos);
|
||||
auto autoArgs = getAutoArgs(*evaluator);
|
||||
auto valPost = evaluator->mem.allocValue();
|
||||
state->autoCallFunction(*autoArgs, val, *valPost, pos);
|
||||
state->forceValue(*valPost, pos);
|
||||
values.push_back({*valPost, what});
|
||||
Value valPost;
|
||||
state->autoCallFunction(*autoArgs, val, valPost, pos);
|
||||
state->forceValue(valPost, pos);
|
||||
values.push_back( {valPost, what });
|
||||
} else {
|
||||
auto [val, pos] = installable.toValue(*state);
|
||||
values.push_back({val, what});
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
#include "buffered-io.hh"
|
||||
#include "eval-args.hh"
|
||||
|
||||
static nix::Value *releaseExprTopLevelValue(nix::EvalState &state,
|
||||
nix::Bindings &autoArgs,
|
||||
MyArgs &args) {
|
||||
static nix::Value releaseExprTopLevelValue(nix::EvalState &state,
|
||||
nix::Bindings &autoArgs,
|
||||
MyArgs &args) {
|
||||
nix::Value vTop;
|
||||
|
||||
if (args.fromArgs) {
|
||||
@@ -57,9 +57,9 @@ static nix::Value *releaseExprTopLevelValue(nix::EvalState &state,
|
||||
vTop);
|
||||
}
|
||||
|
||||
auto vRoot = state.ctx.mem.allocValue();
|
||||
nix::Value vRoot;
|
||||
|
||||
state.autoCallFunction(autoArgs, vTop, *vRoot, {});
|
||||
state.autoCallFunction(autoArgs, vTop, vRoot, {});
|
||||
|
||||
return vRoot;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ static std::optional<Constituents>
|
||||
readConstituents(const nix::Value *v, nix::box_ptr<nix::EvalState> &state,
|
||||
nix::ref<nix::eval_cache::CachingEvaluator> &evaluator) {
|
||||
auto a = v->attrs()->get(state->ctx.symbols.create("_hydraAggregate"));
|
||||
if (a && state->forceBool(*a->value, a->pos,
|
||||
if (a && state->forceBool(a->value, a->pos,
|
||||
"while evaluating the "
|
||||
"`_hydraAggregate` attribute")) {
|
||||
std::vector<std::string> constituents;
|
||||
@@ -92,7 +92,7 @@ readConstituents(const nix::Value *v, nix::box_ptr<nix::EvalState> &state,
|
||||
.debugThrow(nix::always_progresses); // we can't have a debugger here
|
||||
|
||||
nix::NixStringContext context;
|
||||
state->coerceToString(a->pos, *a->value, context,
|
||||
state->coerceToString(a->pos, a->value, context,
|
||||
"while evaluating the `constituents` attribute",
|
||||
nix::StringCoercionMode::ToString, false);
|
||||
for (auto &c : context)
|
||||
@@ -106,14 +106,14 @@ readConstituents(const nix::Value *v, nix::box_ptr<nix::EvalState> &state,
|
||||
},
|
||||
c.raw);
|
||||
|
||||
state->forceList(*a->value, a->pos,
|
||||
state->forceList(a->value, a->pos,
|
||||
"while evaluating the "
|
||||
"`constituents` attribute");
|
||||
for (unsigned int n = 0; n < a->value->listSize(); ++n) {
|
||||
auto v = a->value->listElems()[n];
|
||||
state->forceValue(*v, nix::noPos);
|
||||
if (v->type() == nix::nString)
|
||||
namedConstituents.emplace_back(v->str());
|
||||
for (unsigned int n = 0; n < a->value.listSize(); ++n) {
|
||||
auto v = a->value.listElems()[n];
|
||||
state->forceValue(v, nix::noPos);
|
||||
if (v.type() == nix::nString)
|
||||
namedConstituents.emplace_back(v.str());
|
||||
}
|
||||
|
||||
return Constituents(constituents, namedConstituents);
|
||||
@@ -138,7 +138,7 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
|
||||
|
||||
return flake.toValue(*state).first;
|
||||
} else {
|
||||
return *releaseExprTopLevelValue(*state, autoArgs, args);
|
||||
return releaseExprTopLevelValue(*state, autoArgs, args);
|
||||
}
|
||||
}();
|
||||
|
||||
@@ -171,15 +171,15 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
|
||||
nix::findAlongAttrPath(*state, attrPathS, autoArgs, vRoot)
|
||||
.first;
|
||||
|
||||
auto v = evaluator->mem.allocValue();
|
||||
state->autoCallFunction(autoArgs, vTmp, *v, {});
|
||||
nix::Value v;
|
||||
state->autoCallFunction(autoArgs, vTmp, v, {});
|
||||
|
||||
if (v->type() == nix::nAttrs) {
|
||||
if (auto drvInfo = nix::getDerivation(*state, *v, false)) {
|
||||
if (v.type() == nix::nAttrs) {
|
||||
if (auto drvInfo = nix::getDerivation(*state, v, false)) {
|
||||
std::optional<Constituents> maybeConstituents;
|
||||
if (args.constituents) {
|
||||
maybeConstituents =
|
||||
readConstituents(v, state, evaluator);
|
||||
readConstituents(&v, state, evaluator);
|
||||
}
|
||||
auto drv = Drv(attrPathS, *state, *drvInfo, args,
|
||||
maybeConstituents);
|
||||
@@ -197,16 +197,16 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
|
||||
// = true;` for top-level attrset
|
||||
|
||||
for (auto &i :
|
||||
v->attrs()->lexicographicOrder(evaluator->symbols)) {
|
||||
v.attrs()->lexicographicOrder(evaluator->symbols)) {
|
||||
const std::string_view name = evaluator->symbols[i->name];
|
||||
attrs.emplace_back(name);
|
||||
|
||||
if (name == "recurseForDerivations" &&
|
||||
!args.forceRecurse) {
|
||||
auto attrv = v->attrs()->get(
|
||||
auto attrv = v.attrs()->get(
|
||||
evaluator->s.recurseForDerivations);
|
||||
recurse = state->forceBool(
|
||||
*attrv->value, attrv->pos,
|
||||
attrv->value, attrv->pos,
|
||||
"while evaluating recurseForDerivations");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace nix {
|
||||
auto s = createSymbol("success");
|
||||
auto p = v.attrs()->get(s);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_THAT(*p->value, IsFalse());
|
||||
ASSERT_THAT(p->value, IsFalse());
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, tryEvalSuccess) {
|
||||
@@ -82,11 +82,11 @@ namespace nix {
|
||||
auto s = createSymbol("success");
|
||||
auto p = v.attrs()->get(s);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_THAT(*p->value, IsTrue());
|
||||
ASSERT_THAT(p->value, IsTrue());
|
||||
s = createSymbol("value");
|
||||
p = v.attrs()->get(s);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_THAT(*p->value, IsIntEq(123));
|
||||
ASSERT_THAT(p->value, IsIntEq(123));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, getEnv) {
|
||||
@@ -134,8 +134,8 @@ namespace nix {
|
||||
TEST_F(PrimOpTest, attrValues) {
|
||||
auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }");
|
||||
ASSERT_THAT(v, IsListOfSize(2));
|
||||
ASSERT_THAT(*v.listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(*v.listElems()[1], IsStringEq("foo"));
|
||||
ASSERT_THAT(v.listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(v.listElems()[1], IsStringEq("foo"));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, getAttr) {
|
||||
@@ -203,7 +203,7 @@ namespace nix {
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto key = v.attrs()->get(createSymbol("key"));
|
||||
ASSERT_NE(key, nullptr);
|
||||
ASSERT_THAT(*key->value, IsIntEq(123));
|
||||
ASSERT_THAT(key->value, IsIntEq(123));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, intersectAttrs) {
|
||||
@@ -211,14 +211,14 @@ namespace nix {
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(3));
|
||||
ASSERT_THAT(b->value, IsIntEq(3));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, catAttrs) {
|
||||
auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]");
|
||||
ASSERT_THAT(v, IsListOfSize(2));
|
||||
ASSERT_THAT(*v.listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(*v.listElems()[1], IsIntEq(2));
|
||||
ASSERT_THAT(v.listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(v.listElems()[1], IsIntEq(2));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, functionArgs) {
|
||||
@@ -227,11 +227,11 @@ namespace nix {
|
||||
|
||||
auto x = v.attrs()->get(createSymbol("x"));
|
||||
ASSERT_NE(x, nullptr);
|
||||
ASSERT_THAT(*x->value, IsFalse());
|
||||
ASSERT_THAT(x->value, IsFalse());
|
||||
|
||||
auto y = v.attrs()->get(createSymbol("y"));
|
||||
ASSERT_NE(y, nullptr);
|
||||
ASSERT_THAT(*y->value, IsTrue());
|
||||
ASSERT_THAT(y->value, IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, mapAttrs) {
|
||||
@@ -240,15 +240,15 @@ namespace nix {
|
||||
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
ASSERT_THAT(*a->value, IsThunk());
|
||||
state.forceValue(*a->value, noPos);
|
||||
ASSERT_THAT(*a->value, IsIntEq(10));
|
||||
ASSERT_THAT(a->value, IsThunk());
|
||||
state.forceValue(a->value, noPos);
|
||||
ASSERT_THAT(a->value, IsIntEq(10));
|
||||
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsThunk());
|
||||
state.forceValue(*b->value, noPos);
|
||||
ASSERT_THAT(*b->value, IsIntEq(20));
|
||||
ASSERT_THAT(b->value, IsThunk());
|
||||
state.forceValue(b->value, noPos);
|
||||
ASSERT_THAT(b->value, IsIntEq(20));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, isList) {
|
||||
@@ -288,7 +288,7 @@ namespace nix {
|
||||
auto v = eval("builtins.tail [ 3 2 1 0 ]");
|
||||
ASSERT_THAT(v, IsListOfSize(3));
|
||||
for (const auto [n, elem] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*elem, IsIntEq(2 - static_cast<int>(n)));
|
||||
ASSERT_THAT(elem, IsIntEq(2 - static_cast<int>(n)));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, tailEmpty) {
|
||||
@@ -299,26 +299,26 @@ namespace nix {
|
||||
auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]");
|
||||
ASSERT_THAT(v, IsListOfSize(3));
|
||||
auto elem = v.listElems()[0];
|
||||
ASSERT_THAT(*elem, IsThunk());
|
||||
state.forceValue(*elem, noPos);
|
||||
ASSERT_THAT(*elem, IsStringEq("foobar"));
|
||||
ASSERT_THAT(elem, IsThunk());
|
||||
state.forceValue(elem, noPos);
|
||||
ASSERT_THAT(elem, IsStringEq("foobar"));
|
||||
|
||||
elem = v.listElems()[1];
|
||||
ASSERT_THAT(*elem, IsThunk());
|
||||
state.forceValue(*elem, noPos);
|
||||
ASSERT_THAT(*elem, IsStringEq("foobla"));
|
||||
ASSERT_THAT(elem, IsThunk());
|
||||
state.forceValue(elem, noPos);
|
||||
ASSERT_THAT(elem, IsStringEq("foobla"));
|
||||
|
||||
elem = v.listElems()[2];
|
||||
ASSERT_THAT(*elem, IsThunk());
|
||||
state.forceValue(*elem, noPos);
|
||||
ASSERT_THAT(*elem, IsStringEq("fooabc"));
|
||||
ASSERT_THAT(elem, IsThunk());
|
||||
state.forceValue(elem, noPos);
|
||||
ASSERT_THAT(elem, IsStringEq("fooabc"));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, filter) {
|
||||
auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]");
|
||||
ASSERT_THAT(v, IsListOfSize(3));
|
||||
for (const auto elem : v.listItems())
|
||||
ASSERT_THAT(*elem, IsIntEq(2));
|
||||
ASSERT_THAT(elem, IsIntEq(2));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, elemTrue) {
|
||||
@@ -335,7 +335,7 @@ namespace nix {
|
||||
auto v = eval("builtins.concatLists [[1 2] [3 4]]");
|
||||
ASSERT_THAT(v, IsListOfSize(4));
|
||||
for (const auto [i, elem] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1));
|
||||
ASSERT_THAT(elem, IsIntEq(static_cast<int>(i) + 1));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, length) {
|
||||
@@ -373,9 +373,9 @@ namespace nix {
|
||||
ASSERT_EQ(v.type(), nList);
|
||||
ASSERT_EQ(v.listSize(), 3);
|
||||
for (const auto [i, elem] : enumerate(v.listItems())) {
|
||||
ASSERT_THAT(*elem, IsThunk());
|
||||
state.forceValue(*elem, noPos);
|
||||
ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1));
|
||||
ASSERT_THAT(elem, IsThunk());
|
||||
state.forceValue(elem, noPos);
|
||||
ASSERT_THAT(elem, IsIntEq(static_cast<int>(i) + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ namespace nix {
|
||||
|
||||
const std::vector<int> numbers = { 42, 77, 147, 249, 483, 526 };
|
||||
for (const auto [n, elem] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*elem, IsIntEq(numbers[n]));
|
||||
ASSERT_THAT(elem, IsIntEq(numbers[n]));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, partition) {
|
||||
@@ -395,18 +395,18 @@ namespace nix {
|
||||
|
||||
auto right = v.attrs()->get(createSymbol("right"));
|
||||
ASSERT_NE(right, nullptr);
|
||||
ASSERT_THAT(*right->value, IsListOfSize(2));
|
||||
ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23));
|
||||
ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42));
|
||||
ASSERT_THAT(right->value, IsListOfSize(2));
|
||||
ASSERT_THAT(right->value.listElems()[0], IsIntEq(23));
|
||||
ASSERT_THAT(right->value.listElems()[1], IsIntEq(42));
|
||||
|
||||
auto wrong = v.attrs()->get(createSymbol("wrong"));
|
||||
ASSERT_NE(wrong, nullptr);
|
||||
ASSERT_EQ(wrong->value->type(), nList);
|
||||
ASSERT_EQ(wrong->value->listSize(), 3);
|
||||
ASSERT_THAT(*wrong->value, IsListOfSize(3));
|
||||
ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9));
|
||||
ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3));
|
||||
ASSERT_EQ(wrong->value.type(), nList);
|
||||
ASSERT_EQ(wrong->value.listSize(), 3);
|
||||
ASSERT_THAT(wrong->value, IsListOfSize(3));
|
||||
ASSERT_THAT(wrong->value.listElems()[0], IsIntEq(1));
|
||||
ASSERT_THAT(wrong->value.listElems()[1], IsIntEq(9));
|
||||
ASSERT_THAT(wrong->value.listElems()[2], IsIntEq(3));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, concatMap) {
|
||||
@@ -416,7 +416,7 @@ namespace nix {
|
||||
|
||||
const std::vector<int> numbers = { 1, 2, 0, 3, 4, 0 };
|
||||
for (const auto [n, elem] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*elem, IsIntEq(numbers[n]));
|
||||
ASSERT_THAT(elem, IsIntEq(numbers[n]));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, addInt) {
|
||||
@@ -652,7 +652,7 @@ namespace nix {
|
||||
|
||||
const std::vector<std::string_view> strings = { "1", "2", "3", "git" };
|
||||
for (const auto [n, p] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*p, IsStringEq(strings[n]));
|
||||
ASSERT_THAT(p, IsStringEq(strings[n]));
|
||||
}
|
||||
|
||||
class CompareVersionsPrimOpTest :
|
||||
@@ -706,11 +706,11 @@ namespace nix {
|
||||
|
||||
auto name = v.attrs()->get(createSymbol("name"));
|
||||
ASSERT_TRUE(name);
|
||||
ASSERT_THAT(*name->value, IsStringEq(expectedName));
|
||||
ASSERT_THAT(name->value, IsStringEq(expectedName));
|
||||
|
||||
auto version = v.attrs()->get(createSymbol("version"));
|
||||
ASSERT_TRUE(version);
|
||||
ASSERT_THAT(*version->value, IsStringEq(expectedVersion));
|
||||
ASSERT_THAT(version->value, IsStringEq(expectedVersion));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
@@ -741,12 +741,12 @@ namespace nix {
|
||||
auto v = eval("builtins.split \"(a)b\" \"abc\"");
|
||||
ASSERT_THAT(v, IsListOfSize(3));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
|
||||
ASSERT_THAT(v.listElems()[0], IsStringEq(""));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[1], IsListOfSize(1));
|
||||
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
|
||||
ASSERT_THAT(v.listElems()[1], IsListOfSize(1));
|
||||
ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a"));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[2], IsStringEq("c"));
|
||||
ASSERT_THAT(v.listElems()[2], IsStringEq("c"));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, split2) {
|
||||
@@ -754,17 +754,17 @@ namespace nix {
|
||||
auto v = eval("builtins.split \"([ac])\" \"abc\"");
|
||||
ASSERT_THAT(v, IsListOfSize(5));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
|
||||
ASSERT_THAT(v.listElems()[0], IsStringEq(""));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[1], IsListOfSize(1));
|
||||
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
|
||||
ASSERT_THAT(v.listElems()[1], IsListOfSize(1));
|
||||
ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a"));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[2], IsStringEq("b"));
|
||||
ASSERT_THAT(v.listElems()[2], IsStringEq("b"));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[3], IsListOfSize(1));
|
||||
ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c"));
|
||||
ASSERT_THAT(v.listElems()[3], IsListOfSize(1));
|
||||
ASSERT_THAT(v.listElems()[3].listElems()[0], IsStringEq("c"));
|
||||
|
||||
ASSERT_THAT(*v.listElems()[4], IsStringEq(""));
|
||||
ASSERT_THAT(v.listElems()[4], IsStringEq(""));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, split3) {
|
||||
@@ -772,23 +772,23 @@ namespace nix {
|
||||
ASSERT_THAT(v, IsListOfSize(5));
|
||||
|
||||
// First list element
|
||||
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
|
||||
ASSERT_THAT(v.listElems()[0], IsStringEq(""));
|
||||
|
||||
// 2nd list element is a list [ "" null ]
|
||||
ASSERT_THAT(*v.listElems()[1], IsListOfSize(2));
|
||||
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
|
||||
ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull());
|
||||
ASSERT_THAT(v.listElems()[1], IsListOfSize(2));
|
||||
ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a"));
|
||||
ASSERT_THAT(v.listElems()[1].listElems()[1], IsNull());
|
||||
|
||||
// 3rd element
|
||||
ASSERT_THAT(*v.listElems()[2], IsStringEq("b"));
|
||||
ASSERT_THAT(v.listElems()[2], IsStringEq("b"));
|
||||
|
||||
// 4th element is a list: [ null "c" ]
|
||||
ASSERT_THAT(*v.listElems()[3], IsListOfSize(2));
|
||||
ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull());
|
||||
ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c"));
|
||||
ASSERT_THAT(v.listElems()[3], IsListOfSize(2));
|
||||
ASSERT_THAT(v.listElems()[3].listElems()[0], IsNull());
|
||||
ASSERT_THAT(v.listElems()[3].listElems()[1], IsStringEq("c"));
|
||||
|
||||
// 5th element is the empty string
|
||||
ASSERT_THAT(*v.listElems()[4], IsStringEq(""));
|
||||
ASSERT_THAT(v.listElems()[4], IsStringEq(""));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, split4) {
|
||||
@@ -798,12 +798,12 @@ namespace nix {
|
||||
auto second = v.listElems()[1];
|
||||
auto third = v.listElems()[2];
|
||||
|
||||
ASSERT_THAT(*first, IsStringEq(" "));
|
||||
ASSERT_THAT(first, IsStringEq(" "));
|
||||
|
||||
ASSERT_THAT(*second, IsListOfSize(1));
|
||||
ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO"));
|
||||
ASSERT_THAT(second, IsListOfSize(1));
|
||||
ASSERT_THAT(second.listElems()[0], IsStringEq("FOO"));
|
||||
|
||||
ASSERT_THAT(*third, IsStringEq(" "));
|
||||
ASSERT_THAT(third, IsStringEq(" "));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, match1) {
|
||||
@@ -819,14 +819,14 @@ namespace nix {
|
||||
TEST_F(PrimOpTest, match3) {
|
||||
auto v = eval("builtins.match \"a(b)(c)\" \"abc\"");
|
||||
ASSERT_THAT(v, IsListOfSize(2));
|
||||
ASSERT_THAT(*v.listElems()[0], IsStringEq("b"));
|
||||
ASSERT_THAT(*v.listElems()[1], IsStringEq("c"));
|
||||
ASSERT_THAT(v.listElems()[0], IsStringEq("b"));
|
||||
ASSERT_THAT(v.listElems()[1], IsStringEq("c"));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, match4) {
|
||||
auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \"");
|
||||
ASSERT_THAT(v, IsListOfSize(1));
|
||||
ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO"));
|
||||
ASSERT_THAT(v.listElems()[0], IsStringEq("FOO"));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, attrNames) {
|
||||
@@ -836,7 +836,7 @@ namespace nix {
|
||||
// ensure that the list is sorted
|
||||
const std::vector<std::string_view> expected { "a", "x", "y", "z" };
|
||||
for (const auto [n, elem] : enumerate(v.listItems()))
|
||||
ASSERT_THAT(*elem, IsStringEq(expected[n]));
|
||||
ASSERT_THAT(elem, IsStringEq(expected[n]));
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, genericClosure_not_strict) {
|
||||
|
||||
@@ -69,11 +69,11 @@ namespace nix {
|
||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
ASSERT_THAT(*a->value, IsIntEq(3));
|
||||
ASSERT_THAT(a->value, IsIntEq(3));
|
||||
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(2));
|
||||
ASSERT_THAT(b->value, IsIntEq(2));
|
||||
}
|
||||
|
||||
TEST_F(TrivialExpressionTest, hasAttrOpFalse) {
|
||||
@@ -171,18 +171,18 @@ namespace nix {
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
|
||||
ASSERT_THAT(*a->value, IsThunk());
|
||||
state.forceValue(*a->value, noPos);
|
||||
ASSERT_THAT(a->value, IsThunk());
|
||||
state.forceValue(a->value, noPos);
|
||||
|
||||
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
|
||||
ASSERT_THAT(a->value, IsAttrsOfSize(2));
|
||||
|
||||
auto b = a->value->attrs()->get(createSymbol("b"));
|
||||
auto b = a->value.attrs()->get(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||
ASSERT_THAT(b->value, IsIntEq(1));
|
||||
|
||||
auto c = a->value->attrs()->get(createSymbol("c"));
|
||||
auto c = a->value.attrs()->get(createSymbol("c"));
|
||||
ASSERT_NE(c, nullptr);
|
||||
ASSERT_THAT(*c->value, IsIntEq(2));
|
||||
ASSERT_THAT(c->value, IsIntEq(2));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
@@ -204,7 +204,7 @@ namespace nix {
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto b = v.attrs()->get(createSymbol("or"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||
ASSERT_THAT(b->value, IsIntEq(1));
|
||||
}
|
||||
|
||||
TEST_F(TrivialExpressionTest, orCantBeUsed) {
|
||||
|
||||
@@ -66,8 +66,8 @@ TEST_F(ValuePrintingTests, tAttrs)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), vTwo);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -84,11 +84,11 @@ TEST_F(ValuePrintingTests, tList)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
auto vList = evaluator.mem.newList(5);
|
||||
vList->elems[0] = &vOne;
|
||||
vList->elems[1] = &vTwo;
|
||||
vList->elems[0] = vOne;
|
||||
vList->elems[1] = vTwo;
|
||||
vList->size = 3;
|
||||
|
||||
test(Value(NewValueAs::list, vList), "[ 1 2 «nullptr» ]");
|
||||
test(Value(NewValueAs::list, vList), "[ 1 2 «invalid» ]");
|
||||
}
|
||||
|
||||
TEST_F(ValuePrintingTests, vThunk)
|
||||
@@ -210,23 +210,23 @@ TEST_F(ValuePrintingTests, depthAttrs)
|
||||
vAttrsEmpty.mkAttrs(builderEmpty.finish());
|
||||
|
||||
BindingsBuilder builderNested = evaluator.buildBindings(1);
|
||||
builderNested.insert(evaluator.symbols.create("zero"), &vZero);
|
||||
builderNested.insert(evaluator.symbols.create("zero"), vZero);
|
||||
Value vAttrsNested;
|
||||
vAttrsNested.mkAttrs(builderNested.finish());
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder.insert(evaluator.symbols.create("empty"), &vAttrsEmpty);
|
||||
builder.insert(evaluator.symbols.create("nested"), &vAttrsNested);
|
||||
builder.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), vTwo);
|
||||
builder.insert(evaluator.symbols.create("empty"), vAttrsEmpty);
|
||||
builder.insert(evaluator.symbols.create("nested"), vAttrsNested);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
BindingsBuilder builder2 = evaluator.buildBindings(10);
|
||||
builder2.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder2.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder2.insert(evaluator.symbols.create("nested"), &vAttrs);
|
||||
builder2.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder2.insert(evaluator.symbols.create("two"), vTwo);
|
||||
builder2.insert(evaluator.symbols.create("nested"), vAttrs);
|
||||
|
||||
Value vNested;
|
||||
vNested.mkAttrs(builder2.finish());
|
||||
@@ -246,24 +246,24 @@ TEST_F(ValuePrintingTests, depthList)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), vTwo);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
BindingsBuilder builder2 = evaluator.buildBindings(10);
|
||||
builder2.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder2.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder2.insert(evaluator.symbols.create("nested"), &vAttrs);
|
||||
builder2.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder2.insert(evaluator.symbols.create("two"), vTwo);
|
||||
builder2.insert(evaluator.symbols.create("nested"), vAttrs);
|
||||
|
||||
Value vNested;
|
||||
vNested.mkAttrs(builder2.finish());
|
||||
|
||||
auto list = evaluator.mem.newList(5);
|
||||
list->elems[0] = &vOne;
|
||||
list->elems[1] = &vTwo;
|
||||
list->elems[2] = &vNested;
|
||||
list->elems[0] = vOne;
|
||||
list->elems[1] = vTwo;
|
||||
list->elems[2] = vNested;
|
||||
list->size = 3;
|
||||
|
||||
Value vList{NewValueAs::list, list};
|
||||
@@ -310,8 +310,8 @@ TEST_F(ValuePrintingTests, attrsTypeFirst)
|
||||
vApple.mkString("apple");
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("type"), &vType);
|
||||
builder.insert(evaluator.symbols.create("apple"), &vApple);
|
||||
builder.insert(evaluator.symbols.create("type"), vType);
|
||||
builder.insert(evaluator.symbols.create("apple"), vApple);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -421,8 +421,8 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), vTwo);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -440,7 +440,7 @@ TEST_F(ValuePrintingTests, ansiColorsDerivation)
|
||||
vDerivation.mkString("derivation");
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.s.type, &vDerivation);
|
||||
builder.insert(evaluator.s.type, vDerivation);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -468,7 +468,7 @@ TEST_F(ValuePrintingTests, ansiColorsError)
|
||||
state.eval(e, vError);
|
||||
|
||||
test(
|
||||
*vError.attrs()->begin()->value,
|
||||
vError.attrs()->begin()->value,
|
||||
ANSI_RED "«error: uh oh!»" ANSI_NORMAL,
|
||||
PrintOptions{
|
||||
.ansiColors = true,
|
||||
@@ -519,7 +519,7 @@ TEST_F(ValuePrintingTests, ansiColorsAssert)
|
||||
|
||||
ASSERT_EQ(v.type(), nAttrs);
|
||||
test(
|
||||
*v.attrs()->begin()->value,
|
||||
v.attrs()->begin()->value,
|
||||
ANSI_RED "«error: assertion failed»" ANSI_NORMAL,
|
||||
PrintOptions{.ansiColors = true, .force = true}
|
||||
);
|
||||
@@ -534,14 +534,14 @@ TEST_F(ValuePrintingTests, ansiColorsList)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
auto vList = evaluator.mem.newList(5);
|
||||
vList->elems[0] = &vOne;
|
||||
vList->elems[1] = &vTwo;
|
||||
vList->elems[0] = vOne;
|
||||
vList->elems[1] = vTwo;
|
||||
vList->size = 3;
|
||||
|
||||
test(
|
||||
Value(NewValueAs::list, vList),
|
||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA
|
||||
"«nullptr»" ANSI_NORMAL " ]",
|
||||
"«invalid»" ANSI_NORMAL " ]",
|
||||
PrintOptions{.ansiColors = true}
|
||||
);
|
||||
}
|
||||
@@ -640,14 +640,14 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
|
||||
vZero.mkInt(0);
|
||||
|
||||
BindingsBuilder innerBuilder = evaluator.buildBindings(1);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), &vZero);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), vZero);
|
||||
|
||||
Value vInner;
|
||||
vInner.mkAttrs(innerBuilder.finish());
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("a"), &vInner);
|
||||
builder.insert(evaluator.symbols.create("b"), &vInner);
|
||||
builder.insert(evaluator.symbols.create("a"), vInner);
|
||||
builder.insert(evaluator.symbols.create("b"), vInner);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -665,14 +665,14 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
|
||||
vZero.mkInt(0);
|
||||
|
||||
BindingsBuilder innerBuilder = evaluator.buildBindings(1);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), &vZero);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), vZero);
|
||||
|
||||
Value vInner;
|
||||
vInner.mkAttrs(innerBuilder.finish());
|
||||
|
||||
auto vList = evaluator.mem.newList(3);
|
||||
vList->elems[0] = &vInner;
|
||||
vList->elems[1] = &vInner;
|
||||
vList->elems[0] = vInner;
|
||||
vList->elems[1] = vInner;
|
||||
vList->size = 2;
|
||||
|
||||
test(
|
||||
@@ -688,14 +688,14 @@ TEST_F(ValuePrintingTests, listRepeated)
|
||||
vZero.mkInt(0);
|
||||
|
||||
BindingsBuilder innerBuilder = evaluator.buildBindings(1);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), &vZero);
|
||||
innerBuilder.insert(evaluator.symbols.create("x"), vZero);
|
||||
|
||||
Value vInner;
|
||||
vInner.mkAttrs(innerBuilder.finish());
|
||||
|
||||
auto list = evaluator.mem.newList(3);
|
||||
list->elems[0] = &vInner;
|
||||
list->elems[1] = &vInner;
|
||||
list->elems[0] = vInner;
|
||||
list->elems[1] = vInner;
|
||||
list->size = 2;
|
||||
|
||||
Value vList(NewValueAs::list, list);
|
||||
@@ -716,8 +716,8 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder = evaluator.buildBindings(10);
|
||||
builder.insert(evaluator.symbols.create("one"), &vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), &vTwo);
|
||||
builder.insert(evaluator.symbols.create("one"), vOne);
|
||||
builder.insert(evaluator.symbols.create("two"), vTwo);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -732,7 +732,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||
Value vThree;
|
||||
vThree.mkInt(3);
|
||||
|
||||
builder.insert(evaluator.symbols.create("three"), &vThree);
|
||||
builder.insert(evaluator.symbols.create("three"), vThree);
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
test(vAttrs,
|
||||
@@ -753,8 +753,8 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||
|
||||
auto list = evaluator.mem.newList(4);
|
||||
Value vList{NewValueAs::list, list};
|
||||
list->elems[0] = &vOne;
|
||||
list->elems[1] = &vTwo;
|
||||
list->elems[0] = vOne;
|
||||
list->elems[1] = vTwo;
|
||||
list->size = 2;
|
||||
|
||||
test(vList,
|
||||
@@ -767,7 +767,7 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||
Value vThree;
|
||||
vThree.mkInt(3);
|
||||
|
||||
list->elems[2] = &vThree;
|
||||
list->elems[2] = vThree;
|
||||
list->size = 3;
|
||||
|
||||
test(vList,
|
||||
@@ -787,7 +787,7 @@ TEST_F(ValuePrintingTests, osc8InAttrSets)
|
||||
|
||||
auto vZero = Value{NewValueAs::integer, NixInt{0}};
|
||||
|
||||
builder.insert(evaluator.symbols.create("x"), &vZero, pos);
|
||||
builder.insert(evaluator.symbols.create("x"), vZero, pos);
|
||||
auto vAttrs = Value{NewValueAs::attrs, builder.finish()};
|
||||
|
||||
auto hyperlink = makeHyperlink("x", makeHyperlinkLocalPath("/dev/null", 1));
|
||||
|
||||
Reference in New Issue
Block a user