diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 6197f4be4..c81f76a22 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -235,7 +235,7 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) if (v2.type() == nAttrs) { for (auto & i : *v2.attrs) { - std::string name = i.name; + std::string name = state->symbols[i.name]; if (name.find(searchWord) == 0) { if (prefix_ == "") completions->add(name); @@ -600,7 +600,7 @@ std::tuple InstallableF auto drvInfo = DerivationInfo { std::move(drvPath), - attr->getAttr(state->sOutputName)->getString() + attr->getAttr("outputName")->getString() }; return {attrPath, getLockedFlake()->flake.lockedRef, std::move(drvInfo)}; diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 1c12dfbe2..f63caeb10 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -36,7 +36,7 @@ std::vector parseAttrPath(EvalState & state, std::string_view s) { std::vector res; for (auto & a : parseAttrPath(s)) - res.push_back(state.symbols.create(a)); + res.emplace_back(a); return res; } @@ -77,7 +77,7 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin if (a == v->attrs->end()) { std::set attrNames; for (auto & attr : *v->attrs) - attrNames.insert(attr.name); + attrNames.insert(state.symbols[attr.name]); auto suggestions = Suggestions::bestMatches(attrNames, attr); throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath); diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc index 61996eae4..1d17ef7e4 100644 --- a/src/libexpr/attr-set.cc +++ b/src/libexpr/attr-set.cc @@ -26,7 +26,7 @@ Bindings * EvalState::allocBindings(size_t capacity) /* Create a new attribute named 'name' on an existing attribute set stored in 'vAttrs' and return the newly allocated Value which is associated with this attribute. */ -Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name) +Value * EvalState::allocAttr(Value & vAttrs, const SymbolIdx & name) { Value * v = allocValue(); vAttrs.attrs->push_back(Attr(name, v)); @@ -40,7 +40,7 @@ Value * EvalState::allocAttr(Value & vAttrs, std::string_view name) } -Value & BindingsBuilder::alloc(const Symbol & name, PosIdx pos) +Value & BindingsBuilder::alloc(const SymbolIdx & name, PosIdx pos) { auto value = state.allocValue(); bindings->push_back(Attr(name, value, pos)); diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh index 23d68dda2..c42aba0f6 100644 --- a/src/libexpr/attr-set.hh +++ b/src/libexpr/attr-set.hh @@ -15,10 +15,10 @@ struct Value; /* Map one attribute name to its value. */ struct Attr { - Symbol name; + SymbolIdx name; Value * value; PosIdx pos; - Attr(Symbol name, Value * value, PosIdx pos = noPos) + Attr(SymbolIdx name, Value * value, PosIdx pos = noPos) : name(name), value(value), pos(pos) { }; Attr() { }; bool operator < (const Attr & a) const @@ -57,7 +57,7 @@ public: attrs[size_++] = attr; } - iterator find(const Symbol & name) + iterator find(const SymbolIdx & name) { Attr key(name, 0); iterator i = std::lower_bound(begin(), end(), key); @@ -65,7 +65,7 @@ public: return end(); } - Attr * get(const Symbol & name) + Attr * get(const SymbolIdx & name) { Attr key(name, 0); iterator i = std::lower_bound(begin(), end(), key); @@ -86,14 +86,15 @@ public: size_t capacity() { return capacity_; } /* Returns the attributes in lexicographically sorted order. */ - std::vector lexicographicOrder() const + std::vector lexicographicOrder(const SymbolTable & symbols) const { std::vector res; res.reserve(size_); for (size_t n = 0; n < size_; n++) res.emplace_back(&attrs[n]); - std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) { - return (const std::string &) a->name < (const std::string &) b->name; + std::sort(res.begin(), res.end(), [&](const Attr * a, const Attr * b) { + std::string_view sa = symbols[a->name], sb = symbols[b->name]; + return sa < sb; }); return res; } @@ -118,7 +119,7 @@ public: : bindings(bindings), state(state) { } - void insert(Symbol name, Value * value, PosIdx pos = noPos) + void insert(SymbolIdx name, Value * value, PosIdx pos = noPos) { insert(Attr(name, value, pos)); } @@ -133,7 +134,7 @@ public: bindings->push_back(attr); } - Value & alloc(const Symbol & name, PosIdx pos = noPos); + Value & alloc(const SymbolIdx & name, PosIdx pos = noPos); Value & alloc(std::string_view name, PosIdx pos = noPos); diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 7d3fd01a4..0d2160efd 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -253,7 +253,7 @@ struct AttrDb std::vector attrs; auto queryAttributes(state->queryAttributes.use()(rowId)); while (queryAttributes.next()) - attrs.push_back(symbols.create(queryAttributes.getStr(0))); + attrs.emplace_back(queryAttributes.getStr(0)); return {{rowId, attrs}}; } case AttrType::String: { @@ -325,7 +325,7 @@ AttrCursor::AttrCursor( AttrKey AttrCursor::getKey() { if (!parent) - return {0, root->state.sEpsilon}; + return {0, {""}}; if (!parent->first->cachedValue) { parent->first->cachedValue = root->db->getAttr( parent->first->getKey(), root->state.symbols); @@ -340,7 +340,7 @@ Value & AttrCursor::getValue() if (parent) { auto & vParent = parent->first->getValue(); root->state.forceAttrs(vParent, noPos); - auto attr = vParent.attrs->get(parent->second); + auto attr = vParent.attrs->get(root->state.symbols.create(parent->second)); if (!attr) throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr()); _value = allocRootValue(attr->value); @@ -419,7 +419,7 @@ Suggestions AttrCursor::getSuggestionsForAttr(Symbol name) return Suggestions::bestMatches(strAttrNames, name); } -std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErrors) +std::shared_ptr AttrCursor::maybeGetAttr(std::string_view name, bool forceErrors) { if (root->db) { if (!cachedValue) @@ -461,10 +461,10 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro for (auto & attr : *v.attrs) { if (root->db) - root->db->setPlaceholder({cachedValue->first, attr.name}); + root->db->setPlaceholder({cachedValue->first, root->state.symbols[attr.name]}); } - auto attr = v.attrs->get(name); + auto attr = v.attrs->get(root->state.symbols.create(name)); if (!attr) { if (root->db) { @@ -486,12 +486,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2)); } -std::shared_ptr AttrCursor::maybeGetAttr(std::string_view name) -{ - return maybeGetAttr(root->state.symbols.create(name)); -} - -ref AttrCursor::getAttr(Symbol name, bool forceErrors) +ref AttrCursor::getAttr(std::string_view name, bool forceErrors) { auto p = maybeGetAttr(name, forceErrors); if (!p) @@ -499,11 +494,6 @@ ref AttrCursor::getAttr(Symbol name, bool forceErrors) return ref(p); } -ref AttrCursor::getAttr(std::string_view name) -{ - return getAttr(root->state.symbols.create(name)); -} - OrSuggestions> AttrCursor::findAlongAttrPath(const std::vector & attrPath, bool force) { auto res = shared_from_this(); @@ -616,7 +606,7 @@ std::vector AttrCursor::getAttrs() std::vector attrs; for (auto & attr : *getValue().attrs) - attrs.push_back(attr.name); + attrs.push_back(root->state.symbols[attr.name]); std::sort(attrs.begin(), attrs.end(), [](const Symbol & a, const Symbol & b) { return (const std::string &) a < (const std::string &) b; }); @@ -635,7 +625,7 @@ bool AttrCursor::isDerivation() StorePath AttrCursor::forceDerivation() { - auto aDrvPath = getAttr(root->state.sDrvPath, true); + auto aDrvPath = getAttr("drvPath", true); auto drvPath = root->state.store->parseStorePath(aDrvPath->getString()); if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) { /* The eval cache contains 'drvPath', but the actual path has diff --git a/src/libexpr/eval-cache.hh b/src/libexpr/eval-cache.hh index b0709ebc2..f4481c72a 100644 --- a/src/libexpr/eval-cache.hh +++ b/src/libexpr/eval-cache.hh @@ -96,13 +96,9 @@ public: Suggestions getSuggestionsForAttr(Symbol name); - std::shared_ptr maybeGetAttr(Symbol name, bool forceErrors = false); + std::shared_ptr maybeGetAttr(std::string_view name, bool forceErrors = false); - std::shared_ptr maybeGetAttr(std::string_view name); - - ref getAttr(Symbol name, bool forceErrors = false); - - ref getAttr(std::string_view name); + ref getAttr(std::string_view name, bool forceErrors = false); /* Get an attribute along a chain of attrsets. Note that this does not auto-call functors or functions. */ diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 39f1a625f..8fc144a84 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -96,7 +96,8 @@ RootValue allocRootValue(Value * v) } -void Value::print(std::ostream & str, std::set * seen) const +void Value::print(const SymbolTable & symbols, std::ostream & str, + std::set * seen) const { checkInterrupt(); @@ -129,9 +130,9 @@ void Value::print(std::ostream & str, std::set * seen) const str << "«repeated»"; else { str << "{ "; - for (auto & i : attrs->lexicographicOrder()) { - str << i->name << " = "; - i->value->print(str, seen); + for (auto & i : attrs->lexicographicOrder(symbols)) { + str << symbols[i->name] << " = "; + i->value->print(symbols, str, seen); str << "; "; } str << "}"; @@ -146,7 +147,7 @@ void Value::print(std::ostream & str, std::set * seen) const else { str << "[ "; for (auto v2 : listItems()) { - v2->print(str, seen); + v2->print(symbols, str, seen); str << " "; } str << "]"; @@ -177,17 +178,18 @@ void Value::print(std::ostream & str, std::set * seen) const } -void Value::print(std::ostream & str, bool showRepeated) const +void Value::print(const SymbolTable & symbols, std::ostream & str, bool showRepeated) const { std::set seen; - print(str, showRepeated ? nullptr : &seen); + print(symbols, str, showRepeated ? nullptr : &seen); } -std::ostream & operator << (std::ostream & str, const Value & v) +std::string printValue(const EvalState & state, const Value & v) { - v.print(str, false); - return str; + std::ostringstream out; + v.print(state.symbols, out); + return out.str(); } @@ -306,9 +308,9 @@ static BoehmGCStackAllocator boehmGCStackAllocator; #endif -static Symbol getName(const AttrName & name, EvalState & state, Env & env) +static SymbolIdx getName(const AttrName & name, EvalState & state, Env & env) { - if (name.symbol.set()) { + if (name.symbol) { return name.symbol; } else { Value nameValue; @@ -639,7 +641,7 @@ Value * EvalState::addPrimOp(const std::string & name, size_t arity, PrimOpFun primOp) { auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name; - Symbol sym = symbols.create(name2); + auto sym = symbols.create(name2); /* Hack to make constants lazy: turn them into a application of the primop to a dummy value. */ @@ -673,7 +675,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) return addConstant(primOp.name, v); } - Symbol envName = symbols.create(primOp.name); + auto envName = symbols.create(primOp.name); if (hasPrefix(primOp.name, "__")) primOp.name = primOp.name.substr(2); @@ -767,11 +769,11 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri }); } -void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol & sym, const PosIdx p2) const +void EvalState::throwEvalError(const PosIdx p1, const char * s, const SymbolIdx 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, positions[p2]), + .msg = hintfmt(s, symbols[sym], positions[p2]), .errPos = positions[p1] }); } @@ -785,19 +787,19 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s) const } void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, - const Symbol & s2) const + const SymbolIdx s2) const { throw TypeError({ - .msg = hintfmt(s, fun.showNamePos(positions), s2), + .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), .errPos = positions[pos] }); } void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol & s2) const + const ExprLambda & fun, const SymbolIdx s2) const { throw TypeError(ErrorInfo { - .msg = hintfmt(s, fun.showNamePos(positions), s2), + .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), .errPos = positions[pos], .suggestions = suggestions, }); @@ -901,7 +903,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name]); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1187,7 +1189,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) if (nameVal.type() == nNull) continue; state.forceStringNoCtx(nameVal); - Symbol nameSym = state.symbols.create(nameVal.string.s); + auto 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); @@ -1243,10 +1245,12 @@ static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & a for (auto & i : attrPath) { if (!first) out << '.'; else first = false; try { - out << getName(i, state, env); + out << state.symbols[getName(i, state, env)]; } catch (Error & e) { - assert(!i.symbol.set()); - out << "\"${" << *i.expr << "}\""; + assert(!i.symbol); + out << "\"${"; + i.expr->show(state.symbols, out); + out << "}\""; } } return out.str(); @@ -1266,7 +1270,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) for (auto & i : attrPath) { state.nrLookups++; Bindings::iterator j; - Symbol name = getName(i, state, env); + auto name = getName(i, state, env); if (def) { state.forceValue(*vAttrs, pos); if (vAttrs->type() != nAttrs || @@ -1280,11 +1284,11 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { std::set allAttrNames; for (auto & attr : *vAttrs->attrs) - allAttrNames.insert(attr.name); + allAttrNames.insert(state.symbols[attr.name]); state.throwEvalError( pos, - Suggestions::bestMatches(allAttrNames, name), - "attribute '%1%' missing", name); + Suggestions::bestMatches(allAttrNames, state.symbols[name]), + "attribute '%1%' missing", state.symbols[name]); } } vAttrs = j->value; @@ -1316,7 +1320,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) for (auto & i : attrPath) { state.forceValue(*vAttrs, noPos); Bindings::iterator j; - Symbol name = getName(i, state, env); + auto name = getName(i, state, env); if (vAttrs->type() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { @@ -1366,7 +1370,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & ExprLambda & lambda(*vCur.lambda.fun); auto size = - (!lambda.arg.set() ? 0 : 1) + + (!lambda.arg ? 0 : 1) + (lambda.hasFormals() ? lambda.formals->formals.size() : 0); Env & env2(allocEnv(size)); env2.up = vCur.lambda.env; @@ -1379,7 +1383,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & else { forceAttrs(*args[0], pos); - if (lambda.arg.set()) + if (lambda.arg) env2.values[displ++] = args[0]; /* For each formal argument, get the actual argument. If @@ -1407,10 +1411,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & if (!lambda.formals->has(i.name)) { std::set formalNames; for (auto & formal : lambda.formals->formals) - formalNames.insert(formal.name); + formalNames.insert(symbols[formal.name]); throwTypeError( pos, - Suggestions::bestMatches(formalNames, i.name), + Suggestions::bestMatches(formalNames, symbols[i.name]), "%1% called with unexpected argument '%2%'", lambda, i.name); @@ -1428,8 +1432,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } catch (Error & e) { if (loggerSettings.showTrace.get()) { addErrorTrace(e, lambda.pos, "while evaluating %s", - (lambda.name.set() - ? "'" + (const std::string &) lambda.name + "'" + (lambda.name + ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda")); addErrorTrace(e, pos, "from call site%s", ""); } @@ -1578,7 +1582,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", i.name); +https://nixos.org/manual/nix/stable/#ss-functions.)", symbols[i.name]); } } @@ -1610,7 +1614,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) { if (!state.evalBool(env, cond, pos)) { std::ostringstream out; - cond->show(out); + cond->show(state.symbols, out); state.throwAssertionError(pos, "assertion '%1%' failed", out.str()); } body->eval(state, env, v); @@ -1844,7 +1848,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%'", symbols[i.name]); throw; } } @@ -2267,7 +2271,7 @@ void EvalState::printStats() auto list = topObj.list("functions"); for (auto & i : functionCalls) { auto obj = list.object(); - if (i.first->name.set()) + if (i.first->name) obj.attr("name", (const std::string &) i.first->name); else obj.attr("name", nullptr); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 71d6e7e7f..59c9c4873 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -53,7 +53,8 @@ void copyContext(const Value & v, PathSet & context); typedef std::map SrcToStore; -std::ostream & operator << (std::ostream & str, const Value & v); +std::ostream & printValue(const EvalState & state, std::ostream & str, const Value & v); +std::string printValue(const EvalState & state, const Value & v); typedef std::pair SearchPathElem; @@ -77,7 +78,7 @@ public: static inline std::string derivationNixPath = "//builtin/derivation.nix"; - const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, + const SymbolIdx sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, sFile, sLine, sColumn, sFunctor, sToString, sRight, sWrong, sStructuredAttrs, sBuilder, sArgs, @@ -86,7 +87,7 @@ public: sRecurseForDerivations, sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, sPrefix; - Symbol sDerivationNix; + SymbolIdx sDerivationNix; /* If set, force copying files to the Nix store even if they already exist there. */ @@ -268,14 +269,14 @@ public: [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx p1, const char * s, const Symbol & sym, const PosIdx p2) const; + void throwEvalError(const PosIdx p1, const char * s, const SymbolIdx sym, const PosIdx p2) const; [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol & s2) const; + void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const SymbolIdx s2) const; [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol & s2) const; + const ExprLambda & fun, const SymbolIdx s2) const; [[gnu::noinline, gnu::noreturn]] void throwTypeError(const char * s, const Value & v) const; [[gnu::noinline, gnu::noreturn]] @@ -391,7 +392,7 @@ public: inline Value * allocValue(); inline Env & allocEnv(size_t size); - Value * allocAttr(Value & vAttrs, const Symbol & name); + Value * allocAttr(Value & vAttrs, const SymbolIdx & name); Value * allocAttr(Value & vAttrs, std::string_view name); Bindings * allocBindings(size_t capacity); diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 44fb8317a..cbf4f0a6f 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -127,21 +127,23 @@ static FlakeInput parseFlakeInput(EvalState & state, } else { switch (attr.value->type()) { case nString: - attrs.emplace(attr.name, attr.value->string.s); + attrs.emplace(state.symbols[attr.name], attr.value->string.s); break; case nBool: - attrs.emplace(attr.name, Explicit { attr.value->boolean }); + attrs.emplace(state.symbols[attr.name], Explicit { attr.value->boolean }); break; case nInt: - attrs.emplace(attr.name, (long unsigned int)attr.value->integer); + attrs.emplace(state.symbols[attr.name], (long unsigned int)attr.value->integer); break; default: throw TypeError("flake input attribute '%s' is %s while a string, Boolean, or integer is expected", - attr.name, showType(*attr.value)); + state.symbols[attr.name], showType(*attr.value)); } } } catch (Error & e) { - e.addTrace(state.positions[attr.pos], hintfmt("in flake attribute '%s'", attr.name)); + e.addTrace( + state.positions[attr.pos], + hintfmt("in flake attribute '%s'", state.symbols[attr.name])); throw; } } @@ -176,9 +178,9 @@ static std::map parseFlakeInputs( expectType(state, nAttrs, *value, pos); for (nix::Attr & inputAttr : *(*value).attrs) { - inputs.emplace(inputAttr.name, + inputs.emplace(state.symbols[inputAttr.name], parseFlakeInput(state, - inputAttr.name, + state.symbols[inputAttr.name], inputAttr.value, inputAttr.pos, baseDir, @@ -218,7 +220,7 @@ static Flake getFlake( Value vInfo; state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack - expectType(state, nAttrs, vInfo, state.positions.add({state.symbols.create(flakeFile), foFile}, 0, 0)); + expectType(state, nAttrs, vInfo, state.positions.add({flakeFile, foFile}, 0, 0)); if (auto description = vInfo.attrs->get(state.sDescription)) { expectType(state, nString, *description->value, description->pos); @@ -238,8 +240,8 @@ static Flake getFlake( if (outputs->value->isLambda() && outputs->value->lambda.fun->hasFormals()) { for (auto & formal : outputs->value->lambda.fun->formals->formals) { if (formal.name != state.sSelf) - flake.inputs.emplace(formal.name, FlakeInput { - .ref = parseFlakeRef(formal.name) + flake.inputs.emplace(state.symbols[formal.name], FlakeInput { + .ref = parseFlakeRef(state.symbols[formal.name]) }); } } @@ -255,30 +257,36 @@ static Flake getFlake( for (auto & setting : *nixConfig->value->attrs) { 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.emplace( + state.symbols[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.symbols[setting.name], 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.emplace( + state.symbols[setting.name], + state.forceInt(*setting.value, setting.pos)); else if (setting.value->type() == nBool) - flake.config.settings.insert({setting.name, Explicit { state.forceBool(*setting.value, setting.pos) }}); + flake.config.settings.emplace( + state.symbols[setting.name], + Explicit { state.forceBool(*setting.value, setting.pos) }); else if (setting.value->type() == nList) { std::vector 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)); + state.symbols[setting.name], showType(*setting.value)); ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos)); } - flake.config.settings.insert({setting.name, ss}); + flake.config.settings.emplace(state.symbols[setting.name], ss); } else throw TypeError("flake configuration setting '%s' is %s", - setting.name, showType(*setting.value)); + state.symbols[setting.name], showType(*setting.value)); } } @@ -288,7 +296,7 @@ static Flake getFlake( attr.name != sOutputs && attr.name != sNixConfig) throw Error("flake '%s' has an unsupported attribute '%s', at %s", - lockedRef, attr.name, state.positions[attr.pos]); + lockedRef, state.symbols[attr.name], state.positions[attr.pos]); } return flake; diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index afb35586d..11f2b279d 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -179,7 +179,7 @@ StringSet DrvInfo::queryMetaNames() StringSet res; if (!getMeta()) return res; for (auto & i : *meta) - res.insert(i.name); + res.emplace(state->symbols[i.name]); return res; } @@ -269,7 +269,7 @@ void DrvInfo::setMeta(const std::string & name, Value * v) { getMeta(); auto attrs = state->buildBindings(1 + (meta ? meta->size() : 0)); - Symbol sym = state->symbols.create(name); + auto sym = state->symbols.create(name); if (meta) for (auto i : *meta) if (i.name != sym) @@ -356,11 +356,11 @@ static void getDerivations(EvalState & state, Value & vIn, there are names clashes between derivations, the derivation bound to the attribute with the "lower" name should take precedence). */ - for (auto & i : v.attrs->lexicographicOrder()) { - debug("evaluating attribute '%1%'", i->name); - if (!std::regex_match(std::string(i->name), attrRegex)) + for (auto & i : v.attrs->lexicographicOrder(state.symbols)) { + debug("evaluating attribute '%1%'", state.symbols[i->name]); + if (!std::regex_match(std::string(state.symbols[i->name]), attrRegex)) continue; - std::string pathPrefix2 = addToPath(pathPrefix, i->name); + std::string pathPrefix2 = addToPath(pathPrefix, state.symbols[i->name]); if (combineChannels) getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); else if (getDerivation(state, *i->value, pathPrefix2, drvs, done, ignoreAssertionFailures)) { diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 4138977ea..9fee3cb58 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -1,5 +1,7 @@ #include "nixexpr.hh" #include "derivations.hh" +#include "eval.hh" +#include "symbol-table.hh" #include "util.hh" #include @@ -10,12 +12,6 @@ namespace nix { /* Displaying abstract syntax trees. */ -std::ostream & operator << (std::ostream & str, const Expr & e) -{ - e.show(str); - return str; -} - static void showString(std::ostream & str, std::string_view s) { str << '"'; @@ -54,81 +50,101 @@ static void showId(std::ostream & str, std::string_view s) std::ostream & operator << (std::ostream & str, const Symbol & sym) { - showId(str, *sym.s); + showId(str, sym.s); return str; } -void Expr::show(std::ostream & str) const +void Expr::show(const SymbolTable & symbols, std::ostream & str) const { abort(); } -void ExprInt::show(std::ostream & str) const +void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const { str << n; } -void ExprFloat::show(std::ostream & str) const +void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const { str << nf; } -void ExprString::show(std::ostream & str) const +void ExprString::show(const SymbolTable & symbols, std::ostream & str) const { showString(str, s); } -void ExprPath::show(std::ostream & str) const +void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const { str << s; } -void ExprVar::show(std::ostream & str) const +void ExprVar::show(const SymbolTable & symbols, std::ostream & str) const { - str << name; + str << symbols[name]; } -void ExprSelect::show(std::ostream & str) const +void ExprSelect::show(const SymbolTable & symbols, std::ostream & str) const { - str << "(" << *e << ")." << showAttrPath(attrPath); - if (def) str << " or (" << *def << ")"; + str << "("; + e->show(symbols, str); + str << ")." << showAttrPath(symbols, attrPath); + if (def) { + str << " or ("; + def->show(symbols, str); + str << ")"; + } } -void ExprOpHasAttr::show(std::ostream & str) const +void ExprOpHasAttr::show(const SymbolTable & symbols, std::ostream & str) const { - str << "((" << *e << ") ? " << showAttrPath(attrPath) << ")"; + str << "(("; + e->show(symbols, str); + str << ") ? " << showAttrPath(symbols, attrPath) << ")"; } -void ExprAttrs::show(std::ostream & str) const +void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const { if (recursive) str << "rec "; str << "{ "; typedef const decltype(attrs)::value_type * Attr; std::vector sorted; for (auto & i : attrs) sorted.push_back(&i); - std::sort(sorted.begin(), sorted.end(), [](Attr a, Attr b) { - return (const std::string &) a->first < (const std::string &) b->first; - }); + std::sort(sorted.begin(), sorted.end(), [&](Attr a, Attr b) { + std::string_view sa = symbols[a->first], sb = symbols[b->first]; + return sa < sb; + }); for (auto & i : sorted) { if (i->second.inherited) - str << "inherit " << i->first << " " << "; "; - else - str << i->first << " = " << *i->second.e << "; "; + str << "inherit " << symbols[i->first] << " " << "; "; + else { + str << symbols[i->first] << " = "; + i->second.e->show(symbols, str); + str << "; "; + } + } + for (auto & i : dynamicAttrs) { + str << "\"${"; + i.nameExpr->show(symbols, str); + str << "}\" = "; + i.valueExpr->show(symbols, str); + str << "; "; } - for (auto & i : dynamicAttrs) - str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; "; str << "}"; } -void ExprList::show(std::ostream & str) const +void ExprList::show(const SymbolTable & symbols, std::ostream & str) const { str << "[ "; - for (auto & i : elems) - str << "(" << *i << ") "; + for (auto & i : elems) { + str << "("; + i->show(symbols, str); + str << ") "; + } str << "]"; } -void ExprLambda::show(std::ostream & str) const +void ExprLambda::show(const SymbolTable & symbols, std::ostream & str) const { str << "("; if (hasFormals()) { @@ -136,74 +152,100 @@ void ExprLambda::show(std::ostream & str) const bool first = true; for (auto & i : formals->formals) { if (first) first = false; else str << ", "; - str << i.name; - if (i.def) str << " ? " << *i.def; + str << symbols[i.name]; + if (i.def) { + str << " ? "; + i.def->show(symbols, str); + } } if (formals->ellipsis) { if (!first) str << ", "; str << "..."; } str << " }"; - if (arg.set()) str << " @ "; + if (arg) str << " @ "; } - if (arg.set()) str << arg; - str << ": " << *body << ")"; + if (arg) str << symbols[arg]; + str << ": "; + body->show(symbols, str); + str << ")"; } -void ExprCall::show(std::ostream & str) const +void ExprCall::show(const SymbolTable & symbols, std::ostream & str) const { - str << '(' << *fun; + str << '('; + fun->show(symbols, str); for (auto e : args) { str << ' '; - str << *e; + e->show(symbols, str); } str << ')'; } -void ExprLet::show(std::ostream & str) const +void ExprLet::show(const SymbolTable & symbols, std::ostream & str) const { str << "(let "; for (auto & i : attrs->attrs) if (i.second.inherited) { - str << "inherit " << i.first << "; "; + str << "inherit " << symbols[i.first] << "; "; } - else - str << i.first << " = " << *i.second.e << "; "; - str << "in " << *body << ")"; + else { + str << symbols[i.first] << " = "; + i.second.e->show(symbols, str); + str << "; "; + } + str << "in "; + body->show(symbols, str); + str << ")"; } -void ExprWith::show(std::ostream & str) const +void ExprWith::show(const SymbolTable & symbols, std::ostream & str) const { - str << "(with " << *attrs << "; " << *body << ")"; + str << "(with "; + attrs->show(symbols, str); + str << "; "; + body->show(symbols, str); + str << ")"; } -void ExprIf::show(std::ostream & str) const +void ExprIf::show(const SymbolTable & symbols, std::ostream & str) const { - str << "(if " << *cond << " then " << *then << " else " << *else_ << ")"; + str << "(if "; + cond->show(symbols, str); + str << " then "; + then->show(symbols, str); + str << " else "; + else_->show(symbols, str); + str << ")"; } -void ExprAssert::show(std::ostream & str) const +void ExprAssert::show(const SymbolTable & symbols, std::ostream & str) const { - str << "assert " << *cond << "; " << *body; + str << "assert "; + cond->show(symbols, str); + str << "; "; + body->show(symbols, str); } -void ExprOpNot::show(std::ostream & str) const +void ExprOpNot::show(const SymbolTable & symbols, std::ostream & str) const { - str << "(! " << *e << ")"; + str << "(! "; + e->show(symbols, str); + str << ")"; } -void ExprConcatStrings::show(std::ostream & str) const +void ExprConcatStrings::show(const SymbolTable & symbols, std::ostream & str) const { bool first = true; str << "("; for (auto & i : *es) { if (first) first = false; else str << " + "; - str << *i.second; + i.second->show(symbols, str); } str << ")"; } -void ExprPos::show(std::ostream & str) const +void ExprPos::show(const SymbolTable & symbols, std::ostream & str) const { str << "__curPos"; } @@ -234,16 +276,19 @@ std::ostream & operator << (std::ostream & str, const Pos & pos) } -std::string showAttrPath(const AttrPath & attrPath) +std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath) { std::ostringstream out; bool first = true; for (auto & i : attrPath) { if (!first) out << '.'; else first = false; - if (i.symbol.set()) - out << i.symbol; - else - out << "\"${" << *i.expr << "}\""; + if (i.symbol) + out << symbols[i.symbol]; + else { + out << "\"${"; + i.expr->show(symbols, out); + out << "}\""; + } } return out.str(); } @@ -252,28 +297,28 @@ std::string showAttrPath(const AttrPath & attrPath) /* Computing levels/displacements for variables. */ -void Expr::bindVars(const PosTable & pt, const StaticEnv & env) +void Expr::bindVars(const EvalState & es, const StaticEnv & env) { abort(); } -void ExprInt::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprInt::bindVars(const EvalState & es, const StaticEnv & env) { } -void ExprFloat::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprFloat::bindVars(const EvalState & es, const StaticEnv & env) { } -void ExprString::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprString::bindVars(const EvalState & es, const StaticEnv & env) { } -void ExprPath::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprPath::bindVars(const EvalState & es, const StaticEnv & env) { } -void ExprVar::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprVar::bindVars(const EvalState & es, const StaticEnv & env) { /* Check whether the variable appears in the environment. If so, set its level and displacement. */ @@ -299,31 +344,31 @@ void ExprVar::bindVars(const PosTable & pt, const StaticEnv & env) "undefined variable" error now. */ if (withLevel == -1) throw UndefinedVarError({ - .msg = hintfmt("undefined variable '%1%'", name), - .errPos = pt[pos] + .msg = hintfmt("undefined variable '%1%'", es.symbols[name]), + .errPos = es.positions[pos] }); fromWith = true; this->level = withLevel; } -void ExprSelect::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprSelect::bindVars(const EvalState & es, const StaticEnv & env) { - e->bindVars(pt, env); - if (def) def->bindVars(pt, env); + e->bindVars(es, env); + if (def) def->bindVars(es, env); for (auto & i : attrPath) - if (!i.symbol.set()) - i.expr->bindVars(pt, env); + if (!i.symbol) + i.expr->bindVars(es, env); } -void ExprOpHasAttr::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprOpHasAttr::bindVars(const EvalState & es, const StaticEnv & env) { - e->bindVars(pt, env); + e->bindVars(es, env); for (auto & i : attrPath) - if (!i.symbol.set()) - i.expr->bindVars(pt, env); + if (!i.symbol) + i.expr->bindVars(es, env); } -void ExprAttrs::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprAttrs::bindVars(const EvalState & es, const StaticEnv & env) { const StaticEnv * dynamicEnv = &env; StaticEnv newEnv(false, &env, recursive ? attrs.size() : 0); @@ -338,35 +383,35 @@ void ExprAttrs::bindVars(const PosTable & pt, const StaticEnv & env) // No need to sort newEnv since attrs is in sorted order. for (auto & i : attrs) - i.second.e->bindVars(pt, i.second.inherited ? env : newEnv); + i.second.e->bindVars(es, i.second.inherited ? env : newEnv); } else for (auto & i : attrs) - i.second.e->bindVars(pt, env); + i.second.e->bindVars(es, env); for (auto & i : dynamicAttrs) { - i.nameExpr->bindVars(pt, *dynamicEnv); - i.valueExpr->bindVars(pt, *dynamicEnv); + i.nameExpr->bindVars(es, *dynamicEnv); + i.valueExpr->bindVars(es, *dynamicEnv); } } -void ExprList::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprList::bindVars(const EvalState & es, const StaticEnv & env) { for (auto & i : elems) - i->bindVars(pt, env); + i->bindVars(es, env); } -void ExprLambda::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprLambda::bindVars(const EvalState & es, const StaticEnv & env) { StaticEnv newEnv( false, &env, (hasFormals() ? formals->formals.size() : 0) + - (!arg.set() ? 0 : 1)); + (!arg ? 0 : 1)); Displacement displ = 0; - if (arg.set()) newEnv.vars.emplace_back(arg, displ++); + if (arg) newEnv.vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) @@ -375,20 +420,20 @@ void ExprLambda::bindVars(const PosTable & pt, const StaticEnv & env) newEnv.sort(); for (auto & i : formals->formals) - if (i.def) i.def->bindVars(pt, newEnv); + if (i.def) i.def->bindVars(es, newEnv); } - body->bindVars(pt, newEnv); + body->bindVars(es, newEnv); } -void ExprCall::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprCall::bindVars(const EvalState & es, const StaticEnv & env) { - fun->bindVars(pt, env); + fun->bindVars(es, env); for (auto e : args) - e->bindVars(pt, env); + e->bindVars(es, env); } -void ExprLet::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprLet::bindVars(const EvalState & es, const StaticEnv & env) { StaticEnv newEnv(false, &env, attrs->attrs.size()); @@ -399,12 +444,12 @@ void ExprLet::bindVars(const PosTable & pt, const StaticEnv & env) // No need to sort newEnv since attrs->attrs is in sorted order. for (auto & i : attrs->attrs) - i.second.e->bindVars(pt, i.second.inherited ? env : newEnv); + i.second.e->bindVars(es, i.second.inherited ? env : newEnv); - body->bindVars(pt, newEnv); + body->bindVars(es, newEnv); } -void ExprWith::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprWith::bindVars(const EvalState & es, 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 @@ -418,57 +463,60 @@ void ExprWith::bindVars(const PosTable & pt, const StaticEnv & env) break; } - attrs->bindVars(pt, env); + attrs->bindVars(es, env); StaticEnv newEnv(true, &env); - body->bindVars(pt, newEnv); + body->bindVars(es, newEnv); } -void ExprIf::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprIf::bindVars(const EvalState & es, const StaticEnv & env) { - cond->bindVars(pt, env); - then->bindVars(pt, env); - else_->bindVars(pt, env); + cond->bindVars(es, env); + then->bindVars(es, env); + else_->bindVars(es, env); } -void ExprAssert::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprAssert::bindVars(const EvalState & es, const StaticEnv & env) { - cond->bindVars(pt, env); - body->bindVars(pt, env); + cond->bindVars(es, env); + body->bindVars(es, env); } -void ExprOpNot::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprOpNot::bindVars(const EvalState & es, const StaticEnv & env) { - e->bindVars(pt, env); + e->bindVars(es, env); } -void ExprConcatStrings::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprConcatStrings::bindVars(const EvalState & es, const StaticEnv & env) { - for (auto & i : *es) - i.second->bindVars(pt, env); + for (auto & i : *this->es) + i.second->bindVars(es, env); } -void ExprPos::bindVars(const PosTable & pt, const StaticEnv & env) +void ExprPos::bindVars(const EvalState & es, const StaticEnv & env) { } /* Storing function names. */ -void Expr::setName(Symbol & name) +void Expr::setName(SymbolIdx name) { } -void ExprLambda::setName(Symbol & name) +void ExprLambda::setName(SymbolIdx name) { this->name = name; body->setName(name); } -std::string ExprLambda::showNamePos(const PosTable & pt) const +std::string ExprLambda::showNamePos(const EvalState & state) const { - return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pt[pos]); + std::string id(name + ? concatStrings("'", state.symbols[name], "'") + : "anonymous function"); + return fmt("%1% at %2%", id, state.positions[pos]); } @@ -478,8 +526,7 @@ std::string ExprLambda::showNamePos(const PosTable & pt) const size_t SymbolTable::totalSize() const { size_t n = 0; - for (auto & i : store) - n += i.size(); + dump([&] (const Symbol & s) { n += std::string_view(s).size(); }); return n; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 2e12f0b4f..1a387d4fd 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -125,15 +125,15 @@ struct StaticEnv; /* An attribute path is a sequence of attribute names. */ struct AttrName { - Symbol symbol; + SymbolIdx symbol; Expr * expr; - AttrName(const Symbol & s) : symbol(s) {}; + AttrName(const SymbolIdx & s) : symbol(s) {}; AttrName(Expr * e) : expr(e) {}; }; typedef std::vector AttrPath; -std::string showAttrPath(const AttrPath & attrPath); +std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath); /* Abstract syntax of Nix expressions. */ @@ -141,19 +141,17 @@ std::string showAttrPath(const AttrPath & attrPath); struct Expr { virtual ~Expr() { }; - virtual void show(std::ostream & str) const; - virtual void bindVars(const PosTable & pt, const StaticEnv & env); + virtual void show(const SymbolTable & symbols, std::ostream & str) const; + virtual void bindVars(const EvalState & es, const StaticEnv & env); virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); - virtual void setName(Symbol & name); + virtual void setName(SymbolIdx name); }; -std::ostream & operator << (std::ostream & str, const Expr & e); - #define COMMON_METHODS \ - void show(std::ostream & str) const; \ + void show(const SymbolTable & symbols, std::ostream & str) const; \ void eval(EvalState & state, Env & env, Value & v); \ - void bindVars(const PosTable & pt, const StaticEnv & env); + void bindVars(const EvalState & es, const StaticEnv & env); struct ExprInt : Expr { @@ -197,7 +195,7 @@ typedef uint32_t Displacement; struct ExprVar : Expr { PosIdx pos; - Symbol name; + SymbolIdx name; /* Whether the variable comes from an environment (e.g. a rec, let or function argument) or from a "with". */ @@ -212,8 +210,8 @@ struct ExprVar : Expr Level level; Displacement displ; - ExprVar(const Symbol & name) : name(name) { }; - ExprVar(const PosIdx & pos, const Symbol & name) : pos(pos), name(name) { }; + ExprVar(const SymbolIdx & name) : name(name) { }; + ExprVar(const PosIdx & pos, const SymbolIdx & name) : pos(pos), name(name) { }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); }; @@ -224,7 +222,7 @@ struct ExprSelect : Expr Expr * e, * def; AttrPath attrPath; 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)); }; + ExprSelect(const PosIdx & pos, Expr * e, const SymbolIdx & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; COMMON_METHODS }; @@ -249,7 +247,7 @@ struct ExprAttrs : Expr : inherited(inherited), e(e), pos(pos) { }; AttrDef() { }; }; - typedef std::map AttrDefs; + typedef std::map AttrDefs; AttrDefs attrs; struct DynamicAttrDef { Expr * nameExpr, * valueExpr; @@ -274,9 +272,8 @@ struct ExprList : Expr struct Formal { PosIdx pos; - Symbol name; + SymbolIdx name; Expr * def; - Formal(const PosIdx & pos, const Symbol & name, Expr * def) : pos(pos), name(name), def(def) { }; }; struct Formals @@ -285,18 +282,19 @@ struct Formals Formals_ formals; bool ellipsis; - bool has(Symbol arg) const { + bool has(SymbolIdx arg) const { auto it = std::lower_bound(formals.begin(), formals.end(), arg, - [] (const Formal & f, const Symbol & sym) { return f.name < sym; }); + [] (const Formal & f, const SymbolIdx & sym) { return f.name < sym; }); return it != formals.end() && it->name == arg; } - std::vector lexicographicOrder() const + std::vector lexicographicOrder(const SymbolTable & symbols) const { std::vector result(formals.begin(), formals.end()); std::sort(result.begin(), result.end(), - [] (const Formal & a, const Formal & b) { - return std::string_view(a.name) < std::string_view(b.name); + [&] (const Formal & a, const Formal & b) { + std::string_view sa = symbols[a.name], sb = symbols[b.name]; + return sa < sb; }); return result; } @@ -305,16 +303,20 @@ struct Formals struct ExprLambda : Expr { PosIdx pos; - Symbol name; - Symbol arg; + SymbolIdx name; + SymbolIdx arg; Formals * formals; Expr * body; - ExprLambda(const PosIdx & pos, const Symbol & arg, Formals * formals, Expr * body) + ExprLambda(PosIdx pos, SymbolIdx arg, Formals * formals, Expr * body) : pos(pos), arg(arg), formals(formals), body(body) { }; - void setName(Symbol & name); - std::string showNamePos(const PosTable & pt) const; + ExprLambda(PosIdx pos, Formals * formals, Expr * body) + : pos(pos), formals(formals), body(body) + { + } + void setName(SymbolIdx name); + std::string showNamePos(const EvalState & state) const; inline bool hasFormals() const { return formals != nullptr; } COMMON_METHODS }; @@ -377,13 +379,13 @@ struct ExprOpNot : Expr Expr * e1, * e2; \ name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ - void show(std::ostream & str) const \ + void show(const SymbolTable & symbols, std::ostream & str) const \ { \ - str << "(" << *e1 << " " s " " << *e2 << ")"; \ + str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \ } \ - void bindVars(const PosTable & pt, const StaticEnv & env) \ + void bindVars(const EvalState & es, const StaticEnv & env) \ { \ - e1->bindVars(pt, env); e2->bindVars(pt, env); \ + e1->bindVars(es, env); e2->bindVars(es, env); \ } \ void eval(EvalState & state, Env & env, Value & v); \ }; @@ -423,7 +425,7 @@ struct StaticEnv const StaticEnv * up; // Note: these must be in sorted order. - typedef std::vector> Vars; + typedef std::vector> Vars; Vars vars; StaticEnv(bool isWith, const StaticEnv * up, size_t expectedSize = 0) : isWith(isWith), up(up) { @@ -447,7 +449,7 @@ struct StaticEnv vars.erase(it, end); } - Vars::const_iterator find(const Symbol & name) const + Vars::const_iterator find(const SymbolIdx & name) const { Vars::value_type key(name, 0); auto i = std::lower_bound(vars.begin(), vars.end(), key); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 1f950a057..b73fd1786 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -77,26 +77,26 @@ using namespace nix; namespace nix { -static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos) +static void dupAttr(const EvalState & state, const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos) { throw ParseError({ .msg = hintfmt("attribute '%1%' already defined at %2%", - showAttrPath(attrPath), prevPos), - .errPos = pos + showAttrPath(state.symbols, attrPath), state.positions[prevPos]), + .errPos = state.positions[pos] }); } -static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos) +static void dupAttr(const EvalState & state, SymbolIdx attr, const PosIdx pos, const PosIdx prevPos) { throw ParseError({ - .msg = hintfmt("attribute '%1%' already defined at %2%", attr, prevPos), - .errPos = pos + .msg = hintfmt("attribute '%1%' already defined at %2%", state.symbols[attr], state.positions[prevPos]), + .errPos = state.positions[pos] }); } static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, - Expr * e, const PosIdx pos, const nix::PosTable & pt) + Expr * e, const PosIdx pos, const nix::EvalState & state) { AttrPath::iterator i; // All attrpaths have at least one attr @@ -104,15 +104,15 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, // Checking attrPath validity. // =========================== for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) { - if (i->symbol.set()) { + if (i->symbol) { ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol); if (j != attrs->attrs.end()) { if (!j->second.inherited) { ExprAttrs * attrs2 = dynamic_cast(j->second.e); - if (!attrs2) dupAttr(attrPath, pt[pos], pt[j->second.pos]); + if (!attrs2) dupAttr(state, attrPath, pos, j->second.pos); attrs = attrs2; } else - dupAttr(attrPath, pt[pos], pt[j->second.pos]); + dupAttr(state, attrPath, pos, j->second.pos); } else { ExprAttrs * nested = new ExprAttrs; attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos); @@ -126,7 +126,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, } // Expr insertion. // ========================== - if (i->symbol.set()) { + if (i->symbol) { ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol); if (j != attrs->attrs.end()) { // This attr path is already defined. However, if both @@ -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, pt[j2->second.pos], pt[ad.second.pos]); + dupAttr(state, ad.first, j2->second.pos, ad.second.pos); jAttrs->attrs.emplace(ad.first, ad.second); } } else { - dupAttr(attrPath, pt[pos], pt[j->second.pos]); + dupAttr(state, attrPath, pos, 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, - PosIdx pos = noPos, Symbol arg = {}) + PosIdx pos = noPos, SymbolIdx 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> duplicate; + std::optional> duplicate; for (size_t i = 0; i + 1 < formals->formals.size(); i++) { if (formals->formals[i].name != formals->formals[i + 1].name) continue; @@ -173,7 +173,7 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals, } if (duplicate) throw ParseError({ - .msg = hintfmt("duplicate formal function argument '%1%'", duplicate->first), + .msg = hintfmt("duplicate formal function argument '%1%'", data.symbols[duplicate->first]), .errPos = data.state.positions[duplicate->second] }); @@ -181,9 +181,9 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals, result.ellipsis = formals->ellipsis; result.formals = std::move(formals->formals); - if (arg.set() && result.has(arg)) + if (arg && result.has(arg)) throw ParseError({ - .msg = hintfmt("duplicate formal function argument '%1%'", arg), + .msg = hintfmt("duplicate formal function argument '%1%'", data.symbols[arg]), .errPos = data.state.positions[pos] }); @@ -369,15 +369,15 @@ expr_function : ID ':' expr_function { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), 0, $3); } | '{' formals '}' ':' expr_function - { $$ = new ExprLambda(CUR_POS, {}, toFormals(*data, $2), $5); } + { $$ = new ExprLambda(CUR_POS, toFormals(*data, $2), $5); } | '{' formals '}' '@' ID ':' expr_function { - Symbol arg = data->symbols.create($5); + auto arg = data->symbols.create($5); $$ = new ExprLambda(CUR_POS, arg, toFormals(*data, $2, CUR_POS, arg), $7); } | ID '@' '{' formals '}' ':' expr_function { - Symbol arg = data->symbols.create($1); + auto arg = data->symbols.create($1); $$ = new ExprLambda(CUR_POS, arg, toFormals(*data, $4, CUR_POS, arg), $7); } | ASSERT expr ';' expr_function @@ -532,13 +532,12 @@ ind_string_parts ; binds - : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data), data->state.positions); } + : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data), data->state); } | binds INHERIT attrs ';' { $$ = $1; for (auto & i : *$3) { if ($$->attrs.find(i.symbol) != $$->attrs.end()) - dupAttr(i.symbol, data->state.positions[makeCurPos(@3, data)], - data->state.positions[$$->attrs[i.symbol].pos]); + dupAttr(data->state, i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos); auto pos = makeCurPos(@3, data); $$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true)); } @@ -548,8 +547,7 @@ binds /* !!! Should ensure sharing of the expression in $4. */ for (auto & i : *$6) { if ($$->attrs.find(i.symbol) != $$->attrs.end()) - dupAttr(i.symbol, data->state.positions[makeCurPos(@6, data)], - data->state.positions[$$->attrs[i.symbol].pos]); + dupAttr(data->state, i.symbol, makeCurPos(@6, data), $$->attrs[i.symbol].pos); $$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data))); } } @@ -623,8 +621,8 @@ formals ; formal - : ID { $$ = new Formal(CUR_POS, data->symbols.create($1), 0); } - | ID '?' expr { $$ = new Formal(CUR_POS, data->symbols.create($1), $3); } + : ID { $$ = new Formal{CUR_POS, data->symbols.create($1), 0}; } + | ID '?' expr { $$ = new Formal{CUR_POS, data->symbols.create($1), $3}; } ; %% @@ -670,7 +668,7 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin, if (res) throw ParseError(data.error.value()); - data.result->bindVars(positions, staticEnv); + data.result->bindVars(*this, staticEnv); return data.result; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 81fb5acfb..5892fe3b1 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -403,7 +403,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Val case nFloat: t = "float"; break; case nThunk: abort(); } - v.mkString(state.symbols.create(t)); + v.mkString(t); } static RegisterPrimOp primop_typeOf({ @@ -584,7 +584,7 @@ typedef std::list ValueList; static Bindings::iterator getAttr( EvalState & state, std::string_view funcName, - Symbol attrSym, + SymbolIdx attrSym, Bindings * attrSet, const PosIdx pos) { @@ -592,7 +592,7 @@ static Bindings::iterator getAttr( if (value == attrSet->end()) { hintformat errorMsg = hintfmt( "attribute '%s' missing for call to '%s'", - attrSym, + state.symbols[attrSym], funcName ); @@ -919,7 +919,7 @@ static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Valu if (args[0]->type() == nString) printError("trace: %1%", args[0]->string.s); else - printError("trace: %1%", *args[0]); + printError("trace: %1%", printValue(state, *args[0])); state.forceValue(*args[1], pos); v = *args[1]; } @@ -998,9 +998,9 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * StringSet outputs; outputs.insert("out"); - for (auto & i : args[0]->attrs->lexicographicOrder()) { + for (auto & i : args[0]->attrs->lexicographicOrder(state.symbols)) { if (i->name == state.sIgnoreNulls) continue; - const std::string & key = i->name; + const std::string & key = state.symbols[i->name]; vomit("processing attribute '%1%'", key); auto handleHashMode = [&](const std::string_view s) { @@ -2046,7 +2046,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value PathSet context; for (auto & attr : *args[0]->attrs) { - auto & n(attr.name); + auto & n(state.symbols[attr.name]); if (n == "path") path = state.coerceToPath(attr.pos, *attr.value, context); else if (attr.name == state.sName) @@ -2060,7 +2060,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos), htSHA256); else throw EvalError({ - .msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name), + .msg = hintfmt("unsupported argument '%1%' to 'addPath'", state.symbols[attr.name]), .errPos = state.positions[attr.pos] }); } @@ -2126,7 +2126,7 @@ static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args, size_t n = 0; for (auto & i : *args[0]->attrs) - (v.listElems()[n++] = state.allocValue())->mkString(i.name); + (v.listElems()[n++] = state.allocValue())->mkString(state.symbols[i.name]); std::sort(v.listElems(), v.listElems() + n, [](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; }); @@ -2156,8 +2156,9 @@ static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args, v.listElems()[n++] = (Value *) &i; std::sort(v.listElems(), v.listElems() + n, - [](Value * v1, Value * v2) { - std::string_view s1 = ((Attr *) v1)->name, s2 = ((Attr *) v2)->name; + [&](Value * v1, Value * v2) { + std::string_view s1 = state.symbols[((Attr *) v1)->name], + s2 = state.symbols[((Attr *) v2)->name]; return s1 < s2; }); @@ -2312,7 +2313,7 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args auto attrs = state.buildBindings(args[0]->listSize()); - std::set seen; + std::set seen; for (auto v2 : args[0]->listItems()) { state.forceAttrs(*v2, pos); @@ -2327,7 +2328,7 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args auto name = state.forceStringNoCtx(*j->value, j->pos); - Symbol sym = state.symbols.create(name); + auto sym = state.symbols.create(name); if (seen.insert(sym).second) { Bindings::iterator j2 = getAttr( state, @@ -2396,7 +2397,7 @@ static RegisterPrimOp primop_intersectAttrs({ static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) { - Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos)); + auto attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos)); state.forceList(*args[1], pos); Value * res[args[1]->listSize()]; @@ -2483,7 +2484,7 @@ static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value * * args, V for (auto & i : *args[1]->attrs) { Value * vName = state.allocValue(); Value * vFun2 = state.allocValue(); - vName->mkString(i.name); + vName->mkString(state.symbols[i.name]); vFun2->mkApp(args[0], vName); attrs.alloc(i.name).mkApp(vFun2, i.value); } @@ -2515,7 +2516,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg // attribute with the merge function application. this way we need not // use (slightly slower) temporary storage the GC does not know about. - std::map> attrsSeen; + std::map> attrsSeen; state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -2550,7 +2551,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg for (auto & attr : *v.attrs) { auto name = state.allocValue(); - name->mkString(attr.name); + name->mkString(state.symbols[attr.name]); auto call1 = state.allocValue(); call1->mkApp(args[0], name); auto call2 = state.allocValue(); @@ -3058,7 +3059,7 @@ static void prim_groupBy(EvalState & state, const PosIdx pos, Value * * args, Va Value res; state.callFunction(*args[0], *vElem, res, pos); auto name = state.forceStringNoCtx(res, pos); - Symbol sym = state.symbols.create(name); + auto sym = state.symbols.create(name); auto vector = attrs.try_emplace(sym, ValueVector()).first; vector->second.push_back(vElem); } @@ -3932,7 +3933,7 @@ void EvalState::createBaseEnv() // the parser needs two NUL bytes as terminators; one of them // is implied by being a C string. "\0"; - eval(parse(code, sizeof(code), foFile, sDerivationNix, "/", staticBaseEnv), *vDerivation); + eval(parse(code, sizeof(code), foFile, derivationNixPath, "/", staticBaseEnv), *vDerivation); } diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index 5521586ee..979136984 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -144,45 +144,46 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar auto sPath = state.symbols.create("path"); auto sAllOutputs = state.symbols.create("allOutputs"); for (auto & i : *args[1]->attrs) { - if (!state.store->isStorePath(i.name)) + const auto & name = state.symbols[i.name]; + if (!state.store->isStorePath(name)) throw EvalError({ - .msg = hintfmt("Context key '%s' is not a store path", i.name), + .msg = hintfmt("Context key '%s' is not a store path", name), .errPos = state.positions[i.pos] }); if (!settings.readOnlyMode) - state.store->ensurePath(state.store->parseStorePath(i.name)); + state.store->ensurePath(state.store->parseStorePath(name)); 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)) - context.insert(i.name); + context.emplace(name); } iter = i.value->attrs->find(sAllOutputs); if (iter != i.value->attrs->end()) { if (state.forceBool(*iter->value, iter->pos)) { - if (!isDerivation(i.name)) { + if (!isDerivation(name)) { throw EvalError({ - .msg = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", i.name), + .msg = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", name), .errPos = state.positions[i.pos] }); } - context.insert("=" + std::string(i.name)); + context.insert(concatStrings("=", name)); } } iter = i.value->attrs->find(state.sOutputs); if (iter != i.value->attrs->end()) { state.forceList(*iter->value, iter->pos); - if (iter->value->listSize() && !isDerivation(i.name)) { + if (iter->value->listSize() && !isDerivation(name)) { throw EvalError({ - .msg = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", i.name), + .msg = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", name), .errPos = state.positions[i.pos] }); } for (auto elem : iter->value->listItems()) { - auto name = state.forceStringNoCtx(*elem, iter->pos); - context.insert(concatStrings("!", name, "!", i.name)); + auto outputName = state.forceStringNoCtx(*elem, iter->pos); + context.insert(concatStrings("!", outputName, "!", name)); } } } diff --git a/src/libexpr/primops/fetchClosure.cc b/src/libexpr/primops/fetchClosure.cc index 90e9e6230..662c9652e 100644 --- a/src/libexpr/primops/fetchClosure.cc +++ b/src/libexpr/primops/fetchClosure.cc @@ -15,12 +15,14 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg std::optional toPath; for (auto & attr : *args[0]->attrs) { - if (attr.name == "fromPath") { + const auto & attrName = state.symbols[attr.name]; + + if (attrName == "fromPath") { PathSet context; fromPath = state.coerceToStorePath(attr.pos, *attr.value, context); } - else if (attr.name == "toPath") { + else if (attrName == "toPath") { state.forceValue(*attr.value, attr.pos); toCA = true; if (attr.value->type() != nString || attr.value->string.s != std::string("")) { @@ -29,12 +31,12 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg } } - else if (attr.name == "fromStore") + else if (attrName == "fromStore") fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos); else throw Error({ - .msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attr.name), + .msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attrName), .errPos = state.positions[pos] }); } diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index 252492446..249c0934e 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -22,7 +22,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a state.forceAttrs(*args[0], pos); for (auto & attr : *args[0]->attrs) { - std::string_view n(attr.name); + std::string_view n(state.symbols[attr.name]); if (n == "url") url = state.coerceToString(attr.pos, *attr.value, context, false, false).toOwned(); else if (n == "rev") { @@ -38,7 +38,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a name = state.forceStringNoCtx(*attr.value, attr.pos); else throw EvalError({ - .msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", attr.name), + .msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", state.symbols[attr.name]), .errPos = state.positions[attr.pos] }); } diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index cdcae97b6..d7c3c9918 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -126,20 +126,20 @@ static void fetchTree( 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(); - attrs.emplace(attr.name, - attr.name == "url" + attrs.emplace(state.symbols[attr.name], + state.symbols[attr.name] == "url" ? type == "git" ? fixURIForGit(s, state) : fixURI(s, state) : s); } else if (attr.value->type() == nBool) - attrs.emplace(attr.name, Explicit{attr.value->boolean}); + attrs.emplace(state.symbols[attr.name], Explicit{attr.value->boolean}); else if (attr.value->type() == nInt) - attrs.emplace(attr.name, uint64_t(attr.value->integer)); + attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer)); else throw TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", - attr.name, showType(*attr.value)); + state.symbols[attr.name], showType(*attr.value)); } if (!params.allowNameArgument) @@ -198,7 +198,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v state.forceAttrs(*args[0], pos); for (auto & attr : *args[0]->attrs) { - std::string n(attr.name); + std::string_view n(state.symbols[attr.name]); if (n == "url") url = state.forceStringNoCtx(*attr.value, attr.pos); else if (n == "sha256") @@ -207,7 +207,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v name = state.forceStringNoCtx(*attr.value, attr.pos); else throw EvalError({ - .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), + .msg = hintfmt("unsupported argument '%s' to '%s'", n, who), .errPos = state.positions[attr.pos] }); } diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh index 297605295..d0cd841a0 100644 --- a/src/libexpr/symbol-table.hh +++ b/src/libexpr/symbol-table.hh @@ -16,46 +16,25 @@ namespace nix { class Symbol { -private: - const std::string * s; // pointer into SymbolTable - Symbol(const std::string * s) : s(s) { }; friend class SymbolTable; +private: + std::string s; public: - Symbol() : s(0) { }; - - bool operator == (const Symbol & s2) const - { - return s == s2.s; - } + Symbol(std::string_view s) : s(s) { } // FIXME: remove bool operator == (std::string_view s2) const { - return s->compare(s2) == 0; - } - - bool operator != (const Symbol & s2) const - { - return s != s2.s; - } - - bool operator < (const Symbol & s2) const - { - return s < s2.s; + return s == s2; } operator const std::string & () const { - return *s; + return s; } operator const std::string_view () const - { - return *s; - } - - bool set() const { return s; } @@ -63,38 +42,64 @@ public: friend std::ostream & operator << (std::ostream & str, const Symbol & sym); }; +class SymbolIdx +{ + friend class SymbolTable; + +private: + uint32_t id; + + explicit SymbolIdx(uint32_t id): id(id) {} + +public: + SymbolIdx() : id(0) {} + + explicit operator bool() const { return id > 0; } + + bool operator<(const SymbolIdx other) const { return id < other.id; } + bool operator==(const SymbolIdx other) const { return id == other.id; } + bool operator!=(const SymbolIdx other) const { return id != other.id; } +}; + class SymbolTable { private: - std::unordered_map symbols; - std::list store; + std::unordered_map> symbols; + ChunkedVector store{16}; public: - Symbol create(std::string_view s) + SymbolIdx create(std::string_view s) { // Most symbols are looked up more than once, so we trade off insertion performance // for lookup performance. // TODO: could probably be done more efficiently with transparent Hash and Equals // on the original implementation using unordered_set auto it = symbols.find(s); - if (it != symbols.end()) return it->second; + if (it != symbols.end()) return SymbolIdx(it->second.second + 1); - auto & rawSym = store.emplace_back(s); - return symbols.emplace(rawSym, Symbol(&rawSym)).first->second; + const auto & [rawSym, idx] = store.add(s); + symbols.emplace(rawSym, std::make_pair(&rawSym, idx)); + return SymbolIdx(idx + 1); + } + + const Symbol & operator[](SymbolIdx s) const + { + if (s.id == 0 || s.id > store.size()) + abort(); + return store[s.id - 1]; } size_t size() const { - return symbols.size(); + return store.size(); } size_t totalSize() const; template - void dump(T callback) + void dump(T callback) const { - for (auto & s : store) - callback(s); + store.forEach(callback); } }; diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 307934292..68235ad11 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -50,7 +50,7 @@ void printValueAsJSON(EvalState & state, bool strict, auto obj(out.object()); StringSet names; for (auto & j : *v.attrs) - names.insert(j.name); + names.emplace(state.symbols[j.name]); for (auto & j : names) { Attr & a(*v.attrs->find(state.symbols.create(j))); auto placeholder(obj.placeholder(j)); diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index d1e0c4778..7c3bf9492 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -22,7 +22,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, const PosIdx pos); -static void posToXML(XMLAttrs & xmlAttrs, const Pos & pos) +static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos) { xmlAttrs["path"] = pos.file; xmlAttrs["line"] = (format("%1%") % pos.line).str(); @@ -36,14 +36,14 @@ static void showAttrs(EvalState & state, bool strict, bool location, StringSet names; for (auto & i : attrs) - names.insert(i.name); + names.emplace(state.symbols[i.name]); for (auto & i : names) { Attr & a(*attrs.find(state.symbols.create(i))); XMLAttrs xmlAttrs; xmlAttrs["name"] = i; - if (location && a.pos) posToXML(xmlAttrs, state.positions[a.pos]); + if (location && a.pos) posToXML(state, xmlAttrs, state.positions[a.pos]); XMLOpenElement _(doc, "attr", xmlAttrs); printValueAsXML(state, strict, location, @@ -134,18 +134,18 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, break; } XMLAttrs xmlAttrs; - if (location) posToXML(xmlAttrs, state.positions[v.lambda.fun->pos]); + if (location) posToXML(state, xmlAttrs, state.positions[v.lambda.fun->pos]); XMLOpenElement _(doc, "function", xmlAttrs); if (v.lambda.fun->hasFormals()) { XMLAttrs attrs; - if (v.lambda.fun->arg.set()) attrs["name"] = v.lambda.fun->arg; + if (v.lambda.fun->arg) attrs["name"] = state.symbols[v.lambda.fun->arg]; if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1"; XMLOpenElement _(doc, "attrspat", attrs); - for (auto & i : v.lambda.fun->formals->lexicographicOrder()) - doc.writeEmptyElement("attr", singletonAttrs("name", i.name)); + for (auto & i : v.lambda.fun->formals->lexicographicOrder(state.symbols)) + doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name])); } else - doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg)); + doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.lambda.fun->arg])); break; } diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index dc875615c..c46dd4b73 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -55,7 +55,7 @@ struct Env; struct Expr; struct ExprLambda; struct PrimOp; -class Symbol; +class SymbolIdx; class PosIdx; struct Pos; class StorePath; @@ -121,11 +121,11 @@ private: friend std::string showType(const Value & v); - void print(std::ostream & str, std::set * seen) const; + void print(const SymbolTable & symbols, std::ostream & str, std::set * seen) const; public: - void print(std::ostream & str, bool showRepeated = false) const; + void print(const SymbolTable & symbols, std::ostream & str, bool showRepeated = false) const; // Functions needed to distinguish the type // These should be removed eventually, by putting the functionality that's @@ -253,7 +253,7 @@ public: inline void mkString(const Symbol & s) { - mkString(((const std::string &) s).c_str()); + mkString(std::string_view(s).data()); } inline void mkPath(const char * s) @@ -410,12 +410,12 @@ public: #if HAVE_BOEHMGC typedef std::vector > ValueVector; -typedef std::map, traceable_allocator > > ValueMap; -typedef std::map, traceable_allocator > > ValueVectorMap; +typedef std::map, traceable_allocator > > ValueMap; +typedef std::map, traceable_allocator > > ValueVectorMap; #else typedef std::vector ValueVector; -typedef std::map ValueMap; -typedef std::map ValueVectorMap; +typedef std::map ValueMap; +typedef std::map ValueVectorMap; #endif diff --git a/src/libutil/types.hh b/src/libutil/types.hh index 22bc2b8dd..bd1dd8bee 100644 --- a/src/libutil/types.hh +++ b/src/libutil/types.hh @@ -152,6 +152,14 @@ public: { return chunks[idx / ChunkSize][idx % ChunkSize]; } + + template + void forEach(Fn fn) const + { + for (const auto & c : chunks) + for (const auto & e : c) + fn(e); + } }; } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 9a68899cd..96f3c3b26 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1241,7 +1241,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) Attr & a(*attrs.find(i.name)); if(a.value->type() != nString) continue; XMLAttrs attrs3; - attrs3["type"] = i.name; + attrs3["type"] = globals.state->symbols[i.name]; attrs3["value"] = a.value->string.s; xml.writeEmptyElement("string", attrs3); } diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 156181634..4b1202be3 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -106,7 +106,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, the store; we need it for future modifications of the environment. */ std::ostringstream str; - manifest.print(str, true); + manifest.print(state.symbols, str, true); auto manifestFile = state.store->addTextToStore("env-manifest.nix", str.str(), references); diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 3ec0e6e7c..d3144e131 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -31,7 +31,8 @@ void processExpr(EvalState & state, const Strings & attrPaths, bool evalOnly, OutputKind output, bool location, Expr * e) { if (parseOnly) { - std::cout << format("%1%\n") % *e; + e->show(state.symbols, std::cout); + std::cout << "\n"; return; } @@ -55,7 +56,8 @@ void processExpr(EvalState & state, const Strings & attrPaths, printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context); else { if (strict) state.forceValueDeep(vRes); - std::cout << vRes << std::endl; + vRes.print(state.symbols, std::cout); + std::cout << std::endl; } } else { DrvInfos drvs; diff --git a/src/nix/app.cc b/src/nix/app.cc index df7303e15..95ac1cf5c 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -85,9 +85,9 @@ UnresolvedApp Installable::toApp(EvalState & state) else if (type == "derivation") { auto drvPath = cursor->forceDerivation(); - auto outPath = cursor->getAttr(state.sOutPath)->getString(); - auto outputName = cursor->getAttr(state.sOutputName)->getString(); - auto name = cursor->getAttr(state.sName)->getString(); + auto outPath = cursor->getAttr("outPath")->getString(); + auto outputName = cursor->getAttr("outputName")->getString(); + auto name = cursor->getAttr("name")->getString(); auto aPname = cursor->maybeGetAttr("pname"); auto aMeta = cursor->maybeGetAttr("meta"); auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 81474c2d3..967dc8519 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -88,17 +88,19 @@ struct CmdEval : MixJSON, InstallableCommand else if (v.type() == nAttrs) { if (mkdir(path.c_str(), 0777) == -1) throw SysError("creating directory '%s'", path); - for (auto & attr : *v.attrs) + for (auto & attr : *v.attrs) { + std::string_view name = state->symbols[attr.name]; try { - if (attr.name == "." || attr.name == "..") - throw Error("invalid file name '%s'", attr.name); - recurse(*attr.value, attr.pos, path + "/" + std::string(attr.name)); + if (name == "." || name == "..") + throw Error("invalid file name '%s'", name); + recurse(*attr.value, attr.pos, concatStrings(path, "/", name)); } catch (Error & e) { e.addTrace( state->positions[attr.pos], - hintfmt("while evaluating the attribute '%s'", attr.name)); + hintfmt("while evaluating the attribute '%s'", name)); throw; } + } } else throw TypeError("value at '%s' is not a string or an attribute set", state->positions[pos]); @@ -119,7 +121,7 @@ struct CmdEval : MixJSON, InstallableCommand else { state->forceValueDeep(*v); - logger->cout("%s", *v); + logger->cout("%s", printValue(*state, *v)); } } }; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 23e5cd24e..c8d8461e4 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -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(state.symbols[attr->name], *attr->value, attr->pos); for (auto & attr : *aOutputs->value->attrs) { if (attr.name != sHydraJobs) - callback(attr.name, *attr.value, attr.pos); + callback(state.symbols[attr.name], *attr.value, attr.pos); } } @@ -254,14 +254,6 @@ struct CmdFlakeInfo : CmdFlakeMetadata } }; -static bool argHasName(std::string_view arg, std::string_view expected) -{ - return - arg == expected - || arg == "_" - || (hasPrefix(arg, "_") && arg.substr(1) == expected); -} - struct CmdFlakeCheck : FlakeCommand { bool build = true; @@ -319,6 +311,14 @@ struct CmdFlakeCheck : FlakeCommand return state->positions[p]; }; + auto argHasName = [&] (SymbolIdx arg, std::string_view expected) { + std::string_view name = state->symbols[arg]; + return + name == expected + || name == "_" + || (hasPrefix(name, "_") && name.substr(1) == expected); + }; + auto checkSystemName = [&](const std::string & system, const PosIdx pos) { // FIXME: what's the format of "system"? if (system.find('-') == std::string::npos) @@ -390,7 +390,7 @@ struct CmdFlakeCheck : FlakeCommand } catch (Error & e) { e.addTrace( state->positions[attr.pos], - hintfmt("while evaluating the option '%s'", attr.name)); + hintfmt("while evaluating the option '%s'", state->symbols[attr.name])); throw; } } else @@ -414,7 +414,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *v.attrs) { state->forceAttrs(*attr.value, attr.pos); - auto attrPath2 = attrPath + "." + (std::string) attr.name; + auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]); if (state->isDerivation(*attr.value)) { Activity act(*logger, lvlChatty, actUnknown, fmt("checking Hydra job '%s'", attrPath2)); @@ -468,7 +468,7 @@ struct CmdFlakeCheck : FlakeCommand throw Error("template '%s' lacks attribute 'description'", attrPath); for (auto & attr : *v.attrs) { - std::string name(attr.name); + std::string_view name(state->symbols[attr.name]); if (name != "path" && name != "description" && name != "welcomeText") throw Error("template '%s' has unsupported attribute '%s'", attrPath, name); } @@ -522,13 +522,14 @@ struct CmdFlakeCheck : FlakeCommand if (name == "checks") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + 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), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); - if (drvPath && (std::string) attr.name == settings.thisSystem.get()) + if (drvPath && attr_name == settings.thisSystem.get()) drvPaths.push_back(DerivedPath::Built{*drvPath}); } } @@ -537,9 +538,10 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "formatter") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); checkApp( - fmt("%s.%s", name, attr.name), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -547,11 +549,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "packages" || name == "devShells") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + 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), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -559,11 +562,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "apps") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + 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), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -571,9 +575,10 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "defaultPackage" || name == "devShell") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); checkDerivation( - fmt("%s.%s", name, attr.name), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -581,9 +586,10 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "defaultApp") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); checkApp( - fmt("%s.%s", name, attr.name), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -591,7 +597,7 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "legacyPackages") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + checkSystemName(state->symbols[attr.name], attr.pos); // FIXME: do getDerivations? } } @@ -602,7 +608,7 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "overlays") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkOverlay(fmt("%s.%s", name, attr.name), + checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } @@ -612,14 +618,14 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "nixosModules") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkModule(fmt("%s.%s", name, attr.name), + checkModule(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } else if (name == "nixosConfigurations") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkNixOSConfiguration(fmt("%s.%s", name, attr.name), + checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } @@ -632,16 +638,17 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "templates") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkTemplate(fmt("%s.%s", name, attr.name), + checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } else if (name == "defaultBundler") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); checkBundler( - fmt("%s.%s", name, attr.name), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -649,11 +656,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "bundlers") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, attr.pos); + const auto & attr_name = state->symbols[attr.name]; + 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), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -1000,7 +1008,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON auto showDerivation = [&]() { - auto name = visitor.getAttr(state->sName)->getString(); + auto name = visitor.getAttr("name")->getString(); if (json) { std::optional description; if (auto aMeta = visitor.maybeGetAttr("meta")) { diff --git a/src/nix/main.cc b/src/nix/main.cc index 6198681e7..6d0f6ce6e 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -302,7 +302,7 @@ void mainWrapped(int argc, char * * argv) b["arity"] = primOp->arity; b["args"] = primOp->args; b["doc"] = trim(stripIndentation(primOp->doc)); - res[(std::string) builtin.name] = std::move(b); + res[state.symbols[builtin.name]] = std::move(b); } std::cout << res.dump() << "\n"; return; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index fd1b95afa..998ff7328 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -73,7 +73,7 @@ struct NixRepl void initEnv(); void reloadFiles(); void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value & v); + void addVarToScope(const SymbolIdx name, Value & v); Expr * parseString(std::string s); void evalString(std::string s, Value & v); @@ -347,9 +347,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix) state->forceAttrs(v, noPos); for (auto & i : *v.attrs) { - std::string name = i.name; + std::string_view name = state->symbols[i.name]; if (name.substr(0, cur2.size()) != cur2) continue; - completions.insert(prev + expr + "." + name); + completions.insert(concatStrings(prev, expr, ".", name)); } } catch (ParseError & e) { @@ -464,8 +464,9 @@ bool NixRepl::processLine(std::string line) const auto [file, line] = [&] () -> std::pair { if (v.type() == nPath || v.type() == nString) { PathSet context; - auto filename = state->coerceToString(noPos, v, context); - return {state->symbols.create(*filename), 0}; + auto filename = state->coerceToString(noPos, v, context).toOwned(); + state->symbols.create(filename); + return {filename, 0}; } else if (v.isLambda()) { auto pos = state->positions[v.lambda.fun->pos]; return {pos.file, pos.line}; @@ -672,7 +673,7 @@ void NixRepl::initEnv() varNames.clear(); for (auto & i : state->staticBaseEnv.vars) - varNames.insert(i.first); + varNames.emplace(state->symbols[i.first]); } @@ -702,7 +703,7 @@ void NixRepl::addAttrsToScope(Value & attrs) for (auto & i : *attrs.attrs) { staticEnv.vars.emplace_back(i.name, displ); env->values[displ++] = i.value; - varNames.insert((std::string) i.name); + varNames.emplace(state->symbols[i.name]); } staticEnv.sort(); staticEnv.deduplicate(); @@ -710,7 +711,7 @@ void NixRepl::addAttrsToScope(Value & attrs) } -void NixRepl::addVarToScope(const Symbol & name, Value & v) +void NixRepl::addVarToScope(const SymbolIdx name, Value & v) { if (displ >= envSize) throw Error("environment full; cannot add more variables"); @@ -719,7 +720,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v) staticEnv.vars.emplace_back(name, displ); staticEnv.sort(); env->values[displ++] = &v; - varNames.insert((std::string) name); + varNames.emplace(state->symbols[name]); } @@ -812,7 +813,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m typedef std::map Sorted; Sorted sorted; for (auto & i : *v.attrs) - sorted[i.name] = i.value; + sorted.emplace(state->symbols[i.name], i.value); for (auto & i : sorted) { if (isVarName(i.first)) diff --git a/src/nix/search.cc b/src/nix/search.cc index e284de95c..8b1e9ae6c 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -154,7 +154,7 @@ struct CmdSearch : InstallableCommand, MixJSON recurse(); else if (attrPath[0] == "legacyPackages" && attrPath.size() > 2) { - auto attr = cursor.maybeGetAttr(state->sRecurseForDerivations); + auto attr = cursor.maybeGetAttr("recurseForDerivations"); if (attr && attr->getBool()) recurse(); }