mirror of
https://github.com/NixOS/nix.git
synced 2025-11-15 15:02:42 +01:00
Checkpoint
This commit is contained in:
parent
4237414f4d
commit
7c716b4c49
27 changed files with 596 additions and 440 deletions
|
|
@ -32,7 +32,7 @@ static Strings parseAttrPath(const string & s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
Ptr<Value> findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
Bindings & autoArgs, Value & vIn)
|
Bindings & autoArgs, Value & vIn)
|
||||||
{
|
{
|
||||||
Strings tokens = parseAttrPath(attrPath);
|
Strings tokens = parseAttrPath(attrPath);
|
||||||
|
|
@ -40,7 +40,7 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
Error attrError =
|
Error attrError =
|
||||||
Error(format("attribute selection path '%1%' does not match expression") % attrPath);
|
Error(format("attribute selection path '%1%' does not match expression") % attrPath);
|
||||||
|
|
||||||
Value * v = &vIn;
|
Ptr<Value> v(&vIn);
|
||||||
|
|
||||||
for (auto & attr : tokens) {
|
for (auto & attr : tokens) {
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||||
|
|
||||||
/* Evaluate the expression. */
|
/* Evaluate the expression. */
|
||||||
Value * vNew = state.allocValue();
|
auto vNew = state.allocValue();
|
||||||
state.autoCallFunction(autoArgs, *v, *vNew);
|
state.autoCallFunction(autoArgs, *v, *vNew);
|
||||||
v = vNew;
|
v = vNew;
|
||||||
state.forceValue(*v);
|
state.forceValue(*v);
|
||||||
|
|
@ -71,7 +71,7 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
||||||
if (a == v->attrs->end())
|
if (a == v->attrs->end())
|
||||||
throw Error(format("attribute '%1%' in selection path '%2%' not found") % attr % attrPath);
|
throw Error(format("attribute '%1%' in selection path '%2%' not found") % attr % attrPath);
|
||||||
v = &*a->value;
|
v = a->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (apType == apIndex) {
|
else if (apType == apIndex) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
Ptr<Value> findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
Bindings & autoArgs, Value & vIn);
|
Bindings & autoArgs, Value & vIn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,15 @@ Ptr<Bindings> Bindings::allocBindings(size_t capacity)
|
||||||
|
|
||||||
void EvalState::mkAttrs(Value & v, size_t capacity)
|
void EvalState::mkAttrs(Value & v, size_t capacity)
|
||||||
{
|
{
|
||||||
v.type = tAttrs;
|
|
||||||
if (capacity == 0) {
|
if (capacity == 0) {
|
||||||
v.attrs = emptyBindings;
|
v.attrs = emptyBindings;
|
||||||
return;
|
v.type = tAttrs;
|
||||||
}
|
} else {
|
||||||
v.attrs = Bindings::allocBindings(capacity);
|
v.attrs = Bindings::allocBindings(capacity);
|
||||||
|
v.type = tAttrs;
|
||||||
nrAttrsets++;
|
nrAttrsets++;
|
||||||
nrAttrsInAttrsets += capacity;
|
nrAttrsInAttrsets += capacity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,7 +37,7 @@ void EvalState::mkAttrs(Value & v, size_t capacity)
|
||||||
this attribute. */
|
this attribute. */
|
||||||
Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
||||||
{
|
{
|
||||||
Value * v = allocValue();
|
auto v = allocValue();
|
||||||
vAttrs.attrs->push_back(Attr(name, v));
|
vAttrs.attrs->push_back(Attr(name, v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ private:
|
||||||
size_t size_;
|
size_t size_;
|
||||||
Attr attrs[0];
|
Attr attrs[0];
|
||||||
|
|
||||||
public:
|
Bindings(size_t capacity) : Object(tBindings, capacity), size_(0) {}
|
||||||
// FIXME: make private
|
|
||||||
Bindings(size_t capacity) : Object(tBindings, capacity), size_(0) { }
|
|
||||||
Bindings(const Bindings & bindings) = delete;
|
Bindings(const Bindings & bindings) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
size_t size() const { return size_; }
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
bool empty() const { return !size_; }
|
bool empty() const { return !size_; }
|
||||||
|
|
@ -56,6 +56,7 @@ public:
|
||||||
void push_back(const Attr & attr)
|
void push_back(const Attr & attr)
|
||||||
{
|
{
|
||||||
assert(size_ < capacity());
|
assert(size_ < capacity());
|
||||||
|
gc.assertObject(attr.value);
|
||||||
attrs[size_++] = attr;
|
attrs[size_++] = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ MixEvalArgs::MixEvalArgs()
|
||||||
.handler([&](std::string s) { searchPath.push_back(s); });
|
.handler([&](std::string s) { searchPath.push_back(s); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
Ptr<Bindings> MixEvalArgs::getAutoArgs(EvalState & state)
|
||||||
{
|
{
|
||||||
Bindings * res = Bindings::allocBindings(autoArgs.size());
|
auto res = Bindings::allocBindings(autoArgs.size());
|
||||||
for (auto & i : autoArgs) {
|
for (auto & i : autoArgs) {
|
||||||
Value * v = state.allocValue();
|
Value * v = state.allocValue();
|
||||||
if (i.second[0] == 'E')
|
if (i.second[0] == 'E')
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,14 @@ class Store;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
class Bindings;
|
class Bindings;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Ptr;
|
||||||
|
|
||||||
struct MixEvalArgs : virtual Args
|
struct MixEvalArgs : virtual Args
|
||||||
{
|
{
|
||||||
MixEvalArgs();
|
MixEvalArgs();
|
||||||
|
|
||||||
Bindings * getAutoArgs(EvalState & state);
|
Ptr<Bindings> getAutoArgs(EvalState & state);
|
||||||
|
|
||||||
Strings searchPath;
|
Strings searchPath;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,21 +27,27 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const
|
||||||
void EvalState::forceValue(Value & v, const Pos & pos)
|
void EvalState::forceValue(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
if (v.type == tThunk) {
|
if (v.type == tThunk) {
|
||||||
Env * env = v.thunk.env;
|
// FIXME: this is necessary because some values (like vList2)
|
||||||
|
// are created non-atomically.
|
||||||
|
Ptr<Env> env(v.thunk.env);
|
||||||
Expr * expr = v.thunk.expr;
|
Expr * expr = v.thunk.expr;
|
||||||
try {
|
try {
|
||||||
v.type = tBlackhole;
|
v.type = tBlackhole;
|
||||||
//checkInterrupt();
|
//checkInterrupt();
|
||||||
expr->eval(*this, *env, v);
|
expr->eval(*this, *env, v);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
v.type = tThunk;
|
|
||||||
v.thunk.env = env;
|
v.thunk.env = env;
|
||||||
v.thunk.expr = expr;
|
v.thunk.expr = expr;
|
||||||
|
v.type = tThunk;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v.type == tApp)
|
else if (v.type == tApp) {
|
||||||
|
// FIXME: idem.
|
||||||
|
Ptr<Value> left(v.app.left);
|
||||||
|
Ptr<Value> right(v.app.right);
|
||||||
callFunction(*v.app.left, *v.app.right, v, noPos);
|
callFunction(*v.app.left, *v.app.right, v, noPos);
|
||||||
|
}
|
||||||
else if (v.type == tBlackhole)
|
else if (v.type == tBlackhole)
|
||||||
throwEvalError("infinite recursion encountered, at %1%", pos);
|
throwEvalError("infinite recursion encountered, at %1%", pos);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,10 +166,10 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
||||||
if (name.symbol.set()) {
|
if (name.symbol.set()) {
|
||||||
return name.symbol;
|
return name.symbol;
|
||||||
} else {
|
} else {
|
||||||
Value nameValue;
|
Root<Value> nameValue;
|
||||||
name.expr->eval(state, env, nameValue);
|
name.expr->eval(state, env, nameValue);
|
||||||
state.forceStringNoCtx(nameValue);
|
state.forceStringNoCtx(nameValue);
|
||||||
return state.symbols.create(nameValue.string.s);
|
return state.symbols.create(nameValue->string.s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,7 +384,7 @@ Path EvalState::toRealPath(const Path & path, const PathSet & context)
|
||||||
|
|
||||||
Value * EvalState::addConstant(const string & name, Value & v)
|
Value * EvalState::addConstant(const string & name, Value & v)
|
||||||
{
|
{
|
||||||
Value * v2 = allocValue();
|
auto v2 = allocValue();
|
||||||
*v2 = v;
|
*v2 = v;
|
||||||
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
||||||
baseEnv->values[baseEnvDispl++] = v2;
|
baseEnv->values[baseEnvDispl++] = v2;
|
||||||
|
|
@ -398,11 +398,11 @@ Value * EvalState::addPrimOp(const string & name,
|
||||||
size_t arity, PrimOpFun primOp)
|
size_t arity, PrimOpFun primOp)
|
||||||
{
|
{
|
||||||
if (arity == 0) {
|
if (arity == 0) {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
primOp(*this, noPos, nullptr, v);
|
primOp(*this, noPos, nullptr, v);
|
||||||
return addConstant(name, v);
|
return addConstant(name, v);
|
||||||
}
|
}
|
||||||
Value * v = allocValue();
|
auto v = allocValue();
|
||||||
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
||||||
Symbol sym = symbols.create(name2);
|
Symbol sym = symbols.create(name2);
|
||||||
v->type = tPrimOp;
|
v->type = tPrimOp;
|
||||||
|
|
@ -523,12 +523,18 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
{
|
{
|
||||||
for (size_t l = var.level; l; --l, env = env->up) ;
|
for (size_t l = var.level; l; --l, env = env->up) ;
|
||||||
|
|
||||||
if (!var.fromWith) return env->values[var.displ];
|
assert(((Object *) env)->type == tEnv);
|
||||||
|
|
||||||
|
if (!var.fromWith) {
|
||||||
|
auto v = env->values[var.displ];
|
||||||
|
if (v) gc.assertObject(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (env->type == Env::HasWithExpr) {
|
if (env->type == Env::HasWithExpr) {
|
||||||
if (noEval) return 0;
|
if (noEval) return 0;
|
||||||
Value * v = allocValue();
|
auto 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->type = Env::HasWithAttrs;
|
env->type = Env::HasWithAttrs;
|
||||||
|
|
@ -536,6 +542,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
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()) {
|
||||||
if (countCalls && j->pos) attrSelects[*j->pos]++;
|
if (countCalls && j->pos) attrSelects[*j->pos]++;
|
||||||
|
gc.assertObject(j->value);
|
||||||
return j->value;
|
return j->value;
|
||||||
}
|
}
|
||||||
if (!env->prevWith)
|
if (!env->prevWith)
|
||||||
|
|
@ -559,12 +566,8 @@ Ptr<Env> EvalState::allocEnv(size_t size)
|
||||||
|
|
||||||
nrEnvs++;
|
nrEnvs++;
|
||||||
nrValuesInEnvs += size;
|
nrValuesInEnvs += size;
|
||||||
auto env = gc.alloc<Env>(Env::wordsFor(size), size);
|
|
||||||
|
|
||||||
// FIXME
|
return gc.alloc<Env>(Env::wordsFor(size), size);
|
||||||
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
|
|
||||||
|
|
||||||
return env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -572,14 +575,17 @@ void EvalState::mkList(Value & v, size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
v.type = tList0;
|
v.type = tList0;
|
||||||
else if (size == 1)
|
else if (size == 1) {
|
||||||
|
v.smallList[0] = nullptr;
|
||||||
v.type = tList1;
|
v.type = tList1;
|
||||||
else if (size == 2)
|
} else if (size == 2) {
|
||||||
|
v.smallList[0] = nullptr;
|
||||||
|
v.smallList[1] = nullptr;
|
||||||
v.type = tList2;
|
v.type = tList2;
|
||||||
else {
|
} else {
|
||||||
v.type = tListN;
|
|
||||||
v.bigList = gc.alloc<PtrList<Value>>(
|
v.bigList = gc.alloc<PtrList<Value>>(
|
||||||
PtrList<Value>::wordsFor(size), tValueList, size);
|
PtrList<Value>::wordsFor(size), tValueList, size);
|
||||||
|
v.type = tListN;
|
||||||
}
|
}
|
||||||
nrListElems += size;
|
nrListElems += size;
|
||||||
}
|
}
|
||||||
|
|
@ -616,12 +622,12 @@ void EvalState::mkPos(Value & v, Pos * pos)
|
||||||
|
|
||||||
|
|
||||||
/* Create a thunk for the delayed computation of the given expression
|
/* Create a thunk for the delayed computation of the given expression
|
||||||
in the given environment. But if the expression is a variable,
|
in the given environment. But if the expression is a variable or a
|
||||||
then look it up right away. This significantly reduces the number
|
constant, then look it up right away. This significantly reduces
|
||||||
of thunks allocated. */
|
the number of thunks allocated. */
|
||||||
Value * Expr::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> Expr::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
Value * v = state.allocValue();
|
auto v = state.allocValue();
|
||||||
mkThunk(*v, env, this);
|
mkThunk(*v, env, this);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
@ -629,9 +635,9 @@ Value * Expr::maybeThunk(EvalState & state, Env & env)
|
||||||
|
|
||||||
unsigned long nrAvoided = 0;
|
unsigned long nrAvoided = 0;
|
||||||
|
|
||||||
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
Value * v = state.lookupVar(&env, *this, true);
|
auto v = state.lookupVar(&env, *this, true);
|
||||||
/* The value might not be initialised in the environment yet.
|
/* The value might not be initialised in the environment yet.
|
||||||
In that case, ignore it. */
|
In that case, ignore it. */
|
||||||
if (v) { nrAvoided++; return v; }
|
if (v) { nrAvoided++; return v; }
|
||||||
|
|
@ -639,28 +645,28 @@ Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * ExprString::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> ExprString::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
nrAvoided++;
|
nrAvoided++;
|
||||||
return &*v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * ExprInt::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> ExprInt::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
nrAvoided++;
|
nrAvoided++;
|
||||||
return &*v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * ExprFloat::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> ExprFloat::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
nrAvoided++;
|
nrAvoided++;
|
||||||
return &*v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
Ptr<Value> ExprPath::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
nrAvoided++;
|
nrAvoided++;
|
||||||
return &*v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -723,21 +729,21 @@ void EvalState::eval(Expr * e, Value & v)
|
||||||
|
|
||||||
inline bool EvalState::evalBool(Env & env, Expr * e)
|
inline bool EvalState::evalBool(Env & env, Expr * e)
|
||||||
{
|
{
|
||||||
Value v;
|
Root<Value> v;
|
||||||
e->eval(*this, env, v);
|
e->eval(*this, env, v);
|
||||||
if (v.type != tBool)
|
if (v->type != tBool)
|
||||||
throwTypeError("value is %1% while a Boolean was expected", v);
|
throwTypeError("value is %1% while a Boolean was expected", v);
|
||||||
return v.boolean;
|
return v->boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos)
|
inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos)
|
||||||
{
|
{
|
||||||
Value v;
|
Root<Value> v;
|
||||||
e->eval(*this, env, v);
|
e->eval(*this, env, v);
|
||||||
if (v.type != tBool)
|
if (v->type != tBool)
|
||||||
throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos);
|
throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos);
|
||||||
return v.boolean;
|
return v->boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -781,14 +787,14 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
state.mkAttrs(v, attrs.size() + dynamicAttrs.size());
|
state.mkAttrs(v, attrs.size() + dynamicAttrs.size());
|
||||||
Env *dynamicEnv = &env;
|
Env * dynamicEnv = &env;
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
/* Create a new environment that contains the attributes in
|
/* Create a new environment that contains the attributes in
|
||||||
this `rec'. */
|
this `rec'. */
|
||||||
Env & env2(state.allocEnv(attrs.size()));
|
auto env2 = state.allocEnv(attrs.size());
|
||||||
env2.up = &env;
|
env2->up = &env;
|
||||||
dynamicEnv = &env2;
|
dynamicEnv = &*env2;
|
||||||
|
|
||||||
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
|
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
|
||||||
bool hasOverrides = overrides != attrs.end();
|
bool hasOverrides = overrides != attrs.end();
|
||||||
|
|
@ -798,13 +804,13 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
in the original environment. */
|
in the original environment. */
|
||||||
size_t displ = 0;
|
size_t displ = 0;
|
||||||
for (auto & i : attrs) {
|
for (auto & i : attrs) {
|
||||||
Value * vAttr;
|
Ptr<Value> vAttr; // FIXME: Ptr unnecessary?
|
||||||
if (hasOverrides && !i.second.inherited) {
|
if (hasOverrides && !i.second.inherited) {
|
||||||
vAttr = state.allocValue();
|
vAttr = state.allocValue(); // FIXME
|
||||||
mkThunk(*vAttr, env2, i.second.e);
|
mkThunk(*vAttr, env2, i.second.e);
|
||||||
} else
|
} else
|
||||||
vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
||||||
env2.values[displ++] = vAttr;
|
env2->values[displ++] = vAttr;
|
||||||
v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos));
|
v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -826,7 +832,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
AttrDefs::iterator j = attrs.find(i.name);
|
AttrDefs::iterator j = attrs.find(i.name);
|
||||||
if (j != attrs.end()) {
|
if (j != attrs.end()) {
|
||||||
(*newBnds)[j->second.displ] = i;
|
(*newBnds)[j->second.displ] = i;
|
||||||
env2.values[j->second.displ] = i.value;
|
env2->values[j->second.displ] = i.value;
|
||||||
} else
|
} else
|
||||||
newBnds->push_back(i);
|
newBnds->push_back(i);
|
||||||
}
|
}
|
||||||
|
|
@ -841,13 +847,13 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
/* Dynamic attrs apply *after* rec and __overrides. */
|
/* Dynamic attrs apply *after* rec and __overrides. */
|
||||||
for (auto & i : dynamicAttrs) {
|
for (auto & i : dynamicAttrs) {
|
||||||
Value nameVal;
|
Root<Value> nameVal;
|
||||||
i.nameExpr->eval(state, *dynamicEnv, nameVal);
|
i.nameExpr->eval(state, *dynamicEnv, nameVal);
|
||||||
state.forceValue(nameVal, i.pos);
|
state.forceValue(nameVal, i.pos);
|
||||||
if (nameVal.type == tNull)
|
if (nameVal->type == tNull)
|
||||||
continue;
|
continue;
|
||||||
state.forceStringNoCtx(nameVal);
|
state.forceStringNoCtx(nameVal);
|
||||||
Symbol nameSym = state.symbols.create(nameVal.string.s);
|
Symbol nameSym = state.symbols.create(nameVal->string.s);
|
||||||
Bindings::iterator j = v.attrs->find(nameSym);
|
Bindings::iterator j = v.attrs->find(nameSym);
|
||||||
if (j != v.attrs->end())
|
if (j != v.attrs->end())
|
||||||
throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
|
throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
|
||||||
|
|
@ -864,15 +870,15 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
/* Create a new environment that contains the attributes in this
|
/* Create a new environment that contains the attributes in this
|
||||||
`let'. */
|
`let'. */
|
||||||
Env & env2(state.allocEnv(attrs->attrs.size()));
|
auto env2 = state.allocEnv(attrs->attrs.size());
|
||||||
env2.up = &env;
|
env2->up = &env;
|
||||||
|
|
||||||
/* The recursive attributes are evaluated in the new environment,
|
/* The recursive attributes are evaluated in the new environment,
|
||||||
while the inherited attributes are evaluated in the original
|
while the inherited attributes are evaluated in the original
|
||||||
environment. */
|
environment. */
|
||||||
size_t displ = 0;
|
size_t displ = 0;
|
||||||
for (auto & i : attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
env2->values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
body->eval(state, env2, v);
|
||||||
}
|
}
|
||||||
|
|
@ -915,9 +921,9 @@ unsigned long nrLookups = 0;
|
||||||
|
|
||||||
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value vTmp;
|
Root<Value> vTmp;
|
||||||
Pos * pos2 = 0;
|
Pos * pos2 = 0;
|
||||||
Value * vAttrs = &vTmp;
|
Value * vAttrs = &*vTmp;
|
||||||
|
|
||||||
e->eval(state, env, vTmp);
|
e->eval(state, env, vTmp);
|
||||||
|
|
||||||
|
|
@ -960,8 +966,8 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value vTmp;
|
Root<Value> vTmp;
|
||||||
Value * vAttrs = &vTmp;
|
Value * vAttrs = &*vTmp;
|
||||||
|
|
||||||
e->eval(state, env, vTmp);
|
e->eval(state, env, vTmp);
|
||||||
|
|
||||||
|
|
@ -994,7 +1000,7 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprApp::eval(EvalState & state, Env & env, Value & v)
|
void ExprApp::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
/* FIXME: vFun prevents GCC from doing tail call optimisation. */
|
/* FIXME: vFun prevents GCC from doing tail call optimisation. */
|
||||||
Value vFun;
|
Root<Value> vFun;
|
||||||
e1->eval(state, env, vFun);
|
e1->eval(state, env, vFun);
|
||||||
state.callFunction(vFun, *(e2->maybeThunk(state, env)), v, pos);
|
state.callFunction(vFun, *(e2->maybeThunk(state, env)), v, pos);
|
||||||
}
|
}
|
||||||
|
|
@ -1028,11 +1034,11 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
|
||||||
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
||||||
primOp->primOp->fun(*this, pos, vArgs, v);
|
primOp->primOp->fun(*this, pos, vArgs, v);
|
||||||
} else {
|
} else {
|
||||||
Value * fun2 = allocValue();
|
auto fun2 = allocValue();
|
||||||
*fun2 = fun;
|
*fun2 = fun;
|
||||||
v.type = tPrimOpApp;
|
|
||||||
v.app.left = fun2;
|
v.app.left = fun2;
|
||||||
v.app.right = &arg;
|
v.app.right = &arg;
|
||||||
|
v.type = tPrimOpApp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1053,10 +1059,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
||||||
* but for functors we may keep a reference, so heap-allocate
|
* but for functors we may keep a reference, so heap-allocate
|
||||||
* a copy and use that instead.
|
* a copy and use that instead.
|
||||||
*/
|
*/
|
||||||
auto & fun2 = *allocValue();
|
auto fun2 = allocValue();
|
||||||
fun2 = fun;
|
*fun2 = fun;
|
||||||
/* !!! Should we use the attr pos here? */
|
/* !!! Should we use the attr pos here? */
|
||||||
Value v2;
|
Root<Value> v2;
|
||||||
callFunction(*found->value, fun2, v2, pos);
|
callFunction(*found->value, fun2, v2, pos);
|
||||||
return callFunction(v2, arg, v, pos);
|
return callFunction(v2, arg, v, pos);
|
||||||
}
|
}
|
||||||
|
|
@ -1070,19 +1076,19 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
||||||
auto size =
|
auto size =
|
||||||
(lambda.arg.empty() ? 0 : 1) +
|
(lambda.arg.empty() ? 0 : 1) +
|
||||||
(lambda.matchAttrs ? lambda.formals->formals.size() : 0);
|
(lambda.matchAttrs ? lambda.formals->formals.size() : 0);
|
||||||
Env & env2(allocEnv(size));
|
auto env2 = allocEnv(size);
|
||||||
env2.up = fun.lambda.env;
|
env2->up = fun.lambda.env;
|
||||||
|
|
||||||
size_t displ = 0;
|
size_t displ = 0;
|
||||||
|
|
||||||
if (!lambda.matchAttrs)
|
if (!lambda.matchAttrs)
|
||||||
env2.values[displ++] = &arg;
|
env2->values[displ++] = &arg;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
forceAttrs(arg, pos);
|
forceAttrs(arg, pos);
|
||||||
|
|
||||||
if (!lambda.arg.empty())
|
if (!lambda.arg.empty())
|
||||||
env2.values[displ++] = &arg;
|
env2->values[displ++] = &arg;
|
||||||
|
|
||||||
/* For each formal argument, get the actual argument. If
|
/* For each formal argument, get the actual argument. If
|
||||||
there is no matching actual argument but the formal
|
there is no matching actual argument but the formal
|
||||||
|
|
@ -1093,10 +1099,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!i.def) throwTypeError("%1% called without required argument '%2%', at %3%",
|
if (!i.def) throwTypeError("%1% called without required argument '%2%', at %3%",
|
||||||
lambda, i.name, pos);
|
lambda, i.name, pos);
|
||||||
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
env2->values[displ++] = i.def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
env2.values[displ++] = j->value;
|
env2->values[displ++] = j->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1144,7 +1150,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
if (fun.type == tAttrs) {
|
if (fun.type == tAttrs) {
|
||||||
auto found = fun.attrs->find(sFunctor);
|
auto found = fun.attrs->find(sFunctor);
|
||||||
if (found != fun.attrs->end()) {
|
if (found != fun.attrs->end()) {
|
||||||
Value * v = allocValue();
|
auto v = allocValue();
|
||||||
callFunction(*found->value, fun, *v, noPos);
|
callFunction(*found->value, fun, *v, noPos);
|
||||||
forceValue(*v);
|
forceValue(*v);
|
||||||
return autoCallFunction(args, *v, res);
|
return autoCallFunction(args, *v, res);
|
||||||
|
|
@ -1156,7 +1162,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * actualArgs = allocValue();
|
auto actualArgs = allocValue();
|
||||||
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
||||||
|
|
||||||
for (auto & i : fun.lambda.fun->formals->formals) {
|
for (auto & i : fun.lambda.fun->formals->formals) {
|
||||||
|
|
@ -1175,11 +1181,11 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
|
|
||||||
void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Env & env2(state.allocEnv(1));
|
auto env2 = state.allocEnv(1);
|
||||||
env2.up = &env;
|
env2->up = &env;
|
||||||
env2.prevWith = prevWith;
|
env2->prevWith = prevWith;
|
||||||
env2.type = Env::HasWithExpr;
|
env2->type = Env::HasWithExpr;
|
||||||
env2.values[0] = (Value *) attrs;
|
env2->values[0] = (Value *) attrs;
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
body->eval(state, env2, v);
|
||||||
}
|
}
|
||||||
|
|
@ -1207,16 +1213,16 @@ void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Root<Value> v1; e1->eval(state, env, v1);
|
||||||
Value v2; e2->eval(state, env, v2);
|
Root<Value> v2; e2->eval(state, env, v2);
|
||||||
mkBool(v, state.eqValues(v1, v2));
|
mkBool(v, state.eqValues(v1, v2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Root<Value> v1; e1->eval(state, env, v1);
|
||||||
Value v2; e2->eval(state, env, v2);
|
Root<Value> v2; e2->eval(state, env, v2);
|
||||||
mkBool(v, !state.eqValues(v1, v2));
|
mkBool(v, !state.eqValues(v1, v2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1241,23 +1247,24 @@ void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1, v2;
|
Root<Value> v1;
|
||||||
|
Root<Value> v2;
|
||||||
state.evalAttrs(env, e1, v1);
|
state.evalAttrs(env, e1, v1);
|
||||||
state.evalAttrs(env, e2, v2);
|
state.evalAttrs(env, e2, v2);
|
||||||
|
|
||||||
state.nrOpUpdates++;
|
state.nrOpUpdates++;
|
||||||
|
|
||||||
if (v1.attrs->size() == 0) { v = v2; return; }
|
if (v1->attrs->size() == 0) { v = *v2; return; }
|
||||||
if (v2.attrs->size() == 0) { v = v1; return; }
|
if (v2->attrs->size() == 0) { v = *v1; return; }
|
||||||
|
|
||||||
state.mkAttrs(v, v1.attrs->size() + v2.attrs->size());
|
state.mkAttrs(v, v1->attrs->size() + v2->attrs->size());
|
||||||
|
|
||||||
/* Merge the sets, preferring values from the second set. Make
|
/* Merge the sets, preferring values from the second set. Make
|
||||||
sure to keep the resulting vector in sorted order. */
|
sure to keep the resulting vector in sorted order. */
|
||||||
Bindings::iterator i = v1.attrs->begin();
|
Bindings::iterator i = v1->attrs->begin();
|
||||||
Bindings::iterator j = v2.attrs->begin();
|
Bindings::iterator j = v2->attrs->begin();
|
||||||
|
|
||||||
while (i != v1.attrs->end() && j != v2.attrs->end()) {
|
while (i != v1->attrs->end() && j != v2->attrs->end()) {
|
||||||
if (i->name == j->name) {
|
if (i->name == j->name) {
|
||||||
v.attrs->push_back(*j);
|
v.attrs->push_back(*j);
|
||||||
++i; ++j;
|
++i; ++j;
|
||||||
|
|
@ -1268,8 +1275,8 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
v.attrs->push_back(*j++);
|
v.attrs->push_back(*j++);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i != v1.attrs->end()) v.attrs->push_back(*i++);
|
while (i != v1->attrs->end()) v.attrs->push_back(*i++);
|
||||||
while (j != v2.attrs->end()) v.attrs->push_back(*j++);
|
while (j != v2->attrs->end()) v.attrs->push_back(*j++);
|
||||||
|
|
||||||
state.nrOpUpdateValuesCopied += v.attrs->size();
|
state.nrOpUpdateValuesCopied += v.attrs->size();
|
||||||
}
|
}
|
||||||
|
|
@ -1277,9 +1284,9 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Root<Value> v1; e1->eval(state, env, v1);
|
||||||
Value v2; e2->eval(state, env, v2);
|
Root<Value> v2; e2->eval(state, env, v2);
|
||||||
Value * lists[2] = { &v1, &v2 };
|
Value * lists[2] = { &*v1, &*v2 };
|
||||||
state.concatLists(v, 2, lists, pos);
|
state.concatLists(v, 2, lists, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1324,7 +1331,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
Tag firstType = tString;
|
Tag firstType = tString;
|
||||||
|
|
||||||
for (auto & i : *es) {
|
for (auto & i : *es) {
|
||||||
Value vTmp;
|
Root<Value> vTmp;
|
||||||
i->eval(state, env, vTmp);
|
i->eval(state, env, vTmp);
|
||||||
|
|
||||||
/* If the first element is a path, then the result will also
|
/* If the first element is a path, then the result will also
|
||||||
|
|
@ -1332,25 +1339,25 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
since paths are copied when they are used in a derivation),
|
since paths are copied when they are used in a derivation),
|
||||||
and none of the strings are allowed to have contexts. */
|
and none of the strings are allowed to have contexts. */
|
||||||
if (first) {
|
if (first) {
|
||||||
firstType = vTmp.type;
|
firstType = vTmp->type;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstType == tInt) {
|
if (firstType == tInt) {
|
||||||
if (vTmp.type == tInt) {
|
if (vTmp->type == tInt) {
|
||||||
n += vTmp.integer;
|
n += vTmp->integer;
|
||||||
} else if (vTmp.type == tFloat) {
|
} else if (vTmp->type == tFloat) {
|
||||||
// Upgrade the type from int to float;
|
// Upgrade the type from int to float;
|
||||||
firstType = tFloat;
|
firstType = tFloat;
|
||||||
nf = n;
|
nf = n;
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp->fpoint;
|
||||||
} else
|
} else
|
||||||
throwEvalError("cannot add %1% to an integer, at %2%", showType(vTmp), pos);
|
throwEvalError("cannot add %1% to an integer, at %2%", showType(vTmp), pos);
|
||||||
} else if (firstType == tFloat) {
|
} else if (firstType == tFloat) {
|
||||||
if (vTmp.type == tInt) {
|
if (vTmp->type == tInt) {
|
||||||
nf += vTmp.integer;
|
nf += vTmp->integer;
|
||||||
} else if (vTmp.type == tFloat) {
|
} else if (vTmp->type == tFloat) {
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp->fpoint;
|
||||||
} else
|
} else
|
||||||
throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos);
|
throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos);
|
||||||
} else
|
} else
|
||||||
|
|
@ -1527,7 +1534,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
if (v.type == tAttrs) {
|
if (v.type == tAttrs) {
|
||||||
auto i = v.attrs->find(sToString);
|
auto i = v.attrs->find(sToString);
|
||||||
if (i != v.attrs->end()) {
|
if (i != v.attrs->end()) {
|
||||||
Value v1;
|
Root<Value> v1;
|
||||||
callFunction(*i->value, v, v1, pos);
|
callFunction(*i->value, v, v1, pos);
|
||||||
return coerceToString(pos, v1, context, coerceMore, copyToStore);
|
return coerceToString(pos, v1, context, coerceMore, copyToStore);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,16 @@ struct Env : Object
|
||||||
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2; // FIXME: fold into type?
|
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2; // FIXME: fold into type?
|
||||||
Value * values[0];
|
Value * values[0];
|
||||||
|
|
||||||
Env(unsigned short size) : Object(tEnv, 0), size(size) {}
|
private:
|
||||||
|
|
||||||
|
Env(unsigned short size) : Object(tEnv, 0), size(size) {
|
||||||
|
for (auto i = 0; i < size; i++)
|
||||||
|
values[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class GC;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
Size words() const
|
Size words() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ GC::GC()
|
||||||
|
|
||||||
backSentinel->prev = frontSentinel;
|
backSentinel->prev = frontSentinel;
|
||||||
backSentinel->next = nullptr;
|
backSentinel->next = nullptr;
|
||||||
|
|
||||||
|
frontRootSentinel = (Root<Object> *) malloc(sizeof(Root<Object>));
|
||||||
|
backRootSentinel = (Root<Object> *) malloc(sizeof(Root<Object>));
|
||||||
|
|
||||||
|
frontRootSentinel->prev = nullptr;
|
||||||
|
frontRootSentinel->next = backRootSentinel;
|
||||||
|
|
||||||
|
backRootSentinel->prev = frontRootSentinel;
|
||||||
|
backRootSentinel->next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GC::~GC()
|
GC::~GC()
|
||||||
|
|
@ -26,9 +35,18 @@ GC::~GC()
|
||||||
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next)
|
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next)
|
||||||
n++;
|
n++;
|
||||||
if (n)
|
if (n)
|
||||||
warn("%d GC roots still exist on exit", n);
|
warn("%d GC root pointers still exist on exit", n);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for (Root<Object> * p = frontRootSentinel->next; p != backRootSentinel; p = p->next)
|
||||||
|
n++;
|
||||||
|
if (n)
|
||||||
|
warn("%d GC root objects still exist on exit", n);
|
||||||
|
|
||||||
assert(!frontSentinel->prev);
|
assert(!frontSentinel->prev);
|
||||||
assert(!backSentinel->next);
|
assert(!backSentinel->next);
|
||||||
|
assert(!frontRootSentinel->prev);
|
||||||
|
assert(!backRootSentinel->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC::gc()
|
void GC::gc()
|
||||||
|
|
@ -37,23 +55,10 @@ void GC::gc()
|
||||||
|
|
||||||
std::stack<Object *> stack;
|
std::stack<Object *> stack;
|
||||||
|
|
||||||
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next) {
|
|
||||||
if (!p->value) continue;
|
|
||||||
|
|
||||||
stack.push(p->value);
|
|
||||||
|
|
||||||
while (!stack.empty()) {
|
|
||||||
auto obj = stack.top();
|
|
||||||
stack.pop();
|
|
||||||
|
|
||||||
// FIXME: ensure this gets inlined.
|
// FIXME: ensure this gets inlined.
|
||||||
auto push = [&](Object * p) { if (p) { /* FIXME */ assert(isObject(p)); stack.push(p); } };
|
auto push = [&](Object * p) { if (p) { assertObject(p); stack.push(p); } };
|
||||||
|
|
||||||
//printError("MARK %x", obj);
|
auto pushPointers = [&](Object * obj) {
|
||||||
|
|
||||||
if (!obj->isMarked()) {
|
|
||||||
marked++;
|
|
||||||
obj->mark();
|
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
|
|
||||||
case tFree:
|
case tFree:
|
||||||
|
|
@ -116,6 +121,7 @@ void GC::gc()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tThunk:
|
case tThunk:
|
||||||
|
case tBlackhole:
|
||||||
push(((Value *) obj)->thunk.env);
|
push(((Value *) obj)->thunk.env);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -129,10 +135,6 @@ void GC::gc()
|
||||||
push(((Value *) obj)->lambda.env);
|
push(((Value *) obj)->lambda.env);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tBlackhole:
|
|
||||||
// FIXME
|
|
||||||
break;
|
|
||||||
|
|
||||||
case tPrimOp:
|
case tPrimOp:
|
||||||
// FIXME: GC primops?
|
// FIXME: GC primops?
|
||||||
break;
|
break;
|
||||||
|
|
@ -141,8 +143,32 @@ void GC::gc()
|
||||||
printError("don't know how to traverse object at %x (tag %d)", obj, obj->type);
|
printError("don't know how to traverse object at %x (tag %d)", obj, obj->type);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto processStack = [&]() {
|
||||||
|
while (!stack.empty()) {
|
||||||
|
auto obj = stack.top();
|
||||||
|
stack.pop();
|
||||||
|
|
||||||
|
//printError("MARK %x", obj);
|
||||||
|
|
||||||
|
if (!obj->isMarked()) {
|
||||||
|
marked++;
|
||||||
|
obj->mark();
|
||||||
|
pushPointers(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Root<Object> * p = frontRootSentinel->next; p != backRootSentinel; p = p->next) {
|
||||||
|
pushPointers(&p->value);
|
||||||
|
processStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next) {
|
||||||
|
if (!p->value) continue;
|
||||||
|
stack.push(p->value);
|
||||||
|
processStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
Size totalObjectsFreed = 0;
|
Size totalObjectsFreed = 0;
|
||||||
|
|
@ -162,7 +188,7 @@ void GC::gc()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
printError("freed %d bytes in %d dead objects, keeping %d objects",
|
debug("freed %d bytes in %d dead objects, keeping %d objects",
|
||||||
totalWordsFreed * WORD_SIZE, totalObjectsFreed, marked);
|
totalWordsFreed * WORD_SIZE, totalObjectsFreed, marked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,6 +250,7 @@ std::pair<Size, Size> GC::Arena::freeUnmarked()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (tag == tFree) {
|
if (tag == tFree) {
|
||||||
|
//debug("FREE %x %d", obj, obj->getMisc());
|
||||||
if (curFree) {
|
if (curFree) {
|
||||||
// Merge this object into the previous free
|
// Merge this object into the previous free
|
||||||
// object.
|
// object.
|
||||||
|
|
@ -239,10 +266,13 @@ std::pair<Size, Size> GC::Arena::freeUnmarked()
|
||||||
|
|
||||||
if (obj->isMarked()) {
|
if (obj->isMarked()) {
|
||||||
// Unmark to prepare for the next GC run.
|
// Unmark to prepare for the next GC run.
|
||||||
|
//debug("KEEP OBJECT %x %d %d", obj, obj->type, objSize);
|
||||||
curFree = nullptr;
|
curFree = nullptr;
|
||||||
obj->unmark();
|
obj->unmark();
|
||||||
} else {
|
} else {
|
||||||
//printError("FREE %x %d %d", obj, obj->type, objSize);
|
//debug("FREE OBJECT %x %d %d", obj, obj->type, objSize);
|
||||||
|
for (Size i = 0; i < objSize; ++i)
|
||||||
|
((Word *) obj)[i] = 0xdeadc0dedeadbeefULL;
|
||||||
objectsFreed += 1;
|
objectsFreed += 1;
|
||||||
wordsFreed += objSize;
|
wordsFreed += objSize;
|
||||||
if (curFree) {
|
if (curFree) {
|
||||||
|
|
@ -279,9 +309,18 @@ bool GC::isObject(void * p)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GC::ArenaList::ArenaList()
|
void GC::assertObject(void * p)
|
||||||
: nextSize(1024)
|
|
||||||
{
|
{
|
||||||
|
if (!isObject(p)) {
|
||||||
|
printError("object %p is not an object", p);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::ArenaList::ArenaList()
|
||||||
|
{
|
||||||
|
static Size initialHeapSize = std::stol(getEnv("GC_INITIAL_HEAP_SIZE", "1000000")) / WORD_SIZE;
|
||||||
|
nextSize = initialHeapSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,94 +104,6 @@ struct PtrList : Object
|
||||||
static Size wordsFor(Size size) { return 1 + size; }
|
static Size wordsFor(Size size) { return 1 + size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct Ptr
|
|
||||||
{
|
|
||||||
Ptr * prev = nullptr, * next = nullptr;
|
|
||||||
T * value = nullptr;
|
|
||||||
|
|
||||||
Ptr() { }
|
|
||||||
|
|
||||||
Ptr(Ptr * next, T * value) : next(next), value(value)
|
|
||||||
{
|
|
||||||
assert(value);
|
|
||||||
assert(next == next->prev->next);
|
|
||||||
prev = next->prev;
|
|
||||||
next->prev = this;
|
|
||||||
prev->next = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr(const Ptr & p)
|
|
||||||
{
|
|
||||||
if (p.value) {
|
|
||||||
auto & p2 = const_cast<Ptr &>(p);
|
|
||||||
value = p2.value;
|
|
||||||
next = &p2;
|
|
||||||
prev = p2.prev;
|
|
||||||
prev->next = this;
|
|
||||||
p2.prev = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr(Ptr && p)
|
|
||||||
{
|
|
||||||
*this = std::move(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr & operator =(Ptr && p)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
if (p.value) {
|
|
||||||
value = p.value;
|
|
||||||
next = p.next;
|
|
||||||
prev = p.prev;
|
|
||||||
p.value = nullptr;
|
|
||||||
prev->next = this;
|
|
||||||
next->prev = this;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr & operator =(const Ptr & p)
|
|
||||||
{
|
|
||||||
throw Error("NOT IMPLEMENTED = PTR &");
|
|
||||||
}
|
|
||||||
|
|
||||||
~Ptr()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
if (value) {
|
|
||||||
assert(next);
|
|
||||||
assert(prev);
|
|
||||||
assert(next->prev == this);
|
|
||||||
next->prev = prev;
|
|
||||||
assert(prev->next == this);
|
|
||||||
prev->next = next;
|
|
||||||
value = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T * operator ->()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator T * ()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator T & ()
|
|
||||||
{
|
|
||||||
assert(value);
|
|
||||||
return *value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Free : Object
|
struct Free : Object
|
||||||
{
|
{
|
||||||
Free * next;
|
Free * next;
|
||||||
|
|
@ -204,6 +116,12 @@ struct Free : Object
|
||||||
void setSize(Size size) { assert(size >= 1); setMisc(size); }
|
void setSize(Size size) { assert(size >= 1); setMisc(size); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Ptr;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Root;
|
||||||
|
|
||||||
struct GC
|
struct GC
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -212,6 +130,15 @@ private:
|
||||||
Ptr<Object> * frontSentinel;
|
Ptr<Object> * frontSentinel;
|
||||||
Ptr<Object> * backSentinel;
|
Ptr<Object> * backSentinel;
|
||||||
|
|
||||||
|
Root<Object> * frontRootSentinel;
|
||||||
|
Root<Object> * backRootSentinel;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
friend class Ptr;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
friend class Root;
|
||||||
|
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
Size size; // in words
|
Size size; // in words
|
||||||
|
|
@ -317,18 +244,17 @@ public:
|
||||||
auto raw = arena.alloc(size);
|
auto raw = arena.alloc(size);
|
||||||
if (raw) {
|
if (raw) {
|
||||||
auto obj = new (raw) T(args...);
|
auto obj = new (raw) T(args...);
|
||||||
//printError("ALLOC %x", obj);
|
return obj;
|
||||||
return Ptr<T>((Ptr<T> *) frontSentinel->next, obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
printError("allocation of %d bytes failed, GCing...", size * WORD_SIZE);
|
debug("allocation of %d bytes failed, GCing...", size * WORD_SIZE);
|
||||||
gc();
|
gc();
|
||||||
} else {
|
} else {
|
||||||
Size arenaSize = std::max(arenaList.nextSize, size);
|
Size arenaSize = std::max(arenaList.nextSize, size);
|
||||||
arenaList.nextSize = arenaSize * 2; // FIXME: overflow
|
arenaList.nextSize = arenaSize * 1.5; // FIXME: overflow
|
||||||
printError("allocating arena of %d bytes", arenaSize * WORD_SIZE);
|
debug("allocating arena of %d bytes", arenaSize * WORD_SIZE);
|
||||||
arenaList.arenas.emplace_back(arenaSize);
|
arenaList.arenas.emplace_back(arenaSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -339,8 +265,159 @@ public:
|
||||||
void gc();
|
void gc();
|
||||||
|
|
||||||
bool isObject(void * p);
|
bool isObject(void * p);
|
||||||
|
|
||||||
|
void assertObject(void * p);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GC gc;
|
extern GC gc;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Ptr
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
friend class GC;
|
||||||
|
|
||||||
|
Ptr * prev = nullptr, * next = nullptr;
|
||||||
|
T * value = nullptr;
|
||||||
|
|
||||||
|
void link()
|
||||||
|
{
|
||||||
|
prev = (Ptr *) gc.frontSentinel;
|
||||||
|
next = prev->next;
|
||||||
|
next->prev = this;
|
||||||
|
prev->next = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Ptr() {
|
||||||
|
link();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr(T * value) : value(value)
|
||||||
|
{
|
||||||
|
link();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr(const Ptr & p)
|
||||||
|
{
|
||||||
|
auto & p2 = const_cast<Ptr &>(p);
|
||||||
|
value = p2.value;
|
||||||
|
next = &p2;
|
||||||
|
prev = p2.prev;
|
||||||
|
prev->next = this;
|
||||||
|
p2.prev = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr(Ptr && p)
|
||||||
|
{
|
||||||
|
link();
|
||||||
|
value = p.value;
|
||||||
|
p.value = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr & operator =(const Ptr & p)
|
||||||
|
{
|
||||||
|
value = p.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr & operator =(Ptr && p)
|
||||||
|
{
|
||||||
|
value = p.value;
|
||||||
|
p.value = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr & operator =(T * v)
|
||||||
|
{
|
||||||
|
value = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Ptr()
|
||||||
|
{
|
||||||
|
assert(next);
|
||||||
|
assert(prev);
|
||||||
|
assert(next->prev == this);
|
||||||
|
next->prev = prev;
|
||||||
|
assert(prev->next == this);
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator ->()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator ->() const // FIXME
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T * ()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T & ()
|
||||||
|
{
|
||||||
|
assert(value);
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return value != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Root
|
||||||
|
{
|
||||||
|
Root * prev = nullptr, * next = nullptr;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
Root(const Args & ... args)
|
||||||
|
: value{args... }
|
||||||
|
{
|
||||||
|
prev = (Root *) gc.frontRootSentinel;
|
||||||
|
next = prev->next;
|
||||||
|
next->prev = this;
|
||||||
|
prev->next = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Root(const Root & p) = delete;
|
||||||
|
Root(Root && p) = delete;
|
||||||
|
|
||||||
|
Root & operator =(const T & v) { value = v; return *this; }
|
||||||
|
|
||||||
|
~Root()
|
||||||
|
{
|
||||||
|
assert(next);
|
||||||
|
assert(prev);
|
||||||
|
assert(next->prev == this);
|
||||||
|
next->prev = prev;
|
||||||
|
assert(prev->next == this);
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator ->()
|
||||||
|
{
|
||||||
|
return &value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T * ()
|
||||||
|
{
|
||||||
|
return &value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T & ()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
||||||
return outputs;
|
return outputs;
|
||||||
|
|
||||||
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
||||||
const Value * outTI = queryMeta("outputsToInstall");
|
const auto outTI = queryMeta("outputsToInstall");
|
||||||
if (!outTI) return outputs;
|
if (!outTI) return outputs;
|
||||||
const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
||||||
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
||||||
|
|
@ -194,7 +194,7 @@ Value * DrvInfo::queryMeta(const string & name)
|
||||||
|
|
||||||
string DrvInfo::queryMetaString(const string & name)
|
string DrvInfo::queryMetaString(const string & name)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v || v->type != tString) return "";
|
if (!v || v->type != tString) return "";
|
||||||
return v->string.s;
|
return v->string.s;
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +202,7 @@ string DrvInfo::queryMetaString(const string & name)
|
||||||
|
|
||||||
NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
|
NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tInt) return v->integer;
|
if (v->type == tInt) return v->integer;
|
||||||
if (v->type == tString) {
|
if (v->type == tString) {
|
||||||
|
|
@ -216,7 +216,7 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
|
||||||
|
|
||||||
NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
|
NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tFloat) return v->fpoint;
|
if (v->type == tFloat) return v->fpoint;
|
||||||
if (v->type == tString) {
|
if (v->type == tString) {
|
||||||
|
|
@ -231,7 +231,7 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
|
||||||
|
|
||||||
bool DrvInfo::queryMetaBool(const string & name, bool def)
|
bool DrvInfo::queryMetaBool(const string & name, bool def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tBool) return v->boolean;
|
if (v->type == tBool) return v->boolean;
|
||||||
if (v->type == tString) {
|
if (v->type == tString) {
|
||||||
|
|
@ -247,7 +247,7 @@ bool DrvInfo::queryMetaBool(const string & name, bool def)
|
||||||
void DrvInfo::setMeta(const string & name, Value * v)
|
void DrvInfo::setMeta(const string & name, Value * v)
|
||||||
{
|
{
|
||||||
getMeta();
|
getMeta();
|
||||||
Bindings * old = meta;
|
Ptr<Bindings> old = meta;
|
||||||
meta = Bindings::allocBindings(1 + (old ? old->size() : 0));
|
meta = Bindings::allocBindings(1 + (old ? old->size() : 0));
|
||||||
Symbol sym = state->symbols.create(name);
|
Symbol sym = state->symbols.create(name);
|
||||||
if (old)
|
if (old)
|
||||||
|
|
@ -260,6 +260,7 @@ void DrvInfo::setMeta(const string & name, Value * v)
|
||||||
|
|
||||||
|
|
||||||
/* Cache for already considered attrsets. */
|
/* Cache for already considered attrsets. */
|
||||||
|
// FIXME: Use Ptr?
|
||||||
typedef set<Bindings *> Done;
|
typedef set<Bindings *> Done;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -320,24 +321,24 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
DrvInfos & drvs, Done & done,
|
DrvInfos & drvs, Done & done,
|
||||||
bool ignoreAssertionFailures)
|
bool ignoreAssertionFailures)
|
||||||
{
|
{
|
||||||
Value v;
|
Root<Value> v;
|
||||||
state.autoCallFunction(autoArgs, vIn, v);
|
state.autoCallFunction(autoArgs, vIn, v);
|
||||||
|
|
||||||
/* Process the expression. */
|
/* Process the expression. */
|
||||||
if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ;
|
if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ;
|
||||||
|
|
||||||
else if (v.type == tAttrs) {
|
else if (v->type == tAttrs) {
|
||||||
|
|
||||||
/* !!! undocumented hackery to support combining channels in
|
/* !!! undocumented hackery to support combining channels in
|
||||||
nix-env.cc. */
|
nix-env.cc. */
|
||||||
bool combineChannels = v.attrs->find(state.symbols.create("_combineChannels")) != v.attrs->end();
|
bool combineChannels = v->attrs->find(state.symbols.create("_combineChannels")) != v->attrs->end();
|
||||||
|
|
||||||
/* Consider the attributes in sorted order to get more
|
/* Consider the attributes in sorted order to get more
|
||||||
deterministic behaviour in nix-env operations (e.g. when
|
deterministic behaviour in nix-env operations (e.g. when
|
||||||
there are names clashes between derivations, the derivation
|
there are names clashes between derivations, the derivation
|
||||||
bound to the attribute with the "lower" name should take
|
bound to the attribute with the "lower" name should take
|
||||||
precedence). */
|
precedence). */
|
||||||
for (auto & i : v.attrs->lexicographicOrder()) {
|
for (auto & i : v->attrs->lexicographicOrder()) {
|
||||||
debug("evaluating attribute '%1%'", i->name);
|
debug("evaluating attribute '%1%'", i->name);
|
||||||
if (!std::regex_match(std::string(i->name), attrRegex))
|
if (!std::regex_match(std::string(i->name), attrRegex))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -357,11 +358,11 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (v.isList()) {
|
else if (v->isList()) {
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
for (unsigned int n = 0; n < v->listSize(); ++n) {
|
||||||
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
||||||
if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
if (getDerivation(state, *v->listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
||||||
getDerivations(state, *v.listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
getDerivations(state, *v->listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ private:
|
||||||
|
|
||||||
bool failed = false; // set if we get an AssertionError
|
bool failed = false; // set if we get an AssertionError
|
||||||
|
|
||||||
Bindings * attrs = nullptr, * meta = nullptr;
|
Ptr<Bindings> attrs;
|
||||||
|
Ptr<Bindings> meta;
|
||||||
|
|
||||||
Bindings * getMeta();
|
Bindings * getMeta();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ struct Expr
|
||||||
virtual void show(std::ostream & str) const;
|
virtual void show(std::ostream & str) const;
|
||||||
virtual void bindVars(const StaticEnv & env);
|
virtual void bindVars(const StaticEnv & env);
|
||||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||||
virtual Value * maybeThunk(EvalState & state, Env & env);
|
virtual Ptr<Value> maybeThunk(EvalState & state, Env & env);
|
||||||
virtual void setName(Symbol & name);
|
virtual void setName(Symbol & name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ struct ExprInt : Expr
|
||||||
mkInt(v, n);
|
mkInt(v, n);
|
||||||
};
|
};
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Ptr<Value> maybeThunk(EvalState & state, Env & env) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExprFloat : Expr
|
struct ExprFloat : Expr
|
||||||
|
|
@ -110,7 +110,7 @@ struct ExprFloat : Expr
|
||||||
mkFloat(v, nf);
|
mkFloat(v, nf);
|
||||||
};
|
};
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Ptr<Value> maybeThunk(EvalState & state, Env & env) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExprString : Expr
|
struct ExprString : Expr
|
||||||
|
|
@ -122,7 +122,7 @@ struct ExprString : Expr
|
||||||
mkString(v, s);
|
mkString(v, s);
|
||||||
};
|
};
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Ptr<Value> maybeThunk(EvalState & state, Env & env) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Temporary class used during parsing of indented strings. */
|
/* Temporary class used during parsing of indented strings. */
|
||||||
|
|
@ -141,7 +141,7 @@ struct ExprPath : Expr
|
||||||
mkPathNoCopy(v, this->s.c_str());
|
mkPathNoCopy(v, this->s.c_str());
|
||||||
};
|
};
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Ptr<Value> maybeThunk(EvalState & state, Env & env) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExprVar : Expr
|
struct ExprVar : Expr
|
||||||
|
|
@ -165,7 +165,7 @@ struct ExprVar : Expr
|
||||||
ExprVar(const Symbol & name) : name(name) { };
|
ExprVar(const Symbol & name) : name(name) { };
|
||||||
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
|
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Ptr<Value> maybeThunk(EvalState & state, Env & env) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExprSelect : Expr
|
struct ExprSelect : Expr
|
||||||
|
|
|
||||||
|
|
@ -102,14 +102,13 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
||||||
|
|
||||||
if (state.store->isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) {
|
if (state.store->isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) {
|
||||||
Derivation drv = readDerivation(realPath);
|
Derivation drv = readDerivation(realPath);
|
||||||
Value & w = *state.allocValue();
|
auto w = state.allocValue();
|
||||||
state.mkAttrs(w, 3 + drv.outputs.size());
|
state.mkAttrs(w, 3 + drv.outputs.size());
|
||||||
Value * v2 = state.allocAttr(w, state.sDrvPath);
|
auto v2 = state.allocAttr(w, state.sDrvPath);
|
||||||
mkString(*v2, path, {"=" + path});
|
mkString(*v2, path, {"=" + path});
|
||||||
v2 = state.allocAttr(w, state.sName);
|
v2 = state.allocAttr(w, state.sName);
|
||||||
mkString(*v2, drv.env["name"]);
|
mkString(*v2, drv.env["name"]);
|
||||||
Value * outputsVal =
|
auto outputsVal = state.allocAttr(w, state.symbols.create("outputs"));
|
||||||
state.allocAttr(w, state.symbols.create("outputs"));
|
|
||||||
state.mkList(*outputsVal, drv.outputs.size());
|
state.mkList(*outputsVal, drv.outputs.size());
|
||||||
unsigned int outputs_index = 0;
|
unsigned int outputs_index = 0;
|
||||||
|
|
||||||
|
|
@ -119,8 +118,8 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
||||||
outputsVal->listElems()[outputs_index] = state.allocValue();
|
outputsVal->listElems()[outputs_index] = state.allocValue();
|
||||||
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
||||||
}
|
}
|
||||||
w.attrs->sort();
|
w->attrs->sort();
|
||||||
Value fun;
|
Root<Value> fun;
|
||||||
state.evalFile(settings.nixDataDir + "/nix/corepkgs/imported-drv-to-derivation.nix", fun);
|
state.evalFile(settings.nixDataDir + "/nix/corepkgs/imported-drv-to-derivation.nix", fun);
|
||||||
state.forceFunction(fun, pos);
|
state.forceFunction(fun, pos);
|
||||||
mkApp(v, fun, w);
|
mkApp(v, fun, w);
|
||||||
|
|
@ -355,7 +354,6 @@ typedef list<Ptr<Value>> ValueList;
|
||||||
|
|
||||||
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
state.forceAttrs(*args[0], pos);
|
state.forceAttrs(*args[0], pos);
|
||||||
|
|
||||||
/* Get the start set. */
|
/* Get the start set. */
|
||||||
|
|
@ -381,10 +379,10 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
||||||
no new elements are found. */
|
no new elements are found. */
|
||||||
ValueList res;
|
ValueList res;
|
||||||
// `doneKeys' doesn't need to be a GC root, because its values are
|
// `doneKeys' doesn't need to be a GC root, because its values are
|
||||||
// reachable from res.
|
// reachable from res. FIXME: dubious.
|
||||||
set<Value *, CompareValues> doneKeys;
|
set<Value *, CompareValues> doneKeys;
|
||||||
while (!workSet.empty()) {
|
while (!workSet.empty()) {
|
||||||
Value * e = *(workSet.begin());
|
auto e = *(workSet.begin());
|
||||||
workSet.pop_front();
|
workSet.pop_front();
|
||||||
|
|
||||||
state.forceAttrs(*e, pos);
|
state.forceAttrs(*e, pos);
|
||||||
|
|
@ -395,19 +393,19 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
||||||
throw EvalError(format("attribute 'key' required, at %1%") % pos);
|
throw EvalError(format("attribute 'key' required, at %1%") % pos);
|
||||||
state.forceValue(*key->value);
|
state.forceValue(*key->value);
|
||||||
|
|
||||||
if (doneKeys.find(key->value) != doneKeys.end()) continue;
|
if (doneKeys.count(key->value)) continue;
|
||||||
doneKeys.insert(key->value);
|
doneKeys.insert(key->value);
|
||||||
res.push_back(e);
|
res.push_back(e);
|
||||||
|
|
||||||
/* Call the `operator' function with `e' as argument. */
|
/* Call the `operator' function with `e' as argument. */
|
||||||
Value call;
|
Root<Value> call;
|
||||||
mkApp(call, *op->value, *e);
|
mkApp(call, *op->value, *e);
|
||||||
state.forceList(call, pos);
|
state.forceList(call, pos);
|
||||||
|
|
||||||
/* Add the values returned by the operator to the work set. */
|
/* Add the values returned by the operator to the work set. */
|
||||||
for (unsigned int n = 0; n < call.listSize(); ++n) {
|
for (unsigned int n = 0; n < call->listSize(); ++n) {
|
||||||
state.forceValue(*call.listElems()[n]);
|
state.forceValue(*call->listElems()[n]);
|
||||||
workSet.push_back(call.listElems()[n]);
|
workSet.push_back(call->listElems()[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,8 +414,6 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
for (auto & i : res)
|
for (auto & i : res)
|
||||||
v.listElems()[n++] = i;
|
v.listElems()[n++] = i;
|
||||||
#endif
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -940,7 +936,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
state.mkAttrs(v, entries.size());
|
state.mkAttrs(v, entries.size());
|
||||||
|
|
||||||
for (auto & ent : entries) {
|
for (auto & ent : entries) {
|
||||||
Value * ent_val = state.allocAttr(v, state.symbols.create(ent.name));
|
auto ent_val = state.allocAttr(v, state.symbols.create(ent.name));
|
||||||
if (ent.type == DT_UNKNOWN)
|
if (ent.type == DT_UNKNOWN)
|
||||||
ent.type = getFileType(path + "/" + ent.name);
|
ent.type = getFileType(path + "/" + ent.name);
|
||||||
mkStringNoCopy(*ent_val,
|
mkStringNoCopy(*ent_val,
|
||||||
|
|
@ -1030,20 +1026,20 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
|
||||||
|
|
||||||
/* Call the filter function. The first argument is the path,
|
/* Call the filter function. The first argument is the path,
|
||||||
the second is a string indicating the type of the file. */
|
the second is a string indicating the type of the file. */
|
||||||
Value arg1;
|
auto arg1 = state.allocValue();
|
||||||
mkString(arg1, path);
|
mkString(arg1, path);
|
||||||
|
|
||||||
Value fun2;
|
Root<Value> fun2;
|
||||||
state.callFunction(*filterFun, arg1, fun2, noPos);
|
state.callFunction(*filterFun, arg1, fun2, noPos);
|
||||||
|
|
||||||
Value arg2;
|
auto arg2 = state.allocValue();
|
||||||
mkString(arg2,
|
mkString(arg2,
|
||||||
S_ISREG(st.st_mode) ? "regular" :
|
S_ISREG(st.st_mode) ? "regular" :
|
||||||
S_ISDIR(st.st_mode) ? "directory" :
|
S_ISDIR(st.st_mode) ? "directory" :
|
||||||
S_ISLNK(st.st_mode) ? "symlink" :
|
S_ISLNK(st.st_mode) ? "symlink" :
|
||||||
"unknown" /* not supported, will fail! */);
|
"unknown" /* not supported, will fail! */);
|
||||||
|
|
||||||
Value res;
|
Root<Value> res;
|
||||||
state.callFunction(fun2, arg2, res, noPos);
|
state.callFunction(fun2, arg2, res, noPos);
|
||||||
|
|
||||||
return state.forceBool(res, pos);
|
return state.forceBool(res, pos);
|
||||||
|
|
@ -1355,8 +1351,8 @@ static void prim_mapAttrs(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
state.mkAttrs(v, args[1]->attrs->size());
|
state.mkAttrs(v, args[1]->attrs->size());
|
||||||
|
|
||||||
for (auto & i : *args[1]->attrs) {
|
for (auto & i : *args[1]->attrs) {
|
||||||
Value * vName = state.allocValue();
|
auto vName = state.allocValue();
|
||||||
Value * vFun2 = state.allocValue();
|
auto vFun2 = state.allocValue();
|
||||||
mkString(*vName, i.name);
|
mkString(*vName, i.name);
|
||||||
mkApp(*vFun2, *args[0], *vName);
|
mkApp(*vFun2, *args[0], *vName);
|
||||||
mkApp(*state.allocAttr(v, i.name), *vFun2, *i.value);
|
mkApp(*state.allocAttr(v, i.name), *vFun2, *i.value);
|
||||||
|
|
@ -1443,7 +1439,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
|
|
||||||
bool same = true;
|
bool same = true;
|
||||||
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
||||||
Value res;
|
Root<Value> res;
|
||||||
state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
|
state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
|
||||||
if (state.forceBool(res, pos))
|
if (state.forceBool(res, pos))
|
||||||
vs[k++] = args[1]->listElems()[n];
|
vs[k++] = args[1]->listElems()[n];
|
||||||
|
|
@ -1498,12 +1494,12 @@ static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args,
|
||||||
state.forceList(*args[2], pos);
|
state.forceList(*args[2], pos);
|
||||||
|
|
||||||
if (args[2]->listSize()) {
|
if (args[2]->listSize()) {
|
||||||
Value * vCur = args[1];
|
Ptr<Value> vCur = args[1];
|
||||||
|
|
||||||
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
|
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
|
||||||
Value vTmp;
|
Root<Value> vTmp;
|
||||||
state.callFunction(*args[0], *vCur, vTmp, pos);
|
state.callFunction(*args[0], *vCur, vTmp, pos);
|
||||||
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
|
vCur = n == args[2]->listSize() - 1 ? Ptr(&v) : state.allocValue();
|
||||||
state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
|
state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
|
||||||
}
|
}
|
||||||
state.forceValue(v);
|
state.forceValue(v);
|
||||||
|
|
@ -1519,7 +1515,7 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg
|
||||||
state.forceFunction(*args[0], pos);
|
state.forceFunction(*args[0], pos);
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
Value vTmp;
|
Root<Value> vTmp;
|
||||||
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
||||||
state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos);
|
state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos);
|
||||||
bool res = state.forceBool(vTmp, pos);
|
bool res = state.forceBool(vTmp, pos);
|
||||||
|
|
@ -1555,7 +1551,7 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
state.mkList(v, len);
|
state.mkList(v, len);
|
||||||
|
|
||||||
for (unsigned int n = 0; n < (unsigned int) len; ++n) {
|
for (unsigned int n = 0; n < (unsigned int) len; ++n) {
|
||||||
Value * arg = state.allocValue();
|
auto arg = state.allocValue();
|
||||||
mkInt(*arg, n);
|
mkInt(*arg, n);
|
||||||
mkApp(*(v.listElems()[n] = state.allocValue()), *args[0], *arg);
|
mkApp(*(v.listElems()[n] = state.allocValue()), *args[0], *arg);
|
||||||
}
|
}
|
||||||
|
|
@ -1584,7 +1580,7 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
|
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
|
||||||
return CompareValues()(a, b);
|
return CompareValues()(a, b);
|
||||||
|
|
||||||
Value vTmp1, vTmp2;
|
Root<Value> vTmp1, vTmp2;
|
||||||
state.callFunction(*args[0], *a, vTmp1, pos);
|
state.callFunction(*args[0], *a, vTmp1, pos);
|
||||||
state.callFunction(vTmp1, *b, vTmp2, pos);
|
state.callFunction(vTmp1, *b, vTmp2, pos);
|
||||||
return state.forceBool(vTmp2, pos);
|
return state.forceBool(vTmp2, pos);
|
||||||
|
|
@ -1610,7 +1606,7 @@ static void prim_partition(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
for (unsigned int n = 0; n < len; ++n) {
|
for (unsigned int n = 0; n < len; ++n) {
|
||||||
auto vElem = args[1]->listElems()[n];
|
auto vElem = args[1]->listElems()[n];
|
||||||
state.forceValue(*vElem);
|
state.forceValue(*vElem);
|
||||||
Value res;
|
Root<Value> res;
|
||||||
state.callFunction(*args[0], *vElem, res, pos);
|
state.callFunction(*args[0], *vElem, res, pos);
|
||||||
if (state.forceBool(res, pos))
|
if (state.forceBool(res, pos))
|
||||||
right.push_back(vElem);
|
right.push_back(vElem);
|
||||||
|
|
@ -1620,13 +1616,13 @@ static void prim_partition(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
|
|
||||||
state.mkAttrs(v, 2);
|
state.mkAttrs(v, 2);
|
||||||
|
|
||||||
Value * vRight = state.allocAttr(v, state.sRight);
|
auto vRight = state.allocAttr(v, state.sRight);
|
||||||
auto rsize = right.size();
|
auto rsize = right.size();
|
||||||
state.mkList(*vRight, rsize);
|
state.mkList(*vRight, rsize);
|
||||||
if (rsize)
|
if (rsize)
|
||||||
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * rsize);
|
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * rsize);
|
||||||
|
|
||||||
Value * vWrong = state.allocAttr(v, state.sWrong);
|
auto vWrong = state.allocAttr(v, state.sWrong);
|
||||||
auto wsize = wrong.size();
|
auto wsize = wrong.size();
|
||||||
state.mkList(*vWrong, wsize);
|
state.mkList(*vWrong, wsize);
|
||||||
if (wsize)
|
if (wsize)
|
||||||
|
|
@ -1644,22 +1640,23 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
auto nrLists = args[1]->listSize();
|
auto nrLists = args[1]->listSize();
|
||||||
|
|
||||||
Value lists[nrLists];
|
// FIXME: Root<>[] is inefficient
|
||||||
|
Root<Value> lists[nrLists];
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
for (unsigned int n = 0; n < nrLists; ++n) {
|
for (unsigned int n = 0; n < nrLists; ++n) {
|
||||||
Value * vElem = args[1]->listElems()[n];
|
Value * vElem = args[1]->listElems()[n];
|
||||||
state.callFunction(*args[0], *vElem, lists[n], pos);
|
state.callFunction(*args[0], *vElem, lists[n], pos);
|
||||||
state.forceList(lists[n], pos);
|
state.forceList(lists[n], pos);
|
||||||
len += lists[n].listSize();
|
len += lists[n]->listSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkList(v, len);
|
state.mkList(v, len);
|
||||||
auto out = v.listElems();
|
auto out = v.listElems();
|
||||||
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
||||||
auto l = lists[n].listSize();
|
auto l = lists[n]->listSize();
|
||||||
if (l)
|
if (l)
|
||||||
memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *));
|
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
|
||||||
pos += l;
|
pos += l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2130,7 +2127,7 @@ void EvalState::createBaseEnv()
|
||||||
auto vThrow = addPrimOp("throw", 1, prim_throw);
|
auto vThrow = addPrimOp("throw", 1, prim_throw);
|
||||||
|
|
||||||
auto addPurityError = [&](const std::string & name) {
|
auto addPurityError = [&](const std::string & name) {
|
||||||
Value * v2 = allocValue();
|
auto v2 = allocValue();
|
||||||
mkString(*v2, fmt("'%s' is not allowed in pure evaluation mode", name));
|
mkString(*v2, fmt("'%s' is not allowed in pure evaluation mode", name));
|
||||||
mkApp(v, *vThrow, *v2);
|
mkApp(v, *vThrow, *v2);
|
||||||
addConstant(name, v);
|
addConstant(name, v);
|
||||||
|
|
@ -2161,7 +2158,7 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
auto vScopedImport = addPrimOp("scopedImport", 2, prim_scopedImport);
|
auto vScopedImport = addPrimOp("scopedImport", 2, prim_scopedImport);
|
||||||
Value * v2 = allocValue();
|
auto v2 = allocValue();
|
||||||
mkAttrs(*v2, 0);
|
mkAttrs(*v2, 0);
|
||||||
mkApp(v, *vScopedImport, *v2);
|
mkApp(v, *vScopedImport, *v2);
|
||||||
forceValue(v);
|
forceValue(v);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ typedef double NixFloat;
|
||||||
class ExternalValueBase
|
class ExternalValueBase
|
||||||
{
|
{
|
||||||
friend std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
|
friend std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
|
||||||
protected:
|
|
||||||
|
protected:
|
||||||
/* Print out the value */
|
/* Print out the value */
|
||||||
virtual std::ostream & print(std::ostream & str) const = 0;
|
virtual std::ostream & print(std::ostream & str) const = 0;
|
||||||
|
|
||||||
|
|
@ -121,7 +122,14 @@ struct Value : Object
|
||||||
NixFloat fpoint;
|
NixFloat fpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
Value() : Object(tBlackhole, 0) { }
|
private:
|
||||||
|
|
||||||
|
Value() : Object(tNull, 0) {}
|
||||||
|
|
||||||
|
friend class GC;
|
||||||
|
template<typename T> friend class Root;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
bool isList() const
|
bool isList() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ static void _main(int argc, char * * argv)
|
||||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
||||||
state->repair = repair;
|
state->repair = repair;
|
||||||
|
|
||||||
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||||
|
|
||||||
if (packages) {
|
if (packages) {
|
||||||
std::ostringstream joined;
|
std::ostringstream joined;
|
||||||
|
|
@ -293,13 +293,13 @@ static void _main(int argc, char * * argv)
|
||||||
if (attrPaths.empty()) attrPaths = {""};
|
if (attrPaths.empty()) attrPaths = {""};
|
||||||
|
|
||||||
for (auto e : exprs) {
|
for (auto e : exprs) {
|
||||||
Value vRoot;
|
Root<Value> vRoot;
|
||||||
state->eval(e, vRoot);
|
state->eval(e, vRoot);
|
||||||
|
|
||||||
for (auto & i : attrPaths) {
|
for (auto & i : attrPaths) {
|
||||||
Value & v(*findAlongAttrPath(*state, i, autoArgs, vRoot));
|
auto v = findAlongAttrPath(*state, i, *autoArgs, vRoot);
|
||||||
state->forceValue(v);
|
state->forceValue(v);
|
||||||
getDerivations(*state, v, "", autoArgs, drvs, false);
|
getDerivations(*state, v, "", *autoArgs, drvs, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,7 +339,7 @@ static void _main(int argc, char * * argv)
|
||||||
try {
|
try {
|
||||||
auto expr = state->parseExprFromString("(import <nixpkgs> {}).bashInteractive", absPath("."));
|
auto expr = state->parseExprFromString("(import <nixpkgs> {}).bashInteractive", absPath("."));
|
||||||
|
|
||||||
Value v;
|
Root<Value> v;
|
||||||
state->eval(expr, v);
|
state->eval(expr, v);
|
||||||
|
|
||||||
auto drv = getDerivation(*state, v, false);
|
auto drv = getDerivation(*state, v, false);
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct InstallSourceInfo
|
||||||
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
|
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
|
||||||
Path profile; /* for srcProfile */
|
Path profile; /* for srcProfile */
|
||||||
string systemFilter; /* for srcNixExprDrvs */
|
string systemFilter; /* for srcNixExprDrvs */
|
||||||
Bindings * autoArgs;
|
Ptr<Bindings> autoArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ static void getAllExprs(EvalState & state,
|
||||||
attrs.insert(attrName);
|
attrs.insert(attrName);
|
||||||
/* Load the expression on demand. */
|
/* Load the expression on demand. */
|
||||||
Value & vFun = state.getBuiltin("import");
|
Value & vFun = state.getBuiltin("import");
|
||||||
Value & vArg(*state.allocValue());
|
auto vArg = state.allocValue();
|
||||||
mkString(vArg, path2);
|
mkString(vArg, path2);
|
||||||
if (v.attrs->size() == v.attrs->capacity())
|
if (v.attrs->size() == v.attrs->capacity())
|
||||||
throw Error(format("too many Nix expressions in directory '%1%'") % path);
|
throw Error(format("too many Nix expressions in directory '%1%'") % path);
|
||||||
|
|
@ -176,10 +176,10 @@ static void loadDerivations(EvalState & state, Path nixExprPath,
|
||||||
string systemFilter, Bindings & autoArgs,
|
string systemFilter, Bindings & autoArgs,
|
||||||
const string & pathPrefix, DrvInfos & elems)
|
const string & pathPrefix, DrvInfos & elems)
|
||||||
{
|
{
|
||||||
Value vRoot;
|
auto vRoot = state.allocValue();
|
||||||
loadSourceExpr(state, nixExprPath, vRoot);
|
loadSourceExpr(state, nixExprPath, vRoot);
|
||||||
|
|
||||||
Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot));
|
auto v = findAlongAttrPath(state, pathPrefix, autoArgs, vRoot);
|
||||||
|
|
||||||
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
|
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
|
||||||
|
|
||||||
|
|
@ -360,13 +360,14 @@ static void queryInstSources(EvalState & state,
|
||||||
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
|
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
|
||||||
case srcNixExprs: {
|
case srcNixExprs: {
|
||||||
|
|
||||||
Value vArg;
|
auto vArg = state.allocValue();
|
||||||
loadSourceExpr(state, instSource.nixExprPath, vArg);
|
loadSourceExpr(state, instSource.nixExprPath, vArg);
|
||||||
|
|
||||||
for (auto & i : args) {
|
for (auto & i : args) {
|
||||||
Expr * eFun = state.parseExprFromString(i, absPath("."));
|
Expr * eFun = state.parseExprFromString(i, absPath("."));
|
||||||
Value vFun, vTmp;
|
auto vFun = state.allocValue();
|
||||||
state.eval(eFun, vFun);
|
state.eval(eFun, vFun);
|
||||||
|
auto vTmp = state.allocValue();
|
||||||
mkApp(vTmp, vFun, vArg);
|
mkApp(vTmp, vFun, vArg);
|
||||||
getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true);
|
getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true);
|
||||||
}
|
}
|
||||||
|
|
@ -416,10 +417,10 @@ static void queryInstSources(EvalState & state,
|
||||||
}
|
}
|
||||||
|
|
||||||
case srcAttrPath: {
|
case srcAttrPath: {
|
||||||
Value vRoot;
|
Root<Value> vRoot;
|
||||||
loadSourceExpr(state, instSource.nixExprPath, vRoot);
|
loadSourceExpr(state, instSource.nixExprPath, vRoot);
|
||||||
for (auto & i : args) {
|
for (auto & i : args) {
|
||||||
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot));
|
auto v = findAlongAttrPath(state, i, *instSource.autoArgs, vRoot);
|
||||||
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
|
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -639,7 +640,7 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
||||||
const string & name, const string & value)
|
const string & name, const string & value)
|
||||||
{
|
{
|
||||||
Value * v = state.allocValue();
|
auto v = state.allocValue();
|
||||||
mkString(*v, value.c_str());
|
mkString(*v, value.c_str());
|
||||||
drv.setMeta(name, v);
|
drv.setMeta(name, v);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||||
DrvInfos elems;
|
DrvInfos elems;
|
||||||
Path manifestFile = userEnv + "/manifest.nix";
|
Path manifestFile = userEnv + "/manifest.nix";
|
||||||
if (pathExists(manifestFile)) {
|
if (pathExists(manifestFile)) {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
state.evalFile(manifestFile, v);
|
state.evalFile(manifestFile, v);
|
||||||
auto bindings = Bindings::allocBindings(0);
|
auto bindings = Bindings::allocBindings(0);
|
||||||
getDerivations(state, v, "", bindings, elems, false);
|
getDerivations(state, v, "", bindings, elems, false);
|
||||||
|
|
@ -105,26 +105,27 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
fmt("%1%", (Value &) manifest), references);
|
fmt("%1%", (Value &) manifest), references);
|
||||||
|
|
||||||
/* Get the environment builder expression. */
|
/* Get the environment builder expression. */
|
||||||
Value envBuilder;
|
auto envBuilder = state.allocValue();
|
||||||
state.evalFile(state.findFile("nix/buildenv.nix"), envBuilder);
|
state.evalFile(state.findFile("nix/buildenv.nix"), envBuilder);
|
||||||
|
|
||||||
/* Construct a Nix expression that calls the user environment
|
/* Construct a Nix expression that calls the user environment
|
||||||
builder with the manifest as argument. */
|
builder with the manifest as argument. */
|
||||||
Value args, topLevel;
|
auto args = state.allocValue();
|
||||||
|
Root<Value> topLevel;
|
||||||
state.mkAttrs(args, 3);
|
state.mkAttrs(args, 3);
|
||||||
mkString(*state.allocAttr(args, state.symbols.create("manifest")),
|
mkString(*state.allocAttr(args, state.symbols.create("manifest")),
|
||||||
manifestFile, {manifestFile});
|
manifestFile, {manifestFile});
|
||||||
args.attrs->push_back(Attr(state.symbols.create("derivations"), (Value *) manifest));
|
args->attrs->push_back(Attr(state.symbols.create("derivations"), (Value *) manifest));
|
||||||
args.attrs->sort();
|
args->attrs->sort();
|
||||||
mkApp(topLevel, envBuilder, args);
|
mkApp(topLevel, envBuilder, args);
|
||||||
|
|
||||||
/* Evaluate it. */
|
/* Evaluate it. */
|
||||||
debug("evaluating user environment builder");
|
debug("evaluating user environment builder");
|
||||||
state.forceValue(topLevel);
|
state.forceValue(topLevel);
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
Attr & aDrvPath(*topLevel->attrs->find(state.sDrvPath));
|
||||||
Path topLevelDrv = state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context);
|
Path topLevelDrv = state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context);
|
||||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
Attr & aOutPath(*topLevel->attrs->find(state.sOutPath));
|
||||||
Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context);
|
Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context);
|
||||||
|
|
||||||
/* Realise the resulting store expression. */
|
/* Realise the resulting store expression. */
|
||||||
|
|
|
||||||
|
|
@ -35,18 +35,18 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value vRoot;
|
Root<Value> vRoot;
|
||||||
state.eval(e, vRoot);
|
state.eval(e, vRoot);
|
||||||
|
|
||||||
for (auto & i : attrPaths) {
|
for (auto & i : attrPaths) {
|
||||||
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot));
|
auto v = findAlongAttrPath(state, i, autoArgs, vRoot);
|
||||||
state.forceValue(v);
|
state.forceValue(v);
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
if (evalOnly) {
|
if (evalOnly) {
|
||||||
Value vRes;
|
Root<Value> vRes;
|
||||||
if (autoArgs.empty())
|
if (autoArgs.empty())
|
||||||
vRes = v;
|
vRes = *v;
|
||||||
else
|
else
|
||||||
state.autoCallFunction(autoArgs, v, vRes);
|
state.autoCallFunction(autoArgs, v, vRes);
|
||||||
if (output == okXML)
|
if (output == okXML)
|
||||||
|
|
@ -55,7 +55,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
printValueAsJSON(state, strict, vRes, std::cout, context);
|
printValueAsJSON(state, strict, vRes, std::cout, context);
|
||||||
else {
|
else {
|
||||||
if (strict) state.forceValueDeep(vRes);
|
if (strict) state.forceValueDeep(vRes);
|
||||||
std::cout << vRes << std::endl;
|
std::cout << *vRes << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DrvInfos drvs;
|
DrvInfos drvs;
|
||||||
|
|
@ -159,7 +159,7 @@ static int _main(int argc, char * * argv)
|
||||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
||||||
state->repair = repair;
|
state->repair = repair;
|
||||||
|
|
||||||
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||||
|
|
||||||
if (attrPaths.empty()) attrPaths = {""};
|
if (attrPaths.empty()) attrPaths = {""};
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ static int _main(int argc, char * * argv)
|
||||||
|
|
||||||
if (readStdin) {
|
if (readStdin) {
|
||||||
Expr * e = state->parseStdin();
|
Expr * e = state->parseStdin();
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, *autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
} else if (files.empty() && !fromArgs)
|
} else if (files.empty() && !fromArgs)
|
||||||
files.push_back("./default.nix");
|
files.push_back("./default.nix");
|
||||||
|
|
@ -183,7 +183,7 @@ static int _main(int argc, char * * argv)
|
||||||
Expr * e = fromArgs
|
Expr * e = fromArgs
|
||||||
? state->parseExprFromString(i, absPath("."))
|
? state->parseExprFromString(i, absPath("."))
|
||||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, *autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@ string resolveMirrorUri(EvalState & state, string uri)
|
||||||
if (p == string::npos) throw Error("invalid mirror URI");
|
if (p == string::npos) throw Error("invalid mirror URI");
|
||||||
string mirrorName(s, 0, p);
|
string mirrorName(s, 0, p);
|
||||||
|
|
||||||
Value vMirrors;
|
Root<Value> vMirrors;
|
||||||
state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors);
|
state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors);
|
||||||
state.forceAttrs(vMirrors);
|
state.forceAttrs(vMirrors);
|
||||||
|
|
||||||
auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
|
auto mirrorList = vMirrors->attrs->find(state.symbols.create(mirrorName));
|
||||||
if (mirrorList == vMirrors.attrs->end())
|
if (mirrorList == vMirrors->attrs->end())
|
||||||
throw Error(format("unknown mirror name '%1%'") % mirrorName);
|
throw Error(format("unknown mirror name '%1%'") % mirrorName);
|
||||||
state.forceList(*mirrorList->value);
|
state.forceList(*mirrorList->value);
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ static int _main(int argc, char * * argv)
|
||||||
auto store = openStore();
|
auto store = openStore();
|
||||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
|
||||||
|
|
||||||
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||||
|
|
||||||
/* If -A is given, get the URI from the specified Nix
|
/* If -A is given, get the URI from the specified Nix
|
||||||
expression. */
|
expression. */
|
||||||
|
|
@ -117,14 +117,14 @@ static int _main(int argc, char * * argv)
|
||||||
uri = args[0];
|
uri = args[0];
|
||||||
} else {
|
} else {
|
||||||
Path path = resolveExprPath(lookupFileArg(*state, args.empty() ? "." : args[0]));
|
Path path = resolveExprPath(lookupFileArg(*state, args.empty() ? "." : args[0]));
|
||||||
Value vRoot;
|
Root<Value> vRoot;
|
||||||
state->evalFile(path, vRoot);
|
state->evalFile(path, vRoot);
|
||||||
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot));
|
auto v = findAlongAttrPath(*state, attrPath, *autoArgs, vRoot);
|
||||||
state->forceAttrs(v);
|
state->forceAttrs(v);
|
||||||
|
|
||||||
/* Extract the URI. */
|
/* Extract the URI. */
|
||||||
auto attr = v.attrs->find(state->symbols.create("urls"));
|
auto attr = v->attrs->find(state->symbols.create("urls"));
|
||||||
if (attr == v.attrs->end())
|
if (attr == v->attrs->end())
|
||||||
throw Error("attribute set does not contain a 'urls' attribute");
|
throw Error("attribute set does not contain a 'urls' attribute");
|
||||||
state->forceList(*attr->value);
|
state->forceList(*attr->value);
|
||||||
if (attr->value->listSize() < 1)
|
if (attr->value->listSize() < 1)
|
||||||
|
|
@ -132,16 +132,16 @@ static int _main(int argc, char * * argv)
|
||||||
uri = state->forceString(*attr->value->listElems()[0]);
|
uri = state->forceString(*attr->value->listElems()[0]);
|
||||||
|
|
||||||
/* Extract the hash mode. */
|
/* Extract the hash mode. */
|
||||||
attr = v.attrs->find(state->symbols.create("outputHashMode"));
|
attr = v->attrs->find(state->symbols.create("outputHashMode"));
|
||||||
if (attr == v.attrs->end())
|
if (attr == v->attrs->end())
|
||||||
printInfo("warning: this does not look like a fetchurl call");
|
printInfo("warning: this does not look like a fetchurl call");
|
||||||
else
|
else
|
||||||
unpack = state->forceString(*attr->value) == "recursive";
|
unpack = state->forceString(*attr->value) == "recursive";
|
||||||
|
|
||||||
/* Extract the name. */
|
/* Extract the name. */
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
attr = v.attrs->find(state->symbols.create("name"));
|
attr = v->attrs->find(state->symbols.create("name"));
|
||||||
if (attr != v.attrs->end())
|
if (attr != v->attrs->end())
|
||||||
name = state->forceString(*attr->value);
|
name = state->forceString(*attr->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "args.hh"
|
#include "args.hh"
|
||||||
|
#include "gc.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "common-eval-args.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
@ -66,7 +67,7 @@ struct Installable
|
||||||
|
|
||||||
Buildable toBuildable();
|
Buildable toBuildable();
|
||||||
|
|
||||||
virtual Value * toValue(EvalState & state)
|
virtual Ptr<Value> toValue(EvalState & state)
|
||||||
{
|
{
|
||||||
throw Error("argument '%s' cannot be evaluated", what());
|
throw Error("argument '%s' cannot be evaluated", what());
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +83,7 @@ struct SourceExprCommand : virtual Args, StoreCommand, MixEvalArgs
|
||||||
are installing. This is either the file specified by ‘--file’,
|
are installing. This is either the file specified by ‘--file’,
|
||||||
or an attribute set constructed from $NIX_PATH, e.g. ‘{ nixpkgs
|
or an attribute set constructed from $NIX_PATH, e.g. ‘{ nixpkgs
|
||||||
= import ...; bla = import ...; }’. */
|
= import ...; bla = import ...; }’. */
|
||||||
Value * getSourceExpr(EvalState & state);
|
Ptr<Value> getSourceExpr(EvalState & state);
|
||||||
|
|
||||||
ref<EvalState> getEvalState();
|
ref<EvalState> getEvalState();
|
||||||
|
|
||||||
|
|
@ -90,7 +91,7 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<EvalState> evalState;
|
std::shared_ptr<EvalState> evalState;
|
||||||
|
|
||||||
Value * vSourceExpr = 0;
|
Ptr<Value> vSourceExpr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RealiseMode { Build, NoBuild, DryRun };
|
enum RealiseMode { Build, NoBuild, DryRun };
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct CmdEdit : InstallableCommand
|
||||||
|
|
||||||
auto v = installable->toValue(*state);
|
auto v = installable->toValue(*state);
|
||||||
|
|
||||||
Value * v2;
|
Ptr<Value> v2;
|
||||||
try {
|
try {
|
||||||
auto dummyArgs = Bindings::allocBindings(0);
|
auto dummyArgs = Bindings::allocBindings(0);
|
||||||
v2 = findAlongAttrPath(*state, "meta.position", dummyArgs, *v);
|
v2 = findAlongAttrPath(*state, "meta.position", dummyArgs, *v);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ SourceExprCommand::SourceExprCommand()
|
||||||
.dest(&file);
|
.dest(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * SourceExprCommand::getSourceExpr(EvalState & state)
|
Ptr<Value> SourceExprCommand::getSourceExpr(EvalState & state)
|
||||||
{
|
{
|
||||||
if (vSourceExpr) return vSourceExpr;
|
if (vSourceExpr) return vSourceExpr;
|
||||||
|
|
||||||
|
|
@ -57,9 +57,9 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state)
|
||||||
state.getBuiltin("import"),
|
state.getBuiltin("import"),
|
||||||
mkString(*state.allocValue(), res.second));
|
mkString(*state.allocValue(), res.second));
|
||||||
#endif
|
#endif
|
||||||
Value * v1 = state.allocValue();
|
auto v1 = state.allocValue();
|
||||||
mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
|
mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
|
||||||
Value * v2 = state.allocValue();
|
auto v2 = state.allocValue();
|
||||||
mkApp(*v2, *v1, mkString(*state.allocValue(), i.first));
|
mkApp(*v2, *v1, mkString(*state.allocValue(), i.first));
|
||||||
mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
|
mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
|
||||||
state.getBuiltin("import"), *v2);
|
state.getBuiltin("import"), *v2);
|
||||||
|
|
@ -155,7 +155,7 @@ struct InstallableExpr : InstallableValue
|
||||||
|
|
||||||
std::string what() override { return text; }
|
std::string what() override { return text; }
|
||||||
|
|
||||||
Value * toValue(EvalState & state) override
|
Ptr<Value> toValue(EvalState & state) override
|
||||||
{
|
{
|
||||||
auto v = state.allocValue();
|
auto v = state.allocValue();
|
||||||
state.eval(state.parseExprFromString(text, absPath(".")), *v);
|
state.eval(state.parseExprFromString(text, absPath(".")), *v);
|
||||||
|
|
@ -173,13 +173,13 @@ struct InstallableAttrPath : InstallableValue
|
||||||
|
|
||||||
std::string what() override { return attrPath; }
|
std::string what() override { return attrPath; }
|
||||||
|
|
||||||
Value * toValue(EvalState & state) override
|
Ptr<Value> toValue(EvalState & state) override
|
||||||
{
|
{
|
||||||
auto source = cmd.getSourceExpr(state);
|
auto source = cmd.getSourceExpr(state);
|
||||||
|
|
||||||
Bindings & autoArgs = *cmd.getAutoArgs(state);
|
auto autoArgs = cmd.getAutoArgs(state);
|
||||||
|
|
||||||
Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
|
auto v = findAlongAttrPath(state, attrPath, *autoArgs, *source);
|
||||||
state.forceValue(*v);
|
state.forceValue(*v);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ struct NixRepl
|
||||||
{
|
{
|
||||||
string curDir;
|
string curDir;
|
||||||
EvalState state;
|
EvalState state;
|
||||||
Bindings * autoArgs;
|
Ptr<Bindings> autoArgs;
|
||||||
|
|
||||||
Strings loadedFiles;
|
Strings loadedFiles;
|
||||||
|
|
||||||
|
|
@ -304,11 +304,11 @@ StringSet NixRepl::completePrefix(string prefix)
|
||||||
string cur2 = string(cur, dot + 1);
|
string cur2 = string(cur, dot + 1);
|
||||||
|
|
||||||
Expr * e = parseString(expr);
|
Expr * e = parseString(expr);
|
||||||
Value v;
|
Root<Value> v;
|
||||||
e->eval(state, *env, v);
|
e->eval(state, *env, v);
|
||||||
state.forceAttrs(v);
|
state.forceAttrs(v);
|
||||||
|
|
||||||
for (auto & i : *v.attrs) {
|
for (auto & i : *v->attrs) {
|
||||||
string name = i.name;
|
string name = i.name;
|
||||||
if (string(name, 0, cur2.size()) != cur2) continue;
|
if (string(name, 0, cur2.size()) != cur2) continue;
|
||||||
completions.insert(prev + expr + "." + name);
|
completions.insert(prev + expr + "." + name);
|
||||||
|
|
@ -404,7 +404,7 @@ bool NixRepl::processLine(string line)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":a" || command == ":add") {
|
else if (command == ":a" || command == ":add") {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
addAttrsToScope(v);
|
addAttrsToScope(v);
|
||||||
}
|
}
|
||||||
|
|
@ -420,12 +420,12 @@ bool NixRepl::processLine(string line)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":t") {
|
else if (command == ":t") {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
std::cout << showType(v) << std::endl;
|
std::cout << showType(v) << std::endl;
|
||||||
|
|
||||||
} else if (command == ":u") {
|
} else if (command == ":u") {
|
||||||
Value v, f, result;
|
Root<Value> v, f, result;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
|
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
|
||||||
state.callFunction(f, v, result, Pos());
|
state.callFunction(f, v, result, Pos());
|
||||||
|
|
@ -435,7 +435,7 @@ bool NixRepl::processLine(string line)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":b" || command == ":i" || command == ":s") {
|
else if (command == ":b" || command == ":i" || command == ":s") {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
Path drvPath = getDerivationPath(v);
|
Path drvPath = getDerivationPath(v);
|
||||||
|
|
||||||
|
|
@ -457,7 +457,7 @@ bool NixRepl::processLine(string line)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":p" || command == ":print") {
|
else if (command == ":p" || command == ":print") {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
printValue(std::cout, v, 1000000000) << std::endl;
|
printValue(std::cout, v, 1000000000) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +483,7 @@ bool NixRepl::processLine(string line)
|
||||||
v.thunk.expr = e;
|
v.thunk.expr = e;
|
||||||
addVarToScope(state.symbols.create(name), v);
|
addVarToScope(state.symbols.create(name), v);
|
||||||
} else {
|
} else {
|
||||||
Value v;
|
Root<Value> v;
|
||||||
evalString(line, v);
|
evalString(line, v);
|
||||||
printValue(std::cout, v, 1) << std::endl;
|
printValue(std::cout, v, 1) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
@ -497,9 +497,9 @@ void NixRepl::loadFile(const Path & path)
|
||||||
{
|
{
|
||||||
loadedFiles.remove(path);
|
loadedFiles.remove(path);
|
||||||
loadedFiles.push_back(path);
|
loadedFiles.push_back(path);
|
||||||
Value v, v2;
|
Root<Value> v, v2;
|
||||||
state.evalFile(lookupFileArg(state, path), v);
|
state.evalFile(lookupFileArg(state, path), v);
|
||||||
state.autoCallFunction(*autoArgs, v, v2);
|
state.autoCallFunction(autoArgs, v, v2);
|
||||||
addAttrsToScope(v2);
|
addAttrsToScope(v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,12 +235,12 @@ struct CmdSearch : SourceExprCommand, MixJSON
|
||||||
|
|
||||||
warn("using cached results; pass '-u' to update the cache");
|
warn("using cached results; pass '-u' to update the cache");
|
||||||
|
|
||||||
Value vRoot;
|
Root<Value> vRoot;
|
||||||
parseJSON(*state, readFile(jsonCacheFileName), vRoot);
|
parseJSON(*state, readFile(jsonCacheFileName), vRoot);
|
||||||
|
|
||||||
fromCache = true;
|
fromCache = true;
|
||||||
|
|
||||||
doExpr(&vRoot, "", true, nullptr);
|
doExpr(&*vRoot, "", true, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ export HAVE_SODIUM="@HAVE_SODIUM@"
|
||||||
export version=@PACKAGE_VERSION@
|
export version=@PACKAGE_VERSION@
|
||||||
export system=@system@
|
export system=@system@
|
||||||
|
|
||||||
|
# Make it more likely to trigger GC bugs.
|
||||||
|
export GC_INITIAL_HEAP_SIZE=10
|
||||||
|
|
||||||
cacheDir=$TEST_ROOT/binary-cache
|
cacheDir=$TEST_ROOT/binary-cache
|
||||||
|
|
||||||
readLink() {
|
readLink() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue