forked from lix-project/lix
Make Env self-describing
If the Env denotes a 'with', then values[0] may be an Expr* cast to a Value*. For code that generically traverses Values/Envs, it's useful to know this.
This commit is contained in:
parent
9fd7cf98db
commit
4bb8741b98
|
@ -307,6 +307,8 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
|
||||||
|
|
||||||
assert(gcInitialised);
|
assert(gcInitialised);
|
||||||
|
|
||||||
|
static_assert(sizeof(Env) == 16);
|
||||||
|
|
||||||
/* Initialise the Nix expression search path. */
|
/* Initialise the Nix expression search path. */
|
||||||
if (!settings.pureEval) {
|
if (!settings.pureEval) {
|
||||||
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
|
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
|
||||||
|
@ -568,12 +570,12 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
if (!var.fromWith) return env->values[var.displ];
|
if (!var.fromWith) return env->values[var.displ];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!env->haveWithAttrs) {
|
if (env->type == Env::HasWithExpr) {
|
||||||
if (noEval) return 0;
|
if (noEval) return 0;
|
||||||
Value * v = allocValue();
|
Value * v = allocValue();
|
||||||
evalAttrs(*env->up, (Expr *) env->values[0], *v);
|
evalAttrs(*env->up, (Expr *) env->values[0], *v);
|
||||||
env->values[0] = v;
|
env->values[0] = v;
|
||||||
env->haveWithAttrs = true;
|
env->type = Env::HasWithAttrs;
|
||||||
}
|
}
|
||||||
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
||||||
if (j != env->values[0]->attrs->end()) {
|
if (j != env->values[0]->attrs->end()) {
|
||||||
|
@ -603,6 +605,7 @@ Env & EvalState::allocEnv(size_t size)
|
||||||
nrValuesInEnvs += size;
|
nrValuesInEnvs += size;
|
||||||
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
|
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
|
||||||
env->size = (decltype(Env::size)) size;
|
env->size = (decltype(Env::size)) size;
|
||||||
|
env->type = Env::Plain;
|
||||||
|
|
||||||
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
|
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
|
||||||
|
|
||||||
|
@ -1205,7 +1208,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||||
Env & env2(state.allocEnv(1));
|
Env & env2(state.allocEnv(1));
|
||||||
env2.up = &env;
|
env2.up = &env;
|
||||||
env2.prevWith = prevWith;
|
env2.prevWith = prevWith;
|
||||||
env2.haveWithAttrs = false;
|
env2.type = Env::HasWithExpr;
|
||||||
env2.values[0] = (Value *) attrs;
|
env2.values[0] = (Value *) attrs;
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
body->eval(state, env2, v);
|
||||||
|
@ -1863,6 +1866,7 @@ size_t valueSize(Value & v)
|
||||||
|
|
||||||
size_t sz = sizeof(Env) + sizeof(Value *) * env.size;
|
size_t sz = sizeof(Env) + sizeof(Value *) * env.size;
|
||||||
|
|
||||||
|
if (env.type != Env::HasWithExpr)
|
||||||
for (size_t i = 0; i < env.size; ++i)
|
for (size_t i = 0; i < env.size; ++i)
|
||||||
if (env.values[i])
|
if (env.values[i])
|
||||||
sz += doValue(*env.values[i]);
|
sz += doValue(*env.values[i]);
|
||||||
|
|
|
@ -35,8 +35,8 @@ struct Env
|
||||||
{
|
{
|
||||||
Env * up;
|
Env * up;
|
||||||
unsigned short size; // used by ‘valueSize’
|
unsigned short size; // used by ‘valueSize’
|
||||||
unsigned short prevWith:15; // nr of levels up to next `with' environment
|
unsigned short prevWith:14; // nr of levels up to next `with' environment
|
||||||
unsigned short haveWithAttrs:1;
|
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2;
|
||||||
Value * values[0];
|
Value * values[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue