aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/nixexpr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/nixexpr.cc')
-rw-r--r--src/libexpr/nixexpr.cc113
1 files changed, 87 insertions, 26 deletions
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 3525ea1a3..3bcd35fef 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -68,10 +68,8 @@ void ExprOpHasAttr::show(const SymbolTable & symbols, std::ostream & str) const
str << ") ? " << showAttrPath(symbols, attrPath) << ")";
}
-void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const
+void ExprAttrs::showBindings(const SymbolTable & symbols, std::ostream & str) const
{
- if (recursive) str << "rec ";
- str << "{ ";
typedef const decltype(attrs)::value_type * Attr;
std::vector<Attr> sorted;
for (auto & i : attrs) sorted.push_back(&i);
@@ -79,10 +77,37 @@ void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const
std::string_view sa = symbols[a->first], sb = symbols[b->first];
return sa < sb;
});
+ std::vector<Symbol> inherits;
+ std::map<ExprInheritFrom *, std::vector<Symbol>> inheritsFrom;
for (auto & i : sorted) {
- if (i->second.inherited)
- str << "inherit " << symbols[i->first] << " " << "; ";
- else {
+ switch (i->second.kind) {
+ case AttrDef::Kind::Plain:
+ break;
+ case AttrDef::Kind::Inherited:
+ inherits.push_back(i->first);
+ break;
+ case AttrDef::Kind::InheritedFrom: {
+ auto & select = dynamic_cast<ExprSelect &>(*i->second.e);
+ auto & from = dynamic_cast<ExprInheritFrom &>(*select.e);
+ inheritsFrom[&from].push_back(i->first);
+ break;
+ }
+ }
+ }
+ if (!inherits.empty()) {
+ str << "inherit";
+ for (auto sym : inherits) str << " " << symbols[sym];
+ str << "; ";
+ }
+ for (const auto & [from, syms] : inheritsFrom) {
+ str << "inherit (";
+ (*inheritFromExprs)[from->displ]->show(symbols, str);
+ str << ")";
+ for (auto sym : syms) str << " " << symbols[sym];
+ str << "; ";
+ }
+ for (auto & i : sorted) {
+ if (i->second.kind == AttrDef::Kind::Plain) {
str << symbols[i->first] << " = ";
i->second.e->show(symbols, str);
str << "; ";
@@ -95,6 +120,13 @@ void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const
i.valueExpr->show(symbols, str);
str << "; ";
}
+}
+
+void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const
+{
+ if (recursive) str << "rec ";
+ str << "{ ";
+ showBindings(symbols, str);
str << "}";
}
@@ -150,15 +182,7 @@ void ExprCall::show(const SymbolTable & symbols, 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 " << symbols[i.first] << "; ";
- }
- else {
- str << symbols[i.first] << " = ";
- i.second.e->show(symbols, str);
- str << "; ";
- }
+ attrs->showBindings(symbols, str);
str << "in ";
body->show(symbols, str);
str << ")";
@@ -303,6 +327,12 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
this->level = withLevel;
}
+void ExprInheritFrom::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
+{
+ if (es.debugRepl)
+ es.exprEnvs.insert(std::make_pair(this, env));
+}
+
void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
if (es.debugRepl)
@@ -326,22 +356,47 @@ void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr<const StaticE
i.expr->bindVars(es, env);
}
+std::shared_ptr<const StaticEnv> ExprAttrs::bindInheritSources(
+ EvalState & es, const std::shared_ptr<const StaticEnv> & env)
+{
+ if (!inheritFromExprs)
+ return nullptr;
+
+ // the inherit (from) source values are inserted into an env of its own, which
+ // does not introduce any variable names.
+ // analysis must see an empty env, or an env that contains only entries with
+ // otherwise unused names to not interfere with regular names. the parser
+ // has already filled all exprs that access this env with appropriate level
+ // and displacement, and nothing else is allowed to access it. ideally we'd
+ // not even *have* an expr that grabs anything from this env since it's fully
+ // invisible, but the evaluator does not allow for this yet.
+ auto inner = std::make_shared<StaticEnv>(nullptr, env.get(), 0);
+ for (auto from : *inheritFromExprs)
+ from->bindVars(es, env);
+
+ return inner;
+}
+
void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
if (es.debugRepl)
es.exprEnvs.insert(std::make_pair(this, env));
if (recursive) {
- auto newEnv = std::make_shared<StaticEnv>(nullptr, env.get(), recursive ? attrs.size() : 0);
+ auto newEnv = [&] () -> std::shared_ptr<const StaticEnv> {
+ auto newEnv = std::make_shared<StaticEnv>(nullptr, env.get(), attrs.size());
- Displacement displ = 0;
- for (auto & i : attrs)
- newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
+ Displacement displ = 0;
+ for (auto & i : attrs)
+ newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
+ return newEnv;
+ }();
// No need to sort newEnv since attrs is in sorted order.
+ auto inheritFromEnv = bindInheritSources(es, newEnv);
for (auto & i : attrs)
- i.second.e->bindVars(es, i.second.inherited ? env : newEnv);
+ i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv));
for (auto & i : dynamicAttrs) {
i.nameExpr->bindVars(es, newEnv);
@@ -349,8 +404,10 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
}
}
else {
+ auto inheritFromEnv = bindInheritSources(es, env);
+
for (auto & i : attrs)
- i.second.e->bindVars(es, env);
+ i.second.e->bindVars(es, i.second.chooseByKind(env, env, inheritFromEnv));
for (auto & i : dynamicAttrs) {
i.nameExpr->bindVars(es, env);
@@ -407,16 +464,20 @@ void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- auto newEnv = std::make_shared<StaticEnv>(nullptr, env.get(), attrs->attrs.size());
+ auto newEnv = [&] () -> std::shared_ptr<const StaticEnv> {
+ auto newEnv = std::make_shared<StaticEnv>(nullptr, env.get(), attrs->attrs.size());
- Displacement displ = 0;
- for (auto & i : attrs->attrs)
- newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
+ Displacement displ = 0;
+ for (auto & i : attrs->attrs)
+ newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
+ return newEnv;
+ }();
// No need to sort newEnv since attrs->attrs is in sorted order.
+ auto inheritFromEnv = attrs->bindInheritSources(es, newEnv);
for (auto & i : attrs->attrs)
- i.second.e->bindVars(es, i.second.inherited ? env : newEnv);
+ i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv));
if (es.debugRepl)
es.exprEnvs.insert(std::make_pair(this, newEnv));