Simplify inherited attribute handling

This reduces the difference between inherited and non-inherited
attribute handling to the choice of which env to use (in recs and lets)
by setting the AttrDef::e to a new ExprVar in the parser rather than
carrying a separate AttrDef::v VarRef member.

As an added bonus, this allows inherited attributes that inherit from a
with to delay forcing evaluation of the with's attributes.

Signed-off-by: Shea Levy <shea@shealevy.com>
This commit is contained in:
Shea Levy 2013-07-15 17:10:18 -04:00 committed by Eelco Dolstra
parent 6cd6ce5608
commit afc6c1bad6
7 changed files with 46 additions and 38 deletions

View file

@ -521,23 +521,17 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
environment, while the inherited attributes are evaluated environment, while the inherited attributes are evaluated
in the original environment. */ in the original environment. */
unsigned int displ = 0; unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs) foreach (AttrDefs::iterator, i, attrs) {
if (i->second.inherited) { Value * vAttr;
/* !!! handle overrides? */ if (hasOverrides && !i->second.inherited) {
Value * vAttr = state.lookupVar(&env, i->second.var); vAttr = state.allocValue();
env2.values[displ++] = vAttr; mkThunk(*vAttr, env2, i->second.e);
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos)); } else
} else { vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
Value * vAttr; env2.values[displ++] = vAttr;
if (hasOverrides) { v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
vAttr = state.allocValue(); }
mkThunk(*vAttr, env2, i->second.e);
} else
vAttr = i->second.e->maybeThunk(state, env2);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
}
/* If the rec contains an attribute called `__overrides', then /* If the rec contains an attribute called `__overrides', then
evaluate it, and add the attributes in that set to the rec. evaluate it, and add the attributes in that set to the rec.
This allows overriding of recursive attributes, which is This allows overriding of recursive attributes, which is
@ -563,10 +557,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else { else {
foreach (AttrDefs::iterator, i, attrs) foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
v.attrs->push_back(Attr(i->first, state.lookupVar(&env, i->second.var), &i->second.pos));
else
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
} }
} }
@ -583,10 +574,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
environment. */ environment. */
unsigned int displ = 0; unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited) env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
env2.values[displ++] = state.lookupVar(&env, i->second.var);
else
env2.values[displ++] = i->second.e->maybeThunk(state, env2);
body->eval(state, env2, v); body->eval(state, env2, v);
} }
@ -602,7 +590,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
void ExprVar::eval(EvalState & state, Env & env, Value & v) void ExprVar::eval(EvalState & state, Env & env, Value & v)
{ {
Value * v2 = state.lookupVar(&env, info); Value * v2 = state.lookupVar(&env, info, false);
state.forceValue(*v2); state.forceValue(*v2);
v = *v2; v = *v2;
} }

View file

@ -206,7 +206,7 @@ private:
void addPrimOp(const string & name, void addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp); unsigned int arity, PrimOpFun primOp);
inline Value * lookupVar(Env * env, const VarRef & var, bool noEval = false); inline Value * lookupVar(Env * env, const VarRef & var, bool noEval);
friend class ExprVar; friend class ExprVar;
friend class ExprAttrs; friend class ExprAttrs;

View file

@ -230,14 +230,12 @@ void ExprAttrs::bindVars(const StaticEnv & env)
newEnv.vars[i->first] = i->second.displ = displ++; newEnv.vars[i->first] = i->second.displ = displ++;
foreach (AttrDefs::iterator, i, attrs) foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env); i->second.e->bindVars(i->second.inherited ? env : newEnv);
else i->second.e->bindVars(newEnv);
} }
else else
foreach (AttrDefs::iterator, i, attrs) foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env); i->second.e->bindVars(env);
else i->second.e->bindVars(env);
} }
void ExprList::bindVars(const StaticEnv & env) void ExprList::bindVars(const StaticEnv & env)
@ -274,8 +272,7 @@ void ExprLet::bindVars(const StaticEnv & env)
newEnv.vars[i->first] = i->second.displ = displ++; newEnv.vars[i->first] = i->second.displ = displ++;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited) i->second.var.bind(env); i->second.e->bindVars(i->second.inherited ? env : newEnv);
else i->second.e->bindVars(newEnv);
body->bindVars(newEnv); body->bindVars(newEnv);
} }

View file

@ -159,12 +159,10 @@ struct ExprAttrs : Expr
bool recursive; bool recursive;
struct AttrDef { struct AttrDef {
bool inherited; bool inherited;
Expr * e; // if not inherited Expr * e;
VarRef var; // if inherited
Pos pos; Pos pos;
unsigned int displ; // displacement unsigned int displ; // displacement
AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { }; AttrDef(Expr * e, const Pos & pos, bool inherited=false) : inherited(inherited), e(e), pos(pos) { };
AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { };
AttrDef() { }; AttrDef() { };
}; };
typedef std::map<Symbol, AttrDef> AttrDefs; typedef std::map<Symbol, AttrDef> AttrDefs;

View file

@ -413,7 +413,7 @@ binds
if ($$->attrs.find(*i) != $$->attrs.end()) if ($$->attrs.find(*i) != $$->attrs.end())
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos); dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
Pos pos = makeCurPos(@3, data); Pos pos = makeCurPos(@3, data);
$$->attrs[*i] = ExprAttrs::AttrDef(*i, pos); $$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(*i), pos, true);
} }
} }
| binds INHERIT '(' expr ')' attrs ';' | binds INHERIT '(' expr ')' attrs ';'

View file

@ -0,0 +1 @@
"b-overridden"

View file

@ -0,0 +1,24 @@
let
pkgs_ = with pkgs; {
a = derivation {
name = "a";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
inherit b;
};
inherit b;
};
packageOverrides = p: {
b = derivation {
name = "b-overridden";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
};
};
pkgs = pkgs_ // (packageOverrides pkgs_);
in pkgs.a.b.name