Support range-based for loop over list values

This commit is contained in:
Eelco Dolstra 2021-11-24 20:21:34 +01:00
parent ca82967ee3
commit b6c8e57056
10 changed files with 103 additions and 79 deletions

View file

@ -119,8 +119,8 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
case tList2: case tList2:
case tListN: case tListN:
str << "[ "; str << "[ ";
for (unsigned int n = 0; n < v.listSize(); ++n) { for (auto v2 : v.listItems()) {
printValue(str, active, *v.listElems()[n]); printValue(str, active, *v2);
str << " "; str << " ";
} }
str << "]"; str << "]";
@ -1151,8 +1151,8 @@ 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()); state.mkList(v, elems.size());
for (size_t n = 0; n < elems.size(); ++n) for (auto [n, v2] : enumerate(v.listItems()))
v.listElems()[n] = elems[n]->maybeThunk(state, env); const_cast<Value * &>(v2) = elems[n]->maybeThunk(state, env);
} }
@ -1732,8 +1732,8 @@ void EvalState::forceValueDeep(Value & v)
} }
else if (v.isList()) { else if (v.isList()) {
for (size_t n = 0; n < v.listSize(); ++n) for (auto v2 : v.listItems())
recurse(*v.listElems()[n]); recurse(*v2);
} }
}; };
@ -1917,12 +1917,12 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.isList()) { if (v.isList()) {
string result; string result;
for (size_t n = 0; n < v.listSize(); ++n) { for (auto [n, v2] : enumerate(v.listItems())) {
result += coerceToString(pos, *v.listElems()[n], result += coerceToString(pos, *v2,
context, coerceMore, copyToStore); context, coerceMore, copyToStore);
if (n < v.listSize() - 1 if (n < v.listSize() - 1
/* !!! not quite correct */ /* !!! not quite correct */
&& (!v.listElems()[n]->isList() || v.listElems()[n]->listSize() != 0)) && (!v2->isList() || v2->listSize() != 0))
result += " "; result += " ";
} }
return result; return result;

View file

@ -257,8 +257,7 @@ static Flake getFlake(
flake.config.settings.insert({setting.name, state.forceBool(*setting.value, *setting.pos)}); flake.config.settings.insert({setting.name, state.forceBool(*setting.value, *setting.pos)});
else if (setting.value->type() == nList) { else if (setting.value->type() == nList) {
std::vector<std::string> ss; std::vector<std::string> ss;
for (unsigned int n = 0; n < setting.value->listSize(); ++n) { for (auto elem : setting.value->listItems()) {
auto elem = setting.value->listElems()[n];
if (elem->type() != nString) if (elem->type() != nString)
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected", throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
setting.name, showType(*setting.value)); setting.name, showType(*setting.value));

View file

@ -102,9 +102,9 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
state->forceList(*i->value, *i->pos); state->forceList(*i->value, *i->pos);
/* For each output... */ /* For each output... */
for (unsigned int j = 0; j < i->value->listSize(); ++j) { for (auto elem : i->value->listItems()) {
/* Evaluate the corresponding set. */ /* Evaluate the corresponding set. */
string name = state->forceStringNoCtx(*i->value->listElems()[j], *i->pos); string name = state->forceStringNoCtx(*elem, *i->pos);
Bindings::iterator out = attrs->find(state->symbols.create(name)); Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error? if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value); state->forceAttrs(*out->value);
@ -128,9 +128,9 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* ^ this shows during `nix-env -i` right under the bad derivation */ /* ^ this shows during `nix-env -i` right under the bad derivation */
if (!outTI->isList()) throw errMsg; if (!outTI->isList()) throw errMsg;
Outputs result; Outputs result;
for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) { for (auto elem : outTI->listItems()) {
if ((*i)->type() != nString) throw errMsg; if (elem->type() != nString) throw errMsg;
auto out = outputs.find((*i)->string.s); auto out = outputs.find(elem->string.s);
if (out == outputs.end()) throw errMsg; if (out == outputs.end()) throw errMsg;
result.insert(*out); result.insert(*out);
} }
@ -174,8 +174,8 @@ bool DrvInfo::checkMeta(Value & v)
{ {
state->forceValue(v); state->forceValue(v);
if (v.type() == nList) { if (v.type() == nList) {
for (unsigned int n = 0; n < v.listSize(); ++n) for (auto elem : v.listItems())
if (!checkMeta(*v.listElems()[n])) return false; if (!checkMeta(*elem)) return false;
return true; return true;
} }
else if (v.type() == nAttrs) { else if (v.type() == nAttrs) {
@ -364,10 +364,10 @@ static void getDerivations(EvalState & state, Value & vIn,
} }
else if (v.type() == nList) { else if (v.type() == nList) {
for (unsigned int n = 0; n < v.listSize(); ++n) { for (auto [n, elem] : enumerate(v.listItems())) {
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n));
if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures)) if (getDerivation(state, *elem, pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *v.listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); getDerivations(state, *elem, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
} }
} }

View file

@ -335,9 +335,8 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
PathSet context; PathSet context;
auto program = state.coerceToString(pos, *elems[0], context, false, false); auto program = state.coerceToString(pos, *elems[0], context, false, false);
Strings commandArgs; Strings commandArgs;
for (unsigned int i = 1; i < args[0]->listSize(); ++i) { for (unsigned int i = 1; i < args[0]->listSize(); ++i)
commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false)); commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
}
try { try {
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
@ -616,8 +615,8 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
state.forceList(*startSet->value, pos); state.forceList(*startSet->value, pos);
ValueList workSet; ValueList workSet;
for (unsigned int n = 0; n < startSet->value->listSize(); ++n) for (auto elem : startSet->value->listItems())
workSet.push_back(startSet->value->listElems()[n]); workSet.push_back(elem);
/* Get the operator. */ /* Get the operator. */
Bindings::iterator op = getAttr( Bindings::iterator op = getAttr(
@ -662,9 +661,9 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
state.forceList(call, pos); state.forceList(call, pos);
/* Add the values returned by the operator to the work set. */ /* Add the values returned by the operator to the work set. */
for (unsigned int n = 0; n < call.listSize(); ++n) { for (auto elem : call.listItems()) {
state.forceValue(*call.listElems()[n], pos); state.forceValue(*elem, pos);
workSet.push_back(call.listElems()[n]); workSet.push_back(elem);
} }
} }
@ -1013,8 +1012,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
command-line arguments to the builder. */ command-line arguments to the builder. */
else if (i->name == state.sArgs) { else if (i->name == state.sArgs) {
state.forceList(*i->value, pos); state.forceList(*i->value, pos);
for (unsigned int n = 0; n < i->value->listSize(); ++n) { for (auto elem : i->value->listItems()) {
string s = state.coerceToString(posDrvName, *i->value->listElems()[n], context, true); string s = state.coerceToString(posDrvName, *elem, context, true);
drv.args.push_back(s); drv.args.push_back(s);
} }
} }
@ -1044,8 +1043,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* Require outputs to be a list of strings. */ /* Require outputs to be a list of strings. */
state.forceList(*i->value, posDrvName); state.forceList(*i->value, posDrvName);
Strings ss; Strings ss;
for (unsigned int n = 0; n < i->value->listSize(); ++n) for (auto elem : i->value->listItems())
ss.emplace_back(state.forceStringNoCtx(*i->value->listElems()[n], posDrvName)); ss.emplace_back(state.forceStringNoCtx(*elem, posDrvName));
handleOutputs(ss); handleOutputs(ss);
} }
@ -1460,20 +1459,19 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
SearchPath searchPath; SearchPath searchPath;
for (unsigned int n = 0; n < args[0]->listSize(); ++n) { for (auto v2 : args[0]->listItems()) {
Value & v2(*args[0]->listElems()[n]); state.forceAttrs(*v2, pos);
state.forceAttrs(v2, pos);
string prefix; string prefix;
Bindings::iterator i = v2.attrs->find(state.symbols.create("prefix")); Bindings::iterator i = v2->attrs->find(state.symbols.create("prefix"));
if (i != v2.attrs->end()) if (i != v2->attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos); prefix = state.forceStringNoCtx(*i->value, pos);
i = getAttr( i = getAttr(
state, state,
"findFile", "findFile",
"path", "path",
v2.attrs, v2->attrs,
pos pos
); );
@ -2239,9 +2237,9 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
/* Get the attribute names to be removed. */ /* Get the attribute names to be removed. */
std::set<Symbol> names; std::set<Symbol> names;
for (unsigned int i = 0; i < args[1]->listSize(); ++i) { for (auto elem : args[1]->listItems()) {
state.forceStringNoCtx(*args[1]->listElems()[i], pos); state.forceStringNoCtx(*elem, pos);
names.insert(state.symbols.create(args[1]->listElems()[i]->string.s)); names.insert(state.symbols.create(elem->string.s));
} }
/* Copy all attributes not in that set. Note that we don't need /* Copy all attributes not in that set. Note that we don't need
@ -2249,7 +2247,7 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
vector. */ vector. */
state.mkAttrs(v, args[0]->attrs->size()); state.mkAttrs(v, args[0]->attrs->size());
for (auto & i : *args[0]->attrs) { for (auto & i : *args[0]->attrs) {
if (names.find(i.name) == names.end()) if (!names.count(i.name))
v.attrs->push_back(i); v.attrs->push_back(i);
} }
} }
@ -2283,15 +2281,14 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
std::set<Symbol> seen; std::set<Symbol> seen;
for (unsigned int i = 0; i < args[0]->listSize(); ++i) { for (auto v2 : args[0]->listItems()) {
Value & v2(*args[0]->listElems()[i]); state.forceAttrs(*v2, pos);
state.forceAttrs(v2, pos);
Bindings::iterator j = getAttr( Bindings::iterator j = getAttr(
state, state,
"listToAttrs", "listToAttrs",
state.sName, state.sName,
v2.attrs, v2->attrs,
pos pos
); );
@ -2303,7 +2300,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
state, state,
"listToAttrs", "listToAttrs",
state.sValue, state.sValue,
v2.attrs, v2->attrs,
pos pos
); );
v.attrs->push_back(Attr(sym, j2->value, j2->pos)); v.attrs->push_back(Attr(sym, j2->value, j2->pos));
@ -2370,11 +2367,10 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va
Value * res[args[1]->listSize()]; Value * res[args[1]->listSize()];
unsigned int found = 0; unsigned int found = 0;
for (unsigned int n = 0; n < args[1]->listSize(); ++n) { for (auto v2 : args[1]->listItems()) {
Value & v2(*args[1]->listElems()[n]); state.forceAttrs(*v2, pos);
state.forceAttrs(v2, pos); Bindings::iterator i = v2->attrs->find(attrName);
Bindings::iterator i = v2.attrs->find(attrName); if (i != v2->attrs->end())
if (i != v2.attrs->end())
res[found++] = i->value; res[found++] = i->value;
} }
@ -2649,8 +2645,8 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value
{ {
bool res = false; bool res = false;
state.forceList(*args[1], pos); state.forceList(*args[1], pos);
for (unsigned int n = 0; n < args[1]->listSize(); ++n) for (auto elem : args[1]->listItems())
if (state.eqValues(*args[0], *args[1]->listElems()[n])) { if (state.eqValues(*args[0], *elem)) {
res = true; res = true;
break; break;
} }
@ -2709,8 +2705,8 @@ static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args,
if (args[2]->listSize()) { if (args[2]->listSize()) {
Value * vCur = args[1]; Value * vCur = args[1];
for (unsigned int n = 0; n < args[2]->listSize(); ++n) { for (auto [n, elem] : enumerate(args[2]->listItems())) {
Value * vs []{vCur, args[2]->listElems()[n]}; Value * vs []{vCur, elem};
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue(); vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
state.callFunction(*args[0], 2, vs, *vCur, pos); state.callFunction(*args[0], 2, vs, *vCur, pos);
} }
@ -2740,8 +2736,8 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg
state.forceList(*args[1], pos); state.forceList(*args[1], pos);
Value vTmp; Value vTmp;
for (unsigned int n = 0; n < args[1]->listSize(); ++n) { for (auto elem : args[1]->listItems()) {
state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos); state.callFunction(*args[0], *elem, vTmp, pos);
bool res = state.forceBool(vTmp, pos); bool res = state.forceBool(vTmp, pos);
if (res == any) { if (res == any) {
mkBool(v, any); mkBool(v, any);
@ -3470,9 +3466,9 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
res.reserve((args[1]->listSize() + 32) * sep.size()); res.reserve((args[1]->listSize() + 32) * sep.size());
bool first = true; bool first = true;
for (unsigned int n = 0; n < args[1]->listSize(); ++n) { for (auto elem : args[1]->listItems()) {
if (first) first = false; else res += sep; if (first) first = false; else res += sep;
res += state.coerceToString(pos, *args[1]->listElems()[n], context); res += state.coerceToString(pos, *elem, context);
} }
mkString(v, res, context); mkString(v, res, context);
@ -3501,14 +3497,14 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
vector<string> from; vector<string> from;
from.reserve(args[0]->listSize()); from.reserve(args[0]->listSize());
for (unsigned int n = 0; n < args[0]->listSize(); ++n) for (auto elem : args[0]->listItems())
from.push_back(state.forceString(*args[0]->listElems()[n], pos)); from.push_back(state.forceString(*elem, pos));
vector<std::pair<string, PathSet>> to; vector<std::pair<string, PathSet>> to;
to.reserve(args[1]->listSize()); to.reserve(args[1]->listSize());
for (unsigned int n = 0; n < args[1]->listSize(); ++n) { for (auto elem : args[1]->listItems()) {
PathSet ctx; PathSet ctx;
auto s = state.forceString(*args[1]->listElems()[n], ctx, pos); auto s = state.forceString(*elem, ctx, pos);
to.push_back(std::make_pair(std::move(s), std::move(ctx))); to.push_back(std::make_pair(std::move(s), std::move(ctx)));
} }

View file

@ -118,10 +118,9 @@ static void prim_getContext(EvalState & state, const Pos & pos, Value * * args,
auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs); auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs);
state.mkList(outputsVal, info.second.outputs.size()); state.mkList(outputsVal, info.second.outputs.size());
size_t i = 0; size_t i = 0;
for (const auto & output : info.second.outputs) { for (const auto & output : info.second.outputs)
mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output); mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output);
} }
}
infoVal.attrs->sort(); infoVal.attrs->sort();
} }
v.attrs->sort(); v.attrs->sort();
@ -181,8 +180,8 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
.errPos = *i.pos .errPos = *i.pos
}); });
} }
for (unsigned int n = 0; n < iter->value->listSize(); ++n) { for (auto elem : iter->value->listItems()) {
auto name = state.forceStringNoCtx(*iter->value->listElems()[n], *iter->pos); auto name = state.forceStringNoCtx(*elem, *iter->pos);
context.insert("!" + name + "!" + string(i.name)); context.insert("!" + name + "!" + string(i.name));
} }
} }

