forked from lix-project/lix
9985230c00
use site, allowing environments to be stores as vectors of values rather than maps. This should speed up evaluation and reduce the number of allocations.
298 lines
6.3 KiB
C++
298 lines
6.3 KiB
C++
#include "nixexpr.hh"
|
|
#include "derivations.hh"
|
|
#include "util.hh"
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
/* Displaying abstract syntax trees. */
|
|
|
|
std::ostream & operator << (std::ostream & str, Expr & e)
|
|
{
|
|
e.show(str);
|
|
return str;
|
|
}
|
|
|
|
void Expr::show(std::ostream & str)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
void ExprInt::show(std::ostream & str)
|
|
{
|
|
str << n;
|
|
}
|
|
|
|
void ExprString::show(std::ostream & str)
|
|
{
|
|
str << "\"" << s << "\""; // !!! escaping
|
|
}
|
|
|
|
void ExprPath::show(std::ostream & str)
|
|
{
|
|
str << s;
|
|
}
|
|
|
|
void ExprVar::show(std::ostream & str)
|
|
{
|
|
str << name;
|
|
}
|
|
|
|
void ExprSelect::show(std::ostream & str)
|
|
{
|
|
str << "(" << *e << ")." << name;
|
|
}
|
|
|
|
void ExprOpHasAttr::show(std::ostream & str)
|
|
{
|
|
str << "(" << *e << ") ? " << name;
|
|
}
|
|
|
|
void ExprAttrs::show(std::ostream & str)
|
|
{
|
|
if (recursive) str << "rec ";
|
|
str << "{ ";
|
|
foreach (list<Symbol>::iterator, i, inherited)
|
|
str << "inherit " << *i << "; ";
|
|
foreach (Attrs::iterator, i, attrs)
|
|
str << i->first << " = " << *i->second << "; ";
|
|
str << "}";
|
|
}
|
|
|
|
void ExprList::show(std::ostream & str)
|
|
{
|
|
str << "[ ";
|
|
foreach (vector<Expr *>::iterator, i, elems)
|
|
str << "(" << **i << ") ";
|
|
str << "]";
|
|
}
|
|
|
|
void ExprLambda::show(std::ostream & str)
|
|
{
|
|
str << "(";
|
|
if (matchAttrs) {
|
|
str << "{ ";
|
|
bool first = true;
|
|
foreach (Formals::Formals_::iterator, i, formals->formals) {
|
|
if (first) first = false; else str << ", ";
|
|
str << i->name;
|
|
if (i->def) str << " ? " << *i->def;
|
|
}
|
|
str << " }";
|
|
if (!arg.empty()) str << " @ ";
|
|
}
|
|
if (!arg.empty()) str << arg;
|
|
str << ": " << *body << ")";
|
|
}
|
|
|
|
void ExprLet::show(std::ostream & str)
|
|
{
|
|
str << "let ";
|
|
foreach (list<Symbol>::iterator, i, attrs->inherited)
|
|
str << "inherit " << *i << "; ";
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
|
str << i->first << " = " << *i->second << "; ";
|
|
str << "in " << *body;
|
|
}
|
|
|
|
void ExprWith::show(std::ostream & str)
|
|
{
|
|
str << "with " << *attrs << "; " << *body;
|
|
}
|
|
|
|
void ExprIf::show(std::ostream & str)
|
|
{
|
|
str << "if " << *cond << " then " << *then << " else " << *else_;
|
|
}
|
|
|
|
void ExprAssert::show(std::ostream & str)
|
|
{
|
|
str << "assert " << *cond << "; " << *body;
|
|
}
|
|
|
|
void ExprOpNot::show(std::ostream & str)
|
|
{
|
|
str << "! " << *e;
|
|
}
|
|
|
|
void ExprConcatStrings::show(std::ostream & str)
|
|
{
|
|
bool first = true;
|
|
foreach (vector<Expr *>::iterator, i, *es) {
|
|
if (first) first = false; else str << " + ";
|
|
str << **i;
|
|
}
|
|
}
|
|
|
|
|
|
std::ostream & operator << (std::ostream & str, const Pos & pos)
|
|
{
|
|
if (!pos.line)
|
|
str << "undefined position";
|
|
else
|
|
str << (format("`%1%:%2%:%3%'") % pos.file % pos.line % pos.column).str();
|
|
return str;
|
|
}
|
|
|
|
|
|
/* Computing levels/displacements for variables. */
|
|
|
|
void Expr::bindVars(const StaticEnv & env)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
void ExprInt::bindVars(const StaticEnv & env)
|
|
{
|
|
}
|
|
|
|
void ExprString::bindVars(const StaticEnv & env)
|
|
{
|
|
}
|
|
|
|
void ExprPath::bindVars(const StaticEnv & env)
|
|
{
|
|
}
|
|
|
|
void ExprVar::bindVars(const StaticEnv & env)
|
|
{
|
|
/* Check whether the variable appears in the environment. If so,
|
|
set its level and displacement. */
|
|
const StaticEnv * curEnv;
|
|
unsigned int level;
|
|
int withLevel = -1;
|
|
for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) {
|
|
if (curEnv->isWith) {
|
|
if (withLevel == -1) withLevel = level;
|
|
} else {
|
|
StaticEnv::Vars::const_iterator i = curEnv->vars.find(name);
|
|
if (i != curEnv->vars.end()) {
|
|
fromWith = false;
|
|
this->level = level;
|
|
displ = i->second;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Otherwise, the variable must be obtained from the nearest
|
|
enclosing `with'. If there is no `with', then we can issue an
|
|
"undefined variable" error now. */
|
|
if (withLevel == -1) throw EvalError(format("undefined variable `%1%'") % name);
|
|
|
|
fromWith = true;
|
|
this->level = withLevel;
|
|
}
|
|
|
|
void ExprSelect::bindVars(const StaticEnv & env)
|
|
{
|
|
e->bindVars(env);
|
|
}
|
|
|
|
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
|
{
|
|
e->bindVars(env);
|
|
}
|
|
|
|
void ExprAttrs::bindVars(const StaticEnv & env)
|
|
{
|
|
if (recursive) {
|
|
StaticEnv newEnv(false, &env);
|
|
|
|
unsigned int displ = 0;
|
|
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
|
newEnv.vars[i->first] = displ++;
|
|
|
|
foreach (list<Symbol>::iterator, i, inherited)
|
|
newEnv.vars[*i] = displ++;
|
|
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
|
i->second->bindVars(newEnv);
|
|
}
|
|
|
|
else
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
|
i->second->bindVars(env);
|
|
}
|
|
|
|
void ExprList::bindVars(const StaticEnv & env)
|
|
{
|
|
foreach (vector<Expr *>::iterator, i, elems)
|
|
(*i)->bindVars(env);
|
|
}
|
|
|
|
void ExprLambda::bindVars(const StaticEnv & env)
|
|
{
|
|
StaticEnv newEnv(false, &env);
|
|
|
|
unsigned int displ = 0;
|
|
|
|
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
|
|
|
if (matchAttrs) {
|
|
foreach (Formals::Formals_::iterator, i, formals->formals)
|
|
newEnv.vars[i->name] = displ++;
|
|
|
|
foreach (Formals::Formals_::iterator, i, formals->formals)
|
|
if (i->def) i->def->bindVars(newEnv);
|
|
}
|
|
|
|
body->bindVars(newEnv);
|
|
}
|
|
|
|
void ExprLet::bindVars(const StaticEnv & env)
|
|
{
|
|
StaticEnv newEnv(false, &env);
|
|
|
|
unsigned int displ = 0;
|
|
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
|
newEnv.vars[i->first] = displ++;
|
|
|
|
foreach (list<Symbol>::iterator, i, attrs->inherited)
|
|
newEnv.vars[*i] = displ++;
|
|
|
|
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
|
i->second->bindVars(newEnv);
|
|
|
|
body->bindVars(newEnv);
|
|
}
|
|
|
|
void ExprWith::bindVars(const StaticEnv & env)
|
|
{
|
|
attrs->bindVars(env);
|
|
StaticEnv newEnv(true, &env);
|
|
body->bindVars(newEnv);
|
|
}
|
|
|
|
void ExprIf::bindVars(const StaticEnv & env)
|
|
{
|
|
cond->bindVars(env);
|
|
then->bindVars(env);
|
|
else_->bindVars(env);
|
|
}
|
|
|
|
void ExprAssert::bindVars(const StaticEnv & env)
|
|
{
|
|
cond->bindVars(env);
|
|
body->bindVars(env);
|
|
}
|
|
|
|
void ExprOpNot::bindVars(const StaticEnv & env)
|
|
{
|
|
e->bindVars(env);
|
|
}
|
|
|
|
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
|
{
|
|
foreach (vector<Expr *>::iterator, i, *es)
|
|
(*i)->bindVars(env);
|
|
}
|
|
|
|
|
|
}
|