Files
nix/src/libexpr/attr-path.cc
Sergei Zimmerman 756758d968 chore: get rid of dead code and unused variables where appropriate
Looks like some cruft has been left over from previous refactorings.
This removes dead variables, which should not have side effects in their
constructors. In cases where the variable initialization has a purpose
[[maybe_unused]] is inserted to silence compiler warnings.
2024-11-22 18:05:53 +03:00

142 lines
4.1 KiB
C++

#include "attr-path.hh"
#include "eval-inline.hh"
namespace nix {
static Strings parseAttrPath(std::string_view s)
{
Strings res;
std::string cur;
auto i = s.begin();
while (i != s.end()) {
if (*i == '.') {
res.push_back(cur);
cur.clear();
} else if (*i == '"') {
++i;
while (1) {
if (i == s.end())
throw ParseError("missing closing quote in selection path '%1%'", s);
if (*i == '"') break;
cur.push_back(*i++);
}
} else
cur.push_back(*i);
++i;
}
if (!cur.empty()) res.push_back(cur);
return res;
}
std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
{
std::vector<Symbol> res;
for (auto & a : parseAttrPath(s))
res.push_back(state.symbols.create(a));
return res;
}
std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
{
Strings tokens = parseAttrPath(attrPath);
Value * v = &vIn;
PosIdx pos = noPos;
for (auto & attr : tokens) {
/* Is i an index (integer) or a normal attribute name? */
auto attrIndex = string2Int<unsigned int>(attr);
/* Evaluate the expression. */
Value * vNew = state.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew);
v = vNew;
state.forceValue(*v, noPos);
/* It should evaluate to either a set or an expression,
according to what is specified in the attrPath. */
if (!attrIndex) {
if (v->type() != nAttrs)
state.error<TypeError>(
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v)).debugThrow();
if (attr.empty())
throw Error("empty attribute name in selection path '%1%'", attrPath);
auto a = v->attrs()->get(state.symbols.create(attr));
if (!a) {
std::set<std::string> attrNames;
for (auto & attr : *v->attrs())
attrNames.insert(std::string(state.symbols[attr.name]));
auto suggestions = Suggestions::bestMatches(attrNames, attr);
throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath);
}
v = &*a->value;
pos = a->pos;
}
else {
if (!v->isList())
state.error<TypeError>(
"the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath,
showType(*v)).debugThrow();
if (*attrIndex >= v->listSize())
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath);
v = v->listElems()[*attrIndex];
pos = noPos;
}
}
return {v, pos};
}
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
{
Value * v2;
try {
auto dummyArgs = state.allocBindings(0);
v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
} catch (Error &) {
throw NoPositionInfo("package '%s' has no source location information", what);
}
// FIXME: is it possible to extract the Pos object instead of doing this
// toString + parsing?
NixStringContext context;
auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
auto fn = path.path.abs();
auto fail = [fn]() {
throw ParseError("cannot parse 'meta.position' attribute '%s'", fn);
};
try {
auto colon = fn.rfind(':');
if (colon == std::string::npos) fail();
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
} catch (std::invalid_argument & e) {
fail();
unreachable();
}
}
}