View file

@ -63,9 +63,9 @@ void printValueAsJSON(EvalState & state, bool strict,
case nList: { case nList: {
auto list(out.list()); auto list(out.list());
for (unsigned int n = 0; n < v.listSize(); ++n) { for (auto elem : v.listItems()) {
auto placeholder(list.placeholder()); auto placeholder(list.placeholder());
printValueAsJSON(state, strict, *v.listElems()[n], pos, placeholder, context); printValueAsJSON(state, strict, *elem, pos, placeholder, context);
} }
break; break;
} }

View file

@ -122,8 +122,8 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
case nList: { case nList: {
XMLOpenElement _(doc, "list"); XMLOpenElement _(doc, "list");
for (unsigned int n = 0; n < v.listSize(); ++n) for (auto v2 : v.listItems())
printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen, pos); printValueAsXML(state, strict, location, *v2, doc, context, drvsSeen, pos);
break; break;
} }

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <cassert>
#include "symbol-table.hh" #include "symbol-table.hh"
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
@ -350,6 +352,34 @@ public:
bool isTrivial() const; bool isTrivial() const;
std::vector<std::pair<Path, std::string>> getContext(); std::vector<std::pair<Path, std::string>> getContext();
auto listItems()
{
struct ListIterable
{
typedef Value * const * iterator;
iterator _begin, _end;
iterator begin() const { return _begin; }
iterator end() const { return _end; }
};
assert(isList());
auto begin = listElems();
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() };
}
}; };

View file

@ -1149,10 +1149,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
} else if (v->type() == nList) { } else if (v->type() == nList) {
attrs2["type"] = "strings"; attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2); XMLOpenElement m(xml, "meta", attrs2);
for (unsigned int j = 0; j < v->listSize(); ++j) { for (auto elem : v->listItems()) {
if (v->listElems()[j]->type() != nString) continue; if (elem->type() != nString) continue;
XMLAttrs attrs3; XMLAttrs attrs3;
attrs3["value"] = v->listElems()[j]->string.s; attrs3["value"] = elem->string.s;
xml.writeEmptyElement("string", attrs3); xml.writeEmptyElement("string", attrs3);
} }
} else if (v->type() == nAttrs) { } else if (v->type() == nAttrs) {

View file

@ -771,12 +771,12 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
str << "[ "; str << "[ ";
if (maxDepth > 0) if (maxDepth > 0)
for (unsigned int n = 0; n < v.listSize(); ++n) { for (auto elem : v.listItems()) {
if (seen.find(v.listElems()[n]) != seen.end()) if (seen.count(elem))
str << "«repeated»"; str << "«repeated»";
else else
try { try {
printValue(str, *v.listElems()[n], maxDepth - 1, seen); printValue(str, *elem, maxDepth - 1, seen);
} catch (AssertionError & e) { } catch (AssertionError & e) {
str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL; str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL;
} }