aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libcmd/installables.cc4
-rw-r--r--src/libcmd/installables.hh4
-rw-r--r--src/libexpr/attr-path.cc6
-rw-r--r--src/libexpr/attr-path.hh2
-rw-r--r--src/libexpr/attr-set.cc4
-rw-r--r--src/libexpr/attr-set.hh16
-rw-r--r--src/libexpr/eval-inline.hh6
-rw-r--r--src/libexpr/eval.cc157
-rw-r--r--src/libexpr/eval.hh77
-rw-r--r--src/libexpr/flake/flake.cc56
-rw-r--r--src/libexpr/function-trace.hh2
-rw-r--r--src/libexpr/get-drvs.cc18
-rw-r--r--src/libexpr/lexer.l10
-rw-r--r--src/libexpr/nixexpr.cc96
-rw-r--r--src/libexpr/nixexpr.hh169
-rw-r--r--src/libexpr/parser.y78
-rw-r--r--src/libexpr/primops.cc309
-rw-r--r--src/libexpr/primops.hh4
-rw-r--r--src/libexpr/primops/context.cc26
-rw-r--r--src/libexpr/primops/fetchClosure.cc26
-rw-r--r--src/libexpr/primops/fetchMercurial.cc12
-rw-r--r--src/libexpr/primops/fetchTree.cc36
-rw-r--r--src/libexpr/primops/fromTOML.cc4
-rw-r--r--src/libexpr/value-to-json.cc12
-rw-r--r--src/libexpr/value-to-json.hh4
-rw-r--r--src/libexpr/value-to-xml.cc18
-rw-r--r--src/libexpr/value-to-xml.hh2
-rw-r--r--src/libexpr/value.hh5
-rw-r--r--src/libutil/types.hh52
-rw-r--r--src/nix-env/user-env.cc4
-rw-r--r--src/nix/bundle.cc6
-rw-r--r--src/nix/edit.cc4
-rw-r--r--src/nix/eval.cc12
-rw-r--r--src/nix/flake.cc118
-rw-r--r--src/nix/repl.cc9
-rw-r--r--tests/plugins/plugintest.cc2
36 files changed, 750 insertions, 620 deletions
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 4250c321e..6197f4be4 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -473,7 +473,7 @@ struct InstallableAttrPath : InstallableValue
std::string what() const override { return attrPath; }
- std::pair<Value *, Pos> toValue(EvalState & state) override
+ std::pair<Value *, PosIdx> toValue(EvalState & state) override
{
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
state.forceValue(*vRes, pos);
@@ -613,7 +613,7 @@ std::vector<InstallableValue::DerivationInfo> InstallableFlake::toDerivations()
return res;
}
-std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
+std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
{
return {&getCursor(state)->forceValue(), noPos};
}
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index b847f8939..de8b08525 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -68,7 +68,7 @@ struct Installable
UnresolvedApp toApp(EvalState & state);
- virtual std::pair<Value *, Pos> toValue(EvalState & state)
+ virtual std::pair<Value *, PosIdx> toValue(EvalState & state)
{
throw Error("argument '%s' cannot be evaluated", what());
}
@@ -178,7 +178,7 @@ struct InstallableFlake : InstallableValue
std::vector<DerivationInfo> toDerivations() override;
- std::pair<Value *, Pos> toValue(EvalState & state) override;
+ std::pair<Value *, PosIdx> toValue(EvalState & state) override;
/* Get a cursor to every attrpath in getActualAttrPaths() that
exists. */
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index c6e3a9c92..1c12dfbe2 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -41,13 +41,13 @@ std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
}
-std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const std::string & attrPath,
+std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
{
Strings tokens = parseAttrPath(attrPath);
Value * v = &vIn;
- Pos pos = noPos;
+ PosIdx pos = noPos;
for (auto & attr : tokens) {
@@ -83,7 +83,7 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const std::string &
throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath);
}
v = &*a->value;
- pos = *a->pos;
+ pos = a->pos;
}
else {
diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh
index f06d28f7f..117e0051b 100644
--- a/src/libexpr/attr-path.hh
+++ b/src/libexpr/attr-path.hh
@@ -10,7 +10,7 @@ namespace nix {
MakeError(AttrPathNotFound, Error);
MakeError(NoPositionInfo, Error);
-std::pair<Value *, Pos> findAlongAttrPath(
+std::pair<Value *, PosIdx> findAlongAttrPath(
EvalState & state,
const std::string & attrPath,
Bindings & autoArgs,
diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc
index 52ac47e9b..61996eae4 100644
--- a/src/libexpr/attr-set.cc
+++ b/src/libexpr/attr-set.cc
@@ -40,7 +40,7 @@ Value * EvalState::allocAttr(Value & vAttrs, std::string_view name)
}
-Value & BindingsBuilder::alloc(const Symbol & name, ptr<Pos> pos)
+Value & BindingsBuilder::alloc(const Symbol & name, PosIdx pos)
{
auto value = state.allocValue();
bindings->push_back(Attr(name, value, pos));
@@ -48,7 +48,7 @@ Value & BindingsBuilder::alloc(const Symbol & name, ptr<Pos> pos)
}
-Value & BindingsBuilder::alloc(std::string_view name, ptr<Pos> pos)
+Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
{
return alloc(state.symbols.create(name), pos);
}
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index 1e6c548c6..23d68dda2 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -17,10 +17,10 @@ struct Attr
{
Symbol name;
Value * value;
- ptr<Pos> pos;
- Attr(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
+ PosIdx pos;
+ Attr(Symbol name, Value * value, PosIdx pos = noPos)
: name(name), value(value), pos(pos) { };
- Attr() : pos(&noPos) { };
+ Attr() { };
bool operator < (const Attr & a) const
{
return name < a.name;
@@ -35,13 +35,13 @@ class Bindings
{
public:
typedef uint32_t size_t;
- ptr<Pos> pos;
+ PosIdx pos;
private:
size_t size_, capacity_;
Attr attrs[0];
- Bindings(size_t capacity) : pos(&noPos), size_(0), capacity_(capacity) { }
+ Bindings(size_t capacity) : size_(0), capacity_(capacity) { }
Bindings(const Bindings & bindings) = delete;
public:
@@ -118,7 +118,7 @@ public:
: bindings(bindings), state(state)
{ }
- void insert(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
+ void insert(Symbol name, Value * value, PosIdx pos = noPos)
{
insert(Attr(name, value, pos));
}
@@ -133,9 +133,9 @@ public:
bindings->push_back(attr);
}
- Value & alloc(const Symbol & name, ptr<Pos> pos = ptr(&noPos));
+ Value & alloc(const Symbol & name, PosIdx pos = noPos);
- Value & alloc(std::string_view name, ptr<Pos> pos = ptr(&noPos));
+ Value & alloc(std::string_view name, PosIdx pos = noPos);
Bindings * finish()
{
diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh
index dec122462..7f01d08e3 100644
--- a/src/libexpr/eval-inline.hh
+++ b/src/libexpr/eval-inline.hh
@@ -80,7 +80,7 @@ Env & EvalState::allocEnv(size_t size)
[[gnu::always_inline]]
-void EvalState::forceValue(Value & v, const Pos & pos)
+void EvalState::forceValue(Value & v, const PosIdx pos)
{
forceValue(v, [&]() { return pos; });
}
@@ -109,7 +109,7 @@ void EvalState::forceValue(Value & v, Callable getPos)
[[gnu::always_inline]]
-inline void EvalState::forceAttrs(Value & v, const Pos & pos)
+inline void EvalState::forceAttrs(Value & v, const PosIdx pos)
{
forceAttrs(v, [&]() { return pos; });
}
@@ -126,7 +126,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos)
[[gnu::always_inline]]
-inline void EvalState::forceList(Value & v, const Pos & pos)
+inline void EvalState::forceList(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (!v.isList())
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 418017357..e6314f63e 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -236,10 +236,10 @@ std::string showType(const Value & v)
}
}
-Pos Value::determinePos(const Pos & pos) const
+PosIdx Value::determinePos(const PosIdx pos) const
{
switch (internalType) {
- case tAttrs: return *attrs->pos;
+ case tAttrs: return attrs->pos;
case tLambda: return lambda.fun->pos;
case tApp: return app.left->determinePos(pos);
default: return pos;
@@ -698,7 +698,7 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
auto v2 = &v;
if (v2->primOp->doc)
return Doc {
- .pos = noPos,
+ .pos = {},
.name = v2->primOp->name,
.arity = v2->primOp->arity,
.args = v2->primOp->args,
@@ -714,21 +714,20 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
evaluator. So here are some helper functions for throwing
exceptions. */
-void EvalState::throwEvalError(const Pos & pos, const char * s) const
+void EvalState::throwEvalError(const PosIdx pos, const char * s) const
{
throw EvalError({
.msg = hintfmt(s),
- .errPos = pos
+ .errPos = positions[pos]
});
}
-void EvalState::throwTypeError(const Pos & pos, const char * s, const Value & v) const
+void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const
{
throw TypeError({
.msg = hintfmt(s, showType(v)),
- .errPos = pos
+ .errPos = positions[pos]
});
-
}
void EvalState::throwEvalError(const char * s, const std::string & s2) const
@@ -736,21 +735,21 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const
throw EvalError(s, s2);
}
-void EvalState::throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s,
+void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s,
const std::string & s2) const
{
throw EvalError(ErrorInfo {
.msg = hintfmt(s, s2),
- .errPos = pos,
+ .errPos = positions[pos],
.suggestions = suggestions,
});
}
-void EvalState::throwEvalError(const Pos & pos, const char * s, const std::string & s2) const
+void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const
{
throw EvalError(ErrorInfo {
.msg = hintfmt(s, s2),
- .errPos = pos
+ .errPos = positions[pos]
});
}
@@ -759,47 +758,47 @@ void EvalState::throwEvalError(const char * s, const std::string & s2, const std
throw EvalError(s, s2, s3);
}
-void EvalState::throwEvalError(const Pos & pos, const char * s, const std::string & s2,
+void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2,
const std::string & s3) const
{
throw EvalError({
.msg = hintfmt(s, s2, s3),
- .errPos = pos
+ .errPos = positions[pos]
});
}
-void EvalState::throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2) const
+void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol & sym, const PosIdx p2) const
{
// p1 is where the error occurred; p2 is a position mentioned in the message.
throw EvalError({
- .msg = hintfmt(s, sym, p2),
- .errPos = p1
+ .msg = hintfmt(s, sym, positions[p2]),
+ .errPos = positions[p1]
});
}
-void EvalState::throwTypeError(const Pos & pos, const char * s) const
+void EvalState::throwTypeError(const PosIdx pos, const char * s) const
{
throw TypeError({
.msg = hintfmt(s),
- .errPos = pos
+ .errPos = positions[pos]
});
}
-void EvalState::throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun,
+void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun,
const Symbol & s2) const
{
throw TypeError({
- .msg = hintfmt(s, fun.showNamePos(), s2),
- .errPos = pos
+ .msg = hintfmt(s, fun.showNamePos(positions), s2),
+ .errPos = positions[pos]
});
}
-void EvalState::throwTypeError(const Pos & pos, const Suggestions & suggestions, const char * s,
+void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s,
const ExprLambda & fun, const Symbol & s2) const
{
throw TypeError(ErrorInfo {
- .msg = hintfmt(s, fun.showNamePos(), s2),
- .errPos = pos,
+ .msg = hintfmt(s, fun.showNamePos(positions), s2),
+ .errPos = positions[pos],
.suggestions = suggestions,
});
}
@@ -810,27 +809,27 @@ void EvalState::throwTypeError(const char * s, const Value & v) const
throw TypeError(s, showType(v));
}
-void EvalState::throwAssertionError(const Pos & pos, const char * s, const std::string & s1) const
+void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1) const
{
throw AssertionError({
.msg = hintfmt(s, s1),
- .errPos = pos
+ .errPos = positions[pos]
});
}
-void EvalState::throwUndefinedVarError(const Pos & pos, const char * s, const std::string & s1) const
+void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1) const
{
throw UndefinedVarError({
.msg = hintfmt(s, s1),
- .errPos = pos
+ .errPos = positions[pos]
});
}
-void EvalState::throwMissingArgumentError(const Pos & pos, const char * s, const std::string & s1) const
+void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1) const
{
throw MissingArgumentError({
.msg = hintfmt(s, s1),
- .errPos = pos
+ .errPos = positions[pos]
});
}
@@ -839,9 +838,9 @@ void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2)
e.addTrace(std::nullopt, s, s2);
}
-void EvalState::addErrorTrace(Error & e, const Pos & pos, const char * s, const std::string & s2) const
+void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const
{
- e.addTrace(pos, s, s2);
+ e.addTrace(positions[pos], s, s2);
}
@@ -898,7 +897,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
- if (countCalls) attrSelects[*j->pos]++;
+ if (countCalls) attrSelects[j->pos]++;
return j->value;
}
if (!env->prevWith)
@@ -932,13 +931,14 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
}
-void EvalState::mkPos(Value & v, ptr<Pos> pos)
+void EvalState::mkPos(Value & v, PosIdx p)
{
- if (pos->file.set()) {
+ auto pos = positions[p];
+ if (pos.file.set()) {
auto attrs = buildBindings(3);
- attrs.alloc(sFile).mkString(pos->file);
- attrs.alloc(sLine).mkInt(pos->line);
- attrs.alloc(sColumn).mkInt(pos->column);
+ attrs.alloc(sFile).mkString(pos.file);
+ attrs.alloc(sLine).mkInt(pos.line);
+ attrs.alloc(sColumn).mkInt(pos.column);
v.mkAttrs(attrs);
} else
v.mkNull();
@@ -1071,7 +1071,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e)
}
-inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos)
+inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos)
{
Value v;
e->eval(*this, env, v);
@@ -1145,7 +1145,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
} else
vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
env2.values[displ++] = vAttr;
- v.attrs->push_back(Attr(i.first, vAttr, ptr(&i.second.pos)));
+ v.attrs->push_back(Attr(i.first, vAttr, i.second.pos));
}
/* If the rec contains an attribute called `__overrides', then
@@ -1177,7 +1177,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else
for (auto & i : attrs)
- v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), ptr(&i.second.pos)));
+ v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), i.second.pos));
/* Dynamic attrs apply *after* rec and __overrides. */
for (auto & i : dynamicAttrs) {
@@ -1190,15 +1190,15 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
Symbol nameSym = state.symbols.create(nameVal.string.s);
Bindings::iterator j = v.attrs->find(nameSym);
if (j != v.attrs->end())
- state.throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos);
+ state.throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, j->pos);
i.valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */
- v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), ptr(&i.pos)));
+ v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), i.pos));
v.attrs->sort(); // FIXME: inefficient
}
- v.attrs->pos = ptr(&pos);
+ v.attrs->pos = pos;
}
@@ -1256,7 +1256,7 @@ static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & a
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
{
Value vTmp;
- ptr<Pos> pos2(&noPos);
+ PosIdx pos2;
Value * vAttrs = &vTmp;
e->eval(state, env, vTmp);
@@ -1289,14 +1289,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
vAttrs = j->value;
pos2 = j->pos;
- if (state.countCalls) state.attrSelects[*pos2]++;
+ if (state.countCalls) state.attrSelects[pos2]++;
}
- state.forceValue(*vAttrs, (*pos2 != noPos ? *pos2 : this->pos ) );
+ state.forceValue(*vAttrs, (pos2 ? pos2 : this->pos ) );
} catch (Error & e) {
- if (*pos2 != noPos && pos2->file != state.sDerivationNix)
- state.addErrorTrace(e, *pos2, "while evaluating the attribute '%1%'",
+ auto pos2r = state.positions[pos2];
+ if (pos2 && pos2r.file != state.sDerivationNix)
+ state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'",
showAttrPath(state, env, attrPath));
throw;
}
@@ -1336,9 +1337,11 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v)
}
-void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos)
+void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos)
{
- auto trace = evalSettings.traceFunctionCalls ? std::make_unique<FunctionCallTrace>(pos) : nullptr;
+ auto trace = evalSettings.traceFunctionCalls
+ ? std::make_unique<FunctionCallTrace>(positions[pos])
+ : nullptr;
forceValue(fun, pos);
@@ -1701,7 +1704,7 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
}
-void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos)
+void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos)
{
nrListConcats++;
@@ -1821,7 +1824,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
void ExprPos::eval(EvalState & state, Env & env, Value & v)
{
- state.mkPos(v, ptr(&pos));
+ state.mkPos(v, pos);
}
@@ -1841,7 +1844,7 @@ void EvalState::forceValueDeep(Value & v)
try {
recurse(*i.value);
} catch (Error & e) {
- addErrorTrace(e, *i.pos, "while evaluating the attribute '%1%'", i.name);
+ addErrorTrace(e, i.pos, "while evaluating the attribute '%1%'", i.name);
throw;
}
}
@@ -1856,7 +1859,7 @@ void EvalState::forceValueDeep(Value & v)
}
-NixInt EvalState::forceInt(Value & v, const Pos & pos)
+NixInt EvalState::forceInt(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (v.type() != nInt)
@@ -1865,7 +1868,7 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos)
}
-NixFloat EvalState::forceFloat(Value & v, const Pos & pos)
+NixFloat EvalState::forceFloat(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (v.type() == nInt)
@@ -1876,7 +1879,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos)
}
-bool EvalState::forceBool(Value & v, const Pos & pos)
+bool EvalState::forceBool(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (v.type() != nBool)
@@ -1891,7 +1894,7 @@ bool EvalState::isFunctor(Value & fun)
}
-void EvalState::forceFunction(Value & v, const Pos & pos)
+void EvalState::forceFunction(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (v.type() != nFunction && !isFunctor(v))
@@ -1899,7 +1902,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
}
-std::string_view EvalState::forceString(Value & v, const Pos & pos)
+std::string_view EvalState::forceString(Value & v, const PosIdx pos)
{
forceValue(v, pos);
if (v.type() != nString) {
@@ -1952,7 +1955,7 @@ NixStringContext Value::getContext(const Store & store)
}
-std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
+std::string_view EvalState::forceString(Value & v, PathSet & context, const PosIdx pos)
{
auto s = forceString(v, pos);
copyContext(v, context);
@@ -1960,7 +1963,7 @@ std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos
}
-std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos)
+std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos)
{
auto s = forceString(v, pos);
if (v.string.context) {
@@ -1980,13 +1983,13 @@ bool EvalState::isDerivation(Value & v)
if (v.type() != nAttrs) return false;
Bindings::iterator i = v.attrs->find(sType);
if (i == v.attrs->end()) return false;
- forceValue(*i->value, *i->pos);
+ forceValue(*i->value, i->pos);
if (i->value->type() != nString) return false;
return strcmp(i->value->string.s, "derivation") == 0;
}
-std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
+std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value & v,
PathSet & context, bool coerceMore, bool copyToStore)
{
auto i = v.attrs->find(sToString);
@@ -1999,7 +2002,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value &
return {};
}
-BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
+BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore, bool canonicalizePath)
{
forceValue(v, pos);
@@ -2028,7 +2031,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
}
if (v.type() == nExternal)
- return v.external->coerceToString(pos, context, coerceMore, copyToStore);
+ return v.external->coerceToString(positions[pos], context, coerceMore, copyToStore);
if (coerceMore) {
@@ -2081,7 +2084,7 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
}
-Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
+Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context)
{
auto path = coerceToString(pos, v, context, false, false).toOwned();
if (path == "" || path[0] != '/')
@@ -2090,14 +2093,14 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
}
-StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context)
+StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, PathSet & context)
{
auto path = coerceToString(pos, v, context, false, false).toOwned();
if (auto storePath = store->maybeParseStorePath(path))
return *storePath;
throw EvalError({
.msg = hintfmt("path '%1%' is not in the Nix store", path),
- .errPos = pos
+ .errPos = positions[pos]
});
}
@@ -2268,10 +2271,10 @@ void EvalState::printStats()
obj.attr("name", (const std::string &) i.first->name);
else
obj.attr("name", nullptr);
- if (i.first->pos) {
- obj.attr("file", (const std::string &) i.first->pos.file);
- obj.attr("line", i.first->pos.line);
- obj.attr("column", i.first->pos.column);
+ if (auto pos = positions[i.first->pos]) {
+ obj.attr("file", (const std::string &) pos.file);
+ obj.attr("line", pos.line);
+ obj.attr("column", pos.column);
}
obj.attr("count", i.second);
}
@@ -2280,10 +2283,10 @@ void EvalState::printStats()
auto list = topObj.list("attributes");
for (auto & i : attrSelects) {
auto obj = list.object();
- if (i.first) {
- obj.attr("file", (const std::string &) i.first.file);
- obj.attr("line", i.first.line);
- obj.attr("column", i.first.column);
+ if (auto pos = positions[i.first]) {
+ obj.attr("file", (const std::string &) pos.file);
+ obj.attr("line", pos.line);
+ obj.attr("column", pos.column);
}
obj.attr("count", i.second);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 787294b89..b05e8d5d0 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -23,7 +23,7 @@ class StorePath;
enum RepairFlag : bool;
-typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
+typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v);
struct PrimOp
@@ -73,6 +73,7 @@ class EvalState
{
public:
SymbolTable symbols;
+ PosTable positions;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
@@ -205,7 +206,7 @@ public:
/* Look up a file in the search path. */
Path findFile(const std::string_view path);
- Path findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos = noPos);
+ Path findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
/* If the specified search path element is a URI, download it. */
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
@@ -217,14 +218,14 @@ public:
/* Evaluation the expression, then verify that it has the expected
type. */
inline bool evalBool(Env & env, Expr * e);
- inline bool evalBool(Env & env, Expr * e, const Pos & pos);
+ inline bool evalBool(Env & env, Expr * e, const PosIdx pos);
inline void evalAttrs(Env & env, Expr * e, Value & v);
/* If `v' is a thunk, enter it and overwrite `v' with the result
of the evaluation of the thunk. If `v' is a delayed function
application, call the function and overwrite `v' with the
result. Otherwise, this is a no-op. */
- inline void forceValue(Value & v, const Pos & pos);
+ inline void forceValue(Value & v, const PosIdx pos);
template <typename Callable>
inline void forceValue(Value & v, Callable getPos);
@@ -234,72 +235,72 @@ public:
void forceValueDeep(Value & v);
/* Force `v', and then verify that it has the expected type. */
- NixInt forceInt(Value & v, const Pos & pos);
- NixFloat forceFloat(Value & v, const Pos & pos);
- bool forceBool(Value & v, const Pos & pos);
+ NixInt forceInt(Value & v, const PosIdx pos);
+ NixFloat forceFloat(Value & v, const PosIdx pos);
+ bool forceBool(Value & v, const PosIdx pos);
- void forceAttrs(Value & v, const Pos & pos);
+ void forceAttrs(Value & v, const PosIdx pos);
template <typename Callable>
inline void forceAttrs(Value & v, Callable getPos);
- inline void forceList(Value & v, const Pos & pos);
- void forceFunction(Value & v, const Pos & pos); // either lambda or primop
- std::string_view forceString(Value & v, const Pos & pos = noPos);
- std::string_view forceString(Value & v, PathSet & context, const Pos & pos = noPos);
- std::string_view forceStringNoCtx(Value & v, const Pos & pos = noPos);
+ inline void forceList(Value & v, const PosIdx pos);
+ void forceFunction(Value & v, const PosIdx pos); // either lambda or primop
+ std::string_view forceString(Value & v, const PosIdx pos = noPos);
+ std::string_view forceString(Value & v, PathSet & context, const PosIdx pos = noPos);
+ std::string_view forceStringNoCtx(Value & v, const PosIdx pos = noPos);
[[gnu::noinline, gnu::noreturn]]
- void throwEvalError(const Pos & pos, const char * s) const;
+ void throwEvalError(const PosIdx pos, const char * s) const;
[[gnu::noinline, gnu::noreturn]]
- void throwTypeError(const Pos & pos, const char * s, const Value & v) const;
+ void throwTypeError(const PosIdx pos, const char * s, const Value & v) const;
[[gnu::noinline, gnu::noreturn]]
void throwEvalError(const char * s, const std::string & s2) const;
[[gnu::noinline, gnu::noreturn]]
- void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s,
+ void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s,
const std::string & s2) const;
[[gnu::noinline, gnu::noreturn]]
- void throwEvalError(const Pos & pos, const char * s, const std::string & s2) const;
+ void throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const;
[[gnu::noinline, gnu::noreturn]]
void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const;
[[gnu::noinline, gnu::noreturn]]
- void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3) const;
+ void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) const;
[[gnu::noinline, gnu::noreturn]]
- void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2) const;
+ void throwEvalError(const PosIdx p1, const char * s, const Symbol & sym, const PosIdx p2) const;
[[gnu::noinline, gnu::noreturn]]
- void throwTypeError(const Pos & pos, const char * s) const;
+ void throwTypeError(const PosIdx pos, const char * s) const;
[[gnu::noinline, gnu::noreturn]]
- void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2) const;
+ void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol & s2) const;
[[gnu::noinline, gnu::noreturn]]
- void throwTypeError(const Pos & pos, const Suggestions & suggestions, const char * s,
+ void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s,
const ExprLambda & fun, const Symbol & s2) const;
[[gnu::noinline, gnu::noreturn]]
void throwTypeError(const char * s, const Value & v) const;
[[gnu::noinline, gnu::noreturn]]
- void throwAssertionError(const Pos & pos, const char * s, const std::string & s1) const;
+ void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1) const;
[[gnu::noinline, gnu::noreturn]]
- void throwUndefinedVarError(const Pos & pos, const char * s, const std::string & s1) const;
+ void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1) const;
[[gnu::noinline, gnu::noreturn]]
- void throwMissingArgumentError(const Pos & pos, const char * s, const std::string & s1) const;
+ void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1) const;
[[gnu::noinline]]
void addErrorTrace(Error & e, const char * s, const std::string & s2) const;
[[gnu::noinline]]
- void addErrorTrace(Error & e, const Pos & pos, const char * s, const std::string & s2) const;
+ void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const;
public:
/* Return true iff the value `v' denotes a derivation (i.e. a
set with attribute `type = "derivation"'). */
bool isDerivation(Value & v);
- std::optional<std::string> tryAttrsToString(const Pos & pos, Value & v,
+ std::optional<std::string> tryAttrsToString(const PosIdx pos, Value & v,
PathSet & context, bool coerceMore = false, bool copyToStore = true);
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect. */
- BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
+ BackedStringView coerceToString(const PosIdx pos, Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true,
bool canonicalizePath = true);
@@ -308,10 +309,10 @@ public:
/* Path coercion. Converts strings, paths and derivations to a
path. The result is guaranteed to be a canonicalised, absolute
path. Nothing is copied to the store. */
- Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
+ Path coerceToPath(const PosIdx pos, Value & v, PathSet & context);
/* Like coerceToPath, but the result must be a store path. */
- StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
+ StorePath coerceToStorePath(const PosIdx pos, Value & v, PathSet & context);
public:
@@ -372,9 +373,9 @@ public:
bool isFunctor(Value & fun);
// FIXME: use std::span
- void callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos);
+ void callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos);
- void callFunction(Value & fun, Value & arg, Value & vRes, const Pos & pos)
+ void callFunction(Value & fun, Value & arg, Value & vRes, const PosIdx pos)
{
Value * args[] = {&arg};
callFunction(fun, 1, args, vRes, pos);
@@ -400,9 +401,9 @@ public:
void mkList(Value & v, size_t length);
void mkThunk_(Value & v, Expr * expr);
- void mkPos(Value & v, ptr<Pos> pos);
+ void mkPos(Value & v, PosIdx pos);
- void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos);
+ void concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos);
/* Print statistics. */
void printStats();
@@ -438,7 +439,7 @@ private:
void incrFunctionCall(ExprLambda * fun);
- typedef std::map<Pos, size_t> AttrSelects;
+ typedef std::map<PosIdx, size_t> AttrSelects;
AttrSelects attrSelects;
friend struct ExprOpUpdate;
@@ -449,9 +450,9 @@ private:
friend struct ExprFloat;
friend struct ExprPath;
friend struct ExprSelect;
- friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
- friend void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v);
- friend void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v);
+ friend void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v);
+ friend void prim_match(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;
};
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 22257c6b3..44fb8317a 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -72,7 +72,7 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
return {std::move(tree), resolvedRef, lockedRef};
}
-static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
+static void forceTrivialValue(EvalState & state, Value & value, const PosIdx pos)
{
if (value.isThunk() && value.isTrivial())
state.forceValue(value, pos);
@@ -80,20 +80,20 @@ static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
static void expectType(EvalState & state, ValueType type,
- Value & value, const Pos & pos)
+ Value & value, const PosIdx pos)
{
forceTrivialValue(state, value, pos);
if (value.type() != type)
throw Error("expected %s but got %s at %s",
- showType(type), showType(value.type()), pos);
+ showType(type), showType(value.type()), state.positions[pos]);
}
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
- EvalState & state, Value * value, const Pos & pos,
+ EvalState & state, Value * value, const PosIdx pos,
const std::optional<Path> & baseDir, InputPath lockRootPath);
static FlakeInput parseFlakeInput(EvalState & state,
- const std::string & inputName, Value * value, const Pos & pos,
+ const std::string & inputName, Value * value, const PosIdx pos,
const std::optional<Path> & baseDir, InputPath lockRootPath)
{
expectType(state, nAttrs, *value, pos);
@@ -111,16 +111,16 @@ static FlakeInput parseFlakeInput(EvalState & state,
for (nix::Attr attr : *(value->attrs)) {
try {
if (attr.name == sUrl) {
- expectType(state, nString, *attr.value, *attr.pos);
+ expectType(state, nString, *attr.value, attr.pos);
url = attr.value->string.s;
attrs.emplace("url", *url);
} else if (attr.name == sFlake) {
- expectType(state, nBool, *attr.value, *attr.pos);
+ 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);
+ input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath);
} else if (attr.name == sFollows) {
- expectType(state, nString, *attr.value, *attr.pos);
+ expectType(state, nString, *attr.value, attr.pos);
auto follows(parseInputPath(attr.value->string.s));
follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end());
input.follows = follows;
@@ -141,7 +141,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
}
}
} catch (Error & e) {
- e.addTrace(*attr.pos, hintfmt("in flake attribute '%s'", attr.name));
+ e.addTrace(state.positions[attr.pos], hintfmt("in flake attribute '%s'", attr.name));
throw;
}
}
@@ -150,13 +150,13 @@ static FlakeInput parseFlakeInput(EvalState & state,
try {
input.ref = FlakeRef::fromAttrs(attrs);
} catch (Error & e) {
- e.addTrace(pos, hintfmt("in flake input"));
+ e.addTrace(state.positions[pos], hintfmt("in flake input"));
throw;
}
else {
attrs.erase("url");
if (!attrs.empty())
- throw Error("unexpected flake input attribute '%s', at %s", attrs.begin()->first, pos);
+ throw Error("unexpected flake input attribute '%s', at %s", attrs.begin()->first, state.positions[pos]);
if (url)
input.ref = parseFlakeRef(*url, baseDir, true, input.isFlake);
}
@@ -168,7 +168,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
}
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
- EvalState & state, Value * value, const Pos & pos,
+ EvalState & state, Value * value, const PosIdx pos,
const std::optional<Path> & baseDir, InputPath lockRootPath)
{
std::map<FlakeId, FlakeInput> inputs;
@@ -180,7 +180,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
parseFlakeInput(state,
inputAttr.name,
inputAttr.value,
- *inputAttr.pos,
+ inputAttr.pos,
baseDir,
lockRootPath));
}
@@ -218,22 +218,22 @@ static Flake getFlake(
Value vInfo;
state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack
- expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(flakeFile), 0, 0));
+ expectType(state, nAttrs, vInfo, state.positions.add({state.symbols.create(flakeFile), foFile}, 0, 0));
if (auto description = vInfo.attrs->get(state.sDescription)) {
- expectType(state, nString, *description->value, *description->pos);
+ expectType(state, nString, *description->value, description->pos);
flake.description = description->value->string.s;
}
auto sInputs = state.symbols.create("inputs");
if (auto inputs = vInfo.attrs->get(sInputs))
- flake.inputs = parseFlakeInputs(state, inputs->value, *inputs->pos, flakeDir, lockRootPath);
+ flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, flakeDir, lockRootPath);
auto sOutputs = state.symbols.create("outputs");
if (auto outputs = vInfo.attrs->get(sOutputs)) {
- expectType(state, nFunction, *outputs->value, *outputs->pos);
+ expectType(state, nFunction, *outputs->value, outputs->pos);
if (outputs->value->isLambda() && outputs->value->lambda.fun->hasFormals()) {
for (auto & formal : outputs->value->lambda.fun->formals->formals) {
@@ -250,29 +250,29 @@ static Flake getFlake(
auto sNixConfig = state.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);
+ forceTrivialValue(state, *setting.value, setting.pos);
if (setting.value->type() == nString)
- flake.config.settings.insert({setting.name, std::string(state.forceStringNoCtx(*setting.value, *setting.pos))});
+ flake.config.settings.insert({setting.name, std::string(state.forceStringNoCtx(*setting.value, setting.pos))});
else if (setting.value->type() == nPath) {
PathSet emptyContext = {};
flake.config.settings.emplace(
setting.name,
- state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true) .toOwned());
+ state.coerceToString(setting.pos, *setting.value, emptyContext, false, true, true) .toOwned());
}
else if (setting.value->type() == nInt)
- flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)});
+ flake.config.settings.insert({setting.name, state.forceInt(*setting.value, setting.pos)});
else if (setting.value->type() == nBool)
- flake.config.settings.insert({setting.name, Explicit<bool> { state.forceBool(*setting.value, *setting.pos) }});
+ flake.config.settings.insert({setting.name, Explicit<bool> { state.forceBool(*setting.value, setting.pos) }});
else if (setting.value->type() == nList) {
std::vector<std::string> ss;
for (auto elem : setting.value->listItems()) {
if (elem->type() != nString)
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
setting.name, showType(*setting.value));
- ss.emplace_back(state.forceStringNoCtx(*elem, *setting.pos));
+ ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos));
}
flake.config.settings.insert({setting.name, ss});
}
@@ -288,7 +288,7 @@ static Flake getFlake(
attr.name != sOutputs &&
attr.name != sNixConfig)
throw Error("flake '%s' has an unsupported attribute '%s', at %s",
- lockedRef, attr.name, *attr.pos);
+ lockedRef, attr.name, state.positions[attr.pos]);
}
return flake;
@@ -704,12 +704,12 @@ void callFlake(EvalState & state,
state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos);
}
-static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_getFlake(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::string flakeRefS(state.forceStringNoCtx(*args[0], pos));
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isLocked())
- throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
+ throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, state.positions[pos]);
callFlake(state,
lockFlake(state, flakeRef,
diff --git a/src/libexpr/function-trace.hh b/src/libexpr/function-trace.hh
index 472f2045e..e9a2526bd 100644
--- a/src/libexpr/function-trace.hh
+++ b/src/libexpr/function-trace.hh
@@ -8,7 +8,7 @@ namespace nix {
struct FunctionCallTrace
{
- const Pos & pos;
+ const Pos pos;
FunctionCallTrace(const Pos & pos);
~FunctionCallTrace();
};
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index bb7e77b61..afb35586d 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -61,7 +61,7 @@ std::string DrvInfo::querySystem() const
{
if (system == "" && attrs) {
auto i = attrs->find(state->sSystem);
- system = i == attrs->end() ? "unknown" : state->forceStringNoCtx(*i->value, *i->pos);
+ system = i == attrs->end() ? "unknown" : state->forceStringNoCtx(*i->value, i->pos);
}
return system;
}
@@ -75,7 +75,7 @@ std::optional<StorePath> DrvInfo::queryDrvPath() const
if (i == attrs->end())
drvPath = {std::nullopt};
else
- drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)};
+ drvPath = {state->coerceToStorePath(i->pos, *i->value, context)};
}
return drvPath.value_or(std::nullopt);
}
@@ -95,7 +95,7 @@ StorePath DrvInfo::queryOutPath() const
Bindings::iterator i = attrs->find(state->sOutPath);
PathSet context;
if (i != attrs->end())
- outPath = state->coerceToStorePath(*i->pos, *i->value, context);
+ outPath = state->coerceToStorePath(i->pos, *i->value, context);
}
if (!outPath)
throw UnimplementedError("CA derivations are not yet supported");
@@ -109,23 +109,23 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall
/* Get the ‘outputs’ list. */
Bindings::iterator i;
if (attrs && (i = attrs->find(state->sOutputs)) != attrs->end()) {
- state->forceList(*i->value, *i->pos);
+ state->forceList(*i->value, i->pos);
/* For each output... */
for (auto elem : i->value->listItems()) {
- std::string output(state->forceStringNoCtx(*elem, *i->pos));
+ std::string output(state->forceStringNoCtx(*elem, i->pos));
if (withPaths) {
/* Evaluate the corresponding set. */
Bindings::iterator out = attrs->find(state->symbols.create(output));
if (out == attrs->end()) continue; // FIXME: throw error?
- state->forceAttrs(*out->value, *i->pos);
+ state->forceAttrs(*out->value, i->pos);
/* And evaluate its ‘outPath’ attribute. */
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context;
- outputs.emplace(output, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
+ outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context));
} else
outputs.emplace(output, std::nullopt);
}
@@ -168,7 +168,7 @@ Bindings * DrvInfo::getMeta()
if (!attrs) return 0;
Bindings::iterator a = attrs->find(state->sMeta);
if (a == attrs->end()) return 0;
- state->forceAttrs(*a->value, *a->pos);
+ state->forceAttrs(*a->value, a->pos);
meta = a->value->attrs;
return meta;
}
@@ -369,7 +369,7 @@ static void getDerivations(EvalState & state, Value & vIn,
`recurseForDerivations = true' attribute. */
if (i->value->type() == nAttrs) {
Bindings::iterator j = i->value->attrs->find(state.sRecurseForDerivations);
- if (j != i->value->attrs->end() && state.forceBool(*j->value, *j->pos))
+ if (j != i->value->attrs->end() && state.forceBool(*j->value, j->pos))
getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
}
}
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index d574121b0..4c28b976e 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -28,9 +28,9 @@ using namespace nix;
namespace nix {
-static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
+static inline PosIdx makeCurPos(const YYLTYPE & loc, ParseData * data)
{
- return Pos(data->origin, data->file, loc.first_line, loc.first_column);
+ return data->state.positions.add(data->origin, loc.first_line, loc.first_column);
}
#define CUR_POS makeCurPos(*yylloc, data)
@@ -155,7 +155,7 @@ or { return OR_KW; }
} catch (const boost::bad_lexical_cast &) {
throw ParseError({
.msg = hintfmt("invalid integer '%1%'", yytext),
- .errPos = CUR_POS,
+ .errPos = data->state.positions[CUR_POS],
});
}
return INT;
@@ -165,7 +165,7 @@ or { return OR_KW; }
if (errno != 0)
throw ParseError({
.msg = hintfmt("invalid float '%1%'", yytext),
- .errPos = CUR_POS,
+ .errPos = data->state.positions[CUR_POS],
});
return FLOAT;
}
@@ -294,7 +294,7 @@ or { return OR_KW; }
<INPATH_SLASH><<EOF>> {
throw ParseError({
.msg = hintfmt("path has a trailing slash"),
- .errPos = CUR_POS,
+ .errPos = data->state.positions[CUR_POS],
});
}
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index bf01935a9..4138977ea 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -249,33 +249,31 @@ std::string showAttrPath(const AttrPath & attrPath)
}
-Pos noPos;
-
/* Computing levels/displacements for variables. */
-void Expr::bindVars(const StaticEnv & env)
+void Expr::bindVars(const PosTable & pt, const StaticEnv & env)
{
abort();
}
-void ExprInt::bindVars(const StaticEnv & env)
+void ExprInt::bindVars(const PosTable & pt, const StaticEnv & env)
{
}
-void ExprFloat::bindVars(const StaticEnv & env)
+void ExprFloat::bindVars(const PosTable & pt, const StaticEnv & env)
{
}
-void ExprString::bindVars(const StaticEnv & env)
+void ExprString::bindVars(const PosTable & pt, const StaticEnv & env)
{
}
-void ExprPath::bindVars(const StaticEnv & env)
+void ExprPath::bindVars(const PosTable & pt, const StaticEnv & env)
{
}
-void ExprVar::bindVars(const StaticEnv & env)
+void ExprVar::bindVars(const PosTable & pt, const StaticEnv & env)
{
/* Check whether the variable appears in the environment. If so,
set its level and displacement. */
@@ -302,30 +300,30 @@ void ExprVar::bindVars(const StaticEnv & env)
if (withLevel == -1)
throw UndefinedVarError({
.msg = hintfmt("undefined variable '%1%'", name),
- .errPos = pos
+ .errPos = pt[pos]
});
fromWith = true;
this->level = withLevel;
}
-void ExprSelect::bindVars(const StaticEnv & env)
+void ExprSelect::bindVars(const PosTable & pt, const StaticEnv & env)
{
- e->bindVars(env);
- if (def) def->bindVars(env);
+ e->bindVars(pt, env);
+ if (def) def->bindVars(pt, env);
for (auto & i : attrPath)
if (!i.symbol.set())
- i.expr->bindVars(env);
+ i.expr->bindVars(pt, env);
}
-void ExprOpHasAttr::bindVars(const StaticEnv & env)
+void ExprOpHasAttr::bindVars(const PosTable & pt, const StaticEnv & env)
{
- e->bindVars(env);
+ e->bindVars(pt, env);
for (auto & i : attrPath)
if (!i.symbol.set())
- i.expr->bindVars(env);
+ i.expr->bindVars(pt, env);
}
-void ExprAttrs::bindVars(const StaticEnv & env)
+void ExprAttrs::bindVars(const PosTable & pt, const StaticEnv & env)
{
const StaticEnv * dynamicEnv = &env;
StaticEnv newEnv(false, &env, recursive ? attrs.size() : 0);
@@ -340,26 +338,26 @@ void ExprAttrs::bindVars(const StaticEnv & env)
// No need to sort newEnv since attrs is in sorted order.
for (auto & i : attrs)
- i.second.e->bindVars(i.second.inherited ? env : newEnv);
+ i.second.e->bindVars(pt, i.second.inherited ? env : newEnv);
}
else
for (auto & i : attrs)
- i.second.e->bindVars(env);
+ i.second.e->bindVars(pt, env);
for (auto & i : dynamicAttrs) {
- i.nameExpr->bindVars(*dynamicEnv);
- i.valueExpr->bindVars(*dynamicEnv);
+ i.nameExpr->bindVars(pt, *dynamicEnv);
+ i.valueExpr->bindVars(pt, *dynamicEnv);
}
}
-void ExprList::bindVars(const StaticEnv & env)
+void ExprList::bindVars(const PosTable & pt, const StaticEnv & env)
{
for (auto & i : elems)
- i->bindVars(env);
+ i->bindVars(pt, env);
}
-void ExprLambda::bindVars(const StaticEnv & env)
+void ExprLambda::bindVars(const PosTable & pt, const StaticEnv & env)
{
StaticEnv newEnv(
false, &env,
@@ -377,20 +375,20 @@ void ExprLambda::bindVars(const StaticEnv & env)
newEnv.sort();
for (auto & i : formals->formals)
- if (i.def) i.def->bindVars(newEnv);
+ if (i.def) i.def->bindVars(pt, newEnv);
}
- body->bindVars(newEnv);
+ body->bindVars(pt, newEnv);
}
-void ExprCall::bindVars(const StaticEnv & env)
+void ExprCall::bindVars(const PosTable & pt, const StaticEnv & env)
{
- fun->bindVars(env);
+ fun->bindVars(pt, env);
for (auto e : args)
- e->bindVars(env);
+ e->bindVars(pt, env);
}
-void ExprLet::bindVars(const StaticEnv & env)
+void ExprLet::bindVars(const PosTable & pt, const StaticEnv & env)
{
StaticEnv newEnv(false, &env, attrs->attrs.size());
@@ -401,12 +399,12 @@ void ExprLet::bindVars(const StaticEnv & env)
// No need to sort newEnv since attrs->attrs is in sorted order.
for (auto & i : attrs->attrs)
- i.second.e->bindVars(i.second.inherited ? env : newEnv);
+ i.second.e->bindVars(pt, i.second.inherited ? env : newEnv);
- body->bindVars(newEnv);
+ body->bindVars(pt, newEnv);
}
-void ExprWith::bindVars(const StaticEnv & env)
+void ExprWith::bindVars(const PosTable & pt, const StaticEnv & env)
{
/* Does this `with' have an enclosing `with'? If so, record its
level so that `lookupVar' can look up variables in the previous
@@ -420,36 +418,36 @@ void ExprWith::bindVars(const StaticEnv & env)
break;
}
- attrs->bindVars(env);
+ attrs->bindVars(pt, env);
StaticEnv newEnv(true, &env);
- body->bindVars(newEnv);
+ body->bindVars(pt, newEnv);
}
-void ExprIf::bindVars(const StaticEnv & env)
+void ExprIf::bindVars(const PosTable & pt, const StaticEnv & env)
{
- cond->bindVars(env);
- then->bindVars(env);
- else_->bindVars(env);
+ cond->bindVars(pt, env);
+ then->bindVars(pt, env);
+ else_->bindVars(pt, env);
}
-void ExprAssert::bindVars(const StaticEnv & env)
+void ExprAssert::bindVars(const PosTable & pt, const StaticEnv & env)
{
- cond->bindVars(env);
- body->bindVars(env);
+ cond->bindVars(pt, env);
+ body->bindVars(pt, env);
}
-void ExprOpNot::bindVars(const StaticEnv & env)
+void ExprOpNot::bindVars(const PosTable & pt, const StaticEnv & env)
{
- e->bindVars(env);
+ e->bindVars(pt, env);
}
-void ExprConcatStrings::bindVars(const StaticEnv & env)
+void ExprConcatStrings::bindVars(const PosTable & pt, const StaticEnv & env)
{
for (auto & i : *es)
- i.second->bindVars(env);
+ i.second->bindVars(pt, env);
}
-void ExprPos::bindVars(const StaticEnv & env)
+void ExprPos::bindVars(const PosTable & pt, const StaticEnv & env)
{
}
@@ -468,9 +466,9 @@ void ExprLambda::setName(Symbol & name)
}
-std::string ExprLambda::showNamePos() const
+std::string ExprLambda::showNamePos(const PosTable & pt) const
{
- return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pos);
+ return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pt[pos]);
}
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 4dbe31510..d9392cff5 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -1,5 +1,8 @@
#pragma once
+#include <map>
+#include <vector>
+
#include "value.hh"
#include "symbol-table.hh"
#include "error.hh"
@@ -24,31 +27,91 @@ MakeError(RestrictedPathError, Error);
struct Pos
{
Symbol file;
+ FileOrigin origin;
uint32_t line;
- FileOrigin origin:2;
- uint32_t column:30;
- Pos() : line(0), origin(foString), column(0) { };
- Pos(FileOrigin origin, const Symbol & file, uint32_t line, uint32_t column)
- : file(file), line(line), origin(origin), column(column) { };
- operator bool() const
+ uint32_t column;
+
+ explicit operator bool() const { return line > 0; }
+};
+
+class PosIdx {
+ friend class PosTable;
+
+private:
+ uint32_t id;
+
+ explicit PosIdx(uint32_t id): id(id) {}
+
+public:
+ PosIdx() : id(0) {}
+
+ explicit operator bool() const { return id > 0; }
+
+ bool operator<(const PosIdx other) const { return id < other.id; }
+};
+
+class PosTable
+{
+public:
+ class Origin {
+ friend PosTable;
+ private:
+ // must always be invalid by default, add() replaces this with the actual value.
+ // subsequent add() calls use this index as a token to quickly check whether the
+ // current origins.back() can be reused or not.
+ mutable uint32_t idx = std::numeric_limits<uint32_t>::max();
+
+ explicit Origin(uint32_t idx): idx(idx), file{}, origin{} {}
+
+ public:
+ const Symbol file;
+ const FileOrigin origin;
+
+ Origin(Symbol file, FileOrigin origin): file(file), origin(origin) {}
+ };
+
+ struct Offset {
+ uint32_t line, column;
+ };
+
+private:
+ std::vector<Origin> origins;
+ ChunkedVector<Offset, 8192> offsets;
+
+public:
+ PosTable(): offsets(1024)
{
- return line != 0;
+ origins.reserve(1024);
+ }
+
+ PosIdx add(const Origin & origin, uint32_t line, uint32_t column)
+ {
+ const auto idx = offsets.add({line, column}).second;
+ if (origins.empty() || origins.back().idx != origin.idx) {
+ origin.idx = idx;
+ origins.push_back(origin);
+ }
+ return PosIdx(idx + 1);
}
- bool operator < (const Pos & p2) const
+ Pos operator[](PosIdx p) const
{
- if (!line) return p2.line;
- if (!p2.line) return false;
- int d = ((const std::string &) file).compare((const std::string &) p2.file);
- if (d < 0) return true;
- if (d > 0) return false;
- if (line < p2.line) return true;
- if (line > p2.line) return false;
- return column < p2.column;
+ if (p.id == 0 || p.id > offsets.size())
+ return {};
+ const auto idx = p.id - 1;
+ /* we want the last key <= idx, so we'll take prev(first key > idx).
+ this is guaranteed to never rewind origin.begin because the first
+ key is always 0. */
+ const auto pastOrigin = std::upper_bound(
+ origins.begin(), origins.end(), Origin(idx),
+ [] (const auto & a, const auto & b) { return a.idx < b.idx; });
+ const auto origin = *std::prev(pastOrigin);
+ const auto offset = offsets[idx];
+ return {origin.file, origin.origin, offset.line, offset.column};
}
};
-extern Pos noPos;
+inline PosIdx noPos = {};
std::ostream & operator << (std::ostream & str, const Pos & pos);
@@ -79,7 +142,7 @@ struct Expr
{
virtual ~Expr() { };
virtual void show(std::ostream & str) const;
- virtual void bindVars(const StaticEnv & env);
+ virtual void bindVars(const PosTable & pt, const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
@@ -90,7 +153,7 @@ std::ostream & operator << (std::ostream & str, const Expr & e);
#define COMMON_METHODS \
void show(std::ostream & str) const; \
void eval(EvalState & state, Env & env, Value & v); \
- void bindVars(const StaticEnv & env);
+ void bindVars(const PosTable & pt, const StaticEnv & env);
struct ExprInt : Expr
{
@@ -133,7 +196,7 @@ typedef uint32_t Displacement;
struct ExprVar : Expr
{
- Pos pos;
+ PosIdx pos;
Symbol name;
/* Whether the variable comes from an environment (e.g. a rec, let
@@ -150,18 +213,18 @@ struct ExprVar : Expr
Displacement displ;
ExprVar(const Symbol & name) : name(name) { };
- ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
+ ExprVar(const PosIdx & pos, const Symbol & name) : pos(pos), name(name) { };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
struct ExprSelect : Expr
{
- Pos pos;
+ PosIdx pos;
Expr * e, * def;
AttrPath attrPath;
- ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
- ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
+ ExprSelect(const PosIdx & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
+ ExprSelect(const PosIdx & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
COMMON_METHODS
};
@@ -176,13 +239,13 @@ struct ExprOpHasAttr : Expr
struct ExprAttrs : Expr
{
bool recursive;
- Pos pos;
+ PosIdx pos;
struct AttrDef {
bool inherited;
Expr * e;
- Pos pos;
+ PosIdx pos;
Displacement displ; // displacement
- AttrDef(Expr * e, const Pos & pos, bool inherited=false)
+ AttrDef(Expr * e, const PosIdx & pos, bool inherited=false)
: inherited(inherited), e(e), pos(pos) { };
AttrDef() { };
};
@@ -190,14 +253,14 @@ struct ExprAttrs : Expr
AttrDefs attrs;
struct DynamicAttrDef {
Expr * nameExpr, * valueExpr;
- Pos pos;
- DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const Pos & pos)
+ PosIdx pos;
+ DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const PosIdx & pos)
: nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { };
};
typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
DynamicAttrDefs dynamicAttrs;
- ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { };
- ExprAttrs() : recursive(false), pos(noPos) { };
+ ExprAttrs(const PosIdx &pos) : recursive(false), pos(pos) { };
+ ExprAttrs() : recursive(false) { };
COMMON_METHODS
};
@@ -210,10 +273,10 @@ struct ExprList : Expr
struct Formal
{
- Pos pos;
+ PosIdx pos;
Symbol name;
Expr * def;
- Formal(const Pos & pos, const Symbol & name, Expr * def) : pos(pos), name(name), def(def) { };
+ Formal(const PosIdx & pos, const Symbol & name, Expr * def) : pos(pos), name(name), def(def) { };
};
struct Formals
@@ -241,17 +304,17 @@ struct Formals
struct ExprLambda : Expr
{
- Pos pos;
+ PosIdx pos;
Symbol name;
Symbol arg;
Formals * formals;
Expr * body;
- ExprLambda(const Pos & pos, const Symbol & arg, Formals * formals, Expr * body)
+ ExprLambda(const PosIdx & pos, const Symbol & arg, Formals * formals, Expr * body)
: pos(pos), arg(arg), formals(formals), body(body)
{
};
void setName(Symbol & name);
- std::string showNamePos() const;
+ std::string showNamePos(const PosTable & pt) const;
inline bool hasFormals() const { return formals != nullptr; }
COMMON_METHODS
};
@@ -260,8 +323,8 @@ struct ExprCall : Expr
{
Expr * fun;
std::vector<Expr *> args;
- Pos pos;
- ExprCall(const Pos & pos, Expr * fun, std::vector<Expr *> && args)
+ PosIdx pos;
+ ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
: fun(fun), args(args), pos(pos)
{ }
COMMON_METHODS
@@ -277,26 +340,26 @@ struct ExprLet : Expr
struct ExprWith : Expr
{
- Pos pos;
+ PosIdx pos;
Expr * attrs, * body;
size_t prevWith;
- ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
+ ExprWith(const PosIdx & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
COMMON_METHODS
};
struct ExprIf : Expr
{
- Pos pos;
+ PosIdx pos;
Expr * cond, * then, * else_;
- ExprIf(const Pos & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { };
+ ExprIf(const PosIdx & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { };
COMMON_METHODS
};
struct ExprAssert : Expr
{
- Pos pos;
+ PosIdx pos;
Expr * cond, * body;
- ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
+ ExprAssert(const PosIdx & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
COMMON_METHODS
};
@@ -310,17 +373,17 @@ struct ExprOpNot : Expr
#define MakeBinOp(name, s) \
struct name : Expr \
{ \
- Pos pos; \
+ PosIdx pos; \
Expr * e1, * e2; \
name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
- name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
+ name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
void show(std::ostream & str) const \
{ \
str << "(" << *e1 << " " s " " << *e2 << ")"; \
} \
- void bindVars(const StaticEnv & env) \
+ void bindVars(const PosTable & pt, const StaticEnv & env) \
{ \
- e1->bindVars(env); e2->bindVars(env); \
+ e1->bindVars(pt, env); e2->bindVars(pt, env); \
} \
void eval(EvalState & state, Env & env, Value & v); \
};
@@ -335,18 +398,18 @@ MakeBinOp(ExprOpConcatLists, "++")
struct ExprConcatStrings : Expr
{
- Pos pos;
+ PosIdx pos;
bool forceString;
- std::vector<std::pair<Pos, Expr *> > * es;
- ExprConcatStrings(const Pos & pos, bool forceString, std::vector<std::pair<Pos, Expr *> > * es)
+ std::vector<std::pair<PosIdx, Expr *> > * es;
+ ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector<std::pair<PosIdx, Expr *> > * es)
: pos(pos), forceString(forceString), es(es) { };
COMMON_METHODS
};
struct ExprPos : Expr
{
- Pos pos;
- ExprPos(const Pos & pos) : pos(pos) { };
+ PosIdx pos;
+ ExprPos(const PosIdx & pos) : pos(pos) { };
COMMON_METHODS
};
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 49c401603..0052a8070 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -32,12 +32,12 @@ namespace nix {
SymbolTable & symbols;
Expr * result;
Path basePath;
- Symbol file;
- FileOrigin origin;
+ PosTable::Origin origin;
std::optional<ErrorInfo> error;
- ParseData(EvalState & state)
+ ParseData(EvalState & state, PosTable::Origin origin)
: state(state)
, symbols(state.symbols)
+ , origin(std::move(origin))
{ };
};
@@ -96,7 +96,7 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
- Expr * e, const Pos & pos)
+ Expr * e, const PosIdx pos, const nix::PosTable & pt)
{
AttrPath::iterator i;
// All attrpaths have at least one attr
@@ -109,10 +109,10 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
if (j != attrs->attrs.end()) {
if (!j->second.inherited) {
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
- if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
+ if (!attrs2) dupAttr(attrPath, pt[pos], pt[j->second.pos]);
attrs = attrs2;
} else
- dupAttr(attrPath, pos, j->second.pos);
+ dupAttr(attrPath, pt[pos], pt[j->second.pos]);
} else {
ExprAttrs * nested = new ExprAttrs;
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
@@ -139,11 +139,11 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
for (auto & ad : ae->attrs) {
auto j2 = jAttrs->attrs.find(ad.first);
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
- dupAttr(ad.first, j2->second.pos, ad.second.pos);
+ dupAttr(ad.first, pt[j2->second.pos], pt[ad.second.pos]);
jAttrs->attrs.emplace(ad.first, ad.second);
}
} else {
- dupAttr(attrPath, pos, j->second.pos);
+ dupAttr(attrPath, pt[pos], pt[j->second.pos]);
}
} else {
// This attr path is not defined. Let's create it.
@@ -157,14 +157,14 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
static Formals * toFormals(ParseData & data, ParserFormals * formals,
- Pos pos = noPos, Symbol arg = {})
+ PosIdx pos = noPos, Symbol arg = {})
{
std::sort(formals->formals.begin(), formals->formals.end(),
[] (const auto & a, const auto & b) {
return std::tie(a.name, a.pos) < std::tie(b.name, b.pos);
});
- std::optional<std::pair<Symbol, Pos>> duplicate;
+ std::optional<std::pair<Symbol, PosIdx>> duplicate;
for (size_t i = 0; i + 1 < formals->formals.size(); i++) {
if (formals->formals[i].name != formals->formals[i + 1].name)
continue;
@@ -174,7 +174,7 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals,
if (duplicate)
throw ParseError({
.msg = hintfmt("duplicate formal function argument '%1%'", duplicate->first),
- .errPos = duplicate->second
+ .errPos = data.state.positions[duplicate->second]
});
Formals result;
@@ -184,7 +184,7 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals,
if (arg.set() && result.has(arg))
throw ParseError({
.msg = hintfmt("duplicate formal function argument '%1%'", arg),
- .errPos = pos
+ .errPos = data.state.positions[pos]
});
delete formals;
@@ -192,8 +192,8 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals,
}
-static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
- std::vector<std::pair<Pos, std::variant<Expr *, StringToken> > > & es)
+static Expr * stripIndentation(const PosIdx pos, SymbolTable & symbols,
+ std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken> > > & es)
{
if (es.empty()) return new ExprString("");
@@ -233,7 +233,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
}
/* Strip spaces from each line. */
- std::vector<std::pair<Pos, Expr *> > * es2 = new std::vector<std::pair<Pos, Expr *> >;
+ auto * es2 = new std::vector<std::pair<PosIdx, Expr *> >;
atStartOfLine = true;
size_t curDropped = 0;
size_t n = es.size();
@@ -284,9 +284,9 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
}
-static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
+static inline PosIdx makeCurPos(const YYLTYPE & loc, ParseData * data)
{
- return Pos(data->origin, data->file, loc.first_line, loc.first_column);
+ return data->state.positions.add(data->origin, loc.first_line, loc.first_column);
}
#define CUR_POS makeCurPos(*yylocp, data)
@@ -299,7 +299,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
{
data->error = {
.msg = hintfmt(error),
- .errPos = makeCurPos(*loc, data)
+ .errPos = data->state.positions[makeCurPos(*loc, data)]
};
}
@@ -320,8 +320,8 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
StringToken uri;
StringToken str;
std::vector<nix::AttrName> * attrNames;
- std::vector<std::pair<nix::Pos, nix::Expr *> > * string_parts;
- std::vector<std::pair<nix::Pos, std::variant<nix::Expr *, StringToken> > > * ind_string_parts;
+ std::vector<std::pair<nix::PosIdx, nix::Expr *> > * string_parts;
+ std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, StringToken> > > * ind_string_parts;
}
%type <e> start expr expr_function expr_if expr_op
@@ -388,7 +388,7 @@ expr_function
{ if (!$2->dynamicAttrs.empty())
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in let"),
- .errPos = CUR_POS
+ .errPos = data->state.positions[CUR_POS]
});
$$ = new ExprLet($2, $4);
}
@@ -415,7 +415,7 @@ expr_op
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
| expr_op '+' expr_op
- { $$ = new ExprConcatStrings(CUR_POS, false, new std::vector<std::pair<Pos, Expr *> >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); }
+ { $$ = new ExprConcatStrings(CUR_POS, false, new std::vector<std::pair<PosIdx, Expr *> >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); }
| expr_op '-' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {$1, $3}); }
| expr_op '*' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__mul")), {$1, $3}); }
| expr_op '/' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__div")), {$1, $3}); }
@@ -477,7 +477,7 @@ expr_simple
if (noURLLiterals)
throw ParseError({
.msg = hintfmt("URL literals are disabled"),
- .errPos = CUR_POS
+ .errPos = data->state.positions[CUR_POS]
});
$$ = new ExprString(std::string($1));
}
@@ -503,9 +503,9 @@ string_parts_interpolated
: string_parts_interpolated STR
{ $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(std::string($2))); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
- | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
+ | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<PosIdx, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
| STR DOLLAR_CURLY expr '}' {
- $$ = new std::vector<std::pair<Pos, Expr *> >;
+ $$ = new std::vector<std::pair<PosIdx, Expr *> >;
$$->emplace_back(makeCurPos(@1, data), new ExprString(std::string($1)));
$$->emplace_back(makeCurPos(@2, data), $3);
}
@@ -528,17 +528,18 @@ path_start
ind_string_parts
: ind_string_parts IND_STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $2); }
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
- | { $$ = new std::vector<std::pair<Pos, std::variant<Expr *, StringToken> > >; }
+ | { $$ = new std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken> > >; }
;
binds
- : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
+ : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data), data->state.positions); }
| binds INHERIT attrs ';'
{ $$ = $1;
for (auto & i : *$3) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
- dupAttr(i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos);
- Pos pos = makeCurPos(@3, data);
+ dupAttr(i.symbol, data->state.positions[makeCurPos(@3, data)],
+ data->state.positions[$$->attrs[i.symbol].pos]);
+ auto pos = makeCurPos(@3, data);
$$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true));
}
}
@@ -547,7 +548,8 @@ binds
/* !!! Should ensure sharing of the expression in $4. */
for (auto & i : *$6) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
- dupAttr(i.symbol, makeCurPos(@6, data), $$->attrs[i.symbol].pos);
+ dupAttr(i.symbol, data->state.positions[makeCurPos(@6, data)],
+ data->state.positions[$$->attrs[i.symbol].pos]);
$$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data)));
}
}
@@ -565,7 +567,7 @@ attrs
} else
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in inherit"),
- .errPos = makeCurPos(@2, data)
+ .errPos = data->state.positions[makeCurPos(@2, data)]
});
}
| { $$ = new AttrPath; }
@@ -646,19 +648,19 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
const PathView path, const PathView basePath, StaticEnv & staticEnv)
{
yyscan_t scanner;
- ParseData data(*this);
- data.origin = origin;
+ Symbol file;
switch (origin) {
case foFile:
- data.file = data.symbols.create(path);
+ file = symbols.create(path);
break;
case foStdin:
case foString:
- data.file = data.symbols.create(text);
+ file = symbols.create(text);
break;
default:
assert(false);
}
+ ParseData data(*this, {file, origin});
data.basePath = basePath;
yylex_init(&scanner);
@@ -668,7 +670,7 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
if (res) throw ParseError(data.error.value());
- data.result->bindVars(staticEnv);
+ data.result->bindVars(positions, staticEnv);
return data.result;
}
@@ -760,7 +762,7 @@ Path EvalState::findFile(const std::string_view path)
}
-Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos)
+Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos)
{
for (auto & i : searchPath) {
std::string suffix;
@@ -787,7 +789,7 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c
? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"
: "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)",
path),
- .errPos = pos
+ .errPos = positions[pos]
});
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 3ebc2f1df..9cdcfd0b9 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -96,7 +96,7 @@ struct RealisePathFlags {
bool checkForPureEval = true;
};
-static Path realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {})
+static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const RealisePathFlags flags = {})
{
PathSet context;
@@ -105,7 +105,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea
try {
return state.coerceToPath(pos, v, context);
} catch (Error & e) {
- e.addTrace(pos, "while realising the context of a path");
+ e.addTrace(state.positions[pos], "while realising the context of a path");
throw;
}
}();
@@ -119,7 +119,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea
? state.checkSourcePath(realPath)
: realPath;
} catch (Error & e) {
- e.addTrace(pos, "while realising the context of path '%s'", path);
+ e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
throw;
}
}
@@ -157,7 +157,7 @@ static void mkOutputString(
/* Load and evaluate an expression from path specified by the
argument. */
-static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v)
+static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * vScope, Value & v)
{
auto path = realisePath(state, pos, vPath);
@@ -237,7 +237,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info {
.name = "scopedImport",
.arity = 2,
- .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
import(state, pos, *args[1], args[0], v);
}
@@ -299,7 +299,7 @@ static RegisterPrimOp primop_import({
(The function argument doesn’t have to be called `x` in `foo.nix`;
any name would work.)
)",
- .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
import(state, pos, *args[0], nullptr, v);
}
@@ -310,7 +310,7 @@ static RegisterPrimOp primop_import({
extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
/* Load a ValueInitializer from a DSO and return whatever it initializes */
-void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
@@ -338,7 +338,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
/* Execute a program and parse its output */
-void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
auto elems = args[0]->listElems();
@@ -346,7 +346,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
if (count == 0) {
throw EvalError({
.msg = hintfmt("at least one argument to 'exec' required"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
PathSet context;
@@ -361,29 +361,30 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
throw EvalError({
.msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid",
program, e.path),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
auto output = runProgram(program, true, commandArgs);
Expr * parsed;
try {
- parsed = state.parseExprFromString(std::move(output), pos.file);
+ auto base = state.positions[pos];
+ parsed = state.parseExprFromString(std::move(output), base.file);
} catch (Error & e) {
- e.addTrace(pos, "While parsing the output from '%1%'", program);
+ e.addTrace(state.positions[pos], "While parsing the output from '%1%'", program);
throw;
}
try {
state.eval(parsed, v);
} catch (Error & e) {
- e.addTrace(pos, "While evaluating the output from '%1%'", program);
+ e.addTrace(state.positions[pos], "While evaluating the output from '%1%'", program);
throw;
}
}
/* Return a string representing the type of the expression. */
-static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
std::string t;
@@ -417,7 +418,7 @@ static RegisterPrimOp primop_typeOf({
});
/* Determine whether the argument is the null value. */
-static void prim_isNull(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isNull(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nNull);
@@ -437,7 +438,7 @@ static RegisterPrimOp primop_isNull({
});
/* Determine whether the argument is a function. */
-static void prim_isFunction(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isFunction(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nFunction);
@@ -453,7 +454,7 @@ static RegisterPrimOp primop_isFunction({
});
/* Determine whether the argument is an integer. */
-static void prim_isInt(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isInt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nInt);
@@ -469,7 +470,7 @@ static RegisterPrimOp primop_isInt({
});
/* Determine whether the argument is a float. */
-static void prim_isFloat(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isFloat(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nFloat);
@@ -485,7 +486,7 @@ static RegisterPrimOp primop_isFloat({
});
/* Determine whether the argument is a string. */
-static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nString);
@@ -501,7 +502,7 @@ static RegisterPrimOp primop_isString({
});
/* Determine whether the argument is a Boolean. */
-static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isBool(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nBool);
@@ -517,7 +518,7 @@ static RegisterPrimOp primop_isBool({
});
/* Determine whether the argument is a path. */
-static void prim_isPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nPath);
@@ -585,7 +586,7 @@ static Bindings::iterator getAttr(
std::string_view funcName,
Symbol attrSym,
Bindings * attrSet,
- const Pos & pos)
+ const PosIdx pos)
{
Bindings::iterator value = attrSet->find(attrSym);
if (value == attrSet->end()) {
@@ -595,21 +596,21 @@ static Bindings::iterator getAttr(
funcName
);
- Pos aPos = *attrSet->pos;
- if (aPos == noPos) {
+ auto aPos = attrSet->pos;
+ if (!aPos) {
throw TypeError({
.msg = errorMsg,
- .errPos = pos,
+ .errPos = state.positions[pos],
});
} else {
auto e = TypeError({
.msg = errorMsg,
- .errPos = aPos,
+ .errPos = state.positions[aPos],
});
// Adding another trace for the function name to make it clear
// which call received wrong arguments.
- e.addTrace(pos, hintfmt("while invoking '%s'", funcName));
+ e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", funcName));
throw e;
}
}
@@ -617,7 +618,7 @@ static Bindings::iterator getAttr(
return value;
}
-static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
@@ -666,7 +667,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
if (key == e->attrs->end())
throw EvalError({
.msg = hintfmt("attribute 'key' required"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
state.forceValue(*key->value, pos);
@@ -729,7 +730,7 @@ static RegisterPrimOp primop_abort({
.doc = R"(
Abort Nix expression evaluation and print the error message *s*.
)",
- .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context).toOwned();
@@ -747,7 +748,7 @@ static RegisterPrimOp primop_throw({
derivations, a derivation that throws an error is silently skipped
(which is not the case for `abort`).
)",
- .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context).toOwned();
@@ -755,7 +756,7 @@ static RegisterPrimOp primop_throw({
}
});
-static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
try {
state.forceValue(*args[1], pos);
@@ -773,7 +774,7 @@ static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info {
.fun = prim_addErrorContext,
});
-static void prim_ceil(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_ceil(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos));
v.mkInt(ceil(value));
@@ -792,7 +793,7 @@ static RegisterPrimOp primop_ceil({
.fun = prim_ceil,
});
-static void prim_floor(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_floor(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos));
v.mkInt(floor(value));
@@ -813,7 +814,7 @@ static RegisterPrimOp primop_floor({
/* Try evaluating the argument. Success => {success=true; value=something;},
* else => {success=false; value=false;} */
-static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto attrs = state.buildBindings(2);
try {
@@ -849,7 +850,7 @@ static RegisterPrimOp primop_tryEval({
});
/* Return an environment variable. Use with care. */
-static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::string name(state.forceStringNoCtx(*args[0], pos));
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
@@ -873,7 +874,7 @@ static RegisterPrimOp primop_getEnv({
});
/* Evaluate the first argument, then return the second argument. */
-static void prim_seq(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_seq(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -892,7 +893,7 @@ static RegisterPrimOp primop_seq({
/* Evaluate the first argument deeply (i.e. recursing into lists and
attrsets), then return the second argument. */
-static void prim_deepSeq(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_deepSeq(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValueDeep(*args[0]);
state.forceValue(*args[1], pos);
@@ -912,7 +913,7 @@ static RegisterPrimOp primop_deepSeq({
/* Evaluate the first expression and print it on standard error. Then
return the second expression. Useful for debugging. */
-static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
if (args[0]->type() == nString)
@@ -947,7 +948,7 @@ static RegisterPrimOp primop_trace({
derivation; `drvPath' containing the path of the Nix expression;
and `type' set to `derivation' to indicate that this is a
derivation. */
-static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
@@ -961,11 +962,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
);
std::string drvName;
- Pos & posDrvName(*attr->pos);
+ const auto posDrvName = attr->pos;
try {
drvName = state.forceStringNoCtx(*attr->value, pos);
} catch (Error & e) {
- e.addTrace(posDrvName, "while evaluating the derivation attribute 'name'");
+ e.addTrace(state.positions[posDrvName], "while evaluating the derivation attribute 'name'");
throw;
}
@@ -1008,7 +1009,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else
throw EvalError({
.msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
};
@@ -1018,7 +1019,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (outputs.find(j) != outputs.end())
throw EvalError({
.msg = hintfmt("duplicate derivation output '%1%'", j),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
/* !!! Check whether j is a valid attribute
name. */
@@ -1028,14 +1029,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (j == "drv")
throw EvalError({
.msg = hintfmt("invalid derivation output name 'drv'" ),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
outputs.insert(j);
}
if (outputs.empty())
throw EvalError({
.msg = hintfmt("derivation cannot have an empty set of outputs"),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
};
@@ -1099,7 +1100,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
} else {
- auto s = state.coerceToString(*i->pos, *i->value, context, true).toOwned();
+ auto s = state.coerceToString(i->pos, *i->value, context, true).toOwned();
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = std::move(s);
else if (i->name == state.sSystem) drv.platform = std::move(s);
@@ -1113,7 +1114,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
} catch (Error & e) {
- e.addTrace(posDrvName,
+ e.addTrace(state.positions[posDrvName],
"while evaluating the attribute '%1%' of the derivation '%2%'",
key, drvName);
throw;
@@ -1163,20 +1164,20 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (drv.builder == "")
throw EvalError({
.msg = hintfmt("required attribute 'builder' missing"),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
if (drv.platform == "")
throw EvalError({
.msg = hintfmt("required attribute 'system' missing"),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
/* Check whether the derivation name is valid. */
if (isDerivation(drvName))
throw EvalError({
.msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
if (outputHash) {
@@ -1187,7 +1188,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error({
.msg = hintfmt("multiple outputs are not supported in fixed-output derivations"),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
auto h = newHashAllowEmpty(*outputHash, parseHashTypeOpt(outputHashAlgo));
@@ -1208,7 +1209,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (contentAddressed && isImpure)
throw EvalError({
.msg = hintfmt("derivation cannot be both content-addressed and impure"),
- .errPos = posDrvName
+ .errPos = state.positions[posDrvName]
});
auto ht = parseHashTypeOpt(outputHashAlgo).value_or(htSHA256);
@@ -1300,7 +1301,7 @@ static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info {
time, any occurrence of this string in an derivation attribute will
be replaced with the concrete path in the Nix store of the output
‘out’. */
-static void prim_placeholder(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_placeholder(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
v.mkString(hashPlaceholder(state.forceStringNoCtx(*args[0], pos)));
}
@@ -1323,7 +1324,7 @@ static RegisterPrimOp primop_placeholder({
/* Convert the argument to a path. !!! obsolete? */
-static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[0], context);
@@ -1348,12 +1349,12 @@ static RegisterPrimOp primop_toPath({
/nix/store/newhash-oldhash-oldname. In the past, `toPath' had
special case behaviour for store paths, but that created weird
corner cases. */
-static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
if (evalSettings.pureEval)
throw EvalError({
.msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
PathSet context;
@@ -1365,7 +1366,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
if (!state.store->isInStore(path))
throw EvalError({
.msg = hintfmt("path '%1%' is not in the Nix store", path),
- .errPos = pos
+ .errPos = state.positions[pos]
});
auto path2 = state.store->toStorePath(path).first;
if (!settings.readOnlyMode)
@@ -1392,7 +1393,7 @@ static RegisterPrimOp primop_storePath({
.fun = prim_storePath,
});
-static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
/* We don’t check the path right now, because we don’t want to
throw if the path isn’t allowed, but just return false (and we
@@ -1424,7 +1425,7 @@ static RegisterPrimOp primop_pathExists({
/* Return the base name of the given string, i.e., everything
following the last slash. */
-static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context);
@@ -1444,7 +1445,7 @@ static RegisterPrimOp primop_baseNameOf({
/* Return the directory of the given path, i.e., everything before the
last slash. Return either a path or a string depending on the type
of the argument. */
-static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto path = state.coerceToString(pos, *args[0], context, false, false);
@@ -1464,7 +1465,7 @@ static RegisterPrimOp primop_dirOf({
});
/* Return the contents of a file as a string. */
-static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
auto s = readFile(path);
@@ -1492,7 +1493,7 @@ static RegisterPrimOp primop_readFile({
/* Find a file in the Nix search path. Used to implement <x> paths,
which are desugared to 'findFile __nixPath "x"'. */
-static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
@@ -1523,7 +1524,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
} catch (InvalidPathError & e) {
throw EvalError({
.msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
@@ -1543,14 +1544,14 @@ static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
});
/* Return the cryptographic hash of a file in base-16. */
-static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto type = state.forceStringNoCtx(*args[0], pos);
std::optional<HashType> ht = parseHashType(type);
if (!ht)
throw Error({
.msg = hintfmt("unknown hash type '%1%'", type),
- .errPos = pos
+ .errPos = state.positions[pos]
});
auto path = realisePath(state, pos, *args[1]);
@@ -1570,7 +1571,7 @@ static RegisterPrimOp primop_hashFile({
});
/* Read a directory (without . or ..) */
-static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
@@ -1619,7 +1620,7 @@ static RegisterPrimOp primop_readDir({
/* Convert the argument (which can be any Nix expression) to an XML
representation returned in a string. Not all Nix expressions can
be sensibly or completely represented (e.g., functions). */
-static void prim_toXML(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::ostringstream out;
PathSet context;
@@ -1727,7 +1728,7 @@ static RegisterPrimOp primop_toXML({
/* Convert the argument (which can be any Nix expression) to a JSON
string. Not all Nix expressions can be sensibly or completely
represented (e.g., functions). */
-static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::ostringstream out;
PathSet context;
@@ -1750,13 +1751,13 @@ static RegisterPrimOp primop_toJSON({
});
/* Parse a JSON string to a value. */
-static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fromJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto s = state.forceStringNoCtx(*args[0], pos);
try {
parseJSON(state, s, v);
} catch (JSONParseError &e) {
- e.addTrace(pos, "while decoding a JSON string");
+ e.addTrace(state.positions[pos], "while decoding a JSON string");
throw;
}
}
@@ -1778,7 +1779,7 @@ static RegisterPrimOp primop_fromJSON({
/* Store a string in the Nix store as a source file that can be used
as an input by derivations. */
-static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
std::string name(state.forceStringNoCtx(*args[0], pos));
@@ -1793,7 +1794,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
"in 'toFile': the file named '%1%' must not contain a reference "
"to a derivation but contains (%2%)",
name, path),
- .errPos = pos
+ .errPos = state.positions[pos]
});
refs.insert(state.store->parseStorePath(path));
}
@@ -1889,7 +1890,7 @@ static RegisterPrimOp primop_toFile({
static void addPath(
EvalState & state,
- const Pos & pos,
+ const PosIdx pos,
const std::string & name,
Path path,
Value * filterFun,
@@ -1956,13 +1957,13 @@ static void addPath(
} else
state.allowAndSetStorePathString(*expectedStorePath, v);
} catch (Error & e) {
- e.addTrace(pos, "while adding path '%s'", path);
+ e.addTrace(state.positions[pos], "while adding path '%s'", path);
throw;
}
}
-static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[1], context);
@@ -1973,7 +1974,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
.msg = hintfmt(
"first argument in call to 'filterSource' is not a function but %1%",
showType(*args[0])),
- .errPos = pos
+ .errPos = state.positions[pos]
});
addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
@@ -2034,7 +2035,7 @@ static RegisterPrimOp primop_filterSource({
.fun = prim_filterSource,
});
-static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
Path path;
@@ -2047,26 +2048,26 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
for (auto & attr : *args[0]->attrs) {
auto & n(attr.name);
if (n == "path")
- path = state.coerceToPath(*attr.pos, *attr.value, context);
+ path = state.coerceToPath(attr.pos, *attr.value, context);
else if (attr.name == state.sName)
- name = state.forceStringNoCtx(*attr.value, *attr.pos);
+ name = state.forceStringNoCtx(*attr.value, attr.pos);
else if (n == "filter") {
state.forceValue(*attr.value, pos);
filterFun = attr.value;
} else if (n == "recursive")
- method = FileIngestionMethod { state.forceBool(*attr.value, *attr.pos) };
+ method = FileIngestionMethod { state.forceBool(*attr.value, attr.pos) };
else if (n == "sha256")
- expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
+ expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos), htSHA256);
else
throw EvalError({
.msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name),
- .errPos = *attr.pos
+ .errPos = state.positions[attr.pos]
});
}
if (path.empty())
throw EvalError({
.msg = hintfmt("'path' required"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (name.empty())
name = baseNameOf(path);
@@ -2117,7 +2118,7 @@ static RegisterPrimOp primop_path({
/* Return the names of the attributes in a set as a sorted list of
strings. */
-static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
@@ -2144,7 +2145,7 @@ static RegisterPrimOp primop_attrNames({
/* Return the values of the attributes in a set as a list, in the same
order as attrNames. */
-static void prim_attrValues(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
@@ -2175,7 +2176,7 @@ static RegisterPrimOp primop_attrValues({
});
/* Dynamic version of the `.' operator. */
-void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
@@ -2187,7 +2188,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
pos
);
// !!! add to stack trace?
- if (state.countCalls && *i->pos != noPos) state.attrSelects[*i->pos]++;
+ if (state.countCalls && i->pos) state.attrSelects[i->pos]++;
state.forceValue(*i->value, pos);
v = *i->value;
}
@@ -2205,7 +2206,7 @@ static RegisterPrimOp primop_getAttr({
});
/* Return position information of the specified attribute. */
-static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
@@ -2223,7 +2224,7 @@ static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
});
/* Dynamic version of the `?' operator. */
-static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_hasAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
@@ -2242,7 +2243,7 @@ static RegisterPrimOp primop_hasAttr({
});
/* Determine whether the argument is a set. */
-static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nAttrs);
@@ -2257,7 +2258,7 @@ static RegisterPrimOp primop_isAttrs({
.fun = prim_isAttrs,
});
-static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
state.forceList(*args[1], pos);
@@ -2305,7 +2306,7 @@ static RegisterPrimOp primop_removeAttrs({
"nameN"; value = valueN;}] is transformed to {name1 = value1;
... nameN = valueN;}. In case of duplicate occurrences of the same
name, the first takes precedence. */
-static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
@@ -2324,7 +2325,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
pos
);
- auto name = state.forceStringNoCtx(*j->value, *j->pos);
+ auto name = state.forceStringNoCtx(*j->value, j->pos);
Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) {
@@ -2367,7 +2368,7 @@ static RegisterPrimOp primop_listToAttrs({
.fun = prim_listToAttrs,
});
-static void prim_intersectAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
state.forceAttrs(*args[1], pos);
@@ -2393,7 +2394,7 @@ static RegisterPrimOp primop_intersectAttrs({
.fun = prim_intersectAttrs,
});
-static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos));
state.forceList(*args[1], pos);
@@ -2430,7 +2431,7 @@ static RegisterPrimOp primop_catAttrs({
.fun = prim_catAttrs,
});
-static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) {
@@ -2440,7 +2441,7 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
if (!args[0]->isLambda())
throw TypeError({
.msg = hintfmt("'functionArgs' requires a function"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (!args[0]->lambda.fun->hasFormals()) {
@@ -2451,7 +2452,7 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
auto attrs = state.buildBindings(args[0]->lambda.fun->formals->formals.size());
for (auto & i : args[0]->lambda.fun->formals->formals)
// !!! should optimise booleans (allocate only once)
- attrs.alloc(i.name, ptr(&i.pos)).mkBool(i.def);
+ attrs.alloc(i.name, i.pos).mkBool(i.def);
v.mkAttrs(attrs);
}
@@ -2473,7 +2474,7 @@ static RegisterPrimOp primop_functionArgs({
});
/* */
-static void prim_mapAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[1], pos);
@@ -2505,7 +2506,7 @@ static RegisterPrimOp primop_mapAttrs({
.fun = prim_mapAttrs,
});
-static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
// we will first count how many values are present for each given key.
// we then allocate a single attrset and pre-populate it with lists of
@@ -2528,7 +2529,7 @@ static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args
for (auto & attr : *vElem->attrs)
attrsSeen[attr.name].first++;
} catch (TypeError & e) {
- e.addTrace(pos, hintfmt("while invoking '%s'", "zipAttrsWith"));
+ e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", "zipAttrsWith"));
throw;
}
}
@@ -2597,7 +2598,7 @@ static RegisterPrimOp primop_zipAttrsWith({
/* Determine whether the argument is a list. */
-static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_isList(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nList);
@@ -2612,20 +2613,20 @@ static RegisterPrimOp primop_isList({
.fun = prim_isList,
});
-static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v)
+static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Value & v)
{
state.forceList(list, pos);
if (n < 0 || (unsigned int) n >= list.listSize())
throw Error({
.msg = hintfmt("list index %1% is out of bounds", n),
- .errPos = pos
+ .errPos = state.positions[pos]
});
state.forceValue(*list.listElems()[n], pos);
v = *list.listElems()[n];
}
/* Return the n-1'th element of a list. */
-static void prim_elemAt(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_elemAt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
elemAt(state, pos, *args[0], state.forceInt(*args[1], pos), v);
}
@@ -2641,7 +2642,7 @@ static RegisterPrimOp primop_elemAt({
});
/* Return the first element of a list. */
-static void prim_head(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_head(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
elemAt(state, pos, *args[0], 0, v);
}
@@ -2660,13 +2661,13 @@ static RegisterPrimOp primop_head({
/* Return a list consisting of everything but the first element of
a list. Warning: this function takes O(n) time, so you probably
don't want to use it! */
-static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
if (args[0]->listSize() == 0)
throw Error({
.msg = hintfmt("'tail' called on an empty list"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
state.mkList(v, args[0]->listSize() - 1);
@@ -2691,7 +2692,7 @@ static RegisterPrimOp primop_tail({
});
/* Apply a function to every element of a list. */
-static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_map(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[1], pos);
@@ -2721,7 +2722,7 @@ static RegisterPrimOp primop_map({
/* Filter a list using a predicate; that is, return a list containing
every element from the list for which the predicate function
returns true. */
-static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_filter(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -2759,7 +2760,7 @@ static RegisterPrimOp primop_filter({
});
/* Return true if a list contains a given element. */
-static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_elem(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
bool res = false;
state.forceList(*args[1], pos);
@@ -2782,7 +2783,7 @@ static RegisterPrimOp primop_elem({
});
/* Concatenate a list of lists. */
-static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_concatLists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos);
@@ -2798,7 +2799,7 @@ static RegisterPrimOp primop_concatLists({
});
/* Return the length of a list. This is an O(1) time operation. */
-static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_length(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
v.mkInt(args[0]->listSize());
@@ -2815,7 +2816,7 @@ static RegisterPrimOp primop_length({
/* Reduce a list by applying a binary operator, from left to
right. The operator is applied strictly. */
-static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_foldlStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[2], pos);
@@ -2848,7 +2849,7 @@ static RegisterPrimOp primop_foldlStrict({
.fun = prim_foldlStrict,
});
-static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void anyOrAll(bool any, EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -2867,7 +2868,7 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg
}
-static void prim_any(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_any(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
anyOrAll(true, state, pos, args, v);
}
@@ -2882,7 +2883,7 @@ static RegisterPrimOp primop_any({
.fun = prim_any,
});
-static void prim_all(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_all(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
anyOrAll(false, state, pos, args, v);
}
@@ -2897,14 +2898,14 @@ static RegisterPrimOp primop_all({
.fun = prim_all,
});
-static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto len = state.forceInt(*args[1], pos);
if (len < 0)
throw EvalError({
.msg = hintfmt("cannot create list of size %1%", len),
- .errPos = pos
+ .errPos = state.positions[pos]
});
state.mkList(v, len);
@@ -2932,10 +2933,10 @@ static RegisterPrimOp primop_genList({
.fun = prim_genList,
});
-static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Value & v);
+static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v);
-static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -2986,7 +2987,7 @@ static RegisterPrimOp primop_sort({
.fun = prim_sort,
});
-static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_partition(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -3046,7 +3047,7 @@ static RegisterPrimOp primop_partition({
.fun = prim_partition,
});
-static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_groupBy(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -3098,7 +3099,7 @@ static RegisterPrimOp primop_groupBy({
.fun = prim_groupBy,
});
-static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
@@ -3113,7 +3114,7 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
try {
state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos)));
} catch (TypeError &e) {
- e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap"));
+ e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", "concatMap"));
throw;
}
len += lists[n].listSize();
@@ -3145,7 +3146,7 @@ static RegisterPrimOp primop_concatMap({
*************************************************************/
-static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -3164,7 +3165,7 @@ static RegisterPrimOp primop_add({
.fun = prim_add,
});
-static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -3183,7 +3184,7 @@ static RegisterPrimOp primop_sub({
.fun = prim_sub,
});
-static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -3202,7 +3203,7 @@ static RegisterPrimOp primop_mul({
.fun = prim_mul,
});
-static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -3211,7 +3212,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
if (f2 == 0)
throw EvalError({
.msg = hintfmt("division by zero"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (args[0]->type() == nFloat || args[1]->type() == nFloat) {
@@ -3223,7 +3224,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
if (i1 == std::numeric_limits<NixInt>::min() && i2 == -1)
throw EvalError({
.msg = hintfmt("overflow in integer division"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
v.mkInt(i1 / i2);
@@ -3239,7 +3240,7 @@ static RegisterPrimOp primop_div({
.fun = prim_div,
});
-static void prim_bitAnd(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
v.mkInt(state.forceInt(*args[0], pos) & state.forceInt(*args[1], pos));
}
@@ -3253,7 +3254,7 @@ static RegisterPrimOp primop_bitAnd({
.fun = prim_bitAnd,
});
-static void prim_bitOr(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_bitOr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
v.mkInt(state.forceInt(*args[0], pos) | state.forceInt(*args[1], pos));
}
@@ -3267,7 +3268,7 @@ static RegisterPrimOp primop_bitOr({
.fun = prim_bitOr,
});
-static void prim_bitXor(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_bitXor(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
v.mkInt(state.forceInt(*args[0], pos) ^ state.forceInt(*args[1], pos));
}
@@ -3281,7 +3282,7 @@ static RegisterPrimOp primop_bitXor({
.fun = prim_bitXor,
});
-static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@@ -3309,7 +3310,7 @@ static RegisterPrimOp primop_lessThan({
/* Convert the argument to a string. Paths are *not* copied to the
store, so `toString /foo/bar' yields `"/foo/bar"', not
`"/nix/store/whatever..."'. */
-static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_toString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context, true, false);
@@ -3344,7 +3345,7 @@ static RegisterPrimOp primop_toString({
at character position `min(start, stringLength str)' inclusive and
ending at `min(start + len, stringLength str)'. `start' must be
non-negative. */
-static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
int start = state.forceInt(*args[0], pos);
int len = state.forceInt(*args[1], pos);
@@ -3354,7 +3355,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
if (start < 0)
throw EvalError({
.msg = hintfmt("negative start position in 'substring'"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context);
@@ -3380,7 +3381,7 @@ static RegisterPrimOp primop_substring({
.fun = prim_substring,
});
-static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
@@ -3398,14 +3399,14 @@ static RegisterPrimOp primop_stringLength({
});
/* Return the cryptographic hash of a string in base-16. */
-static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto type = state.forceStringNoCtx(*args[0], pos);
std::optional<HashType> ht = parseHashType(type);
if (!ht)
throw Error({
.msg = hintfmt("unknown hash type '%1%'", type),
- .errPos = pos
+ .errPos = state.positions[pos]
});
PathSet context; // discarded
@@ -3446,7 +3447,7 @@ std::shared_ptr<RegexCache> makeRegexCache()
return std::make_shared<RegexCache>();
}
-void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto re = state.forceStringNoCtx(*args[0], pos);
@@ -3478,12 +3479,12 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
throw EvalError({
.msg = hintfmt("memory limit exceeded by regular expression '%s'", re),
- .errPos = pos
+ .errPos = state.positions[pos]
});
} else {
throw EvalError({
.msg = hintfmt("invalid regular expression '%s'", re),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
}
@@ -3527,7 +3528,7 @@ static RegisterPrimOp primop_match({
/* Split a string with a regular expression, and return a list of the
non-matching parts interleaved by the lists of the matching groups. */
-void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto re = state.forceStringNoCtx(*args[0], pos);
@@ -3583,12 +3584,12 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
throw EvalError({
.msg = hintfmt("memory limit exceeded by regular expression '%s'", re),
- .errPos = pos
+ .errPos = state.positions[pos]
});
} else {
throw EvalError({
.msg = hintfmt("invalid regular expression '%s'", re),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
}
@@ -3631,7 +3632,7 @@ static RegisterPrimOp primop_split({
.fun = prim_split,
});
-static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
@@ -3661,14 +3662,14 @@ static RegisterPrimOp primop_concatStringsSep({
.fun = prim_concatStringsSep,
});
-static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
state.forceList(*args[1], pos);
if (args[0]->listSize() != args[1]->listSize())
throw EvalError({
.msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
std::vector<std::string> from;
@@ -3741,7 +3742,7 @@ static RegisterPrimOp primop_replaceStrings({
*************************************************************/
-static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto name = state.forceStringNoCtx(*args[0], pos);
DrvName parsed(name);
@@ -3765,7 +3766,7 @@ static RegisterPrimOp primop_parseDrvName({
.fun = prim_parseDrvName,
});
-static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_compareVersions(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto version1 = state.forceStringNoCtx(*args[0], pos);
auto version2 = state.forceStringNoCtx(*args[1], pos);
@@ -3785,7 +3786,7 @@ static RegisterPrimOp primop_compareVersions({
.fun = prim_compareVersions,
});
-static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_splitVersion(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto version = state.forceStringNoCtx(*args[0], pos);
auto iter = version.cbegin();
diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh
index 905bd0366..1cfb4356b 100644
--- a/src/libexpr/primops.hh
+++ b/src/libexpr/primops.hh
@@ -38,9 +38,9 @@ struct RegisterPrimOp
them. */
/* Load a ValueInitializer from a DSO and return whatever it initializes */
-void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v);
+void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Value & v);
/* Execute a program and parse its output */
-void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v);
+void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v);
}
diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc
index cc74c7f58..5521586ee 100644
--- a/src/libexpr/primops/context.cc
+++ b/src/libexpr/primops/context.cc
@@ -5,7 +5,7 @@
namespace nix {
-static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
@@ -15,7 +15,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos,
static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
-static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
state.forceString(*args[0], context, pos);
@@ -31,7 +31,7 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
source-only deployment). This primop marks the string context so
that builtins.derivation adds the path to drv.inputSrcs rather than
drv.inputDrvs. */
-static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
@@ -65,7 +65,7 @@ static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutpu
Note that for a given path any combination of the above attributes
may be present.
*/
-static void prim_getContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
struct ContextInfo {
bool path = false;
@@ -134,7 +134,7 @@ static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
See the commentary above unsafeGetContext for details of the
context representation.
*/
-static void prim_appendContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
auto orig = state.forceString(*args[0], context, pos);
@@ -147,24 +147,24 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
if (!state.store->isStorePath(i.name))
throw EvalError({
.msg = hintfmt("Context key '%s' is not a store path", i.name),
- .errPos = *i.pos
+ .errPos = state.positions[i.pos]
});
if (!settings.readOnlyMode)
state.store->ensurePath(state.store->parseStorePath(i.name));
- state.forceAttrs(*i.value, *i.pos);
+ state.forceAttrs(*i.value, i.pos);
auto iter = i.value->attrs->find(sPath);
if (iter != i.value->attrs->end()) {
- if (state.forceBool(*iter->value, *iter->pos))
+ if (state.forceBool(*iter->value, iter->pos))
context.insert(i.name);
}
iter = i.value->attrs->find(sAllOutputs);
if (iter != i.value->attrs->end()) {
- if (state.forceBool(*iter->value, *iter->pos)) {
+ if (state.forceBool(*iter->value, iter->pos)) {
if (!isDerivation(i.name)) {
throw EvalError({
.msg = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", i.name),
- .errPos = *i.pos
+ .errPos = state.positions[i.pos]
});
}
context.insert("=" + std::string(i.name));
@@ -173,15 +173,15 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
iter = i.value->attrs->find(state.sOutputs);
if (iter != i.value->attrs->end()) {
- state.forceList(*iter->value, *iter->pos);
+ state.forceList(*iter->value, iter->pos);
if (iter->value->listSize() && !isDerivation(i.name)) {
throw EvalError({
.msg = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", i.name),
- .errPos = *i.pos
+ .errPos = state.positions[i.pos]
});
}
for (auto elem : iter->value->listItems()) {
- auto name = state.forceStringNoCtx(*elem, *iter->pos);
+ auto name = state.forceStringNoCtx(*elem, iter->pos);
context.insert(concatStrings("!", name, "!", i.name));
}
}
diff --git a/src/libexpr/primops/fetchClosure.cc b/src/libexpr/primops/fetchClosure.cc
index 821eba698..90e9e6230 100644
--- a/src/libexpr/primops/fetchClosure.cc
+++ b/src/libexpr/primops/fetchClosure.cc
@@ -5,7 +5,7 @@
namespace nix {
-static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
@@ -17,38 +17,38 @@ static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args
for (auto & attr : *args[0]->attrs) {
if (attr.name == "fromPath") {
PathSet context;
- fromPath = state.coerceToStorePath(*attr.pos, *attr.value, context);
+ fromPath = state.coerceToStorePath(attr.pos, *attr.value, context);
}
else if (attr.name == "toPath") {
- state.forceValue(*attr.value, *attr.pos);
+ state.forceValue(*attr.value, attr.pos);
toCA = true;
if (attr.value->type() != nString || attr.value->string.s != std::string("")) {
PathSet context;
- toPath = state.coerceToStorePath(*attr.pos, *attr.value, context);
+ toPath = state.coerceToStorePath(attr.pos, *attr.value, context);
}
}
else if (attr.name == "fromStore")
- fromStoreUrl = state.forceStringNoCtx(*attr.value, *attr.pos);
+ fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos);
else
throw Error({
.msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attr.name),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
if (!fromPath)
throw Error({
.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromPath"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (!fromStoreUrl)
throw Error({
.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
auto parsedURL = parseURL(*fromStoreUrl);
@@ -58,13 +58,13 @@ static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args
!(getEnv("_NIX_IN_TEST").has_value() && parsedURL.scheme == "file"))
throw Error({
.msg = hintfmt("'fetchClosure' only supports http:// and https:// stores"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (!parsedURL.query.empty())
throw Error({
.msg = hintfmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl),
- .errPos = pos
+ .errPos = state.positions[pos]
});
auto fromStore = openStore(parsedURL.to_string());
@@ -80,7 +80,7 @@ static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args
state.store->printStorePath(*fromPath),
state.store->printStorePath(i->second),
state.store->printStorePath(*toPath)),
- .errPos = pos
+ .errPos = state.positions[pos]
});
if (!toPath)
throw Error({
@@ -89,7 +89,7 @@ static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args
"please set this in the 'toPath' attribute passed to 'fetchClosure'",
state.store->printStorePath(*fromPath),
state.store->printStorePath(i->second)),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
} else {
@@ -105,7 +105,7 @@ static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args
throw Error({
.msg = hintfmt("in pure mode, 'fetchClosure' requires a content-addressed path, which '%s' isn't",
state.store->printStorePath(*toPath)),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc
index b7f715859..252492446 100644
--- a/src/libexpr/primops/fetchMercurial.cc
+++ b/src/libexpr/primops/fetchMercurial.cc
@@ -7,7 +7,7 @@
namespace nix {
-static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::string url;
std::optional<Hash> rev;
@@ -24,29 +24,29 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
for (auto & attr : *args[0]->attrs) {
std::string_view n(attr.name);
if (n == "url")
- url = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
+ url = state.coerceToString(attr.pos, *attr.value, context, false, false).toOwned();
else if (n == "rev") {
// Ugly: unlike fetchGit, here the "rev" attribute can
// be both a revision or a branch/tag name.
- auto value = state.forceStringNoCtx(*attr.value, *attr.pos);
+ auto value = state.forceStringNoCtx(*attr.value, attr.pos);
if (std::regex_match(value.begin(), value.end(), revRegex))
rev = Hash::parseAny(value, htSHA1);
else
ref = value;
}
else if (n == "name")
- name = state.forceStringNoCtx(*attr.value, *attr.pos);
+ name = state.forceStringNoCtx(*attr.value, attr.pos);
else
throw EvalError({
.msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", attr.name),
- .errPos = *attr.pos
+ .errPos = state.positions[attr.pos]
});
}
if (url.empty())
throw EvalError({
.msg = hintfmt("'url' argument required"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
} else
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index 42c98e312..cdcae97b6 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -90,7 +90,7 @@ struct FetchTreeParams {
static void fetchTree(
EvalState & state,
- const Pos & pos,
+ const PosIdx pos,
Value * * args,
Value & v,
std::optional<std::string> type,
@@ -110,22 +110,22 @@ static void fetchTree(
if (type)
throw Error({
.msg = hintfmt("unexpected attribute 'type'"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
- type = state.forceStringNoCtx(*aType->value, *aType->pos);
+ type = state.forceStringNoCtx(*aType->value, aType->pos);
} else if (!type)
throw Error({
.msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
attrs.emplace("type", type.value());
for (auto & attr : *args[0]->attrs) {
if (attr.name == state.sType) continue;
- state.forceValue(*attr.value, *attr.pos);
+ state.forceValue(*attr.value, attr.pos);
if (attr.value->type() == nPath || attr.value->type() == nString) {
- auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
+ auto s = state.coerceToString(attr.pos, *attr.value, context, false, false).toOwned();
attrs.emplace(attr.name,
attr.name == "url"
? type == "git"
@@ -146,7 +146,7 @@ static void fetchTree(
if (auto nameIter = attrs.find("name"); nameIter != attrs.end())
throw Error({
.msg = hintfmt("attribute 'name' isn't supported in call to 'fetchTree'"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
input = fetchers::Input::fromAttrs(std::move(attrs));
@@ -167,7 +167,7 @@ static void fetchTree(
input = lookupInRegistries(state.store, input).first;
if (evalSettings.pureEval && !input.isLocked())
- throw Error("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", pos);
+ throw Error("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos]);
auto [tree, input2] = input.fetch(state.store);
@@ -176,7 +176,7 @@ static void fetchTree(
emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback, false);
}
-static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
settings.requireExperimentalFeature(Xp::Flakes);
fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams { .allowNameArgument = false });
@@ -185,7 +185,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
// FIXME: document
static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree);
-static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
+static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v,
const std::string & who, bool unpack, std::string name)
{
std::optional<std::string> url;
@@ -200,22 +200,22 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
for (auto & attr : *args[0]->attrs) {
std::string n(attr.name);
if (n == "url")
- url = state.forceStringNoCtx(*attr.value, *attr.pos);
+ url = state.forceStringNoCtx(*attr.value, attr.pos);
else if (n == "sha256")
- expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
+ expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos), htSHA256);
else if (n == "name")
- name = state.forceStringNoCtx(*attr.value, *attr.pos);
+ name = state.forceStringNoCtx(*attr.value, attr.pos);
else
throw EvalError({
.msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who),
- .errPos = *attr.pos
+ .errPos = state.positions[attr.pos]
});
}
if (!url)
throw EvalError({
.msg = hintfmt("'url' argument required"),
- .errPos = pos
+ .errPos = state.positions[pos]
});
} else
url = state.forceStringNoCtx(*args[0], pos);
@@ -262,7 +262,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
state.allowAndSetStorePathString(storePath, v);
}
-static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchurl(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
fetch(state, pos, args, v, "fetchurl", false, "");
}
@@ -278,7 +278,7 @@ static RegisterPrimOp primop_fetchurl({
.fun = prim_fetchurl,
});
-static void prim_fetchTarball(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchTarball(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
fetch(state, pos, args, v, "fetchTarball", true, "source");
}
@@ -329,7 +329,7 @@ static RegisterPrimOp primop_fetchTarball({
.fun = prim_fetchTarball,
});
-static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void prim_fetchGit(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
fetchTree(state, pos, args, v, "git", FetchTreeParams { .emptyRevFallback = true, .allowNameArgument = true });
}
diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc
index dd4280030..9753e2ac9 100644
--- a/src/libexpr/primops/fromTOML.cc
+++ b/src/libexpr/primops/fromTOML.cc
@@ -5,7 +5,7 @@
namespace nix {
-static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & val)
+static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, Value & val)
{
auto toml = state.forceStringNoCtx(*args[0], pos);
@@ -73,7 +73,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
} catch (std::exception & e) { // TODO: toml::syntax_error
throw EvalError({
.msg = hintfmt("while parsing a TOML string: %s", e.what()),
- .errPos = pos
+ .errPos = state.positions[pos]
});
}
}
diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc
index 7b35abca2..307934292 100644
--- a/src/libexpr/value-to-json.cc
+++ b/src/libexpr/value-to-json.cc
@@ -10,7 +10,7 @@
namespace nix {
void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const Pos & pos, JSONPlaceholder & out, PathSet & context)
+ Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context)
{
checkInterrupt();
@@ -54,10 +54,10 @@ void printValueAsJSON(EvalState & state, bool strict,
for (auto & j : names) {
Attr & a(*v.attrs->find(state.symbols.create(j)));
auto placeholder(obj.placeholder(j));
- printValueAsJSON(state, strict, *a.value, *a.pos, placeholder, context);
+ printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context);
}
} else
- printValueAsJSON(state, strict, *i->value, *i->pos, out, context);
+ printValueAsJSON(state, strict, *i->value, i->pos, out, context);
break;
}
@@ -82,15 +82,15 @@ void printValueAsJSON(EvalState & state, bool strict,
case nFunction:
auto e = TypeError({
.msg = hintfmt("cannot convert %1% to JSON", showType(v)),
- .errPos = v.determinePos(pos)
+ .errPos = state.positions[v.determinePos(pos)]
});
- e.addTrace(pos, hintfmt("message for the trace"));
+ e.addTrace(state.positions[pos], hintfmt("message for the trace"));
throw e;
}
}
void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const Pos & pos, std::ostream & str, PathSet & context)
+ Value & v, const PosIdx pos, std::ostream & str, PathSet & context)
{
JSONPlaceholder out(str);
printValueAsJSON(state, strict, v, pos, out, context);
diff --git a/src/libexpr/value-to-json.hh b/src/libexpr/value-to-json.hh
index c2f797b29..c020a817a 100644
--- a/src/libexpr/value-to-json.hh
+++ b/src/libexpr/value-to-json.hh
@@ -11,9 +11,9 @@ namespace nix {
class JSONPlaceholder;
void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const Pos & pos, JSONPlaceholder & out, PathSet & context);
+ Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context);
void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const Pos & pos, std::ostream & str, PathSet & context);
+ Value & v, const PosIdx pos, std::ostream & str, PathSet & context);
}
diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc
index 7f8edcba6..d1e0c4778 100644
--- a/src/libexpr/value-to-xml.cc
+++ b/src/libexpr/value-to-xml.cc
@@ -19,7 +19,7 @@ static XMLAttrs singletonAttrs(const std::string & name, const std::string & val
static void printValueAsXML(EvalState & state, bool strict, bool location,
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
- const Pos & pos);
+ const PosIdx pos);
static void posToXML(XMLAttrs & xmlAttrs, const Pos & pos)
@@ -43,18 +43,18 @@ static void showAttrs(EvalState & state, bool strict, bool location,
XMLAttrs xmlAttrs;
xmlAttrs["name"] = i;
- if (location && a.pos != ptr(&noPos)) posToXML(xmlAttrs, *a.pos);
+ if (location && a.pos) posToXML(xmlAttrs, state.positions[a.pos]);
XMLOpenElement _(doc, "attr", xmlAttrs);
printValueAsXML(state, strict, location,
- *a.value, doc, context, drvsSeen, *a.pos);
+ *a.value, doc, context, drvsSeen, a.pos);
}
}
static void printValueAsXML(EvalState & state, bool strict, bool location,
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
- const Pos & pos)
+ const PosIdx pos)
{
checkInterrupt();
@@ -93,14 +93,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
Path drvPath;
a = v.attrs->find(state.sDrvPath);
if (a != v.attrs->end()) {
- if (strict) state.forceValue(*a->value, *a->pos);
+ if (strict) state.forceValue(*a->value, a->pos);
if (a->value->type() == nString)
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
}
a = v.attrs->find(state.sOutPath);
if (a != v.attrs->end()) {
- if (strict) state.forceValue(*a->value, *a->pos);
+ if (strict) state.forceValue(*a->value, a->pos);
if (a->value->type() == nString)
xmlAttrs["outPath"] = a->value->string.s;
}
@@ -134,7 +134,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
break;
}
XMLAttrs xmlAttrs;
- if (location) posToXML(xmlAttrs, v.lambda.fun->pos);
+ if (location) posToXML(xmlAttrs, state.positions[v.lambda.fun->pos]);
XMLOpenElement _(doc, "function", xmlAttrs);
if (v.lambda.fun->hasFormals()) {
@@ -166,14 +166,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
- const Pos & pos) const
+ const PosIdx pos) const
{
doc.writeEmptyElement("unevaluated");
}
void printValueAsXML(EvalState & state, bool strict, bool location,
- Value & v, std::ostream & out, PathSet & context, const Pos & pos)
+ Value & v, std::ostream & out, PathSet & context, const PosIdx pos)
{
XMLWriter doc(true, out);
XMLOpenElement root(doc, "expr");
diff --git a/src/libexpr/value-to-xml.hh b/src/libexpr/value-to-xml.hh
index cc778a2cb..506f32b6b 100644
--- a/src/libexpr/value-to-xml.hh
+++ b/src/libexpr/value-to-xml.hh
@@ -9,6 +9,6 @@
namespace nix {
void printValueAsXML(EvalState & state, bool strict, bool location,
- Value & v, std::ostream & out, PathSet & context, const Pos & pos);
+ Value & v, std::ostream & out, PathSet & context, const PosIdx pos);
}
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 3d07c3198..dc875615c 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -56,6 +56,7 @@ struct Expr;
struct ExprLambda;
struct PrimOp;
class Symbol;
+class PosIdx;
struct Pos;
class StorePath;
class Store;
@@ -103,7 +104,7 @@ class ExternalValueBase
/* Print the value as XML. Defaults to unevaluated */
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
- const Pos & pos) const;
+ const PosIdx pos) const;
virtual ~ExternalValueBase()
{
@@ -368,7 +369,7 @@ public:
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
}
- Pos determinePos(const Pos & pos) const;
+ PosIdx determinePos(const PosIdx pos) const;
/* Check whether forcing this value requires a trivial amount of
computation. In particular, function applications are
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index 00ba567c6..22bc2b8dd 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -5,6 +5,7 @@
#include <list>
#include <set>
#include <string>
+#include <limits>
#include <map>
#include <variant>
#include <vector>
@@ -102,4 +103,55 @@ public:
Ptr operator->() const { return Ptr(**this); }
};
+/* Provides an indexable container like vector<> with memory overhead
+ guarantees like list<> by allocating storage in chunks of ChunkSize
+ elements instead of using a contiguous memory allocation like vector<>
+ does. Not using a single vector that is resized reduces memory overhead
+ on large data sets by on average (growth factor)/2, mostly
+ eliminates copies within the vector during resizing, and provides stable
+ references to its elements. */
+template<typename T, size_t ChunkSize>
+class ChunkedVector {
+private:
+ uint32_t size_ = 0;
+ std::vector<std::vector<T>> chunks;
+
+ /* keep this out of the ::add hot path */
+ [[gnu::noinline]]
+ auto & addChunk()
+ {
+ if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize)
+ abort();
+ chunks.emplace_back();
+ chunks.back().reserve(ChunkSize);
+ return chunks.back();
+ }
+
+public:
+ ChunkedVector(uint32_t reserve)
+ {
+ chunks.reserve(reserve);
+ addChunk();
+ }
+
+ uint32_t size() const { return size_; }
+
+ std::pair<T &, uint32_t> add(T value)
+ {
+ const auto idx = size_++;
+ auto & chunk = [&] () -> auto & {
+ if (auto & back = chunks.back(); back.size() < ChunkSize)
+ return back;
+ return addChunk();
+ }();
+ auto & result = chunk.emplace_back(std::move(value));
+ return {result, idx};
+ }
+
+ const T & operator[](uint32_t idx) const
+ {
+ return chunks[idx / ChunkSize][idx % ChunkSize];
+ }
+};
+
}
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index 78692b9c6..156181634 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -134,9 +134,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
- auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context);
+ auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context);
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
- 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");
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index ee91e8ed0..2421adf4e 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -97,13 +97,13 @@ struct CmdBundle : InstallableCommand
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
PathSet context2;
- auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2);
+ auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2);
auto attr2 = vRes->attrs->get(evalState->sOutPath);
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);
store->buildPaths({ DerivedPath::Built { drvPath } });
@@ -113,7 +113,7 @@ struct CmdBundle : InstallableCommand
auto * attr = vRes->attrs->get(evalState->sName);
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?
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index ffe79af89..76a134b1f 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -28,9 +28,9 @@ struct CmdEdit : InstallableCommand
{
auto state = getEvalState();
- auto [v, pos] = installable->toValue(*state);
-
const auto [file, line] = [&] {
+ auto [v, pos] = installable->toValue(*state);
+
try {
return findPackageFilename(*state, *v, installable->what());
} catch (NoPositionInfo &) {
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index 733b93661..81474c2d3 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -77,9 +77,9 @@ struct CmdEval : MixJSON, InstallableCommand
if (pathExists(*writeTo))
throw Error("path '%s' already exists", *writeTo);
- std::function<void(Value & v, const Pos & pos, const Path & path)> recurse;
+ std::function<void(Value & v, const PosIdx pos, const Path & path)> recurse;
- recurse = [&](Value & v, const Pos & pos, const Path & path)
+ recurse = [&](Value & v, const PosIdx pos, const Path & path)
{
state->forceValue(v, pos);
if (v.type() == nString)
@@ -92,14 +92,16 @@ struct CmdEval : MixJSON, InstallableCommand
try {
if (attr.name == "." || attr.name == "..")
throw Error("invalid file name '%s'", attr.name);
- recurse(*attr.value, *attr.pos, path + "/" + std::string(attr.name));
+ recurse(*attr.value, attr.pos, path + "/" + std::string(attr.name));
} catch (Error & e) {
- e.addTrace(*attr.pos, hintfmt("while evaluating the attribute '%s'", attr.name));
+ e.addTrace(
+ state->positions[attr.pos],
+ hintfmt("while evaluating the attribute '%s'", attr.name));
throw;
}
}
else
- throw TypeError("value at '%s' is not a string or an attribute set", pos);
+ throw TypeError("value at '%s' is not a string or an attribute set", state->positions[pos]);
};
recurse(*v, pos, *writeTo);
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 04b23ed0f..23e5cd24e 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -123,7 +123,7 @@ struct CmdFlakeLock : FlakeCommand
};
static void enumerateOutputs(EvalState & state, Value & vFlake,
- std::function<void(const std::string & name, Value & vProvide, const Pos & pos)> callback)
+ std::function<void(const std::string & name, Value & vProvide, const PosIdx pos)> callback)
{
auto pos = vFlake.determinePos(noPos);
state.forceAttrs(vFlake, pos);
@@ -139,11 +139,11 @@ static void enumerateOutputs(EvalState & state, Value & vFlake,
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(attr->name, *attr->value, *attr->pos);
+ callback(attr->name, *attr->value, attr->pos);
for (auto & attr : *aOutputs->value->attrs) {
if (attr.name != sHydraJobs)
- callback(attr.name, *attr.value, *attr.pos);
+ callback(attr.name, *attr.value, attr.pos);
}
}
@@ -315,13 +315,17 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: rewrite to use EvalCache.
- auto checkSystemName = [&](const std::string & system, const Pos & pos) {
+ auto resolve = [&] (PosIdx p) {
+ return state->positions[p];
+ };
+
+ auto checkSystemName = [&](const std::string & system, const PosIdx pos) {
// FIXME: what's the format of "system"?
if (system.find('-') == std::string::npos)
- reportError(Error("'%s' is not a valid system type, at %s", system, pos));
+ reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos)));
};
- auto checkDerivation = [&](const std::string & attrPath, Value & v, const Pos & pos) -> std::optional<StorePath> {
+ auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional<StorePath> {
try {
auto drvInfo = getDerivation(*state, v, false);
if (!drvInfo)
@@ -329,7 +333,7 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: check meta attributes
return drvInfo->queryDrvPath();
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the derivation '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the derivation '%s'", attrPath));
reportError(e);
}
return std::nullopt;
@@ -337,7 +341,7 @@ struct CmdFlakeCheck : FlakeCommand
std::vector<DerivedPath> drvPaths;
- auto checkApp = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkApp = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
#if 0
// FIXME
@@ -348,12 +352,12 @@ struct CmdFlakeCheck : FlakeCommand
}
#endif
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the app definition '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the app definition '%s'", attrPath));
reportError(e);
}
};
- auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkOverlay = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (!v.isLambda()
@@ -368,12 +372,12 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: if we have a 'nixpkgs' input, use it to
// evaluate the overlay.
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the overlay '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the overlay '%s'", attrPath));
reportError(e);
}
};
- auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkModule = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (v.isLambda()) {
@@ -382,9 +386,11 @@ struct CmdFlakeCheck : FlakeCommand
} else if (v.type() == nAttrs) {
for (auto & attr : *v.attrs)
try {
- state->forceValue(*attr.value, *attr.pos);
+ state->forceValue(*attr.value, attr.pos);
} catch (Error & e) {
- e.addTrace(*attr.pos, hintfmt("while evaluating the option '%s'", attr.name));
+ e.addTrace(
+ state->positions[attr.pos],
+ hintfmt("while evaluating the option '%s'", attr.name));
throw;
}
} else
@@ -392,14 +398,14 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: if we have a 'nixpkgs' input, use it to
// check the module.
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the NixOS module '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the NixOS module '%s'", attrPath));
reportError(e);
}
};
- std::function<void(const std::string & attrPath, Value & v, const Pos & pos)> checkHydraJobs;
+ std::function<void(const std::string & attrPath, Value & v, const PosIdx pos)> checkHydraJobs;
- checkHydraJobs = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ checkHydraJobs = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceAttrs(v, pos);
@@ -407,23 +413,23 @@ 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 = attrPath + "." + (std::string) attr.name;
if (state->isDerivation(*attr.value)) {
Activity act(*logger, lvlChatty, 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);
}
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the Hydra jobset '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the Hydra jobset '%s'", attrPath));
reportError(e);
}
};
- auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking NixOS configuration '%s'", attrPath));
@@ -433,12 +439,12 @@ struct CmdFlakeCheck : FlakeCommand
if (!state->isDerivation(*vToplevel))
throw Error("attribute 'config.system.build.toplevel' is not a derivation");
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the NixOS configuration '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the NixOS configuration '%s'", attrPath));
reportError(e);
}
};
- auto checkTemplate = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkTemplate = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking template '%s'", attrPath));
@@ -448,7 +454,7 @@ struct CmdFlakeCheck : FlakeCommand
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
if (attr->name == state->symbols.create("path")) {
PathSet context;
- auto path = state->coerceToPath(*attr->pos, *attr->value, context);
+ auto path = state->coerceToPath(attr->pos, *attr->value, context);
if (!store->isInStore(path))
throw Error("template '%s' has a bad 'path' attribute");
// TODO: recursively check the flake in 'path'.
@@ -457,7 +463,7 @@ struct CmdFlakeCheck : FlakeCommand
throw Error("template '%s' lacks attribute 'path'", attrPath);
if (auto attr = v.attrs->get(state->symbols.create("description")))
- state->forceStringNoCtx(*attr->value, *attr->pos);
+ state->forceStringNoCtx(*attr->value, attr->pos);
else
throw Error("template '%s' lacks attribute 'description'", attrPath);
@@ -467,19 +473,19 @@ struct CmdFlakeCheck : FlakeCommand
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
}
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the template '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath));
reportError(e);
}
};
- auto checkBundler = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkBundler = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (!v.isLambda())
throw Error("bundler must be a function");
// TODO: check types of inputs/outputs?
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the template '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath));
reportError(e);
}
};
@@ -492,7 +498,7 @@ struct CmdFlakeCheck : FlakeCommand
enumerateOutputs(*state,
*vFlake,
- [&](const std::string & name, Value & vOutput, const Pos & pos) {
+ [&](const std::string & name, Value & vOutput, const PosIdx pos) {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking flake output '%s'", name));
@@ -516,12 +522,12 @@ struct CmdFlakeCheck : FlakeCommand
if (name == "checks") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs) {
auto drvPath = checkDerivation(
fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ *attr2.value, attr2.pos);
if (drvPath && (std::string) attr.name == settings.thisSystem.get())
drvPaths.push_back(DerivedPath::Built{*drvPath});
}
@@ -531,61 +537,61 @@ struct CmdFlakeCheck : FlakeCommand
else if (name == "formatter") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
checkApp(
fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
}
else if (name == "packages" || name == "devShells") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs)
checkDerivation(
fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ *attr2.value, attr2.pos);
}
}
else if (name == "apps") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs)
checkApp(
fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ *attr2.value, attr2.pos);
}
}
else if (name == "defaultPackage" || name == "devShell") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
checkDerivation(
fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
}
else if (name == "defaultApp") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
checkApp(
fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
}
else if (name == "legacyPackages") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
// FIXME: do getDerivations?
}
}
@@ -597,7 +603,7 @@ struct CmdFlakeCheck : FlakeCommand
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
checkOverlay(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
else if (name == "nixosModule")
@@ -607,14 +613,14 @@ struct CmdFlakeCheck : FlakeCommand
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
checkModule(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
else if (name == "nixosConfigurations") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
checkNixOSConfiguration(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
else if (name == "hydraJobs")
@@ -627,28 +633,28 @@ struct CmdFlakeCheck : FlakeCommand
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
checkTemplate(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
else if (name == "defaultBundler") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
checkBundler(
fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ *attr.value, attr.pos);
}
}
else if (name == "bundlers") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ checkSystemName(attr.name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs) {
checkBundler(
fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ *attr2.value, attr2.pos);
}
}
}
@@ -657,7 +663,7 @@ struct CmdFlakeCheck : FlakeCommand
warn("unknown flake output '%s'", name);
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking flake output '%s'", name));
+ e.addTrace(resolve(pos), hintfmt("while checking flake output '%s'", name));
reportError(e);
}
});
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 391255ce9..fd1b95afa 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -467,7 +467,8 @@ bool NixRepl::processLine(std::string line)
auto filename = state->coerceToString(noPos, v, context);
return {state->symbols.create(*filename), 0};
} else if (v.isLambda()) {
- return {v.lambda.fun->pos.file, v.lambda.fun->pos.line};
+ auto pos = state->positions[v.lambda.fun->pos];
+ return {pos.file, pos.line};
} else {
// assume it's a derivation
return findPackageFilename(*state, v, arg);
@@ -498,7 +499,7 @@ bool NixRepl::processLine(std::string line)
Value v, f, result;
evalString(arg, v);
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
- state->callFunction(f, v, result, Pos());
+ state->callFunction(f, v, result, PosIdx());
StorePath drvPath = getDerivationPath(result);
runNix("nix-shell", {state->store->printStorePath(drvPath)});
@@ -799,7 +800,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
Bindings::iterator i = v.attrs->find(state->sDrvPath);
PathSet context;
if (i != v.attrs->end())
- str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
+ str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context));
else
str << "???";
str << "»";
@@ -861,7 +862,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
case nFunction:
if (v.isLambda()) {
std::ostringstream s;
- s << v.lambda.fun->pos;
+ s << state->positions[v.lambda.fun->pos];
str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL;
} else if (v.isPrimOp()) {
str << ANSI_MAGENTA "«primop»" ANSI_NORMAL;
diff --git a/tests/plugins/plugintest.cc b/tests/plugins/plugintest.cc
index cd7c9f8b1..04b791021 100644
--- a/tests/plugins/plugintest.cc
+++ b/tests/plugins/plugintest.cc
@@ -13,7 +13,7 @@ MySettings mySettings;
static GlobalConfig::Register rs(&mySettings);
-static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
+static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
if (mySettings.settingSet)
v.mkNull();