diff options
Diffstat (limited to 'src/libexpr/nixexpr.cc')
-rw-r--r-- | src/libexpr/nixexpr.cc | 451 |
1 files changed, 291 insertions, 160 deletions
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index a2def65a6..eb6f062b4 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -1,21 +1,67 @@ #include "nixexpr.hh" #include "derivations.hh" +#include "eval.hh" +#include "symbol-table.hh" #include "util.hh" #include <cstdlib> - namespace nix { +struct PosAdapter : AbstractPos +{ + Pos::Origin origin; -/* Displaying abstract syntax trees. */ + PosAdapter(Pos::Origin origin) + : origin(std::move(origin)) + { + } -std::ostream & operator << (std::ostream & str, const Expr & e) + std::optional<std::string> getSource() const override + { + return std::visit(overloaded { + [](const Pos::none_tag &) -> std::optional<std::string> { + return std::nullopt; + }, + [](const Pos::Stdin & s) -> std::optional<std::string> { + // Get rid of the null terminators added by the parser. + return std::string(s.source->c_str()); + }, + [](const Pos::String & s) -> std::optional<std::string> { + // Get rid of the null terminators added by the parser. + return std::string(s.source->c_str()); + }, + [](const Path & path) -> std::optional<std::string> { + try { + return readFile(path); + } catch (Error &) { + return std::nullopt; + } + } + }, origin); + } + + void print(std::ostream & out) const override + { + std::visit(overloaded { + [&](const Pos::none_tag &) { out << "«none»"; }, + [&](const Pos::Stdin &) { out << "«stdin»"; }, + [&](const Pos::String & s) { out << "«string»"; }, + [&](const Path & path) { out << path; } + }, origin); + } +}; + +Pos::operator std::shared_ptr<AbstractPos>() const { - e.show(str); - return str; + auto pos = std::make_shared<PosAdapter>(origin); + pos->line = line; + pos->column = column; + return pos; } +/* Displaying abstract syntax trees. */ + static void showString(std::ostream & str, std::string_view s) { str << '"'; @@ -28,8 +74,10 @@ static void showString(std::ostream & str, std::string_view s) str << '"'; } -static void showId(std::ostream & str, std::string_view s) +std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol) { + std::string_view s = symbol; + if (s.empty()) str << "\"\""; else if (s == "if") // FIXME: handle other keywords @@ -38,7 +86,7 @@ static void showId(std::ostream & str, std::string_view s) char c = s[0]; if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) { showString(str, s); - return; + return str; } for (auto c : s) if (!((c >= 'a' && c <= 'z') || @@ -46,89 +94,104 @@ static void showId(std::ostream & str, std::string_view s) (c >= '0' && c <= '9') || c == '_' || c == '\'' || c == '-')) { showString(str, s); - return; + return str; } str << s; } -} - -std::ostream & operator << (std::ostream & str, const Symbol & sym) -{ - 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<Attr> 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 +199,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.empty()) str << " @ "; + if (arg) str << " @ "; } - if (!arg.empty()) 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"; } @@ -211,78 +300,75 @@ void ExprPos::show(std::ostream & str) const std::ostream & operator << (std::ostream & str, const Pos & pos) { - if (!pos) + if (auto pos2 = (std::shared_ptr<AbstractPos>) pos) { + str << *pos2; + } else str << "undefined position"; - else - { - auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%"); - switch (pos.origin) { - case foFile: - f % (const std::string &) pos.file; - break; - case foStdin: - case foString: - f % "(string)"; - break; - default: - throw Error("unhandled Pos origin!"); - } - str << (f % pos.line % pos.column).str(); - } return str; } -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(); } -Pos noPos; - - /* Computing levels/displacements for variables. */ -void Expr::bindVars(const StaticEnv & env) +void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { abort(); } -void ExprInt::bindVars(const StaticEnv & env) +void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprFloat::bindVars(const StaticEnv & env) +void ExprFloat::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprString::bindVars(const StaticEnv & env) +void ExprString::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprPath::bindVars(const StaticEnv & env) +void ExprPath::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprVar::bindVars(const StaticEnv & env) +void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + /* Check whether the variable appears in the environment. If so, set its level and displacement. */ const StaticEnv * curEnv; Level level; int withLevel = -1; - for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) { + for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { if (curEnv->isWith) { if (withLevel == -1) withLevel = level; } else { @@ -301,176 +387,222 @@ void ExprVar::bindVars(const StaticEnv & env) "undefined variable" error now. */ if (withLevel == -1) throw UndefinedVarError({ - .msg = hintfmt("undefined variable '%1%'", name), - .errPos = pos + .msg = hintfmt("undefined variable '%1%'", es.symbols[name]), + .errPos = es.positions[pos] }); fromWith = true; this->level = withLevel; } -void ExprSelect::bindVars(const StaticEnv & env) +void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - e->bindVars(env); - if (def) def->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + e->bindVars(es, env); + if (def) def->bindVars(es, env); for (auto & i : attrPath) - if (!i.symbol.set()) - i.expr->bindVars(env); + if (!i.symbol) + i.expr->bindVars(es, env); } -void ExprOpHasAttr::bindVars(const StaticEnv & env) +void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - e->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + e->bindVars(es, env); for (auto & i : attrPath) - if (!i.symbol.set()) - i.expr->bindVars(env); + if (!i.symbol) + i.expr->bindVars(es, env); } -void ExprAttrs::bindVars(const StaticEnv & env) +void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - const StaticEnv * dynamicEnv = &env; - StaticEnv newEnv(false, &env, recursive ? attrs.size() : 0); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); if (recursive) { - dynamicEnv = &newEnv; + auto newEnv = std::make_shared<StaticEnv>(false, env.get(), recursive ? attrs.size() : 0); Displacement displ = 0; for (auto & i : attrs) - newEnv.vars.emplace_back(i.first, i.second.displ = displ++); + newEnv->vars.emplace_back(i.first, i.second.displ = displ++); // No need to sort newEnv since attrs is in sorted order. for (auto & i : attrs) - i.second.e->bindVars(i.second.inherited ? env : newEnv); - } + i.second.e->bindVars(es, i.second.inherited ? env : newEnv); - else + for (auto & i : dynamicAttrs) { + i.nameExpr->bindVars(es, newEnv); + i.valueExpr->bindVars(es, newEnv); + } + } + else { for (auto & i : attrs) - i.second.e->bindVars(env); + i.second.e->bindVars(es, env); - for (auto & i : dynamicAttrs) { - i.nameExpr->bindVars(*dynamicEnv); - i.valueExpr->bindVars(*dynamicEnv); + for (auto & i : dynamicAttrs) { + i.nameExpr->bindVars(es, env); + i.valueExpr->bindVars(es, env); + } } } -void ExprList::bindVars(const StaticEnv & env) +void ExprList::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + for (auto & i : elems) - i->bindVars(env); + i->bindVars(es, env); } -void ExprLambda::bindVars(const StaticEnv & env) +void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - StaticEnv newEnv( - false, &env, + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + auto newEnv = std::make_shared<StaticEnv>( + false, env.get(), (hasFormals() ? formals->formals.size() : 0) + - (arg.empty() ? 0 : 1)); + (!arg ? 0 : 1)); Displacement displ = 0; - if (!arg.empty()) newEnv.vars.emplace_back(arg, displ++); + if (arg) newEnv->vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) - newEnv.vars.emplace_back(i.name, displ++); + newEnv->vars.emplace_back(i.name, displ++); - newEnv.sort(); + newEnv->sort(); for (auto & i : formals->formals) - if (i.def) i.def->bindVars(newEnv); + if (i.def) i.def->bindVars(es, newEnv); } - body->bindVars(newEnv); + body->bindVars(es, newEnv); } -void ExprCall::bindVars(const StaticEnv & env) +void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - fun->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + fun->bindVars(es, env); for (auto e : args) - e->bindVars(env); + e->bindVars(es, env); } -void ExprLet::bindVars(const StaticEnv & env) +void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - StaticEnv newEnv(false, &env, attrs->attrs.size()); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + auto newEnv = std::make_shared<StaticEnv>(false, env.get(), attrs->attrs.size()); Displacement displ = 0; for (auto & i : attrs->attrs) - newEnv.vars.emplace_back(i.first, i.second.displ = displ++); + newEnv->vars.emplace_back(i.first, i.second.displ = displ++); // No need to sort newEnv since attrs->attrs is in sorted order. for (auto & i : attrs->attrs) - i.second.e->bindVars(i.second.inherited ? env : newEnv); + i.second.e->bindVars(es, i.second.inherited ? env : newEnv); - body->bindVars(newEnv); + body->bindVars(es, newEnv); } -void ExprWith::bindVars(const StaticEnv & env) +void ExprWith::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous `with' if this one doesn't contain the desired attribute. */ const StaticEnv * curEnv; Level level; prevWith = 0; - for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++) + for (curEnv = env.get(), level = 1; curEnv; curEnv = curEnv->up, level++) if (curEnv->isWith) { prevWith = level; break; } - attrs->bindVars(env); - StaticEnv newEnv(true, &env); - body->bindVars(newEnv); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + attrs->bindVars(es, env); + auto newEnv = std::make_shared<StaticEnv>(true, env.get()); + body->bindVars(es, newEnv); } -void ExprIf::bindVars(const StaticEnv & env) +void ExprIf::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - cond->bindVars(env); - then->bindVars(env); - else_->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + cond->bindVars(es, env); + then->bindVars(es, env); + else_->bindVars(es, env); } -void ExprAssert::bindVars(const StaticEnv & env) +void ExprAssert::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - cond->bindVars(env); - body->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + cond->bindVars(es, env); + body->bindVars(es, env); } -void ExprOpNot::bindVars(const StaticEnv & env) +void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - e->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + e->bindVars(es, env); } -void ExprConcatStrings::bindVars(const StaticEnv & env) +void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { - for (auto & i : *es) - i.second->bindVars(env); + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); + + for (auto & i : *this->es) + i.second->bindVars(es, env); } -void ExprPos::bindVars(const StaticEnv & env) +void ExprPos::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) { + if (es.debugRepl) + es.exprEnvs.insert(std::make_pair(this, env)); } /* Storing function names. */ -void Expr::setName(Symbol & name) +void Expr::setName(Symbol name) { } -void ExprLambda::setName(Symbol & name) +void ExprLambda::setName(Symbol name) { this->name = name; body->setName(name); } -std::string ExprLambda::showNamePos() const +std::string ExprLambda::showNamePos(const EvalState & state) const { - return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pos); + std::string id(name + ? concatStrings("'", state.symbols[name], "'") + : "anonymous function"); + return fmt("%1% at %2%", id, state.positions[pos]); } @@ -480,8 +612,7 @@ std::string ExprLambda::showNamePos() const size_t SymbolTable::totalSize() const { size_t n = 0; - for (auto & i : store) - n += i.size(); + dump([&] (const std::string & s) { n += s.size(); }); return n; } |