mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 23:36:16 +02:00
Merge pull request #10251 from edolstra/list-builder
Add a ListBuilder helper for constructing list values
This commit is contained in:
commit
d16d7f5f31
10 changed files with 235 additions and 164 deletions
|
@ -435,7 +435,8 @@ EvalState::EvalState(
|
||||||
|
|
||||||
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
||||||
|
|
||||||
vEmptyList.mkList(0);
|
vEmptyList.mkList(buildList(0));
|
||||||
|
vNull.mkNull();
|
||||||
|
|
||||||
/* Initialise the Nix expression search path. */
|
/* Initialise the Nix expression search path. */
|
||||||
if (!evalSettings.pureEval) {
|
if (!evalSettings.pureEval) {
|
||||||
|
@ -923,12 +924,11 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalState::mkList(Value & v, size_t size)
|
ListBuilder::ListBuilder(EvalState & state, size_t size)
|
||||||
|
: size(size)
|
||||||
|
, elems(size <= 2 ? inlineElems : (Value * *) allocBytes(size * sizeof(Value *)))
|
||||||
{
|
{
|
||||||
v.mkList(size);
|
state.nrListElems += size;
|
||||||
if (size > 2)
|
|
||||||
v.bigList.elems = (Value * *) allocBytes(size * sizeof(Value *));
|
|
||||||
nrListElems += size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1353,9 +1353,10 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprList::eval(EvalState & state, Env & env, Value & v)
|
void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
state.mkList(v, elems.size());
|
auto list = state.buildList(elems.size());
|
||||||
for (auto [n, v2] : enumerate(v.listItems()))
|
for (const auto & [n, v2] : enumerate(list))
|
||||||
const_cast<Value * &>(v2) = elems[n]->maybeThunk(state, env);
|
v2 = elems[n]->maybeThunk(state, env);
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1945,7 +1946,7 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos, std::string_view errorCtx)
|
void EvalState::concatLists(Value & v, size_t nrLists, Value * const * lists, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
nrListConcats++;
|
nrListConcats++;
|
||||||
|
|
||||||
|
@ -1963,14 +1964,15 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mkList(v, len);
|
auto list = buildList(len);
|
||||||
auto out = v.listElems();
|
auto out = list.elems;
|
||||||
for (size_t n = 0, pos = 0; n < nrLists; ++n) {
|
for (size_t n = 0, pos = 0; n < nrLists; ++n) {
|
||||||
auto l = lists[n]->listSize();
|
auto l = lists[n]->listSize();
|
||||||
if (l)
|
if (l)
|
||||||
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
|
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
|
||||||
pos += l;
|
pos += l;
|
||||||
}
|
}
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,11 @@ public:
|
||||||
*/
|
*/
|
||||||
Value vEmptyList;
|
Value vEmptyList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null constant.
|
||||||
|
*/
|
||||||
|
Value vNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The accessor for the root filesystem.
|
* The accessor for the root filesystem.
|
||||||
*/
|
*/
|
||||||
|
@ -615,7 +620,11 @@ public:
|
||||||
return BindingsBuilder(*this, allocBindings(capacity));
|
return BindingsBuilder(*this, allocBindings(capacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkList(Value & v, size_t length);
|
ListBuilder buildList(size_t size)
|
||||||
|
{
|
||||||
|
return ListBuilder(*this, size);
|
||||||
|
}
|
||||||
|
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
void mkPos(Value & v, PosIdx pos);
|
void mkPos(Value & v, PosIdx pos);
|
||||||
|
|
||||||
|
@ -662,7 +671,7 @@ public:
|
||||||
const SingleDerivedPath & p,
|
const SingleDerivedPath & p,
|
||||||
Value & v);
|
Value & v);
|
||||||
|
|
||||||
void concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos, std::string_view errorCtx);
|
void concatLists(Value & v, size_t nrLists, Value * const * lists, const PosIdx pos, std::string_view errorCtx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print statistics, if enabled.
|
* Print statistics, if enabled.
|
||||||
|
@ -756,6 +765,7 @@ private:
|
||||||
friend void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v);
|
friend void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v);
|
||||||
|
|
||||||
friend struct Value;
|
friend struct Value;
|
||||||
|
friend class ListBuilder;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DebugTraceStacker {
|
struct DebugTraceStacker {
|
||||||
|
|
|
@ -57,11 +57,10 @@ class JSONSax : nlohmann::json_sax<json> {
|
||||||
ValueVector values;
|
ValueVector values;
|
||||||
std::unique_ptr<JSONState> resolve(EvalState & state) override
|
std::unique_ptr<JSONState> resolve(EvalState & state) override
|
||||||
{
|
{
|
||||||
Value & v = parent->value(state);
|
auto list = state.buildList(values.size());
|
||||||
state.mkList(v, values.size());
|
for (const auto & [n, v2] : enumerate(list))
|
||||||
for (size_t n = 0; n < values.size(); ++n) {
|
v2 = values[n];
|
||||||
v.listElems()[n] = values[n];
|
parent->value(state).mkList(list);
|
||||||
}
|
|
||||||
return std::move(parent);
|
return std::move(parent);
|
||||||
}
|
}
|
||||||
void add() override {
|
void add() override {
|
||||||
|
|
|
@ -187,13 +187,13 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||||
NixStringContextElem::DrvDeep { .drvPath = *storePath },
|
NixStringContextElem::DrvDeep { .drvPath = *storePath },
|
||||||
});
|
});
|
||||||
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
||||||
auto & outputsVal = attrs.alloc(state.sOutputs);
|
|
||||||
state.mkList(outputsVal, drv.outputs.size());
|
|
||||||
|
|
||||||
|
auto list = state.buildList(drv.outputs.size());
|
||||||
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
||||||
mkOutputString(state, attrs, *storePath, o);
|
mkOutputString(state, attrs, *storePath, o);
|
||||||
(outputsVal.listElems()[i] = state.allocValue())->mkString(o.first);
|
(list[i] = state.allocValue())->mkString(o.first);
|
||||||
}
|
}
|
||||||
|
attrs.alloc(state.sOutputs).mkList(list);
|
||||||
|
|
||||||
auto w = state.allocValue();
|
auto w = state.allocValue();
|
||||||
w->mkAttrs(attrs);
|
w->mkAttrs(attrs);
|
||||||
|
@ -694,10 +694,10 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the result list. */
|
/* Create the result list. */
|
||||||
state.mkList(v, res.size());
|
auto list = state.buildList(res.size());
|
||||||
unsigned int n = 0;
|
for (const auto & [n, i] : enumerate(res))
|
||||||
for (auto & i : res)
|
list[n] = i;
|
||||||
v.listElems()[n++] = i;
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_genericClosure(PrimOp {
|
static RegisterPrimOp primop_genericClosure(PrimOp {
|
||||||
|
@ -2423,14 +2423,15 @@ static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrNames");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrNames");
|
||||||
|
|
||||||
state.mkList(v, args[0]->attrs->size());
|
auto list = state.buildList(args[0]->attrs->size());
|
||||||
|
|
||||||
size_t n = 0;
|
for (const auto & [n, i] : enumerate(*args[0]->attrs))
|
||||||
for (auto & i : *args[0]->attrs)
|
(list[n] = state.allocValue())->mkString(state.symbols[i.name]);
|
||||||
(v.listElems()[n++] = state.allocValue())->mkString(state.symbols[i.name]);
|
|
||||||
|
|
||||||
std::sort(v.listElems(), v.listElems() + n,
|
std::sort(list.begin(), list.end(),
|
||||||
[](Value * v1, Value * v2) { return strcmp(v1->c_str(), v2->c_str()) < 0; });
|
[](Value * v1, Value * v2) { return strcmp(v1->c_str(), v2->c_str()) < 0; });
|
||||||
|
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_attrNames({
|
static RegisterPrimOp primop_attrNames({
|
||||||
|
@ -2450,21 +2451,22 @@ static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrValues");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrValues");
|
||||||
|
|
||||||
state.mkList(v, args[0]->attrs->size());
|
auto list = state.buildList(args[0]->attrs->size());
|
||||||
|
|
||||||
unsigned int n = 0;
|
for (const auto & [n, i] : enumerate(*args[0]->attrs))
|
||||||
for (auto & i : *args[0]->attrs)
|
list[n] = (Value *) &i;
|
||||||
v.listElems()[n++] = (Value *) &i;
|
|
||||||
|
|
||||||
std::sort(v.listElems(), v.listElems() + n,
|
std::sort(list.begin(), list.end(),
|
||||||
[&](Value * v1, Value * v2) {
|
[&](Value * v1, Value * v2) {
|
||||||
std::string_view s1 = state.symbols[((Attr *) v1)->name],
|
std::string_view s1 = state.symbols[((Attr *) v1)->name],
|
||||||
s2 = state.symbols[((Attr *) v2)->name];
|
s2 = state.symbols[((Attr *) v2)->name];
|
||||||
return s1 < s2;
|
return s1 < s2;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (unsigned int i = 0; i < n; ++i)
|
for (auto & v : list)
|
||||||
v.listElems()[i] = ((Attr *) v.listElems()[i])->value;
|
v = ((Attr *) v)->value;
|
||||||
|
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_attrValues({
|
static RegisterPrimOp primop_attrValues({
|
||||||
|
@ -2805,9 +2807,10 @@ static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
res[found++] = i->value;
|
res[found++] = i->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkList(v, found);
|
auto list = state.buildList(found);
|
||||||
for (unsigned int n = 0; n < found; ++n)
|
for (unsigned int n = 0; n < found; ++n)
|
||||||
v.listElems()[n] = res[n];
|
list[n] = res[n];
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_catAttrs({
|
static RegisterPrimOp primop_catAttrs({
|
||||||
|
@ -2908,43 +2911,50 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
// attribute with the merge function application. this way we need not
|
// attribute with the merge function application. this way we need not
|
||||||
// use (slightly slower) temporary storage the GC does not know about.
|
// use (slightly slower) temporary storage the GC does not know about.
|
||||||
|
|
||||||
std::map<Symbol, std::pair<size_t, Value * *>> attrsSeen;
|
struct Item
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
std::optional<ListBuilder> list;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<Symbol, Item> attrsSeen;
|
||||||
|
|
||||||
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.zipAttrsWith");
|
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.zipAttrsWith");
|
||||||
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.zipAttrsWith");
|
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.zipAttrsWith");
|
||||||
const auto listSize = args[1]->listSize();
|
const auto listItems = args[1]->listItems();
|
||||||
const auto listElems = args[1]->listElems();
|
|
||||||
|
|
||||||
for (unsigned int n = 0; n < listSize; ++n) {
|
for (auto & vElem : listItems) {
|
||||||
Value * vElem = listElems[n];
|
|
||||||
state.forceAttrs(*vElem, noPos, "while evaluating a value of the list passed as second argument to builtins.zipAttrsWith");
|
state.forceAttrs(*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++;
|
attrsSeen.try_emplace(attr.name).first->second.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & [sym, elem] : attrsSeen)
|
||||||
|
elem.list.emplace(state.buildList(elem.size));
|
||||||
|
|
||||||
|
for (auto & vElem : listItems) {
|
||||||
|
for (auto & attr : *vElem->attrs) {
|
||||||
|
auto & item = attrsSeen.at(attr.name);
|
||||||
|
(*item.list)[item.pos++] = attr.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attrs = state.buildBindings(attrsSeen.size());
|
auto attrs = state.buildBindings(attrsSeen.size());
|
||||||
|
|
||||||
for (auto & [sym, elem] : attrsSeen) {
|
for (auto & [sym, elem] : attrsSeen) {
|
||||||
auto & list = attrs.alloc(sym);
|
|
||||||
state.mkList(list, elem.first);
|
|
||||||
elem.second = list.listElems();
|
|
||||||
}
|
|
||||||
v.mkAttrs(attrs.alreadySorted());
|
|
||||||
|
|
||||||
for (unsigned int n = 0; n < listSize; ++n) {
|
|
||||||
Value * vElem = listElems[n];
|
|
||||||
for (auto & attr : *vElem->attrs)
|
|
||||||
*attrsSeen[attr.name].second++ = attr.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto & attr : *v.attrs) {
|
|
||||||
auto name = state.allocValue();
|
auto name = state.allocValue();
|
||||||
name->mkString(state.symbols[attr.name]);
|
name->mkString(state.symbols[sym]);
|
||||||
auto call1 = state.allocValue();
|
auto call1 = state.allocValue();
|
||||||
call1->mkApp(args[0], name);
|
call1->mkApp(args[0], name);
|
||||||
auto call2 = state.allocValue();
|
auto call2 = state.allocValue();
|
||||||
call2->mkApp(call1, attr.value);
|
auto arg = state.allocValue();
|
||||||
attr.value = call2;
|
arg->mkList(*elem.list);
|
||||||
|
call2->mkApp(call1, arg);
|
||||||
|
attrs.insert(sym, call2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v.mkAttrs(attrs.alreadySorted());
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_zipAttrsWith({
|
static RegisterPrimOp primop_zipAttrsWith({
|
||||||
|
@ -3055,9 +3065,10 @@ static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
if (args[0]->listSize() == 0)
|
if (args[0]->listSize() == 0)
|
||||||
state.error<EvalError>("'tail' called on an empty list").atPos(pos).debugThrow();
|
state.error<EvalError>("'tail' called on an empty list").atPos(pos).debugThrow();
|
||||||
|
|
||||||
state.mkList(v, args[0]->listSize() - 1);
|
auto list = state.buildList(args[0]->listSize() - 1);
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n)
|
for (const auto & [n, v] : enumerate(list))
|
||||||
v.listElems()[n] = args[0]->listElems()[n + 1];
|
v = args[0]->listElems()[n + 1];
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_tail({
|
static RegisterPrimOp primop_tail({
|
||||||
|
@ -3088,10 +3099,11 @@ static void prim_map(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
|
|
||||||
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.map");
|
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.map");
|
||||||
|
|
||||||
state.mkList(v, args[1]->listSize());
|
auto list = state.buildList(args[1]->listSize());
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n)
|
for (const auto & [n, v] : enumerate(list))
|
||||||
(v.listElems()[n] = state.allocValue())->mkApp(
|
(v = state.allocValue())->mkApp(
|
||||||
args[0], args[1]->listElems()[n]);
|
args[0], args[1]->listElems()[n]);
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_map({
|
static RegisterPrimOp primop_map({
|
||||||
|
@ -3140,8 +3152,9 @@ static void prim_filter(EvalState & state, const PosIdx pos, Value * * args, Val
|
||||||
if (same)
|
if (same)
|
||||||
v = *args[1];
|
v = *args[1];
|
||||||
else {
|
else {
|
||||||
state.mkList(v, k);
|
auto list = state.buildList(k);
|
||||||
for (unsigned int n = 0; n < k; ++n) v.listElems()[n] = vs[n];
|
for (const auto & [n, v] : enumerate(list)) v = vs[n];
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3316,12 +3329,13 @@ static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Va
|
||||||
// as evaluating map without accessing any values makes little sense.
|
// as evaluating map without accessing any values makes little sense.
|
||||||
state.forceFunction(*args[0], noPos, "while evaluating the first argument passed to builtins.genList");
|
state.forceFunction(*args[0], noPos, "while evaluating the first argument passed to builtins.genList");
|
||||||
|
|
||||||
state.mkList(v, len);
|
auto list = state.buildList(len);
|
||||||
for (unsigned int n = 0; n < (unsigned int) len; ++n) {
|
for (const auto & [n, v] : enumerate(list)) {
|
||||||
auto arg = state.allocValue();
|
auto arg = state.allocValue();
|
||||||
arg->mkInt(n);
|
arg->mkInt(n);
|
||||||
(v.listElems()[n] = state.allocValue())->mkApp(args[0], arg);
|
(v = state.allocValue())->mkApp(args[0], arg);
|
||||||
}
|
}
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_genList({
|
static RegisterPrimOp primop_genList({
|
||||||
|
@ -3355,11 +3369,9 @@ static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
|
|
||||||
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.sort");
|
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.sort");
|
||||||
|
|
||||||
state.mkList(v, len);
|
auto list = state.buildList(len);
|
||||||
for (unsigned int n = 0; n < len; ++n) {
|
for (const auto & [n, v] : enumerate(list))
|
||||||
state.forceValue(*args[1]->listElems()[n], pos);
|
state.forceValue(*(v = args[1]->listElems()[n]), pos);
|
||||||
v.listElems()[n] = args[1]->listElems()[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto comparator = [&](Value * a, Value * b) {
|
auto comparator = [&](Value * a, Value * b) {
|
||||||
/* Optimization: if the comparator is lessThan, bypass
|
/* Optimization: if the comparator is lessThan, bypass
|
||||||
|
@ -3378,7 +3390,9 @@ static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
/* FIXME: std::sort can segfault if the comparator is not a strict
|
/* FIXME: std::sort can segfault if the comparator is not a strict
|
||||||
weak ordering. What to do? std::stable_sort() seems more
|
weak ordering. What to do? std::stable_sort() seems more
|
||||||
resilient, but no guarantees... */
|
resilient, but no guarantees... */
|
||||||
std::stable_sort(v.listElems(), v.listElems() + len, comparator);
|
std::stable_sort(list.begin(), list.end(), comparator);
|
||||||
|
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_sort({
|
static RegisterPrimOp primop_sort({
|
||||||
|
@ -3424,17 +3438,17 @@ static void prim_partition(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
|
|
||||||
auto attrs = state.buildBindings(2);
|
auto attrs = state.buildBindings(2);
|
||||||
|
|
||||||
auto & vRight = attrs.alloc(state.sRight);
|
|
||||||
auto rsize = right.size();
|
auto rsize = right.size();
|
||||||
state.mkList(vRight, rsize);
|
auto rlist = state.buildList(rsize);
|
||||||
if (rsize)
|
if (rsize)
|
||||||
memcpy(vRight.listElems(), right.data(), sizeof(Value *) * rsize);
|
memcpy(rlist.elems, right.data(), sizeof(Value *) * rsize);
|
||||||
|
attrs.alloc(state.sRight).mkList(rlist);
|
||||||
|
|
||||||
auto & vWrong = attrs.alloc(state.sWrong);
|
|
||||||
auto wsize = wrong.size();
|
auto wsize = wrong.size();
|
||||||
state.mkList(vWrong, wsize);
|
auto wlist = state.buildList(wsize);
|
||||||
if (wsize)
|
if (wsize)
|
||||||
memcpy(vWrong.listElems(), wrong.data(), sizeof(Value *) * wsize);
|
memcpy(wlist.elems, wrong.data(), sizeof(Value *) * wsize);
|
||||||
|
attrs.alloc(state.sWrong).mkList(wlist);
|
||||||
|
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
@ -3481,10 +3495,10 @@ static void prim_groupBy(EvalState & state, const PosIdx pos, Value * * args, Va
|
||||||
auto attrs2 = state.buildBindings(attrs.size());
|
auto attrs2 = state.buildBindings(attrs.size());
|
||||||
|
|
||||||
for (auto & i : attrs) {
|
for (auto & i : attrs) {
|
||||||
auto & list = attrs2.alloc(i.first);
|
|
||||||
auto size = i.second.size();
|
auto size = i.second.size();
|
||||||
state.mkList(list, size);
|
auto list = state.buildList(size);
|
||||||
memcpy(list.listElems(), i.second.data(), sizeof(Value *) * size);
|
memcpy(list.elems, i.second.data(), sizeof(Value *) * size);
|
||||||
|
attrs2.alloc(i.first).mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
v.mkAttrs(attrs2.alreadySorted());
|
v.mkAttrs(attrs2.alreadySorted());
|
||||||
|
@ -3531,14 +3545,15 @@ static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
len += lists[n].listSize();
|
len += lists[n].listSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkList(v, len);
|
auto list = state.buildList(len);
|
||||||
auto out = v.listElems();
|
auto out = list.elems;
|
||||||
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
||||||
auto l = lists[n].listSize();
|
auto l = lists[n].listSize();
|
||||||
if (l)
|
if (l)
|
||||||
memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *));
|
memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *));
|
||||||
pos += l;
|
pos += l;
|
||||||
}
|
}
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_concatMap({
|
static RegisterPrimOp primop_concatMap({
|
||||||
|
@ -3986,14 +4001,13 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// the first match is the whole string
|
// the first match is the whole string
|
||||||
const size_t len = match.size() - 1;
|
auto list = state.buildList(match.size() - 1);
|
||||||
state.mkList(v, len);
|
for (const auto & [i, v2] : enumerate(list))
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
if (!match[i + 1].matched)
|
if (!match[i + 1].matched)
|
||||||
(v.listElems()[i] = state.allocValue())->mkNull();
|
v2 = &state.vNull;
|
||||||
else
|
else
|
||||||
(v.listElems()[i] = state.allocValue())->mkString(match[i + 1].str());
|
(v2 = state.allocValue())->mkString(match[i + 1].str());
|
||||||
}
|
v.mkList(list);
|
||||||
|
|
||||||
} catch (std::regex_error & e) {
|
} catch (std::regex_error & e) {
|
||||||
if (e.code() == std::regex_constants::error_space) {
|
if (e.code() == std::regex_constants::error_space) {
|
||||||
|
@ -4062,11 +4076,12 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
|
||||||
// Any matches results are surrounded by non-matching results.
|
// Any matches results are surrounded by non-matching results.
|
||||||
const size_t len = std::distance(begin, end);
|
const size_t len = std::distance(begin, end);
|
||||||
state.mkList(v, 2 * len + 1);
|
auto list = state.buildList(2 * len + 1);
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
v.listElems()[idx++] = args[1];
|
list[0] = args[1];
|
||||||
|
v.mkList(list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4075,28 +4090,31 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
auto match = *i;
|
auto match = *i;
|
||||||
|
|
||||||
// Add a string for non-matched characters.
|
// Add a string for non-matched characters.
|
||||||
(v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str());
|
(list[idx++] = state.allocValue())->mkString(match.prefix().str());
|
||||||
|
|
||||||
// Add a list for matched substrings.
|
// Add a list for matched substrings.
|
||||||
const size_t slen = match.size() - 1;
|
const size_t slen = match.size() - 1;
|
||||||
auto elem = v.listElems()[idx++] = state.allocValue();
|
|
||||||
|
|
||||||
// Start at 1, beacause the first match is the whole string.
|
// Start at 1, beacause the first match is the whole string.
|
||||||
state.mkList(*elem, slen);
|
auto list2 = state.buildList(slen);
|
||||||
for (size_t si = 0; si < slen; ++si) {
|
for (const auto & [si, v2] : enumerate(list2)) {
|
||||||
if (!match[si + 1].matched)
|
if (!match[si + 1].matched)
|
||||||
(elem->listElems()[si] = state.allocValue())->mkNull();
|
v2 = &state.vNull;
|
||||||
else
|
else
|
||||||
(elem->listElems()[si] = state.allocValue())->mkString(match[si + 1].str());
|
(v2 = state.allocValue())->mkString(match[si + 1].str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(list[idx++] = state.allocValue())->mkList(list2);
|
||||||
|
|
||||||
// Add a string for non-matched suffix characters.
|
// Add a string for non-matched suffix characters.
|
||||||
if (idx == 2 * len)
|
if (idx == 2 * len)
|
||||||
(v.listElems()[idx++] = state.allocValue())->mkString(match.suffix().str());
|
(list[idx++] = state.allocValue())->mkString(match.suffix().str());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(idx == 2 * len + 1);
|
assert(idx == 2 * len + 1);
|
||||||
|
|
||||||
|
v.mkList(list);
|
||||||
|
|
||||||
} catch (std::regex_error & e) {
|
} catch (std::regex_error & e) {
|
||||||
if (e.code() == std::regex_constants::error_space) {
|
if (e.code() == std::regex_constants::error_space) {
|
||||||
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
|
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
|
||||||
|
@ -4316,9 +4334,10 @@ static void prim_splitVersion(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
break;
|
break;
|
||||||
components.emplace_back(component);
|
components.emplace_back(component);
|
||||||
}
|
}
|
||||||
state.mkList(v, components.size());
|
auto list = state.buildList(components.size());
|
||||||
for (const auto & [n, component] : enumerate(components))
|
for (const auto & [n, component] : enumerate(components))
|
||||||
(v.listElems()[n] = state.allocValue())->mkString(std::move(component));
|
(list[n] = state.allocValue())->mkString(std::move(component));
|
||||||
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_splitVersion({
|
static RegisterPrimOp primop_splitVersion({
|
||||||
|
@ -4411,8 +4430,7 @@ void EvalState::createBaseEnv()
|
||||||
)",
|
)",
|
||||||
});
|
});
|
||||||
|
|
||||||
v.mkNull();
|
addConstant("null", &vNull, {
|
||||||
addConstant("null", v, {
|
|
||||||
.type = nNull,
|
.type = nNull,
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Primitive value.
|
Primitive value.
|
||||||
|
@ -4559,14 +4577,14 @@ void EvalState::createBaseEnv()
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Add a value containing the current Nix expression search path. */
|
/* Add a value containing the current Nix expression search path. */
|
||||||
mkList(v, searchPath.elements.size());
|
auto list = buildList(searchPath.elements.size());
|
||||||
int n = 0;
|
for (const auto & [n, i] : enumerate(searchPath.elements)) {
|
||||||
for (auto & i : searchPath.elements) {
|
|
||||||
auto attrs = buildBindings(2);
|
auto attrs = buildBindings(2);
|
||||||
attrs.alloc("path").mkString(i.path.s);
|
attrs.alloc("path").mkString(i.path.s);
|
||||||
attrs.alloc("prefix").mkString(i.prefix.s);
|
attrs.alloc("prefix").mkString(i.prefix.s);
|
||||||
(v.listElems()[n++] = allocValue())->mkAttrs(attrs);
|
(list[n] = allocValue())->mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
v.mkList(list);
|
||||||
addConstant("__nixPath", v, {
|
addConstant("__nixPath", v, {
|
||||||
.type = nList,
|
.type = nList,
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
|
|
|
@ -207,10 +207,10 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
if (info.second.allOutputs)
|
if (info.second.allOutputs)
|
||||||
infoAttrs.alloc(sAllOutputs).mkBool(true);
|
infoAttrs.alloc(sAllOutputs).mkBool(true);
|
||||||
if (!info.second.outputs.empty()) {
|
if (!info.second.outputs.empty()) {
|
||||||
auto & outputsVal = infoAttrs.alloc(state.sOutputs);
|
auto list = state.buildList(info.second.outputs.size());
|
||||||
state.mkList(outputsVal, info.second.outputs.size());
|
|
||||||
for (const auto & [i, output] : enumerate(info.second.outputs))
|
for (const auto & [i, output] : enumerate(info.second.outputs))
|
||||||
(outputsVal.listElems()[i] = state.allocValue())->mkString(output);
|
(list[i] = state.allocValue())->mkString(output);
|
||||||
|
infoAttrs.alloc(state.sOutputs).mkList(list);
|
||||||
}
|
}
|
||||||
attrs.alloc(state.store->printStorePath(info.first)).mkAttrs(infoAttrs);
|
attrs.alloc(state.store->printStorePath(info.first)).mkAttrs(infoAttrs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
{
|
{
|
||||||
auto array = toml::get<std::vector<toml::value>>(t);
|
auto array = toml::get<std::vector<toml::value>>(t);
|
||||||
|
|
||||||
size_t size = array.size();
|
auto list = state.buildList(array.size());
|
||||||
state.mkList(v, size);
|
for (const auto & [n, v] : enumerate(list))
|
||||||
for (size_t i = 0; i < size; ++i)
|
visit(*(v = state.allocValue()), array[n]);
|
||||||
visit(*(v.listElems()[i] = state.allocValue()), array[i]);
|
v.mkList(list);
|
||||||
}
|
}
|
||||||
break;;
|
break;;
|
||||||
case toml::value_t::boolean:
|
case toml::value_t::boolean:
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
struct Value;
|
||||||
class BindingsBuilder;
|
class BindingsBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +135,34 @@ class ExternalValueBase
|
||||||
std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
|
std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
|
||||||
|
|
||||||
|
|
||||||
|
class ListBuilder
|
||||||
|
{
|
||||||
|
const size_t size;
|
||||||
|
Value * inlineElems[2] = {nullptr, nullptr};
|
||||||
|
public:
|
||||||
|
Value * * elems;
|
||||||
|
ListBuilder(EvalState & state, size_t size);
|
||||||
|
|
||||||
|
ListBuilder(ListBuilder && x)
|
||||||
|
: size(x.size)
|
||||||
|
, inlineElems{x.inlineElems[0], x.inlineElems[1]}
|
||||||
|
, elems(size <= 2 ? inlineElems : x.elems)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Value * & operator [](size_t n)
|
||||||
|
{
|
||||||
|
return elems[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Value * * iterator;
|
||||||
|
|
||||||
|
iterator begin() { return &elems[0]; }
|
||||||
|
iterator end() { return &elems[size]; }
|
||||||
|
|
||||||
|
friend class Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -217,7 +246,7 @@ public:
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
Value * * elems;
|
Value * const * elems;
|
||||||
} bigList;
|
} bigList;
|
||||||
Value * smallList[2];
|
Value * smallList[2];
|
||||||
ClosureThunk thunk;
|
ClosureThunk thunk;
|
||||||
|
@ -323,16 +352,20 @@ public:
|
||||||
|
|
||||||
Value & mkAttrs(BindingsBuilder & bindings);
|
Value & mkAttrs(BindingsBuilder & bindings);
|
||||||
|
|
||||||
inline void mkList(size_t size)
|
void mkList(const ListBuilder & builder)
|
||||||
{
|
{
|
||||||
clearValue();
|
clearValue();
|
||||||
if (size == 1)
|
if (builder.size == 1) {
|
||||||
|
smallList[0] = builder.inlineElems[0];
|
||||||
internalType = tList1;
|
internalType = tList1;
|
||||||
else if (size == 2)
|
} else if (builder.size == 2) {
|
||||||
|
smallList[0] = builder.inlineElems[0];
|
||||||
|
smallList[1] = builder.inlineElems[1];
|
||||||
internalType = tList2;
|
internalType = tList2;
|
||||||
else {
|
} else {
|
||||||
|
bigList.size = builder.size;
|
||||||
|
bigList.elems = builder.elems;
|
||||||
internalType = tListN;
|
internalType = tListN;
|
||||||
bigList.size = size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +425,7 @@ public:
|
||||||
return internalType == tList1 || internalType == tList2 || internalType == tListN;
|
return internalType == tList1 || internalType == tList2 || internalType == tListN;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * * listElems()
|
Value * const * listElems()
|
||||||
{
|
{
|
||||||
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
|
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v
|
||||||
directory). */
|
directory). */
|
||||||
else if (st.type == InputAccessor::tDirectory) {
|
else if (st.type == InputAccessor::tDirectory) {
|
||||||
auto attrs = state.buildBindings(maxAttrs);
|
auto attrs = state.buildBindings(maxAttrs);
|
||||||
state.mkList(attrs.alloc("_combineChannels"), 0);
|
attrs.insert(state.symbols.create("_combineChannels"), &state.vEmptyList);
|
||||||
StringSet seen;
|
StringSet seen;
|
||||||
getAllExprs(state, path, seen, attrs);
|
getAllExprs(state, path, seen, attrs);
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
|
|
|
@ -49,10 +49,8 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
|
||||||
|
|
||||||
/* Construct the whole top level derivation. */
|
/* Construct the whole top level derivation. */
|
||||||
StorePathSet references;
|
StorePathSet references;
|
||||||
Value manifest;
|
auto list = state.buildList(elems.size());
|
||||||
state.mkList(manifest, elems.size());
|
for (const auto & [n, i] : enumerate(elems)) {
|
||||||
size_t n = 0;
|
|
||||||
for (auto & i : elems) {
|
|
||||||
/* Create a pseudo-derivation containing the name, system,
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
output paths, and optionally the derivation path, as well
|
output paths, and optionally the derivation path, as well
|
||||||
as the meta attributes. */
|
as the meta attributes. */
|
||||||
|
@ -72,10 +70,9 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
|
||||||
attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
|
attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
|
||||||
|
|
||||||
// Copy each output meant for installation.
|
// Copy each output meant for installation.
|
||||||
auto & vOutputs = attrs.alloc(state.sOutputs);
|
auto outputsList = state.buildList(outputs.size());
|
||||||
state.mkList(vOutputs, outputs.size());
|
|
||||||
for (const auto & [m, j] : enumerate(outputs)) {
|
for (const auto & [m, j] : enumerate(outputs)) {
|
||||||
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
(outputsList[m] = state.allocValue())->mkString(j.first);
|
||||||
auto outputAttrs = state.buildBindings(2);
|
auto outputAttrs = state.buildBindings(2);
|
||||||
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
|
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
|
||||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||||
|
@ -87,6 +84,7 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
|
||||||
|
|
||||||
references.insert(*j.second);
|
references.insert(*j.second);
|
||||||
}
|
}
|
||||||
|
attrs.alloc(state.sOutputs).mkList(outputsList);
|
||||||
|
|
||||||
// Copy the meta attributes.
|
// Copy the meta attributes.
|
||||||
auto meta = state.buildBindings(metaNames.size());
|
auto meta = state.buildBindings(metaNames.size());
|
||||||
|
@ -98,11 +96,14 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
|
||||||
|
|
||||||
attrs.alloc(state.sMeta).mkAttrs(meta);
|
attrs.alloc(state.sMeta).mkAttrs(meta);
|
||||||
|
|
||||||
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
(list[n] = state.allocValue())->mkAttrs(attrs);
|
||||||
|
|
||||||
if (drvPath) references.insert(*drvPath);
|
if (drvPath) references.insert(*drvPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value manifest;
|
||||||
|
manifest.mkList(list);
|
||||||
|
|
||||||
/* Also write a copy of the list of user environment elements to
|
/* Also write a copy of the list of user environment elements to
|
||||||
the store; we need it for future modifications of the
|
the store; we need it for future modifications of the
|
||||||
environment. */
|
environment. */
|
||||||
|
|
|
@ -79,11 +79,11 @@ TEST_F(ValuePrintingTests, tList)
|
||||||
Value vTwo;
|
Value vTwo;
|
||||||
vTwo.mkInt(2);
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
auto list = state.buildList(3);
|
||||||
|
list.elems[0] = &vOne;
|
||||||
|
list.elems[1] = &vTwo;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 5);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vOne;
|
|
||||||
vList.bigList.elems[1] = &vTwo;
|
|
||||||
vList.bigList.size = 3;
|
|
||||||
|
|
||||||
test(vList, "[ 1 2 «nullptr» ]");
|
test(vList, "[ 1 2 «nullptr» ]");
|
||||||
}
|
}
|
||||||
|
@ -249,12 +249,12 @@ TEST_F(ValuePrintingTests, depthList)
|
||||||
Value vNested;
|
Value vNested;
|
||||||
vNested.mkAttrs(builder2.finish());
|
vNested.mkAttrs(builder2.finish());
|
||||||
|
|
||||||
|
auto list = state.buildList(3);
|
||||||
|
list.elems[0] = &vOne;
|
||||||
|
list.elems[1] = &vTwo;
|
||||||
|
list.elems[2] = &vNested;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 5);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vOne;
|
|
||||||
vList.bigList.elems[1] = &vTwo;
|
|
||||||
vList.bigList.elems[2] = &vNested;
|
|
||||||
vList.bigList.size = 3;
|
|
||||||
|
|
||||||
test(vList, "[ 1 2 { ... } ]", PrintOptions { .maxDepth = 1 });
|
test(vList, "[ 1 2 { ... } ]", PrintOptions { .maxDepth = 1 });
|
||||||
test(vList, "[ 1 2 { nested = { ... }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 2 });
|
test(vList, "[ 1 2 { nested = { ... }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 2 });
|
||||||
|
@ -539,11 +539,11 @@ TEST_F(ValuePrintingTests, ansiColorsList)
|
||||||
Value vTwo;
|
Value vTwo;
|
||||||
vTwo.mkInt(2);
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
auto list = state.buildList(3);
|
||||||
|
list.elems[0] = &vOne;
|
||||||
|
list.elems[1] = &vTwo;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 5);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vOne;
|
|
||||||
vList.bigList.elems[1] = &vTwo;
|
|
||||||
vList.bigList.size = 3;
|
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA "«nullptr»" ANSI_NORMAL " ]",
|
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA "«nullptr»" ANSI_NORMAL " ]",
|
||||||
|
@ -670,11 +670,11 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
|
||||||
Value vEmpty;
|
Value vEmpty;
|
||||||
vEmpty.mkAttrs(emptyBuilder.finish());
|
vEmpty.mkAttrs(emptyBuilder.finish());
|
||||||
|
|
||||||
|
auto list = state.buildList(2);
|
||||||
|
list.elems[0] = &vEmpty;
|
||||||
|
list.elems[1] = &vEmpty;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 3);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vEmpty;
|
|
||||||
vList.bigList.elems[1] = &vEmpty;
|
|
||||||
vList.bigList.size = 2;
|
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ { } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]",
|
"[ { } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]",
|
||||||
|
@ -690,11 +690,11 @@ TEST_F(ValuePrintingTests, listRepeated)
|
||||||
Value vEmpty;
|
Value vEmpty;
|
||||||
vEmpty.mkAttrs(emptyBuilder.finish());
|
vEmpty.mkAttrs(emptyBuilder.finish());
|
||||||
|
|
||||||
|
auto list = state.buildList(2);
|
||||||
|
list.elems[0] = &vEmpty;
|
||||||
|
list.elems[1] = &vEmpty;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 3);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vEmpty;
|
|
||||||
vList.bigList.elems[1] = &vEmpty;
|
|
||||||
vList.bigList.size = 2;
|
|
||||||
|
|
||||||
test(vList, "[ { } «repeated» ]", PrintOptions { });
|
test(vList, "[ { } «repeated» ]", PrintOptions { });
|
||||||
test(vList,
|
test(vList,
|
||||||
|
@ -750,11 +750,12 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||||
Value vTwo;
|
Value vTwo;
|
||||||
vTwo.mkInt(2);
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto list = state.buildList(2);
|
||||||
|
list.elems[0] = &vOne;
|
||||||
|
list.elems[1] = &vTwo;
|
||||||
Value vList;
|
Value vList;
|
||||||
state.mkList(vList, 4);
|
vList.mkList(list);
|
||||||
vList.bigList.elems[0] = &vOne;
|
|
||||||
vList.bigList.elems[1] = &vTwo;
|
|
||||||
vList.bigList.size = 2;
|
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«1 item elided»" ANSI_NORMAL " ]",
|
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«1 item elided»" ANSI_NORMAL " ]",
|
||||||
|
@ -762,12 +763,18 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxListItems = 1
|
.maxListItems = 1
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Value vThree;
|
Value vThree;
|
||||||
vThree.mkInt(3);
|
vThree.mkInt(3);
|
||||||
|
|
||||||
vList.bigList.elems[2] = &vThree;
|
{
|
||||||
vList.bigList.size = 3;
|
auto list = state.buildList(3);
|
||||||
|
list.elems[0] = &vOne;
|
||||||
|
list.elems[1] = &vTwo;
|
||||||
|
list.elems[2] = &vThree;
|
||||||
|
Value vList;
|
||||||
|
vList.mkList(list);
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«2 items elided»" ANSI_NORMAL " ]",
|
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«2 items elided»" ANSI_NORMAL " ]",
|
||||||
|
@ -776,5 +783,6 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||||
.maxListItems = 1
|
.maxListItems = 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nix
|
} // namespace nix
|
||||||
|
|
Loading…
Reference in a new issue