mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 23:36:16 +02:00
Merge pull request #10322 from edolstra/finish-value
Ensure immutability of non-thunk values
This commit is contained in:
commit
4638ddd855
36 changed files with 534 additions and 568 deletions
|
@ -49,7 +49,7 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked
|
||||||
|
|
||||||
callFlake(state, lockedFlake, *vFlake);
|
callFlake(state, lockedFlake, *vFlake);
|
||||||
|
|
||||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
auto aOutputs = vFlake->attrs()->get(state.symbols.create("outputs"));
|
||||||
assert(aOutputs);
|
assert(aOutputs);
|
||||||
|
|
||||||
state.forceValue(*aOutputs->value, aOutputs->value->determinePos(noPos));
|
state.forceValue(*aOutputs->value, aOutputs->value->determinePos(noPos));
|
||||||
|
|
|
@ -289,7 +289,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||||
state->autoCallFunction(*autoArgs, v1, v2);
|
state->autoCallFunction(*autoArgs, v1, v2);
|
||||||
|
|
||||||
if (v2.type() == nAttrs) {
|
if (v2.type() == nAttrs) {
|
||||||
for (auto & i : *v2.attrs) {
|
for (auto & i : *v2.attrs()) {
|
||||||
std::string name = state->symbols[i.name];
|
std::string name = state->symbols[i.name];
|
||||||
if (name.find(searchWord) == 0) {
|
if (name.find(searchWord) == 0) {
|
||||||
if (prefix_ == "")
|
if (prefix_ == "")
|
||||||
|
@ -461,7 +461,7 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||||
|
|
||||||
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
||||||
|
|
||||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
auto aOutputs = vFlake->attrs()->get(state.symbols.create("outputs"));
|
||||||
assert(aOutputs);
|
assert(aOutputs);
|
||||||
|
|
||||||
return aOutputs->value;
|
return aOutputs->value;
|
||||||
|
|
|
@ -290,7 +290,7 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||||
e->eval(*state, *env, v);
|
e->eval(*state, *env, v);
|
||||||
state->forceAttrs(v, noPos, "while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
|
state->forceAttrs(v, noPos, "while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
|
||||||
|
|
||||||
for (auto & i : *v.attrs) {
|
for (auto & i : *v.attrs()) {
|
||||||
std::string_view name = state->symbols[i.name];
|
std::string_view name = state->symbols[i.name];
|
||||||
if (name.substr(0, cur2.size()) != cur2) continue;
|
if (name.substr(0, cur2.size()) != cur2) continue;
|
||||||
completions.insert(concatStrings(prev, expr, ".", name));
|
completions.insert(concatStrings(prev, expr, ".", name));
|
||||||
|
@ -490,7 +490,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||||
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
||||||
return {path, 0};
|
return {path, 0};
|
||||||
} else if (v.isLambda()) {
|
} else if (v.isLambda()) {
|
||||||
auto pos = state->positions[v.lambda.fun->pos];
|
auto pos = state->positions[v.payload.lambda.fun->pos];
|
||||||
if (auto path = std::get_if<SourcePath>(&pos.origin))
|
if (auto path = std::get_if<SourcePath>(&pos.origin))
|
||||||
return {*path, pos.line};
|
return {*path, pos.line};
|
||||||
else
|
else
|
||||||
|
@ -742,17 +742,17 @@ void NixRepl::loadFiles()
|
||||||
void NixRepl::addAttrsToScope(Value & attrs)
|
void NixRepl::addAttrsToScope(Value & attrs)
|
||||||
{
|
{
|
||||||
state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }, "while evaluating an attribute set to be merged in the global scope");
|
state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }, "while evaluating an attribute set to be merged in the global scope");
|
||||||
if (displ + attrs.attrs->size() >= envSize)
|
if (displ + attrs.attrs()->size() >= envSize)
|
||||||
throw Error("environment full; cannot add more variables");
|
throw Error("environment full; cannot add more variables");
|
||||||
|
|
||||||
for (auto & i : *attrs.attrs) {
|
for (auto & i : *attrs.attrs()) {
|
||||||
staticEnv->vars.emplace_back(i.name, displ);
|
staticEnv->vars.emplace_back(i.name, displ);
|
||||||
env->values[displ++] = i.value;
|
env->values[displ++] = i.value;
|
||||||
varNames.emplace(state->symbols[i.name]);
|
varNames.emplace(state->symbols[i.name]);
|
||||||
}
|
}
|
||||||
staticEnv->sort();
|
staticEnv->sort();
|
||||||
staticEnv->deduplicate();
|
staticEnv->deduplicate();
|
||||||
notice("Added %1% variables.", attrs.attrs->size());
|
notice("Added %1% variables.", attrs.attrs()->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ bool nix_get_bool(nix_c_context * context, const Value * value)
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nBool);
|
assert(v.type() == nix::nBool);
|
||||||
return v.boolean;
|
return v.boolean();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_RES(false);
|
NIXC_CATCH_ERRS_RES(false);
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ const char * nix_get_path_string(nix_c_context * context, const Value * value)
|
||||||
// We could use v.path().to_string().c_str(), but I'm concerned this
|
// We could use v.path().to_string().c_str(), but I'm concerned this
|
||||||
// crashes. Looks like .path() allocates a CanonPath with a copy of the
|
// crashes. Looks like .path() allocates a CanonPath with a copy of the
|
||||||
// string, then it gets the underlying data from that.
|
// string, then it gets the underlying data from that.
|
||||||
return v._path.path;
|
return v.payload.path.path;
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_NULL
|
NIXC_CATCH_ERRS_NULL
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nAttrs);
|
assert(v.type() == nix::nAttrs);
|
||||||
return v.attrs->size();
|
return v.attrs()->size();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_RES(0);
|
NIXC_CATCH_ERRS_RES(0);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ double nix_get_float(nix_c_context * context, const Value * value)
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nFloat);
|
assert(v.type() == nix::nFloat);
|
||||||
return v.fpoint;
|
return v.fpoint();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_RES(0.0);
|
NIXC_CATCH_ERRS_RES(0.0);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ int64_t nix_get_int(nix_c_context * context, const Value * value)
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nInt);
|
assert(v.type() == nix::nInt);
|
||||||
return v.integer;
|
return v.integer();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_RES(0);
|
NIXC_CATCH_ERRS_RES(0);
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nExternal);
|
assert(v.type() == nix::nExternal);
|
||||||
return (ExternalValue *) v.external;
|
return (ExternalValue *) v.external();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_NULL;
|
NIXC_CATCH_ERRS_NULL;
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nAttrs);
|
assert(v.type() == nix::nAttrs);
|
||||||
nix::Symbol s = state->state.symbols.create(name);
|
nix::Symbol s = state->state.symbols.create(name);
|
||||||
auto attr = v.attrs->get(s);
|
auto attr = v.attrs()->get(s);
|
||||||
if (attr) {
|
if (attr) {
|
||||||
nix_gc_incref(nullptr, attr->value);
|
nix_gc_incref(nullptr, attr->value);
|
||||||
state->state.forceValue(*attr->value, nix::noPos);
|
state->state.forceValue(*attr->value, nix::noPos);
|
||||||
|
@ -301,7 +301,7 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
assert(v.type() == nix::nAttrs);
|
assert(v.type() == nix::nAttrs);
|
||||||
nix::Symbol s = state->state.symbols.create(name);
|
nix::Symbol s = state->state.symbols.create(name);
|
||||||
auto attr = v.attrs->get(s);
|
auto attr = v.attrs()->get(s);
|
||||||
if (attr)
|
if (attr)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -316,7 +316,7 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
|
||||||
context->last_err_code = NIX_OK;
|
context->last_err_code = NIX_OK;
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
const nix::Attr & a = (*v.attrs)[i];
|
const nix::Attr & a = (*v.attrs())[i];
|
||||||
*name = ((const std::string &) (state->state.symbols[a.name])).c_str();
|
*name = ((const std::string &) (state->state.symbols[a.name])).c_str();
|
||||||
nix_gc_incref(nullptr, a.value);
|
nix_gc_incref(nullptr, a.value);
|
||||||
state->state.forceValue(*a.value, nix::noPos);
|
state->state.forceValue(*a.value, nix::noPos);
|
||||||
|
@ -331,7 +331,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
|
||||||
context->last_err_code = NIX_OK;
|
context->last_err_code = NIX_OK;
|
||||||
try {
|
try {
|
||||||
auto & v = check_value_not_null(value);
|
auto & v = check_value_not_null(value);
|
||||||
const nix::Attr & a = (*v.attrs)[i];
|
const nix::Attr & a = (*v.attrs())[i];
|
||||||
return ((const std::string &) (state->state.symbols[a.name])).c_str();
|
return ((const std::string &) (state->state.symbols[a.name])).c_str();
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS_NULL
|
NIXC_CATCH_ERRS_NULL
|
||||||
|
|
|
@ -72,10 +72,10 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
|
||||||
if (attr.empty())
|
if (attr.empty())
|
||||||
throw Error("empty attribute name in selection path '%1%'", attrPath);
|
throw Error("empty attribute name in selection path '%1%'", attrPath);
|
||||||
|
|
||||||
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
auto a = v->attrs()->get(state.symbols.create(attr));
|
||||||
if (a == v->attrs->end()) {
|
if (!a) {
|
||||||
std::set<std::string> attrNames;
|
std::set<std::string> attrNames;
|
||||||
for (auto & attr : *v->attrs)
|
for (auto & attr : *v->attrs())
|
||||||
attrNames.insert(state.symbols[attr.name]);
|
attrNames.insert(state.symbols[attr.name]);
|
||||||
|
|
||||||
auto suggestions = Suggestions::bestMatches(attrNames, attr);
|
auto suggestions = Suggestions::bestMatches(attrNames, attr);
|
||||||
|
|
|
@ -23,23 +23,6 @@ Bindings * EvalState::allocBindings(size_t capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a new attribute named 'name' on an existing attribute set stored
|
|
||||||
in 'vAttrs' and return the newly allocated Value which is associated with
|
|
||||||
this attribute. */
|
|
||||||
Value * EvalState::allocAttr(Value & vAttrs, Symbol name)
|
|
||||||
{
|
|
||||||
Value * v = allocValue();
|
|
||||||
vAttrs.attrs->push_back(Attr(name, v));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value * EvalState::allocAttr(Value & vAttrs, std::string_view name)
|
|
||||||
{
|
|
||||||
return allocAttr(vAttrs, symbols.create(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
|
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
|
||||||
{
|
{
|
||||||
auto value = state.allocValue();
|
auto value = state.allocValue();
|
||||||
|
|
|
@ -65,24 +65,26 @@ public:
|
||||||
|
|
||||||
typedef Attr * iterator;
|
typedef Attr * iterator;
|
||||||
|
|
||||||
|
typedef const Attr * const_iterator;
|
||||||
|
|
||||||
void push_back(const Attr & attr)
|
void push_back(const Attr & attr)
|
||||||
{
|
{
|
||||||
assert(size_ < capacity_);
|
assert(size_ < capacity_);
|
||||||
attrs[size_++] = attr;
|
attrs[size_++] = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find(Symbol name)
|
const_iterator find(Symbol name) const
|
||||||
{
|
{
|
||||||
Attr key(name, 0);
|
Attr key(name, 0);
|
||||||
iterator i = std::lower_bound(begin(), end(), key);
|
const_iterator i = std::lower_bound(begin(), end(), key);
|
||||||
if (i != end() && i->name == name) return i;
|
if (i != end() && i->name == name) return i;
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
Attr * get(Symbol name)
|
const Attr * get(Symbol name) const
|
||||||
{
|
{
|
||||||
Attr key(name, 0);
|
Attr key(name, 0);
|
||||||
iterator i = std::lower_bound(begin(), end(), key);
|
const_iterator i = std::lower_bound(begin(), end(), key);
|
||||||
if (i != end() && i->name == name) return &*i;
|
if (i != end() && i->name == name) return &*i;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -90,14 +92,22 @@ public:
|
||||||
iterator begin() { return &attrs[0]; }
|
iterator begin() { return &attrs[0]; }
|
||||||
iterator end() { return &attrs[size_]; }
|
iterator end() { return &attrs[size_]; }
|
||||||
|
|
||||||
|
const_iterator begin() const { return &attrs[0]; }
|
||||||
|
const_iterator end() const { return &attrs[size_]; }
|
||||||
|
|
||||||
Attr & operator[](size_t pos)
|
Attr & operator[](size_t pos)
|
||||||
{
|
{
|
||||||
return attrs[pos];
|
return attrs[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Attr & operator[](size_t pos) const
|
||||||
|
{
|
||||||
|
return attrs[pos];
|
||||||
|
}
|
||||||
|
|
||||||
void sort();
|
void sort();
|
||||||
|
|
||||||
size_t capacity() { return capacity_; }
|
size_t capacity() const { return capacity_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the attributes in lexicographically sorted order.
|
* Returns the attributes in lexicographically sorted order.
|
||||||
|
@ -166,6 +176,20 @@ public:
|
||||||
{
|
{
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t capacity()
|
||||||
|
{
|
||||||
|
return bindings->capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow(Bindings * newBindings)
|
||||||
|
{
|
||||||
|
for (auto & i : *bindings)
|
||||||
|
newBindings->push_back(i);
|
||||||
|
bindings = newBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class ExprAttrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ Value & AttrCursor::getValue()
|
||||||
if (parent) {
|
if (parent) {
|
||||||
auto & vParent = parent->first->getValue();
|
auto & vParent = parent->first->getValue();
|
||||||
root->state.forceAttrs(vParent, noPos, "while searching for an attribute");
|
root->state.forceAttrs(vParent, noPos, "while searching for an attribute");
|
||||||
auto attr = vParent.attrs->get(parent->second);
|
auto attr = vParent.attrs()->get(parent->second);
|
||||||
if (!attr)
|
if (!attr)
|
||||||
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
|
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
|
||||||
_value = allocRootValue(attr->value);
|
_value = allocRootValue(attr->value);
|
||||||
|
@ -448,9 +448,9 @@ Value & AttrCursor::forceValue()
|
||||||
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
|
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
|
||||||
}
|
}
|
||||||
else if (v.type() == nBool)
|
else if (v.type() == nBool)
|
||||||
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
|
cachedValue = {root->db->setBool(getKey(), v.boolean()), v.boolean()};
|
||||||
else if (v.type() == nInt)
|
else if (v.type() == nInt)
|
||||||
cachedValue = {root->db->setInt(getKey(), v.integer), int_t{v.integer}};
|
cachedValue = {root->db->setInt(getKey(), v.integer()), int_t{v.integer()}};
|
||||||
else if (v.type() == nAttrs)
|
else if (v.type() == nAttrs)
|
||||||
; // FIXME: do something?
|
; // FIXME: do something?
|
||||||
else
|
else
|
||||||
|
@ -510,7 +510,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
|
||||||
return nullptr;
|
return nullptr;
|
||||||
//error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
|
//error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
|
||||||
|
|
||||||
auto attr = v.attrs->get(name);
|
auto attr = v.attrs()->get(name);
|
||||||
|
|
||||||
if (!attr) {
|
if (!attr) {
|
||||||
if (root->db) {
|
if (root->db) {
|
||||||
|
@ -652,7 +652,7 @@ bool AttrCursor::getBool()
|
||||||
if (v.type() != nBool)
|
if (v.type() != nBool)
|
||||||
root->state.error<TypeError>("'%s' is not a Boolean", getAttrPathStr()).debugThrow();
|
root->state.error<TypeError>("'%s' is not a Boolean", getAttrPathStr()).debugThrow();
|
||||||
|
|
||||||
return v.boolean;
|
return v.boolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
NixInt AttrCursor::getInt()
|
NixInt AttrCursor::getInt()
|
||||||
|
@ -674,7 +674,7 @@ NixInt AttrCursor::getInt()
|
||||||
if (v.type() != nInt)
|
if (v.type() != nInt)
|
||||||
root->state.error<TypeError>("'%s' is not an integer", getAttrPathStr()).debugThrow();
|
root->state.error<TypeError>("'%s' is not an integer", getAttrPathStr()).debugThrow();
|
||||||
|
|
||||||
return v.integer;
|
return v.integer();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AttrCursor::getListOfStrings()
|
std::vector<std::string> AttrCursor::getListOfStrings()
|
||||||
|
@ -730,7 +730,7 @@ std::vector<Symbol> AttrCursor::getAttrs()
|
||||||
root->state.error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
|
root->state.error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
|
||||||
|
|
||||||
std::vector<Symbol> attrs;
|
std::vector<Symbol> attrs;
|
||||||
for (auto & attr : *getValue().attrs)
|
for (auto & attr : *getValue().attrs())
|
||||||
attrs.push_back(attr.name);
|
attrs.push_back(attr.name);
|
||||||
std::sort(attrs.begin(), attrs.end(), [&](Symbol a, Symbol b) {
|
std::sort(attrs.begin(), attrs.end(), [&](Symbol a, Symbol b) {
|
||||||
std::string_view sa = root->state.symbols[a], sb = root->state.symbols[b];
|
std::string_view sa = root->state.symbols[a], sb = root->state.symbols[b];
|
||||||
|
|
|
@ -85,8 +85,8 @@ Env & EvalState::allocEnv(size_t size)
|
||||||
void EvalState::forceValue(Value & v, const PosIdx pos)
|
void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||||
{
|
{
|
||||||
if (v.isThunk()) {
|
if (v.isThunk()) {
|
||||||
Env * env = v.thunk.env;
|
Env * env = v.payload.thunk.env;
|
||||||
Expr * expr = v.thunk.expr;
|
Expr * expr = v.payload.thunk.expr;
|
||||||
try {
|
try {
|
||||||
v.mkBlackhole();
|
v.mkBlackhole();
|
||||||
//checkInterrupt();
|
//checkInterrupt();
|
||||||
|
@ -98,7 +98,7 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v.isApp())
|
else if (v.isApp())
|
||||||
callFunction(*v.app.left, *v.app.right, v, pos);
|
callFunction(*v.payload.app.left, *v.payload.app.right, v, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ void Value::print(EvalState & state, std::ostream & str, PrintOptions options)
|
||||||
const Value * getPrimOp(const Value &v) {
|
const Value * getPrimOp(const Value &v) {
|
||||||
const Value * primOp = &v;
|
const Value * primOp = &v;
|
||||||
while (primOp->isPrimOpApp()) {
|
while (primOp->isPrimOpApp()) {
|
||||||
primOp = primOp->primOpApp.left;
|
primOp = primOp->payload.primOpApp.left;
|
||||||
}
|
}
|
||||||
assert(primOp->isPrimOp());
|
assert(primOp->isPrimOp());
|
||||||
return primOp;
|
return primOp;
|
||||||
|
@ -163,12 +163,12 @@ std::string showType(const Value & v)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
switch (v.internalType) {
|
switch (v.internalType) {
|
||||||
case tString: return v.string.context ? "a string with context" : "a string";
|
case tString: return v.payload.string.context ? "a string with context" : "a string";
|
||||||
case tPrimOp:
|
case tPrimOp:
|
||||||
return fmt("the built-in function '%s'", std::string(v.primOp->name));
|
return fmt("the built-in function '%s'", std::string(v.payload.primOp->name));
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name));
|
return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->payload.primOp->name));
|
||||||
case tExternal: return v.external->showType();
|
case tExternal: return v.external()->showType();
|
||||||
case tThunk: return v.isBlackhole() ? "a black hole" : "a thunk";
|
case tThunk: return v.isBlackhole() ? "a black hole" : "a thunk";
|
||||||
case tApp: return "a function application";
|
case tApp: return "a function application";
|
||||||
default:
|
default:
|
||||||
|
@ -183,9 +183,9 @@ PosIdx Value::determinePos(const PosIdx pos) const
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
switch (internalType) {
|
switch (internalType) {
|
||||||
case tAttrs: return attrs->pos;
|
case tAttrs: return attrs()->pos;
|
||||||
case tLambda: return lambda.fun->pos;
|
case tLambda: return payload.lambda.fun->pos;
|
||||||
case tApp: return app.left->determinePos(pos);
|
case tApp: return payload.app.left->determinePos(pos);
|
||||||
default: return pos;
|
default: return pos;
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
@ -197,10 +197,10 @@ bool Value::isTrivial() const
|
||||||
internalType != tApp
|
internalType != tApp
|
||||||
&& internalType != tPrimOpApp
|
&& internalType != tPrimOpApp
|
||||||
&& (internalType != tThunk
|
&& (internalType != tThunk
|
||||||
|| (dynamic_cast<ExprAttrs *>(thunk.expr)
|
|| (dynamic_cast<ExprAttrs *>(payload.thunk.expr)
|
||||||
&& ((ExprAttrs *) thunk.expr)->dynamicAttrs.empty())
|
&& ((ExprAttrs *) payload.thunk.expr)->dynamicAttrs.empty())
|
||||||
|| dynamic_cast<ExprLambda *>(thunk.expr)
|
|| dynamic_cast<ExprLambda *>(payload.thunk.expr)
|
||||||
|| dynamic_cast<ExprList *>(thunk.expr));
|
|| dynamic_cast<ExprList *>(payload.thunk.expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -584,7 +584,7 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
||||||
/* Install value the base environment. */
|
/* Install value the base environment. */
|
||||||
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
baseEnv.values[0]->payload.attrs->push_back(Attr(symbols.create(name2), v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,32 +597,30 @@ void PrimOp::check()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream & output, PrimOp & primOp)
|
std::ostream & operator<<(std::ostream & output, const PrimOp & primOp)
|
||||||
{
|
{
|
||||||
output << "primop " << primOp.name;
|
output << "primop " << primOp.name;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PrimOp * Value::primOpAppPrimOp() const
|
const PrimOp * Value::primOpAppPrimOp() const
|
||||||
{
|
{
|
||||||
Value * left = primOpApp.left;
|
Value * left = payload.primOpApp.left;
|
||||||
while (left && !left->isPrimOp()) {
|
while (left && !left->isPrimOp()) {
|
||||||
left = left->primOpApp.left;
|
left = left->payload.primOpApp.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!left)
|
if (!left)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return left->primOp;
|
return left->primOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Value::mkPrimOp(PrimOp * p)
|
void Value::mkPrimOp(PrimOp * p)
|
||||||
{
|
{
|
||||||
p->check();
|
p->check();
|
||||||
clearValue();
|
finishValue(tPrimOp, { .primOp = p });
|
||||||
internalType = tPrimOp;
|
|
||||||
primOp = p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -650,14 +648,14 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||||
v->mkPrimOp(new PrimOp(primOp));
|
v->mkPrimOp(new PrimOp(primOp));
|
||||||
staticBaseEnv->vars.emplace_back(envName, baseEnvDispl);
|
staticBaseEnv->vars.emplace_back(envName, baseEnvDispl);
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(primOp.name), v));
|
baseEnv.values[0]->payload.attrs->push_back(Attr(symbols.create(primOp.name), v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value & EvalState::getBuiltin(const std::string & name)
|
Value & EvalState::getBuiltin(const std::string & name)
|
||||||
{
|
{
|
||||||
return *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
|
return *baseEnv.values[0]->attrs()->find(symbols.create(name))->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -665,12 +663,12 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||||
{
|
{
|
||||||
if (v.isPrimOp()) {
|
if (v.isPrimOp()) {
|
||||||
auto v2 = &v;
|
auto v2 = &v;
|
||||||
if (auto * doc = v2->primOp->doc)
|
if (auto * doc = v2->primOp()->doc)
|
||||||
return Doc {
|
return Doc {
|
||||||
.pos = {},
|
.pos = {},
|
||||||
.name = v2->primOp->name,
|
.name = v2->primOp()->name,
|
||||||
.arity = v2->primOp->arity,
|
.arity = v2->primOp()->arity,
|
||||||
.args = v2->primOp->args,
|
.args = v2->primOp()->args,
|
||||||
.doc = doc,
|
.doc = doc,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -694,8 +692,8 @@ void printWithBindings(const SymbolTable & st, const Env & env)
|
||||||
if (!env.values[0]->isThunk()) {
|
if (!env.values[0]->isThunk()) {
|
||||||
std::cout << "with: ";
|
std::cout << "with: ";
|
||||||
std::cout << ANSI_MAGENTA;
|
std::cout << ANSI_MAGENTA;
|
||||||
Bindings::iterator j = env.values[0]->attrs->begin();
|
auto j = env.values[0]->attrs()->begin();
|
||||||
while (j != env.values[0]->attrs->end()) {
|
while (j != env.values[0]->attrs()->end()) {
|
||||||
std::cout << st[j->name] << " ";
|
std::cout << st[j->name] << " ";
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
|
@ -749,11 +747,8 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En
|
||||||
|
|
||||||
if (se.isWith && !env.values[0]->isThunk()) {
|
if (se.isWith && !env.values[0]->isThunk()) {
|
||||||
// add 'with' bindings.
|
// add 'with' bindings.
|
||||||
Bindings::iterator j = env.values[0]->attrs->begin();
|
for (auto & j : *env.values[0]->attrs())
|
||||||
while (j != env.values[0]->attrs->end()) {
|
vm[st[j.name]] = j.value;
|
||||||
vm[st[j->name]] = j->value;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// iterate through staticenv bindings and add them.
|
// iterate through staticenv bindings and add them.
|
||||||
for (auto & i : se.vars)
|
for (auto & i : se.vars)
|
||||||
|
@ -873,28 +868,28 @@ void Value::mkString(std::string_view s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void copyContextToValue(Value & v, const NixStringContext & context)
|
static const char * * encodeContext(const NixStringContext & context)
|
||||||
{
|
{
|
||||||
if (!context.empty()) {
|
if (!context.empty()) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
v.string.context = (const char * *)
|
auto ctx = (const char * *)
|
||||||
allocBytes((context.size() + 1) * sizeof(char *));
|
allocBytes((context.size() + 1) * sizeof(char *));
|
||||||
for (auto & i : context)
|
for (auto & i : context)
|
||||||
v.string.context[n++] = dupString(i.to_string().c_str());
|
ctx[n++] = dupString(i.to_string().c_str());
|
||||||
v.string.context[n] = 0;
|
ctx[n] = 0;
|
||||||
}
|
return ctx;
|
||||||
|
} else
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::mkString(std::string_view s, const NixStringContext & context)
|
void Value::mkString(std::string_view s, const NixStringContext & context)
|
||||||
{
|
{
|
||||||
mkString(s);
|
mkString(makeImmutableString(s), encodeContext(context));
|
||||||
copyContextToValue(*this, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::mkStringMove(const char * s, const NixStringContext & context)
|
void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||||
{
|
{
|
||||||
mkString(s);
|
mkString(s, encodeContext(context));
|
||||||
copyContextToValue(*this, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::mkPath(const SourcePath & path)
|
void Value::mkPath(const SourcePath & path)
|
||||||
|
@ -917,8 +912,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
auto * fromWith = var.fromWith;
|
auto * fromWith = var.fromWith;
|
||||||
while (1) {
|
while (1) {
|
||||||
forceAttrs(*env->values[0], fromWith->pos, "while evaluating the first subexpression of a with expression");
|
forceAttrs(*env->values[0], fromWith->pos, "while evaluating the first subexpression of a with expression");
|
||||||
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
if (auto j = env->values[0]->attrs()->get(var.name)) {
|
||||||
if (j != env->values[0]->attrs->end()) {
|
|
||||||
if (countCalls) attrSelects[j->pos]++;
|
if (countCalls) attrSelects[j->pos]++;
|
||||||
return j->value;
|
return j->value;
|
||||||
}
|
}
|
||||||
|
@ -1166,7 +1160,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos, std::stri
|
||||||
showType(v),
|
showType(v),
|
||||||
ValuePrinter(*this, v, errorPrintOptions)
|
ValuePrinter(*this, v, errorPrintOptions)
|
||||||
).atPos(pos).withFrame(env, *e).debugThrow();
|
).atPos(pos).withFrame(env, *e).debugThrow();
|
||||||
return v.boolean;
|
return v.boolean();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(positions[pos], errorCtx);
|
e.addTrace(positions[pos], errorCtx);
|
||||||
throw;
|
throw;
|
||||||
|
@ -1234,8 +1228,9 @@ Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
|
||||||
|
|
||||||
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
v.mkAttrs(state.buildBindings(attrs.size() + dynamicAttrs.size()).finish());
|
auto bindings = state.buildBindings(attrs.size() + dynamicAttrs.size());
|
||||||
auto dynamicEnv = &env;
|
auto dynamicEnv = &env;
|
||||||
|
bool sort = false;
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
/* Create a new environment that contains the attributes in
|
/* Create a new environment that contains the attributes in
|
||||||
|
@ -1260,7 +1255,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
} else
|
} else
|
||||||
vAttr = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
|
vAttr = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
|
||||||
env2.values[displ++] = vAttr;
|
env2.values[displ++] = vAttr;
|
||||||
v.attrs->push_back(Attr(i.first, vAttr, i.second.pos));
|
bindings.insert(i.first, vAttr, i.second.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the rec contains an attribute called `__overrides', then
|
/* If the rec contains an attribute called `__overrides', then
|
||||||
|
@ -1272,32 +1267,28 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
been substituted into the bodies of the other attributes.
|
been substituted into the bodies of the other attributes.
|
||||||
Hence we need __overrides.) */
|
Hence we need __overrides.) */
|
||||||
if (hasOverrides) {
|
if (hasOverrides) {
|
||||||
Value * vOverrides = (*v.attrs)[overrides->second.displ].value;
|
Value * vOverrides = (*bindings.bindings)[overrides->second.displ].value;
|
||||||
state.forceAttrs(*vOverrides, [&]() { return vOverrides->determinePos(noPos); }, "while evaluating the `__overrides` attribute");
|
state.forceAttrs(*vOverrides, [&]() { return vOverrides->determinePos(noPos); }, "while evaluating the `__overrides` attribute");
|
||||||
Bindings * newBnds = state.allocBindings(v.attrs->capacity() + vOverrides->attrs->size());
|
bindings.grow(state.allocBindings(bindings.capacity() + vOverrides->attrs()->size()));
|
||||||
for (auto & i : *v.attrs)
|
for (auto & i : *vOverrides->attrs()) {
|
||||||
newBnds->push_back(i);
|
|
||||||
for (auto & i : *vOverrides->attrs) {
|
|
||||||
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;
|
(*bindings.bindings)[j->second.displ] = i;
|
||||||
env2.values[j->second.displ] = i.value;
|
env2.values[j->second.displ] = i.value;
|
||||||
} else
|
} else
|
||||||
newBnds->push_back(i);
|
bindings.push_back(i);
|
||||||
}
|
}
|
||||||
newBnds->sort();
|
sort = true;
|
||||||
v.attrs = newBnds;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env) : nullptr;
|
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env) : nullptr;
|
||||||
for (auto & i : attrs) {
|
for (auto & i : attrs)
|
||||||
v.attrs->push_back(Attr(
|
bindings.insert(
|
||||||
i.first,
|
i.first,
|
||||||
i.second.e->maybeThunk(state, *i.second.chooseByKind(&env, &env, inheritEnv)),
|
i.second.e->maybeThunk(state, *i.second.chooseByKind(&env, &env, inheritEnv)),
|
||||||
i.second.pos));
|
i.second.pos);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dynamic attrs apply *after* rec and __overrides. */
|
/* Dynamic attrs apply *after* rec and __overrides. */
|
||||||
|
@ -1309,17 +1300,21 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
continue;
|
continue;
|
||||||
state.forceStringNoCtx(nameVal, i.pos, "while evaluating the name of a dynamic attribute");
|
state.forceStringNoCtx(nameVal, i.pos, "while evaluating the name of a dynamic attribute");
|
||||||
auto nameSym = state.symbols.create(nameVal.string_view());
|
auto nameSym = state.symbols.create(nameVal.string_view());
|
||||||
Bindings::iterator j = v.attrs->find(nameSym);
|
if (sort)
|
||||||
if (j != v.attrs->end())
|
// FIXME: inefficient
|
||||||
|
bindings.bindings->sort();
|
||||||
|
if (auto j = bindings.bindings->get(nameSym))
|
||||||
state.error<EvalError>("dynamic attribute '%1%' already defined at %2%", state.symbols[nameSym], state.positions[j->pos]).atPos(i.pos).withFrame(env, *this).debugThrow();
|
state.error<EvalError>("dynamic attribute '%1%' already defined at %2%", state.symbols[nameSym], state.positions[j->pos]).atPos(i.pos).withFrame(env, *this).debugThrow();
|
||||||
|
|
||||||
i.valueExpr->setName(nameSym);
|
i.valueExpr->setName(nameSym);
|
||||||
/* Keep sorted order so find can catch duplicates */
|
/* Keep sorted order so find can catch duplicates */
|
||||||
v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), i.pos));
|
bindings.insert(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), i.pos);
|
||||||
v.attrs->sort(); // FIXME: inefficient
|
sort = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
v.attrs->pos = pos;
|
bindings.bindings->pos = pos;
|
||||||
|
|
||||||
|
v.mkAttrs(sort ? bindings.finish() : bindings.alreadySorted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1425,21 +1420,21 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
for (auto & i : attrPath) {
|
for (auto & i : attrPath) {
|
||||||
state.nrLookups++;
|
state.nrLookups++;
|
||||||
Bindings::iterator j;
|
const Attr * j;
|
||||||
auto name = getName(i, state, env);
|
auto name = getName(i, state, env);
|
||||||
if (def) {
|
if (def) {
|
||||||
state.forceValue(*vAttrs, pos);
|
state.forceValue(*vAttrs, pos);
|
||||||
if (vAttrs->type() != nAttrs ||
|
if (vAttrs->type() != nAttrs ||
|
||||||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
!(j = vAttrs->attrs()->get(name)))
|
||||||
{
|
{
|
||||||
def->eval(state, env, v);
|
def->eval(state, env, v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.forceAttrs(*vAttrs, pos, "while selecting an attribute");
|
state.forceAttrs(*vAttrs, pos, "while selecting an attribute");
|
||||||
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) {
|
if (!(j = vAttrs->attrs()->get(name))) {
|
||||||
std::set<std::string> allAttrNames;
|
std::set<std::string> allAttrNames;
|
||||||
for (auto & attr : *vAttrs->attrs)
|
for (auto & attr : *vAttrs->attrs())
|
||||||
allAttrNames.insert(state.symbols[attr.name]);
|
allAttrNames.insert(state.symbols[attr.name]);
|
||||||
auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]);
|
auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]);
|
||||||
state.error<EvalError>("attribute '%1%' missing", state.symbols[name])
|
state.error<EvalError>("attribute '%1%' missing", state.symbols[name])
|
||||||
|
@ -1477,15 +1472,15 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
for (auto & i : attrPath) {
|
for (auto & i : attrPath) {
|
||||||
state.forceValue(*vAttrs, getPos());
|
state.forceValue(*vAttrs, getPos());
|
||||||
Bindings::iterator j;
|
const Attr * j;
|
||||||
auto name = getName(i, state, env);
|
auto name = getName(i, state, env);
|
||||||
if (vAttrs->type() != nAttrs ||
|
if (vAttrs->type() == nAttrs &&
|
||||||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
(j = vAttrs->attrs()->get(name)))
|
||||||
{
|
{
|
||||||
|
vAttrs = j->value;
|
||||||
|
} else {
|
||||||
v.mkBool(false);
|
v.mkBool(false);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
vAttrs = j->value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1537,19 +1532,19 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Attr * functor;
|
const Attr * functor;
|
||||||
|
|
||||||
while (nrArgs > 0) {
|
while (nrArgs > 0) {
|
||||||
|
|
||||||
if (vCur.isLambda()) {
|
if (vCur.isLambda()) {
|
||||||
|
|
||||||
ExprLambda & lambda(*vCur.lambda.fun);
|
ExprLambda & lambda(*vCur.payload.lambda.fun);
|
||||||
|
|
||||||
auto size =
|
auto size =
|
||||||
(!lambda.arg ? 0 : 1) +
|
(!lambda.arg ? 0 : 1) +
|
||||||
(lambda.hasFormals() ? lambda.formals->formals.size() : 0);
|
(lambda.hasFormals() ? lambda.formals->formals.size() : 0);
|
||||||
Env & env2(allocEnv(size));
|
Env & env2(allocEnv(size));
|
||||||
env2.up = vCur.lambda.env;
|
env2.up = vCur.payload.lambda.env;
|
||||||
|
|
||||||
Displacement displ = 0;
|
Displacement displ = 0;
|
||||||
|
|
||||||
|
@ -1571,7 +1566,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
argument has a default, use the default. */
|
argument has a default, use the default. */
|
||||||
size_t attrsUsed = 0;
|
size_t attrsUsed = 0;
|
||||||
for (auto & i : lambda.formals->formals) {
|
for (auto & i : lambda.formals->formals) {
|
||||||
auto j = args[0]->attrs->get(i.name);
|
auto j = args[0]->attrs()->get(i.name);
|
||||||
if (!j) {
|
if (!j) {
|
||||||
if (!i.def) {
|
if (!i.def) {
|
||||||
error<TypeError>("function '%1%' called without required argument '%2%'",
|
error<TypeError>("function '%1%' called without required argument '%2%'",
|
||||||
|
@ -1579,7 +1574,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
symbols[i.name])
|
symbols[i.name])
|
||||||
.atPos(lambda.pos)
|
.atPos(lambda.pos)
|
||||||
.withTrace(pos, "from call site")
|
.withTrace(pos, "from call site")
|
||||||
.withFrame(*fun.lambda.env, lambda)
|
.withFrame(*fun.payload.lambda.env, lambda)
|
||||||
.debugThrow();
|
.debugThrow();
|
||||||
}
|
}
|
||||||
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
||||||
|
@ -1591,10 +1586,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
|
|
||||||
/* Check that each actual argument is listed as a formal
|
/* Check that each actual argument is listed as a formal
|
||||||
argument (unless the attribute match specifies a `...'). */
|
argument (unless the attribute match specifies a `...'). */
|
||||||
if (!lambda.formals->ellipsis && attrsUsed != args[0]->attrs->size()) {
|
if (!lambda.formals->ellipsis && attrsUsed != args[0]->attrs()->size()) {
|
||||||
/* Nope, so show the first unexpected argument to the
|
/* Nope, so show the first unexpected argument to the
|
||||||
user. */
|
user. */
|
||||||
for (auto & i : *args[0]->attrs)
|
for (auto & i : *args[0]->attrs())
|
||||||
if (!lambda.formals->has(i.name)) {
|
if (!lambda.formals->has(i.name)) {
|
||||||
std::set<std::string> formalNames;
|
std::set<std::string> formalNames;
|
||||||
for (auto & formal : lambda.formals->formals)
|
for (auto & formal : lambda.formals->formals)
|
||||||
|
@ -1606,7 +1601,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
.atPos(lambda.pos)
|
.atPos(lambda.pos)
|
||||||
.withTrace(pos, "from call site")
|
.withTrace(pos, "from call site")
|
||||||
.withSuggestions(suggestions)
|
.withSuggestions(suggestions)
|
||||||
.withFrame(*fun.lambda.env, lambda)
|
.withFrame(*fun.payload.lambda.env, lambda)
|
||||||
.debugThrow();
|
.debugThrow();
|
||||||
}
|
}
|
||||||
abort(); // can't happen
|
abort(); // can't happen
|
||||||
|
@ -1648,7 +1643,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
|
|
||||||
else if (vCur.isPrimOp()) {
|
else if (vCur.isPrimOp()) {
|
||||||
|
|
||||||
size_t argsLeft = vCur.primOp->arity;
|
size_t argsLeft = vCur.primOp()->arity;
|
||||||
|
|
||||||
if (nrArgs < argsLeft) {
|
if (nrArgs < argsLeft) {
|
||||||
/* We don't have enough arguments, so create a tPrimOpApp chain. */
|
/* We don't have enough arguments, so create a tPrimOpApp chain. */
|
||||||
|
@ -1656,7 +1651,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
/* We have all the arguments, so call the primop. */
|
/* We have all the arguments, so call the primop. */
|
||||||
auto * fn = vCur.primOp;
|
auto * fn = vCur.primOp();
|
||||||
|
|
||||||
nrPrimOpCalls++;
|
nrPrimOpCalls++;
|
||||||
if (countCalls) primOpCalls[fn->name]++;
|
if (countCalls) primOpCalls[fn->name]++;
|
||||||
|
@ -1680,10 +1675,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
Value * primOp = &vCur;
|
Value * primOp = &vCur;
|
||||||
while (primOp->isPrimOpApp()) {
|
while (primOp->isPrimOpApp()) {
|
||||||
argsDone++;
|
argsDone++;
|
||||||
primOp = primOp->primOpApp.left;
|
primOp = primOp->payload.primOpApp.left;
|
||||||
}
|
}
|
||||||
assert(primOp->isPrimOp());
|
assert(primOp->isPrimOp());
|
||||||
auto arity = primOp->primOp->arity;
|
auto arity = primOp->primOp()->arity;
|
||||||
auto argsLeft = arity - argsDone;
|
auto argsLeft = arity - argsDone;
|
||||||
|
|
||||||
if (nrArgs < argsLeft) {
|
if (nrArgs < argsLeft) {
|
||||||
|
@ -1696,13 +1691,13 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
|
|
||||||
Value * vArgs[maxPrimOpArity];
|
Value * vArgs[maxPrimOpArity];
|
||||||
auto n = argsDone;
|
auto n = argsDone;
|
||||||
for (Value * arg = &vCur; arg->isPrimOpApp(); arg = arg->primOpApp.left)
|
for (Value * arg = &vCur; arg->isPrimOpApp(); arg = arg->payload.primOpApp.left)
|
||||||
vArgs[--n] = arg->primOpApp.right;
|
vArgs[--n] = arg->payload.primOpApp.right;
|
||||||
|
|
||||||
for (size_t i = 0; i < argsLeft; ++i)
|
for (size_t i = 0; i < argsLeft; ++i)
|
||||||
vArgs[argsDone + i] = args[i];
|
vArgs[argsDone + i] = args[i];
|
||||||
|
|
||||||
auto fn = primOp->primOp;
|
auto fn = primOp->primOp();
|
||||||
nrPrimOpCalls++;
|
nrPrimOpCalls++;
|
||||||
if (countCalls) primOpCalls[fn->name]++;
|
if (countCalls) primOpCalls[fn->name]++;
|
||||||
|
|
||||||
|
@ -1723,7 +1718,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (vCur.type() == nAttrs && (functor = vCur.attrs->get(sFunctor))) {
|
else if (vCur.type() == nAttrs && (functor = vCur.attrs()->get(sFunctor))) {
|
||||||
/* 'vCur' may be allocated on the stack of the calling
|
/* 'vCur' may be allocated on the stack of the calling
|
||||||
function, but for functors we may keep a reference, so
|
function, but for functors we may keep a reference, so
|
||||||
heap-allocate a copy and use that instead. */
|
heap-allocate a copy and use that instead. */
|
||||||
|
@ -1798,8 +1793,8 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
forceValue(fun, pos);
|
forceValue(fun, pos);
|
||||||
|
|
||||||
if (fun.type() == nAttrs) {
|
if (fun.type() == nAttrs) {
|
||||||
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();
|
Value * v = allocValue();
|
||||||
callFunction(*found->value, fun, *v, pos);
|
callFunction(*found->value, fun, *v, pos);
|
||||||
forceValue(*v, pos);
|
forceValue(*v, pos);
|
||||||
|
@ -1807,14 +1802,14 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fun.isLambda() || !fun.lambda.fun->hasFormals()) {
|
if (!fun.isLambda() || !fun.payload.lambda.fun->hasFormals()) {
|
||||||
res = fun;
|
res = fun;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attrs = buildBindings(std::max(static_cast<uint32_t>(fun.lambda.fun->formals->formals.size()), args.size()));
|
auto attrs = buildBindings(std::max(static_cast<uint32_t>(fun.payload.lambda.fun->formals->formals.size()), args.size()));
|
||||||
|
|
||||||
if (fun.lambda.fun->formals->ellipsis) {
|
if (fun.payload.lambda.fun->formals->ellipsis) {
|
||||||
// If the formals have an ellipsis (eg the function accepts extra args) pass
|
// If the formals have an ellipsis (eg the function accepts extra args) pass
|
||||||
// all available automatic arguments (which includes arguments specified on
|
// all available automatic arguments (which includes arguments specified on
|
||||||
// the command line via --arg/--argstr)
|
// the command line via --arg/--argstr)
|
||||||
|
@ -1822,9 +1817,9 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
attrs.insert(v);
|
attrs.insert(v);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, only pass the arguments that the function accepts
|
// Otherwise, only pass the arguments that the function accepts
|
||||||
for (auto & i : fun.lambda.fun->formals->formals) {
|
for (auto & i : fun.payload.lambda.fun->formals->formals) {
|
||||||
Bindings::iterator j = args.find(i.name);
|
auto j = args.get(i.name);
|
||||||
if (j != args.end()) {
|
if (j) {
|
||||||
attrs.insert(*j);
|
attrs.insert(*j);
|
||||||
} else if (!i.def) {
|
} else if (!i.def) {
|
||||||
error<MissingArgumentError>(R"(cannot evaluate a function that has an argument without a value ('%1%')
|
error<MissingArgumentError>(R"(cannot evaluate a function that has an argument without a value ('%1%')
|
||||||
|
@ -1832,7 +1827,7 @@ Nix attempted to evaluate a function as a top level expression; in
|
||||||
this case it must have its arguments supplied either by default
|
this case it must have its arguments supplied either by default
|
||||||
values, or passed explicitly with '--arg' or '--argstr'. See
|
values, or passed explicitly with '--arg' or '--argstr'. See
|
||||||
https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbols[i.name])
|
https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbols[i.name])
|
||||||
.atPos(i.pos).withFrame(*fun.lambda.env, *fun.lambda.fun).debugThrow();
|
.atPos(i.pos).withFrame(*fun.payload.lambda.env, *fun.payload.lambda.fun).debugThrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1917,17 +1912,17 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
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; }
|
||||||
|
|
||||||
auto attrs = state.buildBindings(v1.attrs->size() + v2.attrs->size());
|
auto attrs = state.buildBindings(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();
|
auto i = v1.attrs()->begin();
|
||||||
Bindings::iterator j = v2.attrs->begin();
|
auto 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) {
|
||||||
attrs.insert(*j);
|
attrs.insert(*j);
|
||||||
++i; ++j;
|
++i; ++j;
|
||||||
|
@ -1938,12 +1933,12 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
attrs.insert(*j++);
|
attrs.insert(*j++);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i != v1.attrs->end()) attrs.insert(*i++);
|
while (i != v1.attrs()->end()) attrs.insert(*i++);
|
||||||
while (j != v2.attrs->end()) attrs.insert(*j++);
|
while (j != v2.attrs()->end()) attrs.insert(*j++);
|
||||||
|
|
||||||
v.mkAttrs(attrs.alreadySorted());
|
v.mkAttrs(attrs.alreadySorted());
|
||||||
|
|
||||||
state.nrOpUpdateValuesCopied += v.attrs->size();
|
state.nrOpUpdateValuesCopied += v.attrs()->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2035,19 +2030,19 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
if (firstType == nInt) {
|
if (firstType == nInt) {
|
||||||
if (vTmp.type() == nInt) {
|
if (vTmp.type() == nInt) {
|
||||||
n += vTmp.integer;
|
n += vTmp.integer();
|
||||||
} else if (vTmp.type() == nFloat) {
|
} else if (vTmp.type() == nFloat) {
|
||||||
// Upgrade the type from int to float;
|
// Upgrade the type from int to float;
|
||||||
firstType = nFloat;
|
firstType = nFloat;
|
||||||
nf = n;
|
nf = n;
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp.fpoint();
|
||||||
} else
|
} else
|
||||||
state.error<EvalError>("cannot add %1% to an integer", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
|
state.error<EvalError>("cannot add %1% to an integer", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
|
||||||
} else if (firstType == nFloat) {
|
} else if (firstType == nFloat) {
|
||||||
if (vTmp.type() == nInt) {
|
if (vTmp.type() == nInt) {
|
||||||
nf += vTmp.integer;
|
nf += vTmp.integer();
|
||||||
} else if (vTmp.type() == nFloat) {
|
} else if (vTmp.type() == nFloat) {
|
||||||
nf += vTmp.fpoint;
|
nf += vTmp.fpoint();
|
||||||
} else
|
} else
|
||||||
state.error<EvalError>("cannot add %1% to a float", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
|
state.error<EvalError>("cannot add %1% to a float", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2120,11 +2115,11 @@ void EvalState::forceValueDeep(Value & v)
|
||||||
forceValue(v, v.determinePos(noPos));
|
forceValue(v, v.determinePos(noPos));
|
||||||
|
|
||||||
if (v.type() == nAttrs) {
|
if (v.type() == nAttrs) {
|
||||||
for (auto & i : *v.attrs)
|
for (auto & i : *v.attrs())
|
||||||
try {
|
try {
|
||||||
// If the value is a thunk, we're evaling. Otherwise no trace necessary.
|
// If the value is a thunk, we're evaling. Otherwise no trace necessary.
|
||||||
auto dts = debugRepl && i.value->isThunk()
|
auto dts = debugRepl && i.value->isThunk()
|
||||||
? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos],
|
? makeDebugTraceStacker(*this, *i.value->payload.thunk.expr, *i.value->payload.thunk.env, positions[i.pos],
|
||||||
"while evaluating the attribute '%1%'", symbols[i.name])
|
"while evaluating the attribute '%1%'", symbols[i.name])
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
|
@ -2155,13 +2150,13 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos, std::string_view errorCt
|
||||||
showType(v),
|
showType(v),
|
||||||
ValuePrinter(*this, v, errorPrintOptions)
|
ValuePrinter(*this, v, errorPrintOptions)
|
||||||
).atPos(pos).debugThrow();
|
).atPos(pos).debugThrow();
|
||||||
return v.integer;
|
return v.integer();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(positions[pos], errorCtx);
|
e.addTrace(positions[pos], errorCtx);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.integer;
|
return v.integer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2170,14 +2165,14 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos, std::string_view err
|
||||||
try {
|
try {
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
if (v.type() == nInt)
|
if (v.type() == nInt)
|
||||||
return v.integer;
|
return v.integer();
|
||||||
else if (v.type() != nFloat)
|
else if (v.type() != nFloat)
|
||||||
error<TypeError>(
|
error<TypeError>(
|
||||||
"expected a float but found %1%: %2%",
|
"expected a float but found %1%: %2%",
|
||||||
showType(v),
|
showType(v),
|
||||||
ValuePrinter(*this, v, errorPrintOptions)
|
ValuePrinter(*this, v, errorPrintOptions)
|
||||||
).atPos(pos).debugThrow();
|
).atPos(pos).debugThrow();
|
||||||
return v.fpoint;
|
return v.fpoint();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(positions[pos], errorCtx);
|
e.addTrace(positions[pos], errorCtx);
|
||||||
throw;
|
throw;
|
||||||
|
@ -2195,19 +2190,19 @@ bool EvalState::forceBool(Value & v, const PosIdx pos, std::string_view errorCtx
|
||||||
showType(v),
|
showType(v),
|
||||||
ValuePrinter(*this, v, errorPrintOptions)
|
ValuePrinter(*this, v, errorPrintOptions)
|
||||||
).atPos(pos).debugThrow();
|
).atPos(pos).debugThrow();
|
||||||
return v.boolean;
|
return v.boolean();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(positions[pos], errorCtx);
|
e.addTrace(positions[pos], errorCtx);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.boolean;
|
return v.boolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EvalState::isFunctor(Value & fun)
|
bool EvalState::isFunctor(Value & fun)
|
||||||
{
|
{
|
||||||
return fun.type() == nAttrs && fun.attrs->find(sFunctor) != fun.attrs->end();
|
return fun.type() == nAttrs && fun.attrs()->find(sFunctor) != fun.attrs()->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2248,8 +2243,8 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos, std::string
|
||||||
|
|
||||||
void copyContext(const Value & v, NixStringContext & context)
|
void copyContext(const Value & v, NixStringContext & context)
|
||||||
{
|
{
|
||||||
if (v.string.context)
|
if (v.payload.string.context)
|
||||||
for (const char * * p = v.string.context; *p; ++p)
|
for (const char * * p = v.payload.string.context; *p; ++p)
|
||||||
context.insert(NixStringContextElem::parse(*p));
|
context.insert(NixStringContextElem::parse(*p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2275,8 +2270,8 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
|
||||||
bool EvalState::isDerivation(Value & v)
|
bool EvalState::isDerivation(Value & v)
|
||||||
{
|
{
|
||||||
if (v.type() != nAttrs) return false;
|
if (v.type() != nAttrs) return false;
|
||||||
Bindings::iterator i = v.attrs->find(sType);
|
auto i = v.attrs()->get(sType);
|
||||||
if (i == v.attrs->end()) return false;
|
if (!i) return false;
|
||||||
forceValue(*i->value, i->pos);
|
forceValue(*i->value, i->pos);
|
||||||
if (i->value->type() != nString) return false;
|
if (i->value->type() != nString) return false;
|
||||||
return i->value->string_view().compare("derivation") == 0;
|
return i->value->string_view().compare("derivation") == 0;
|
||||||
|
@ -2286,8 +2281,8 @@ bool EvalState::isDerivation(Value & v)
|
||||||
std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value & v,
|
std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value & v,
|
||||||
NixStringContext & context, bool coerceMore, bool copyToStore)
|
NixStringContext & context, bool coerceMore, bool copyToStore)
|
||||||
{
|
{
|
||||||
auto i = v.attrs->find(sToString);
|
auto i = v.attrs()->find(sToString);
|
||||||
if (i != v.attrs->end()) {
|
if (i != v.attrs()->end()) {
|
||||||
Value v1;
|
Value v1;
|
||||||
callFunction(*i->value, v, v1, pos);
|
callFunction(*i->value, v, v1, pos);
|
||||||
return coerceToString(pos, v1, context,
|
return coerceToString(pos, v1, context,
|
||||||
|
@ -2319,7 +2314,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
!canonicalizePath && !copyToStore
|
!canonicalizePath && !copyToStore
|
||||||
? // FIXME: hack to preserve path literals that end in a
|
? // FIXME: hack to preserve path literals that end in a
|
||||||
// slash, as in /foo/${x}.
|
// slash, as in /foo/${x}.
|
||||||
v._path.path
|
v.payload.path.path
|
||||||
: copyToStore
|
: copyToStore
|
||||||
? store->printStorePath(copyPathToStore(context, v.path()))
|
? store->printStorePath(copyPathToStore(context, v.path()))
|
||||||
: std::string(v.path().path.abs());
|
: std::string(v.path().path.abs());
|
||||||
|
@ -2329,8 +2324,8 @@ BackedStringView EvalState::coerceToString(
|
||||||
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
|
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
|
||||||
if (maybeString)
|
if (maybeString)
|
||||||
return std::move(*maybeString);
|
return std::move(*maybeString);
|
||||||
auto i = v.attrs->find(sOutPath);
|
auto i = v.attrs()->find(sOutPath);
|
||||||
if (i == v.attrs->end()) {
|
if (i == v.attrs()->end()) {
|
||||||
error<TypeError>(
|
error<TypeError>(
|
||||||
"cannot coerce %1% to a string: %2%",
|
"cannot coerce %1% to a string: %2%",
|
||||||
showType(v),
|
showType(v),
|
||||||
|
@ -2345,7 +2340,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
|
|
||||||
if (v.type() == nExternal) {
|
if (v.type() == nExternal) {
|
||||||
try {
|
try {
|
||||||
return v.external->coerceToString(*this, pos, context, coerceMore, copyToStore);
|
return v.external()->coerceToString(*this, pos, context, coerceMore, copyToStore);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(nullptr, errorCtx);
|
e.addTrace(nullptr, errorCtx);
|
||||||
throw;
|
throw;
|
||||||
|
@ -2355,10 +2350,10 @@ BackedStringView EvalState::coerceToString(
|
||||||
if (coerceMore) {
|
if (coerceMore) {
|
||||||
/* Note that `false' is represented as an empty string for
|
/* Note that `false' is represented as an empty string for
|
||||||
shell scripting convenience, just like `null'. */
|
shell scripting convenience, just like `null'. */
|
||||||
if (v.type() == nBool && v.boolean) return "1";
|
if (v.type() == nBool && v.boolean()) return "1";
|
||||||
if (v.type() == nBool && !v.boolean) return "";
|
if (v.type() == nBool && !v.boolean()) return "";
|
||||||
if (v.type() == nInt) return std::to_string(v.integer);
|
if (v.type() == nInt) return std::to_string(v.integer());
|
||||||
if (v.type() == nFloat) return std::to_string(v.fpoint);
|
if (v.type() == nFloat) return std::to_string(v.fpoint());
|
||||||
if (v.type() == nNull) return "";
|
if (v.type() == nNull) return "";
|
||||||
|
|
||||||
if (v.isList()) {
|
if (v.isList()) {
|
||||||
|
@ -2437,8 +2432,8 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
|
||||||
/* Similarly, handle __toString where the result may be a path
|
/* Similarly, handle __toString where the result may be a path
|
||||||
value. */
|
value. */
|
||||||
if (v.type() == nAttrs) {
|
if (v.type() == nAttrs) {
|
||||||
auto i = v.attrs->find(sToString);
|
auto i = v.attrs()->find(sToString);
|
||||||
if (i != v.attrs->end()) {
|
if (i != v.attrs()->end()) {
|
||||||
Value v1;
|
Value v1;
|
||||||
callFunction(*i->value, v, v1, pos);
|
callFunction(*i->value, v, v1, pos);
|
||||||
return coerceToPath(pos, v1, context, errorCtx);
|
return coerceToPath(pos, v1, context, errorCtx);
|
||||||
|
@ -2532,19 +2527,19 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||||
|
|
||||||
// Special case type-compatibility between float and int
|
// Special case type-compatibility between float and int
|
||||||
if (v1.type() == nInt && v2.type() == nFloat)
|
if (v1.type() == nInt && v2.type() == nFloat)
|
||||||
return v1.integer == v2.fpoint;
|
return v1.integer() == v2.fpoint();
|
||||||
if (v1.type() == nFloat && v2.type() == nInt)
|
if (v1.type() == nFloat && v2.type() == nInt)
|
||||||
return v1.fpoint == v2.integer;
|
return v1.fpoint() == v2.integer();
|
||||||
|
|
||||||
// All other types are not compatible with each other.
|
// All other types are not compatible with each other.
|
||||||
if (v1.type() != v2.type()) return false;
|
if (v1.type() != v2.type()) return false;
|
||||||
|
|
||||||
switch (v1.type()) {
|
switch (v1.type()) {
|
||||||
case nInt:
|
case nInt:
|
||||||
return v1.integer == v2.integer;
|
return v1.integer() == v2.integer();
|
||||||
|
|
||||||
case nBool:
|
case nBool:
|
||||||
return v1.boolean == v2.boolean;
|
return v1.boolean() == v2.boolean();
|
||||||
|
|
||||||
case nString:
|
case nString:
|
||||||
return strcmp(v1.c_str(), v2.c_str()) == 0;
|
return strcmp(v1.c_str(), v2.c_str()) == 0;
|
||||||
|
@ -2552,8 +2547,8 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||||
case nPath:
|
case nPath:
|
||||||
return
|
return
|
||||||
// FIXME: compare accessors by their fingerprint.
|
// FIXME: compare accessors by their fingerprint.
|
||||||
v1._path.accessor == v2._path.accessor
|
v1.payload.path.accessor == v2.payload.path.accessor
|
||||||
&& strcmp(v1._path.path, v2._path.path) == 0;
|
&& strcmp(v1.payload.path.path, v2.payload.path.path) == 0;
|
||||||
|
|
||||||
case nNull:
|
case nNull:
|
||||||
return true;
|
return true;
|
||||||
|
@ -2568,17 +2563,17 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||||
/* If both sets denote a derivation (type = "derivation"),
|
/* If both sets denote a derivation (type = "derivation"),
|
||||||
then compare their outPaths. */
|
then compare their outPaths. */
|
||||||
if (isDerivation(v1) && isDerivation(v2)) {
|
if (isDerivation(v1) && isDerivation(v2)) {
|
||||||
Bindings::iterator i = v1.attrs->find(sOutPath);
|
auto i = v1.attrs()->get(sOutPath);
|
||||||
Bindings::iterator j = v2.attrs->find(sOutPath);
|
auto j = v2.attrs()->get(sOutPath);
|
||||||
if (i != v1.attrs->end() && j != v2.attrs->end())
|
if (i && j)
|
||||||
return eqValues(*i->value, *j->value, pos, errorCtx);
|
return eqValues(*i->value, *j->value, pos, errorCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v1.attrs->size() != v2.attrs->size()) return false;
|
if (v1.attrs()->size() != v2.attrs()->size()) return false;
|
||||||
|
|
||||||
/* Otherwise, compare the attributes one by one. */
|
/* Otherwise, compare the attributes one by one. */
|
||||||
Bindings::iterator i, j;
|
Bindings::const_iterator i, j;
|
||||||
for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j)
|
for (i = v1.attrs()->begin(), j = v2.attrs()->begin(); i != v1.attrs()->end(); ++i, ++j)
|
||||||
if (i->name != j->name || !eqValues(*i->value, *j->value, pos, errorCtx))
|
if (i->name != j->name || !eqValues(*i->value, *j->value, pos, errorCtx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -2590,10 +2585,10 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case nExternal:
|
case nExternal:
|
||||||
return *v1.external == *v2.external;
|
return *v1.external() == *v2.external();
|
||||||
|
|
||||||
case nFloat:
|
case nFloat:
|
||||||
return v1.fpoint == v2.fpoint;
|
return v1.fpoint() == v2.fpoint();
|
||||||
|
|
||||||
case nThunk: // Must not be left by forceValue
|
case nThunk: // Must not be left by forceValue
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -94,7 +94,7 @@ struct PrimOp
|
||||||
void check();
|
void check();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream & output, PrimOp & primOp);
|
std::ostream & operator<<(std::ostream & output, const PrimOp & primOp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Info about a constant
|
* Info about a constant
|
||||||
|
@ -643,9 +643,6 @@ public:
|
||||||
inline Value * allocValue();
|
inline Value * allocValue();
|
||||||
inline Env & allocEnv(size_t size);
|
inline Env & allocEnv(size_t size);
|
||||||
|
|
||||||
Value * allocAttr(Value & vAttrs, Symbol name);
|
|
||||||
Value * allocAttr(Value & vAttrs, std::string_view name);
|
|
||||||
|
|
||||||
Bindings * allocBindings(size_t capacity);
|
Bindings * allocBindings(size_t capacity);
|
||||||
|
|
||||||
BindingsBuilder buildBindings(size_t capacity)
|
BindingsBuilder buildBindings(size_t capacity)
|
||||||
|
|
|
@ -112,7 +112,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
||||||
fetchers::Attrs attrs;
|
fetchers::Attrs attrs;
|
||||||
std::optional<std::string> url;
|
std::optional<std::string> url;
|
||||||
|
|
||||||
for (nix::Attr attr : *(value->attrs)) {
|
for (auto & attr : *value->attrs()) {
|
||||||
try {
|
try {
|
||||||
if (attr.name == sUrl) {
|
if (attr.name == sUrl) {
|
||||||
expectType(state, nString, *attr.value, attr.pos);
|
expectType(state, nString, *attr.value, attr.pos);
|
||||||
|
@ -120,7 +120,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
||||||
attrs.emplace("url", *url);
|
attrs.emplace("url", *url);
|
||||||
} else if (attr.name == sFlake) {
|
} else if (attr.name == sFlake) {
|
||||||
expectType(state, nBool, *attr.value, attr.pos);
|
expectType(state, nBool, *attr.value, attr.pos);
|
||||||
input.isFlake = attr.value->boolean;
|
input.isFlake = attr.value->boolean();
|
||||||
} else if (attr.name == sInputs) {
|
} else if (attr.name == sInputs) {
|
||||||
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath);
|
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath);
|
||||||
} else if (attr.name == sFollows) {
|
} else if (attr.name == sFollows) {
|
||||||
|
@ -137,10 +137,10 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
||||||
attrs.emplace(state.symbols[attr.name], attr.value->c_str());
|
attrs.emplace(state.symbols[attr.name], attr.value->c_str());
|
||||||
break;
|
break;
|
||||||
case nBool:
|
case nBool:
|
||||||
attrs.emplace(state.symbols[attr.name], Explicit<bool> { attr.value->boolean });
|
attrs.emplace(state.symbols[attr.name], Explicit<bool> { attr.value->boolean() });
|
||||||
break;
|
break;
|
||||||
case nInt:
|
case nInt:
|
||||||
attrs.emplace(state.symbols[attr.name], (long unsigned int) attr.value->integer);
|
attrs.emplace(state.symbols[attr.name], (long unsigned int) attr.value->integer());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (attr.name == state.symbols.create("publicKeys")) {
|
if (attr.name == state.symbols.create("publicKeys")) {
|
||||||
|
@ -190,7 +190,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
|
||||||
|
|
||||||
expectType(state, nAttrs, *value, pos);
|
expectType(state, nAttrs, *value, pos);
|
||||||
|
|
||||||
for (nix::Attr & inputAttr : *(*value).attrs) {
|
for (auto & inputAttr : *value->attrs()) {
|
||||||
inputs.emplace(state.symbols[inputAttr.name],
|
inputs.emplace(state.symbols[inputAttr.name],
|
||||||
parseFlakeInput(state,
|
parseFlakeInput(state,
|
||||||
state.symbols[inputAttr.name],
|
state.symbols[inputAttr.name],
|
||||||
|
@ -224,23 +224,23 @@ static Flake readFlake(
|
||||||
.path = flakePath,
|
.path = flakePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto description = vInfo.attrs->get(state.sDescription)) {
|
if (auto description = vInfo.attrs()->get(state.sDescription)) {
|
||||||
expectType(state, nString, *description->value, description->pos);
|
expectType(state, nString, *description->value, description->pos);
|
||||||
flake.description = description->value->c_str();
|
flake.description = description->value->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sInputs = state.symbols.create("inputs");
|
auto sInputs = state.symbols.create("inputs");
|
||||||
|
|
||||||
if (auto inputs = vInfo.attrs->get(sInputs))
|
if (auto inputs = vInfo.attrs()->get(sInputs))
|
||||||
flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, flakePath.parent().path.abs(), lockRootPath); // FIXME
|
flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, flakePath.parent().path.abs(), lockRootPath); // FIXME
|
||||||
|
|
||||||
auto sOutputs = state.symbols.create("outputs");
|
auto sOutputs = state.symbols.create("outputs");
|
||||||
|
|
||||||
if (auto outputs = vInfo.attrs->get(sOutputs)) {
|
if (auto outputs = vInfo.attrs()->get(sOutputs)) {
|
||||||
expectType(state, nFunction, *outputs->value, outputs->pos);
|
expectType(state, nFunction, *outputs->value, outputs->pos);
|
||||||
|
|
||||||
if (outputs->value->isLambda() && outputs->value->lambda.fun->hasFormals()) {
|
if (outputs->value->isLambda() && outputs->value->payload.lambda.fun->hasFormals()) {
|
||||||
for (auto & formal : outputs->value->lambda.fun->formals->formals) {
|
for (auto & formal : outputs->value->payload.lambda.fun->formals->formals) {
|
||||||
if (formal.name != state.sSelf)
|
if (formal.name != state.sSelf)
|
||||||
flake.inputs.emplace(state.symbols[formal.name], FlakeInput {
|
flake.inputs.emplace(state.symbols[formal.name], FlakeInput {
|
||||||
.ref = parseFlakeRef(state.symbols[formal.name])
|
.ref = parseFlakeRef(state.symbols[formal.name])
|
||||||
|
@ -253,10 +253,10 @@ static Flake readFlake(
|
||||||
|
|
||||||
auto sNixConfig = state.symbols.create("nixConfig");
|
auto sNixConfig = state.symbols.create("nixConfig");
|
||||||
|
|
||||||
if (auto nixConfig = vInfo.attrs->get(sNixConfig)) {
|
if (auto nixConfig = vInfo.attrs()->get(sNixConfig)) {
|
||||||
expectType(state, nAttrs, *nixConfig->value, nixConfig->pos);
|
expectType(state, nAttrs, *nixConfig->value, nixConfig->pos);
|
||||||
|
|
||||||
for (auto & setting : *nixConfig->value->attrs) {
|
for (auto & setting : *nixConfig->value->attrs()) {
|
||||||
forceTrivialValue(state, *setting.value, setting.pos);
|
forceTrivialValue(state, *setting.value, setting.pos);
|
||||||
if (setting.value->type() == nString)
|
if (setting.value->type() == nString)
|
||||||
flake.config.settings.emplace(
|
flake.config.settings.emplace(
|
||||||
|
@ -292,7 +292,7 @@ static Flake readFlake(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & attr : *vInfo.attrs) {
|
for (auto & attr : *vInfo.attrs()) {
|
||||||
if (attr.name != state.sDescription &&
|
if (attr.name != state.sDescription &&
|
||||||
attr.name != sInputs &&
|
attr.name != sInputs &&
|
||||||
attr.name != sOutputs &&
|
attr.name != sOutputs &&
|
||||||
|
@ -893,17 +893,17 @@ static void prim_flakeRefToString(
|
||||||
state.forceAttrs(*args[0], noPos,
|
state.forceAttrs(*args[0], noPos,
|
||||||
"while evaluating the argument passed to builtins.flakeRefToString");
|
"while evaluating the argument passed to builtins.flakeRefToString");
|
||||||
fetchers::Attrs attrs;
|
fetchers::Attrs attrs;
|
||||||
for (const auto & attr : *args[0]->attrs) {
|
for (const auto & attr : *args[0]->attrs()) {
|
||||||
auto t = attr.value->type();
|
auto t = attr.value->type();
|
||||||
if (t == nInt) {
|
if (t == nInt) {
|
||||||
attrs.emplace(state.symbols[attr.name],
|
attrs.emplace(state.symbols[attr.name],
|
||||||
(uint64_t) attr.value->integer);
|
(uint64_t) attr.value->integer());
|
||||||
} else if (t == nBool) {
|
} else if (t == nBool) {
|
||||||
attrs.emplace(state.symbols[attr.name],
|
attrs.emplace(state.symbols[attr.name],
|
||||||
Explicit<bool> { attr.value->boolean });
|
Explicit<bool> { attr.value->boolean() });
|
||||||
} else if (t == nString) {
|
} else if (t == nString) {
|
||||||
attrs.emplace(state.symbols[attr.name],
|
attrs.emplace(state.symbols[attr.name],
|
||||||
std::string(attr.value->string_view()));
|
std::string(attr.value->string_view()));
|
||||||
} else {
|
} else {
|
||||||
state.error<EvalError>(
|
state.error<EvalError>(
|
||||||
"flake reference attribute sets may only contain integers, Booleans, "
|
"flake reference attribute sets may only contain integers, Booleans, "
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
PackageInfo::PackageInfo(EvalState & state, std::string attrPath, Bindings * attrs)
|
PackageInfo::PackageInfo(EvalState & state, std::string attrPath, const Bindings * attrs)
|
||||||
: state(&state), attrs(attrs), attrPath(std::move(attrPath))
|
: state(&state), attrs(attrs), attrPath(std::move(attrPath))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -69,12 +69,11 @@ std::string PackageInfo::querySystem() const
|
||||||
std::optional<StorePath> PackageInfo::queryDrvPath() const
|
std::optional<StorePath> PackageInfo::queryDrvPath() const
|
||||||
{
|
{
|
||||||
if (!drvPath && attrs) {
|
if (!drvPath && attrs) {
|
||||||
Bindings::iterator i = attrs->find(state->sDrvPath);
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
if (i == attrs->end())
|
if (auto i = attrs->get(state->sDrvPath))
|
||||||
drvPath = {std::nullopt};
|
|
||||||
else
|
|
||||||
drvPath = {state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation")};
|
drvPath = {state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation")};
|
||||||
|
else
|
||||||
|
drvPath = {std::nullopt};
|
||||||
}
|
}
|
||||||
return drvPath.value_or(std::nullopt);
|
return drvPath.value_or(std::nullopt);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +90,7 @@ StorePath PackageInfo::requireDrvPath() const
|
||||||
StorePath PackageInfo::queryOutPath() const
|
StorePath PackageInfo::queryOutPath() const
|
||||||
{
|
{
|
||||||
if (!outPath && attrs) {
|
if (!outPath && attrs) {
|
||||||
Bindings::iterator i = attrs->find(state->sOutPath);
|
auto i = attrs->find(state->sOutPath);
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
if (i != attrs->end())
|
if (i != attrs->end())
|
||||||
outPath = state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the output path of a derivation");
|
outPath = state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the output path of a derivation");
|
||||||
|
@ -106,8 +105,8 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||||
{
|
{
|
||||||
if (outputs.empty()) {
|
if (outputs.empty()) {
|
||||||
/* Get the ‘outputs’ list. */
|
/* Get the ‘outputs’ list. */
|
||||||
Bindings::iterator i;
|
const Attr * i;
|
||||||
if (attrs && (i = attrs->find(state->sOutputs)) != attrs->end()) {
|
if (attrs && (i = attrs->get(state->sOutputs))) {
|
||||||
state->forceList(*i->value, i->pos, "while evaluating the 'outputs' attribute of a derivation");
|
state->forceList(*i->value, i->pos, "while evaluating the 'outputs' attribute of a derivation");
|
||||||
|
|
||||||
/* For each output... */
|
/* For each output... */
|
||||||
|
@ -116,13 +115,13 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||||
|
|
||||||
if (withPaths) {
|
if (withPaths) {
|
||||||
/* Evaluate the corresponding set. */
|
/* Evaluate the corresponding set. */
|
||||||
Bindings::iterator out = attrs->find(state->symbols.create(output));
|
auto out = attrs->get(state->symbols.create(output));
|
||||||
if (out == attrs->end()) continue; // FIXME: throw error?
|
if (!out) continue; // FIXME: throw error?
|
||||||
state->forceAttrs(*out->value, i->pos, "while evaluating an output of a derivation");
|
state->forceAttrs(*out->value, i->pos, "while evaluating an output of a derivation");
|
||||||
|
|
||||||
/* And evaluate its ‘outPath’ attribute. */
|
/* And evaluate its ‘outPath’ attribute. */
|
||||||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
auto outPath = out->value->attrs()->get(state->sOutPath);
|
||||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
if (!outPath) continue; // FIXME: throw error?
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context, "while evaluating an output path of a derivation"));
|
outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context, "while evaluating an output path of a derivation"));
|
||||||
} else
|
} else
|
||||||
|
@ -135,8 +134,8 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||||
if (!onlyOutputsToInstall || !attrs)
|
if (!onlyOutputsToInstall || !attrs)
|
||||||
return outputs;
|
return outputs;
|
||||||
|
|
||||||
Bindings::iterator i;
|
const Attr * i;
|
||||||
if (attrs && (i = attrs->find(state->sOutputSpecified)) != attrs->end() && state->forceBool(*i->value, i->pos, "while evaluating the 'outputSpecified' attribute of a derivation")) {
|
if (attrs && (i = attrs->get(state->sOutputSpecified)) && state->forceBool(*i->value, i->pos, "while evaluating the 'outputSpecified' attribute of a derivation")) {
|
||||||
Outputs result;
|
Outputs result;
|
||||||
auto out = outputs.find(queryOutputName());
|
auto out = outputs.find(queryOutputName());
|
||||||
if (out == outputs.end())
|
if (out == outputs.end())
|
||||||
|
@ -167,21 +166,21 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||||
std::string PackageInfo::queryOutputName() const
|
std::string PackageInfo::queryOutputName() const
|
||||||
{
|
{
|
||||||
if (outputName == "" && attrs) {
|
if (outputName == "" && attrs) {
|
||||||
Bindings::iterator i = attrs->find(state->sOutputName);
|
auto i = attrs->get(state->sOutputName);
|
||||||
outputName = i != attrs->end() ? state->forceStringNoCtx(*i->value, noPos, "while evaluating the output name of a derivation") : "";
|
outputName = i ? state->forceStringNoCtx(*i->value, noPos, "while evaluating the output name of a derivation") : "";
|
||||||
}
|
}
|
||||||
return outputName;
|
return outputName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Bindings * PackageInfo::getMeta()
|
const Bindings * PackageInfo::getMeta()
|
||||||
{
|
{
|
||||||
if (meta) return meta;
|
if (meta) return meta;
|
||||||
if (!attrs) return 0;
|
if (!attrs) return 0;
|
||||||
Bindings::iterator a = attrs->find(state->sMeta);
|
auto a = attrs->get(state->sMeta);
|
||||||
if (a == attrs->end()) return 0;
|
if (!a) return 0;
|
||||||
state->forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
|
state->forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
|
||||||
meta = a->value->attrs;
|
meta = a->value->attrs();
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,9 +204,8 @@ bool PackageInfo::checkMeta(Value & v)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (v.type() == nAttrs) {
|
else if (v.type() == nAttrs) {
|
||||||
Bindings::iterator i = v.attrs->find(state->sOutPath);
|
if (v.attrs()->get(state->sOutPath)) return false;
|
||||||
if (i != v.attrs->end()) return false;
|
for (auto & i : *v.attrs())
|
||||||
for (auto & i : *v.attrs)
|
|
||||||
if (!checkMeta(*i.value)) return false;
|
if (!checkMeta(*i.value)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -219,8 +217,8 @@ bool PackageInfo::checkMeta(Value & v)
|
||||||
Value * PackageInfo::queryMeta(const std::string & name)
|
Value * PackageInfo::queryMeta(const std::string & name)
|
||||||
{
|
{
|
||||||
if (!getMeta()) return 0;
|
if (!getMeta()) return 0;
|
||||||
Bindings::iterator a = meta->find(state->symbols.create(name));
|
auto a = meta->get(state->symbols.create(name));
|
||||||
if (a == meta->end() || !checkMeta(*a->value)) return 0;
|
if (!a || !checkMeta(*a->value)) return 0;
|
||||||
return a->value;
|
return a->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +235,7 @@ NixInt PackageInfo::queryMetaInt(const std::string & name, NixInt def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
Value * v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type() == nInt) return v->integer;
|
if (v->type() == nInt) return v->integer();
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
integer meta fields. */
|
integer meta fields. */
|
||||||
|
@ -251,7 +249,7 @@ NixFloat PackageInfo::queryMetaFloat(const std::string & name, NixFloat def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
Value * v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type() == nFloat) return v->fpoint;
|
if (v->type() == nFloat) return v->fpoint();
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
float meta fields. */
|
float meta fields. */
|
||||||
|
@ -266,7 +264,7 @@ bool PackageInfo::queryMetaBool(const std::string & name, bool def)
|
||||||
{
|
{
|
||||||
Value * v = queryMeta(name);
|
Value * v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type() == nBool) return v->boolean;
|
if (v->type() == nBool) return v->boolean();
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
Boolean meta fields. */
|
Boolean meta fields. */
|
||||||
|
@ -292,7 +290,7 @@ void PackageInfo::setMeta(const std::string & name, Value * v)
|
||||||
|
|
||||||
|
|
||||||
/* Cache for already considered attrsets. */
|
/* Cache for already considered attrsets. */
|
||||||
typedef std::set<Bindings *> Done;
|
typedef std::set<const Bindings *> Done;
|
||||||
|
|
||||||
|
|
||||||
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
|
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
|
||||||
|
@ -309,9 +307,9 @@ static bool getDerivation(EvalState & state, Value & v,
|
||||||
|
|
||||||
/* Remove spurious duplicates (e.g., a set like `rec { x =
|
/* Remove spurious duplicates (e.g., a set like `rec { x =
|
||||||
derivation {...}; y = x;}'. */
|
derivation {...}; y = x;}'. */
|
||||||
if (!done.insert(v.attrs).second) return false;
|
if (!done.insert(v.attrs()).second) return false;
|
||||||
|
|
||||||
PackageInfo drv(state, attrPath, v.attrs);
|
PackageInfo drv(state, attrPath, v.attrs());
|
||||||
|
|
||||||
drv.queryName();
|
drv.queryName();
|
||||||
|
|
||||||
|
@ -361,14 +359,14 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
|
|
||||||
/* !!! 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()->get(state.symbols.create("_combineChannels"));
|
||||||
|
|
||||||
/* 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(state.symbols)) {
|
for (auto & i : v.attrs()->lexicographicOrder(state.symbols)) {
|
||||||
debug("evaluating attribute '%1%'", state.symbols[i->name]);
|
debug("evaluating attribute '%1%'", state.symbols[i->name]);
|
||||||
if (!std::regex_match(std::string(state.symbols[i->name]), attrRegex))
|
if (!std::regex_match(std::string(state.symbols[i->name]), attrRegex))
|
||||||
continue;
|
continue;
|
||||||
|
@ -380,8 +378,8 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
should we recurse into it? => Only if it has a
|
should we recurse into it? => Only if it has a
|
||||||
`recurseForDerivations = true' attribute. */
|
`recurseForDerivations = true' attribute. */
|
||||||
if (i->value->type() == nAttrs) {
|
if (i->value->type() == nAttrs) {
|
||||||
Bindings::iterator j = i->value->attrs->find(state.sRecurseForDerivations);
|
auto j = i->value->attrs()->get(state.sRecurseForDerivations);
|
||||||
if (j != i->value->attrs->end() && state.forceBool(*j->value, j->pos, "while evaluating the attribute `recurseForDerivations`"))
|
if (j && state.forceBool(*j->value, j->pos, "while evaluating the attribute `recurseForDerivations`"))
|
||||||
getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ private:
|
||||||
*/
|
*/
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
Bindings * attrs = nullptr, * meta = nullptr;
|
const Bindings * attrs = nullptr, * meta = nullptr;
|
||||||
|
|
||||||
Bindings * getMeta();
|
const Bindings * getMeta();
|
||||||
|
|
||||||
bool checkMeta(Value & v);
|
bool checkMeta(Value & v);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public:
|
||||||
std::string attrPath;
|
std::string attrPath;
|
||||||
|
|
||||||
PackageInfo(EvalState & state) : state(&state) { };
|
PackageInfo(EvalState & state) : state(&state) { };
|
||||||
PackageInfo(EvalState & state, std::string attrPath, Bindings * attrs);
|
PackageInfo(EvalState & state, std::string attrPath, const Bindings * attrs);
|
||||||
PackageInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs);
|
PackageInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs);
|
||||||
|
|
||||||
std::string queryName() const;
|
std::string queryName() const;
|
||||||
|
|
|
@ -28,12 +28,12 @@ void Expr::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
|
|
||||||
void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const
|
void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
{
|
{
|
||||||
str << v.integer;
|
str << v.integer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const
|
void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
{
|
{
|
||||||
str << v.fpoint;
|
str << v.fpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
|
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
|
|
|
@ -223,13 +223,13 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||||
else {
|
else {
|
||||||
state.forceAttrs(*vScope, pos, "while evaluating the first argument passed to builtins.scopedImport");
|
state.forceAttrs(*vScope, pos, "while evaluating the first argument passed to builtins.scopedImport");
|
||||||
|
|
||||||
Env * env = &state.allocEnv(vScope->attrs->size());
|
Env * env = &state.allocEnv(vScope->attrs()->size());
|
||||||
env->up = &state.baseEnv;
|
env->up = &state.baseEnv;
|
||||||
|
|
||||||
auto staticEnv = std::make_shared<StaticEnv>(nullptr, state.staticBaseEnv.get(), vScope->attrs->size());
|
auto staticEnv = std::make_shared<StaticEnv>(nullptr, state.staticBaseEnv.get(), vScope->attrs()->size());
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
for (auto & attr : *vScope->attrs) {
|
for (auto & attr : *vScope->attrs()) {
|
||||||
staticEnv->vars.emplace_back(attr.name, displ);
|
staticEnv->vars.emplace_back(attr.name, displ);
|
||||||
env->values[displ++] = attr.value;
|
env->values[displ++] = attr.value;
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Val
|
||||||
case nList: t = "list"; break;
|
case nList: t = "list"; break;
|
||||||
case nFunction: t = "lambda"; break;
|
case nFunction: t = "lambda"; break;
|
||||||
case nExternal:
|
case nExternal:
|
||||||
t = args[0]->external->typeOf();
|
t = args[0]->external()->typeOf();
|
||||||
break;
|
break;
|
||||||
case nFloat: t = "float"; break;
|
case nFloat: t = "float"; break;
|
||||||
case nThunk: abort();
|
case nThunk: abort();
|
||||||
|
@ -582,9 +582,9 @@ struct CompareValues
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (v1->type() == nFloat && v2->type() == nInt)
|
if (v1->type() == nFloat && v2->type() == nInt)
|
||||||
return v1->fpoint < v2->integer;
|
return v1->fpoint() < v2->integer();
|
||||||
if (v1->type() == nInt && v2->type() == nFloat)
|
if (v1->type() == nInt && v2->type() == nFloat)
|
||||||
return v1->integer < v2->fpoint;
|
return v1->integer() < v2->fpoint();
|
||||||
if (v1->type() != v2->type())
|
if (v1->type() != v2->type())
|
||||||
state.error<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow();
|
state.error<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow();
|
||||||
// Allow selecting a subset of enum values
|
// Allow selecting a subset of enum values
|
||||||
|
@ -592,16 +592,16 @@ struct CompareValues
|
||||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
switch (v1->type()) {
|
switch (v1->type()) {
|
||||||
case nInt:
|
case nInt:
|
||||||
return v1->integer < v2->integer;
|
return v1->integer() < v2->integer();
|
||||||
case nFloat:
|
case nFloat:
|
||||||
return v1->fpoint < v2->fpoint;
|
return v1->fpoint() < v2->fpoint();
|
||||||
case nString:
|
case nString:
|
||||||
return strcmp(v1->c_str(), v2->c_str()) < 0;
|
return strcmp(v1->c_str(), v2->c_str()) < 0;
|
||||||
case nPath:
|
case nPath:
|
||||||
// Note: we don't take the accessor into account
|
// Note: we don't take the accessor into account
|
||||||
// since it's not obvious how to compare them in a
|
// since it's not obvious how to compare them in a
|
||||||
// reproducible way.
|
// reproducible way.
|
||||||
return strcmp(v1->_path.path, v2->_path.path) < 0;
|
return strcmp(v1->payload.path.path, v2->payload.path.path) < 0;
|
||||||
case nList:
|
case nList:
|
||||||
// Lexicographic comparison
|
// Lexicographic comparison
|
||||||
for (size_t i = 0;; i++) {
|
for (size_t i = 0;; i++) {
|
||||||
|
@ -633,13 +633,13 @@ typedef std::list<Value *> ValueList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static Bindings::iterator getAttr(
|
static Bindings::const_iterator getAttr(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
Symbol attrSym,
|
Symbol attrSym,
|
||||||
Bindings * attrSet,
|
const Bindings * attrSet,
|
||||||
std::string_view errorCtx)
|
std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
Bindings::iterator value = attrSet->find(attrSym);
|
auto value = attrSet->find(attrSym);
|
||||||
if (value == attrSet->end()) {
|
if (value == attrSet->end()) {
|
||||||
state.error<TypeError>("attribute '%s' missing", state.symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow();
|
state.error<TypeError>("attribute '%s' missing", state.symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow();
|
||||||
}
|
}
|
||||||
|
@ -651,7 +651,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
|
||||||
state.forceAttrs(*args[0], noPos, "while evaluating the first argument passed to builtins.genericClosure");
|
state.forceAttrs(*args[0], noPos, "while evaluating the first argument passed to builtins.genericClosure");
|
||||||
|
|
||||||
/* Get the start set. */
|
/* Get the start set. */
|
||||||
Bindings::iterator startSet = getAttr(state, state.sStartSet, args[0]->attrs, "in the attrset passed as argument to builtins.genericClosure");
|
auto startSet = getAttr(state, state.sStartSet, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||||
|
|
||||||
state.forceList(*startSet->value, noPos, "while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure");
|
state.forceList(*startSet->value, noPos, "while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure");
|
||||||
|
|
||||||
|
@ -665,7 +665,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the operator. */
|
/* Get the operator. */
|
||||||
Bindings::iterator op = getAttr(state, state.sOperator, args[0]->attrs, "in the attrset passed as argument to builtins.genericClosure");
|
auto op = getAttr(state, state.sOperator, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||||
state.forceFunction(*op->value, noPos, "while evaluating the 'operator' attribute passed as argument to builtins.genericClosure");
|
state.forceFunction(*op->value, noPos, "while evaluating the 'operator' attribute passed as argument to builtins.genericClosure");
|
||||||
|
|
||||||
/* Construct the closure by applying the operator to elements of
|
/* Construct the closure by applying the operator to elements of
|
||||||
|
@ -682,7 +682,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
|
||||||
|
|
||||||
state.forceAttrs(*e, noPos, "while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure");
|
state.forceAttrs(*e, noPos, "while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure");
|
||||||
|
|
||||||
Bindings::iterator key = getAttr(state, state.sKey, e->attrs, "in one of the attrsets generated by (or initially passed to) builtins.genericClosure");
|
auto key = getAttr(state, state.sKey, e->attrs(), "in one of the attrsets generated by (or initially passed to) builtins.genericClosure");
|
||||||
state.forceValue(*key->value, noPos);
|
state.forceValue(*key->value, noPos);
|
||||||
|
|
||||||
if (!doneKeys.insert(key->value).second) continue;
|
if (!doneKeys.insert(key->value).second) continue;
|
||||||
|
@ -1050,7 +1050,11 @@ static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Val
|
||||||
* Derivations
|
* Derivations
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
|
||||||
static void derivationStrictInternal(EvalState & state, const std::string & name, Bindings * attrs, Value & v);
|
static void derivationStrictInternal(
|
||||||
|
EvalState & state,
|
||||||
|
const std::string & name,
|
||||||
|
const Bindings * attrs,
|
||||||
|
Value & v);
|
||||||
|
|
||||||
/* Construct (as a unobservable side effect) a Nix derivation
|
/* Construct (as a unobservable side effect) a Nix derivation
|
||||||
expression that performs the derivation described by the argument
|
expression that performs the derivation described by the argument
|
||||||
|
@ -1063,10 +1067,10 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.derivationStrict");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.derivationStrict");
|
||||||
|
|
||||||
Bindings * attrs = args[0]->attrs;
|
auto attrs = args[0]->attrs();
|
||||||
|
|
||||||
/* Figure out the name first (for stack backtraces). */
|
/* Figure out the name first (for stack backtraces). */
|
||||||
Bindings::iterator nameAttr = getAttr(state, state.sName, attrs, "in the attrset passed as argument to builtins.derivationStrict");
|
auto nameAttr = getAttr(state, state.sName, attrs, "in the attrset passed as argument to builtins.derivationStrict");
|
||||||
|
|
||||||
std::string drvName;
|
std::string drvName;
|
||||||
try {
|
try {
|
||||||
|
@ -1105,8 +1109,11 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void derivationStrictInternal(EvalState & state, const std::string &
|
static void derivationStrictInternal(
|
||||||
drvName, Bindings * attrs, Value & v)
|
EvalState & state,
|
||||||
|
const std::string & drvName,
|
||||||
|
const Bindings * attrs,
|
||||||
|
Value & v)
|
||||||
{
|
{
|
||||||
/* Check whether attributes should be passed as a JSON file. */
|
/* Check whether attributes should be passed as a JSON file. */
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
@ -1708,11 +1715,11 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.findFile");
|
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.findFile");
|
||||||
|
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
Bindings::iterator i = v2->attrs->find(state.sPrefix);
|
auto i = v2->attrs()->find(state.sPrefix);
|
||||||
if (i != v2->attrs->end())
|
if (i != v2->attrs()->end())
|
||||||
prefix = state.forceStringNoCtx(*i->value, pos, "while evaluating the `prefix` attribute of an element of the list passed to builtins.findFile");
|
prefix = state.forceStringNoCtx(*i->value, pos, "while evaluating the `prefix` attribute of an element of the list passed to builtins.findFile");
|
||||||
|
|
||||||
i = getAttr(state, state.sPath, v2->attrs, "in an element of the __nixPath");
|
i = getAttr(state, state.sPath, v2->attrs(), "in an element of the __nixPath");
|
||||||
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
auto path = state.coerceToString(pos, *i->value, context,
|
auto path = state.coerceToString(pos, *i->value, context,
|
||||||
|
@ -2386,7 +2393,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
|
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to 'builtins.path'");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to 'builtins.path'");
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs()) {
|
||||||
auto n = state.symbols[attr.name];
|
auto n = state.symbols[attr.name];
|
||||||
if (n == "path")
|
if (n == "path")
|
||||||
path.emplace(state.coerceToPath(attr.pos, *attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'"));
|
path.emplace(state.coerceToPath(attr.pos, *attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'"));
|
||||||
|
@ -2461,9 +2468,9 @@ static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrNames");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrNames");
|
||||||
|
|
||||||
auto list = state.buildList(args[0]->attrs->size());
|
auto list = state.buildList(args[0]->attrs()->size());
|
||||||
|
|
||||||
for (const auto & [n, i] : enumerate(*args[0]->attrs))
|
for (const auto & [n, i] : enumerate(*args[0]->attrs()))
|
||||||
(list[n] = state.allocValue())->mkString(state.symbols[i.name]);
|
(list[n] = state.allocValue())->mkString(state.symbols[i.name]);
|
||||||
|
|
||||||
std::sort(list.begin(), list.end(),
|
std::sort(list.begin(), list.end(),
|
||||||
|
@ -2489,9 +2496,9 @@ static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrValues");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrValues");
|
||||||
|
|
||||||
auto list = state.buildList(args[0]->attrs->size());
|
auto list = state.buildList(args[0]->attrs()->size());
|
||||||
|
|
||||||
for (const auto & [n, i] : enumerate(*args[0]->attrs))
|
for (const auto & [n, i] : enumerate(*args[0]->attrs()))
|
||||||
list[n] = (Value *) &i;
|
list[n] = (Value *) &i;
|
||||||
|
|
||||||
std::sort(list.begin(), list.end(),
|
std::sort(list.begin(), list.end(),
|
||||||
|
@ -2522,10 +2529,10 @@ void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
{
|
{
|
||||||
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getAttr");
|
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getAttr");
|
||||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.getAttr");
|
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.getAttr");
|
||||||
Bindings::iterator i = getAttr(
|
auto i = getAttr(
|
||||||
state,
|
state,
|
||||||
state.symbols.create(attr),
|
state.symbols.create(attr),
|
||||||
args[1]->attrs,
|
args[1]->attrs(),
|
||||||
"in the attribute set under consideration"
|
"in the attribute set under consideration"
|
||||||
);
|
);
|
||||||
// !!! add to stack trace?
|
// !!! add to stack trace?
|
||||||
|
@ -2551,8 +2558,8 @@ static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * *
|
||||||
{
|
{
|
||||||
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.unsafeGetAttrPos");
|
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.unsafeGetAttrPos");
|
||||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.unsafeGetAttrPos");
|
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.unsafeGetAttrPos");
|
||||||
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
|
auto i = args[1]->attrs()->find(state.symbols.create(attr));
|
||||||
if (i == args[1]->attrs->end())
|
if (i == args[1]->attrs()->end())
|
||||||
v.mkNull();
|
v.mkNull();
|
||||||
else
|
else
|
||||||
state.mkPos(v, i->pos);
|
state.mkPos(v, i->pos);
|
||||||
|
@ -2580,13 +2587,13 @@ static struct LazyPosAcessors {
|
||||||
PrimOp primop_lineOfPos{
|
PrimOp primop_lineOfPos{
|
||||||
.arity = 1,
|
.arity = 1,
|
||||||
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
||||||
v.mkInt(state.positions[PosIdx(args[0]->integer)].line);
|
v.mkInt(state.positions[PosIdx(args[0]->integer())].line);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PrimOp primop_columnOfPos{
|
PrimOp primop_columnOfPos{
|
||||||
.arity = 1,
|
.arity = 1,
|
||||||
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
||||||
v.mkInt(state.positions[PosIdx(args[0]->integer)].column);
|
v.mkInt(state.positions[PosIdx(args[0]->integer())].column);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2617,7 +2624,7 @@ static void prim_hasAttr(EvalState & state, const PosIdx pos, Value * * args, Va
|
||||||
{
|
{
|
||||||
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hasAttr");
|
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hasAttr");
|
||||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.hasAttr");
|
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.hasAttr");
|
||||||
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
|
v.mkBool(args[1]->attrs()->find(state.symbols.create(attr)) != args[1]->attrs()->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_hasAttr({
|
static RegisterPrimOp primop_hasAttr({
|
||||||
|
@ -2667,9 +2674,9 @@ static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value * * args
|
||||||
/* Copy all attributes not in that set. Note that we don't need
|
/* Copy all attributes not in that set. Note that we don't need
|
||||||
to sort v.attrs because it's a subset of an already sorted
|
to sort v.attrs because it's a subset of an already sorted
|
||||||
vector. */
|
vector. */
|
||||||
auto attrs = state.buildBindings(args[0]->attrs->size());
|
auto attrs = state.buildBindings(args[0]->attrs()->size());
|
||||||
std::set_difference(
|
std::set_difference(
|
||||||
args[0]->attrs->begin(), args[0]->attrs->end(),
|
args[0]->attrs()->begin(), args[0]->attrs()->end(),
|
||||||
names.begin(), names.end(),
|
names.begin(), names.end(),
|
||||||
std::back_inserter(attrs));
|
std::back_inserter(attrs));
|
||||||
v.mkAttrs(attrs.alreadySorted());
|
v.mkAttrs(attrs.alreadySorted());
|
||||||
|
@ -2707,13 +2714,13 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args
|
||||||
for (auto v2 : args[0]->listItems()) {
|
for (auto v2 : args[0]->listItems()) {
|
||||||
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.listToAttrs");
|
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.listToAttrs");
|
||||||
|
|
||||||
Bindings::iterator j = getAttr(state, state.sName, v2->attrs, "in a {name=...; value=...;} pair");
|
auto j = getAttr(state, state.sName, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||||
|
|
||||||
auto name = state.forceStringNoCtx(*j->value, j->pos, "while evaluating the `name` attribute of an element of the list passed to builtins.listToAttrs");
|
auto name = state.forceStringNoCtx(*j->value, j->pos, "while evaluating the `name` attribute of an element of the list passed to builtins.listToAttrs");
|
||||||
|
|
||||||
auto sym = state.symbols.create(name);
|
auto sym = state.symbols.create(name);
|
||||||
if (seen.insert(sym).second) {
|
if (seen.insert(sym).second) {
|
||||||
Bindings::iterator j2 = getAttr(state, state.sValue, v2->attrs, "in a {name=...; value=...;} pair");
|
auto j2 = getAttr(state, state.sValue, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||||
attrs.insert(sym, j2->value, j2->pos);
|
attrs.insert(sym, j2->value, j2->pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2757,8 +2764,8 @@ static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value * * a
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.intersectAttrs");
|
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.intersectAttrs");
|
||||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.intersectAttrs");
|
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.intersectAttrs");
|
||||||
|
|
||||||
Bindings &left = *args[0]->attrs;
|
auto & left = *args[0]->attrs();
|
||||||
Bindings &right = *args[1]->attrs;
|
auto & right = *args[1]->attrs();
|
||||||
|
|
||||||
auto attrs = state.buildBindings(std::min(left.size(), right.size()));
|
auto attrs = state.buildBindings(std::min(left.size(), right.size()));
|
||||||
|
|
||||||
|
@ -2802,14 +2809,14 @@ static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value * * a
|
||||||
|
|
||||||
if (left.size() < right.size()) {
|
if (left.size() < right.size()) {
|
||||||
for (auto & l : left) {
|
for (auto & l : left) {
|
||||||
Bindings::iterator r = right.find(l.name);
|
auto r = right.find(l.name);
|
||||||
if (r != right.end())
|
if (r != right.end())
|
||||||
attrs.insert(*r);
|
attrs.insert(*r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (auto & r : right) {
|
for (auto & r : right) {
|
||||||
Bindings::iterator l = left.find(r.name);
|
auto l = left.find(r.name);
|
||||||
if (l != left.end())
|
if (l != left.end())
|
||||||
attrs.insert(r);
|
attrs.insert(r);
|
||||||
}
|
}
|
||||||
|
@ -2840,8 +2847,7 @@ static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
|
|
||||||
for (auto v2 : args[1]->listItems()) {
|
for (auto v2 : args[1]->listItems()) {
|
||||||
state.forceAttrs(*v2, pos, "while evaluating an element in the list passed as second argument to builtins.catAttrs");
|
state.forceAttrs(*v2, pos, "while evaluating an element in the list passed as second argument to builtins.catAttrs");
|
||||||
Bindings::iterator i = v2->attrs->find(attrName);
|
if (auto i = v2->attrs()->get(attrName))
|
||||||
if (i != v2->attrs->end())
|
|
||||||
res[found++] = i->value;
|
res[found++] = i->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2878,13 +2884,13 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
if (!args[0]->isLambda())
|
if (!args[0]->isLambda())
|
||||||
state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
|
state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
|
||||||
|
|
||||||
if (!args[0]->lambda.fun->hasFormals()) {
|
if (!args[0]->payload.lambda.fun->hasFormals()) {
|
||||||
v.mkAttrs(&state.emptyBindings);
|
v.mkAttrs(&state.emptyBindings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attrs = state.buildBindings(args[0]->lambda.fun->formals->formals.size());
|
auto attrs = state.buildBindings(args[0]->payload.lambda.fun->formals->formals.size());
|
||||||
for (auto & i : args[0]->lambda.fun->formals->formals)
|
for (auto & i : args[0]->payload.lambda.fun->formals->formals)
|
||||||
attrs.insert(i.name, state.getBool(i.def), i.pos);
|
attrs.insert(i.name, state.getBool(i.def), i.pos);
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
@ -2911,9 +2917,9 @@ static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.mapAttrs");
|
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.mapAttrs");
|
||||||
|
|
||||||
auto attrs = state.buildBindings(args[1]->attrs->size());
|
auto attrs = state.buildBindings(args[1]->attrs()->size());
|
||||||
|
|
||||||
for (auto & i : *args[1]->attrs) {
|
for (auto & i : *args[1]->attrs()) {
|
||||||
Value * vName = state.allocValue();
|
Value * vName = state.allocValue();
|
||||||
Value * vFun2 = state.allocValue();
|
Value * vFun2 = state.allocValue();
|
||||||
vName->mkString(state.symbols[i.name]);
|
vName->mkString(state.symbols[i.name]);
|
||||||
|
@ -2963,7 +2969,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
|
|
||||||
for (auto & vElem : listItems) {
|
for (auto & vElem : listItems) {
|
||||||
state.forceAttrs(*vElem, noPos, "while evaluating a value of the list passed as second argument to builtins.zipAttrsWith");
|
state.forceAttrs(*vElem, noPos, "while evaluating a value of the list passed as second argument to builtins.zipAttrsWith");
|
||||||
for (auto & attr : *vElem->attrs)
|
for (auto & attr : *vElem->attrs())
|
||||||
attrsSeen.try_emplace(attr.name).first->second.size++;
|
attrsSeen.try_emplace(attr.name).first->second.size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2971,7 +2977,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
elem.list.emplace(state.buildList(elem.size));
|
elem.list.emplace(state.buildList(elem.size));
|
||||||
|
|
||||||
for (auto & vElem : listItems) {
|
for (auto & vElem : listItems) {
|
||||||
for (auto & attr : *vElem->attrs) {
|
for (auto & attr : *vElem->attrs()) {
|
||||||
auto & item = attrsSeen.at(attr.name);
|
auto & item = attrsSeen.at(attr.name);
|
||||||
(*item.list)[item.pos++] = attr.value;
|
(*item.list)[item.pos++] = attr.value;
|
||||||
}
|
}
|
||||||
|
@ -3413,10 +3419,8 @@ static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||||
auto comparator = [&](Value * a, Value * b) {
|
auto comparator = [&](Value * a, Value * b) {
|
||||||
/* Optimization: if the comparator is lessThan, bypass
|
/* Optimization: if the comparator is lessThan, bypass
|
||||||
callFunction. */
|
callFunction. */
|
||||||
/* TODO: (layus) this is absurd. An optimisation like this
|
|
||||||
should be outside the lambda creation */
|
|
||||||
if (args[0]->isPrimOp()) {
|
if (args[0]->isPrimOp()) {
|
||||||
auto ptr = args[0]->primOp->fun.target<decltype(&prim_lessThan)>();
|
auto ptr = args[0]->primOp()->fun.target<decltype(&prim_lessThan)>();
|
||||||
if (ptr && *ptr == prim_lessThan)
|
if (ptr && *ptr == prim_lessThan)
|
||||||
return CompareValues(state, noPos, "while evaluating the ordering function passed to builtins.sort")(a, b);
|
return CompareValues(state, noPos, "while evaluating the ordering function passed to builtins.sort")(a, b);
|
||||||
}
|
}
|
||||||
|
@ -3909,18 +3913,17 @@ static RegisterPrimOp primop_hashString({
|
||||||
static void prim_convertHash(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_convertHash(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.convertHash");
|
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.convertHash");
|
||||||
auto &inputAttrs = args[0]->attrs;
|
auto inputAttrs = args[0]->attrs();
|
||||||
|
|
||||||
Bindings::iterator iteratorHash = getAttr(state, state.symbols.create("hash"), inputAttrs, "while locating the attribute 'hash'");
|
auto iteratorHash = getAttr(state, state.symbols.create("hash"), inputAttrs, "while locating the attribute 'hash'");
|
||||||
auto hash = state.forceStringNoCtx(*iteratorHash->value, pos, "while evaluating the attribute 'hash'");
|
auto hash = state.forceStringNoCtx(*iteratorHash->value, pos, "while evaluating the attribute 'hash'");
|
||||||
|
|
||||||
Bindings::iterator iteratorHashAlgo = inputAttrs->find(state.symbols.create("hashAlgo"));
|
auto iteratorHashAlgo = inputAttrs->get(state.symbols.create("hashAlgo"));
|
||||||
std::optional<HashAlgorithm> ha = std::nullopt;
|
std::optional<HashAlgorithm> ha = std::nullopt;
|
||||||
if (iteratorHashAlgo != inputAttrs->end()) {
|
if (iteratorHashAlgo)
|
||||||
ha = parseHashAlgo(state.forceStringNoCtx(*iteratorHashAlgo->value, pos, "while evaluating the attribute 'hashAlgo'"));
|
ha = parseHashAlgo(state.forceStringNoCtx(*iteratorHashAlgo->value, pos, "while evaluating the attribute 'hashAlgo'"));
|
||||||
}
|
|
||||||
|
|
||||||
Bindings::iterator iteratorToHashFormat = getAttr(state, state.symbols.create("toHashFormat"), args[0]->attrs, "while locating the attribute 'toHashFormat'");
|
auto iteratorToHashFormat = getAttr(state, state.symbols.create("toHashFormat"), args[0]->attrs(), "while locating the attribute 'toHashFormat'");
|
||||||
HashFormat hf = parseHashFormat(state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'"));
|
HashFormat hf = parseHashFormat(state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'"));
|
||||||
|
|
||||||
v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI));
|
v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI));
|
||||||
|
@ -4666,7 +4669,7 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
/* Now that we've added all primops, sort the `builtins' set,
|
/* Now that we've added all primops, sort the `builtins' set,
|
||||||
because attribute lookups expect it to be sorted. */
|
because attribute lookups expect it to be sorted. */
|
||||||
baseEnv.values[0]->attrs->sort();
|
baseEnv.values[0]->payload.attrs->sort();
|
||||||
|
|
||||||
staticBaseEnv->sort();
|
staticBaseEnv->sort();
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||||
|
|
||||||
auto sPath = state.symbols.create("path");
|
auto sPath = state.symbols.create("path");
|
||||||
auto sAllOutputs = state.symbols.create("allOutputs");
|
auto sAllOutputs = state.symbols.create("allOutputs");
|
||||||
for (auto & i : *args[1]->attrs) {
|
for (auto & i : *args[1]->attrs()) {
|
||||||
const auto & name = state.symbols[i.name];
|
const auto & name = state.symbols[i.name];
|
||||||
if (!state.store->isStorePath(name))
|
if (!state.store->isStorePath(name))
|
||||||
state.error<EvalError>(
|
state.error<EvalError>(
|
||||||
|
@ -269,17 +269,16 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||||
if (!settings.readOnlyMode)
|
if (!settings.readOnlyMode)
|
||||||
state.store->ensurePath(namePath);
|
state.store->ensurePath(namePath);
|
||||||
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
||||||
auto iter = i.value->attrs->find(sPath);
|
|
||||||
if (iter != i.value->attrs->end()) {
|
if (auto attr = i.value->attrs()->get(sPath)) {
|
||||||
if (state.forceBool(*iter->value, iter->pos, "while evaluating the `path` attribute of a string context"))
|
if (state.forceBool(*attr->value, attr->pos, "while evaluating the `path` attribute of a string context"))
|
||||||
context.emplace(NixStringContextElem::Opaque {
|
context.emplace(NixStringContextElem::Opaque {
|
||||||
.path = namePath,
|
.path = namePath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = i.value->attrs->find(sAllOutputs);
|
if (auto attr = i.value->attrs()->get(sAllOutputs)) {
|
||||||
if (iter != i.value->attrs->end()) {
|
if (state.forceBool(*attr->value, attr->pos, "while evaluating the `allOutputs` attribute of a string context")) {
|
||||||
if (state.forceBool(*iter->value, iter->pos, "while evaluating the `allOutputs` attribute of a string context")) {
|
|
||||||
if (!isDerivation(name)) {
|
if (!isDerivation(name)) {
|
||||||
state.error<EvalError>(
|
state.error<EvalError>(
|
||||||
"tried to add all-outputs context of %s, which is not a derivation, to a string",
|
"tried to add all-outputs context of %s, which is not a derivation, to a string",
|
||||||
|
@ -292,17 +291,16 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = i.value->attrs->find(state.sOutputs);
|
if (auto attr = i.value->attrs()->get(state.sOutputs)) {
|
||||||
if (iter != i.value->attrs->end()) {
|
state.forceList(*attr->value, attr->pos, "while evaluating the `outputs` attribute of a string context");
|
||||||
state.forceList(*iter->value, iter->pos, "while evaluating the `outputs` attribute of a string context");
|
if (attr->value->listSize() && !isDerivation(name)) {
|
||||||
if (iter->value->listSize() && !isDerivation(name)) {
|
|
||||||
state.error<EvalError>(
|
state.error<EvalError>(
|
||||||
"tried to add derivation output context of %s, which is not a derivation, to a string",
|
"tried to add derivation output context of %s, which is not a derivation, to a string",
|
||||||
name
|
name
|
||||||
).atPos(i.pos).debugThrow();
|
).atPos(i.pos).debugThrow();
|
||||||
}
|
}
|
||||||
for (auto elem : iter->value->listItems()) {
|
for (auto elem : attr->value->listItems()) {
|
||||||
auto outputName = state.forceStringNoCtx(*elem, iter->pos, "while evaluating an output name within a string context");
|
auto outputName = state.forceStringNoCtx(*elem, attr->pos, "while evaluating an output name within a string context");
|
||||||
context.emplace(NixStringContextElem::Built {
|
context.emplace(NixStringContextElem::Built {
|
||||||
.drvPath = makeConstantStorePathRef(namePath),
|
.drvPath = makeConstantStorePathRef(namePath),
|
||||||
.output = std::string { outputName },
|
.output = std::string { outputName },
|
||||||
|
|
|
@ -121,7 +121,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
std::optional<StorePathOrGap> toPath;
|
std::optional<StorePathOrGap> toPath;
|
||||||
std::optional<bool> inputAddressedMaybe;
|
std::optional<bool> inputAddressedMaybe;
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs()) {
|
||||||
const auto & attrName = state.symbols[attr.name];
|
const auto & attrName = state.symbols[attr.name];
|
||||||
auto attrHint = [&]() -> std::string {
|
auto attrHint = [&]() -> std::string {
|
||||||
return "while evaluating the '" + attrName + "' attribute passed to builtins.fetchClosure";
|
return "while evaluating the '" + attrName + "' attribute passed to builtins.fetchClosure";
|
||||||
|
|
|
@ -20,7 +20,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||||
|
|
||||||
if (args[0]->type() == nAttrs) {
|
if (args[0]->type() == nAttrs) {
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs()) {
|
||||||
std::string_view n(state.symbols[attr.name]);
|
std::string_view n(state.symbols[attr.name]);
|
||||||
if (n == "url")
|
if (n == "url")
|
||||||
url = state.coerceToString(attr.pos, *attr.value, context,
|
url = state.coerceToString(attr.pos, *attr.value, context,
|
||||||
|
|
|
@ -97,7 +97,7 @@ static void fetchTree(
|
||||||
|
|
||||||
fetchers::Attrs attrs;
|
fetchers::Attrs attrs;
|
||||||
|
|
||||||
if (auto aType = args[0]->attrs->get(state.sType)) {
|
if (auto aType = args[0]->attrs()->get(state.sType)) {
|
||||||
if (type)
|
if (type)
|
||||||
state.error<EvalError>(
|
state.error<EvalError>(
|
||||||
"unexpected attribute 'type'"
|
"unexpected attribute 'type'"
|
||||||
|
@ -110,7 +110,7 @@ static void fetchTree(
|
||||||
|
|
||||||
attrs.emplace("type", type.value());
|
attrs.emplace("type", type.value());
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs()) {
|
||||||
if (attr.name == state.sType) continue;
|
if (attr.name == state.sType) continue;
|
||||||
state.forceValue(*attr.value, attr.pos);
|
state.forceValue(*attr.value, attr.pos);
|
||||||
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
||||||
|
@ -121,9 +121,9 @@ static void fetchTree(
|
||||||
: s);
|
: s);
|
||||||
}
|
}
|
||||||
else if (attr.value->type() == nBool)
|
else if (attr.value->type() == nBool)
|
||||||
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean});
|
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||||
else if (attr.value->type() == nInt)
|
else if (attr.value->type() == nInt)
|
||||||
attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer));
|
attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer()));
|
||||||
else if (state.symbols[attr.name] == "publicKeys") {
|
else if (state.symbols[attr.name] == "publicKeys") {
|
||||||
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
||||||
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, context).dump());
|
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, context).dump());
|
||||||
|
@ -422,7 +422,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
|
|
||||||
if (args[0]->type() == nAttrs) {
|
if (args[0]->type() == nAttrs) {
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs()) {
|
||||||
std::string_view n(state.symbols[attr.name]);
|
std::string_view n(state.symbols[attr.name]);
|
||||||
if (n == "url")
|
if (n == "url")
|
||||||
url = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the url we should fetch");
|
url = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the url we should fetch");
|
||||||
|
|
|
@ -21,10 +21,10 @@ void printAmbiguous(
|
||||||
}
|
}
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
case nInt:
|
case nInt:
|
||||||
str << v.integer;
|
str << v.integer();
|
||||||
break;
|
break;
|
||||||
case nBool:
|
case nBool:
|
||||||
printLiteralBool(str, v.boolean);
|
printLiteralBool(str, v.boolean());
|
||||||
break;
|
break;
|
||||||
case nString:
|
case nString:
|
||||||
printLiteralString(str, v.string_view());
|
printLiteralString(str, v.string_view());
|
||||||
|
@ -36,11 +36,11 @@ void printAmbiguous(
|
||||||
str << "null";
|
str << "null";
|
||||||
break;
|
break;
|
||||||
case nAttrs: {
|
case nAttrs: {
|
||||||
if (seen && !v.attrs->empty() && !seen->insert(v.attrs).second)
|
if (seen && !v.attrs()->empty() && !seen->insert(v.attrs()).second)
|
||||||
str << "«repeated»";
|
str << "«repeated»";
|
||||||
else {
|
else {
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
for (auto & i : v.attrs->lexicographicOrder(symbols)) {
|
for (auto & i : v.attrs()->lexicographicOrder(symbols)) {
|
||||||
str << symbols[i->name] << " = ";
|
str << symbols[i->name] << " = ";
|
||||||
printAmbiguous(*i->value, symbols, str, seen, depth - 1);
|
printAmbiguous(*i->value, symbols, str, seen, depth - 1);
|
||||||
str << "; ";
|
str << "; ";
|
||||||
|
@ -87,10 +87,10 @@ void printAmbiguous(
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nExternal:
|
case nExternal:
|
||||||
str << *v.external;
|
str << *v.external();
|
||||||
break;
|
break;
|
||||||
case nFloat:
|
case nFloat:
|
||||||
str << v.fpoint;
|
str << v.fpoint();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printError("Nix evaluator internal error: printAmbiguous: invalid value type");
|
printError("Nix evaluator internal error: printAmbiguous: invalid value type");
|
||||||
|
|
|
@ -223,7 +223,7 @@ private:
|
||||||
{
|
{
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_CYAN;
|
output << ANSI_CYAN;
|
||||||
output << v.integer;
|
output << v.integer();
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_NORMAL;
|
output << ANSI_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ private:
|
||||||
{
|
{
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_CYAN;
|
output << ANSI_CYAN;
|
||||||
output << v.fpoint;
|
output << v.fpoint();
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_NORMAL;
|
output << ANSI_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ private:
|
||||||
{
|
{
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_CYAN;
|
output << ANSI_CYAN;
|
||||||
printLiteralBool(output, v.boolean);
|
printLiteralBool(output, v.boolean());
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
output << ANSI_NORMAL;
|
output << ANSI_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -271,10 +271,9 @@ private:
|
||||||
|
|
||||||
void printDerivation(Value & v)
|
void printDerivation(Value & v)
|
||||||
{
|
{
|
||||||
Bindings::iterator i = v.attrs->find(state.sDrvPath);
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
std::string storePath;
|
std::string storePath;
|
||||||
if (i != v.attrs->end())
|
if (auto i = v.attrs()->get(state.sDrvPath))
|
||||||
storePath = state.store->printStorePath(state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
|
storePath = state.store->printStorePath(state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
|
||||||
|
|
||||||
if (options.ansiColors)
|
if (options.ansiColors)
|
||||||
|
@ -312,7 +311,7 @@ private:
|
||||||
|
|
||||||
void printAttrs(Value & v, size_t depth)
|
void printAttrs(Value & v, size_t depth)
|
||||||
{
|
{
|
||||||
if (seen && !seen->insert(v.attrs).second) {
|
if (seen && !seen->insert(v.attrs()).second) {
|
||||||
printRepeated();
|
printRepeated();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -324,7 +323,7 @@ private:
|
||||||
output << "{";
|
output << "{";
|
||||||
|
|
||||||
AttrVec sorted;
|
AttrVec sorted;
|
||||||
for (auto & i : *v.attrs)
|
for (auto & i : *v.attrs())
|
||||||
sorted.emplace_back(std::pair(state.symbols[i.name], i.value));
|
sorted.emplace_back(std::pair(state.symbols[i.name], i.value));
|
||||||
|
|
||||||
if (options.maxAttrs == std::numeric_limits<size_t>::max())
|
if (options.maxAttrs == std::numeric_limits<size_t>::max())
|
||||||
|
@ -423,18 +422,18 @@ private:
|
||||||
|
|
||||||
if (v.isLambda()) {
|
if (v.isLambda()) {
|
||||||
output << "lambda";
|
output << "lambda";
|
||||||
if (v.lambda.fun) {
|
if (v.payload.lambda.fun) {
|
||||||
if (v.lambda.fun->name) {
|
if (v.payload.lambda.fun->name) {
|
||||||
output << " " << state.symbols[v.lambda.fun->name];
|
output << " " << state.symbols[v.payload.lambda.fun->name];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << state.positions[v.lambda.fun->pos];
|
s << state.positions[v.payload.lambda.fun->pos];
|
||||||
output << " @ " << filterANSIEscapes(s.str());
|
output << " @ " << filterANSIEscapes(s.str());
|
||||||
}
|
}
|
||||||
} else if (v.isPrimOp()) {
|
} else if (v.isPrimOp()) {
|
||||||
if (v.primOp)
|
if (v.primOp())
|
||||||
output << *v.primOp;
|
output << *v.primOp();
|
||||||
else
|
else
|
||||||
output << "primop";
|
output << "primop";
|
||||||
} else if (v.isPrimOpApp()) {
|
} else if (v.isPrimOpApp()) {
|
||||||
|
@ -480,7 +479,7 @@ private:
|
||||||
|
|
||||||
void printExternal(Value & v)
|
void printExternal(Value & v)
|
||||||
{
|
{
|
||||||
v.external->print(output);
|
v.external()->print(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printUnknown()
|
void printUnknown()
|
||||||
|
|
|
@ -22,11 +22,11 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
|
|
||||||
case nInt:
|
case nInt:
|
||||||
out = v.integer;
|
out = v.integer();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nBool:
|
case nBool:
|
||||||
out = v.boolean;
|
out = v.boolean();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nString:
|
case nString:
|
||||||
|
@ -52,24 +52,20 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
out = *maybeString;
|
out = *maybeString;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto i = v.attrs->find(state.sOutPath);
|
if (auto i = v.attrs()->get(state.sOutPath))
|
||||||
if (i == v.attrs->end()) {
|
return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
|
||||||
|
else {
|
||||||
out = json::object();
|
out = json::object();
|
||||||
StringSet names;
|
for (auto & a : v.attrs()->lexicographicOrder(state.symbols)) {
|
||||||
for (auto & j : *v.attrs)
|
|
||||||
names.emplace(state.symbols[j.name]);
|
|
||||||
for (auto & j : names) {
|
|
||||||
Attr & a(*v.attrs->find(state.symbols.create(j)));
|
|
||||||
try {
|
try {
|
||||||
out[j] = printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore);
|
out[state.symbols[a->name]] = printValueAsJSON(state, strict, *a->value, a->pos, context, copyToStore);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(state.positions[a.pos],
|
e.addTrace(state.positions[a->pos],
|
||||||
HintFmt("while evaluating attribute '%1%'", j));
|
HintFmt("while evaluating attribute '%1%'", state.symbols[a->name]));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +86,11 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
}
|
}
|
||||||
|
|
||||||
case nExternal:
|
case nExternal:
|
||||||
return v.external->printValueAsJSON(state, strict, context, copyToStore);
|
return v.external()->printValueAsJSON(state, strict, context, copyToStore);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nFloat:
|
case nFloat:
|
||||||
out = v.fpoint;
|
out = v.fpoint();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nThunk:
|
case nThunk:
|
||||||
|
|
|
@ -32,23 +32,18 @@ static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos)
|
||||||
|
|
||||||
|
|
||||||
static void showAttrs(EvalState & state, bool strict, bool location,
|
static void showAttrs(EvalState & state, bool strict, bool location,
|
||||||
Bindings & attrs, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen)
|
const Bindings & attrs, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen)
|
||||||
{
|
{
|
||||||
StringSet names;
|
StringSet names;
|
||||||
|
|
||||||
for (auto & i : attrs)
|
for (auto & a : attrs.lexicographicOrder(state.symbols)) {
|
||||||
names.emplace(state.symbols[i.name]);
|
|
||||||
|
|
||||||
for (auto & i : names) {
|
|
||||||
Attr & a(*attrs.find(state.symbols.create(i)));
|
|
||||||
|
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
xmlAttrs["name"] = i;
|
xmlAttrs["name"] = state.symbols[a->name];
|
||||||
if (location && a.pos) posToXML(state, xmlAttrs, state.positions[a.pos]);
|
if (location && a->pos) posToXML(state, xmlAttrs, state.positions[a->pos]);
|
||||||
|
|
||||||
XMLOpenElement _(doc, "attr", xmlAttrs);
|
XMLOpenElement _(doc, "attr", xmlAttrs);
|
||||||
printValueAsXML(state, strict, location,
|
printValueAsXML(state, strict, location,
|
||||||
*a.value, doc, context, drvsSeen, a.pos);
|
*a->value, doc, context, drvsSeen, a->pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,11 +59,11 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
|
|
||||||
case nInt:
|
case nInt:
|
||||||
doc.writeEmptyElement("int", singletonAttrs("value", fmt("%1%", v.integer)));
|
doc.writeEmptyElement("int", singletonAttrs("value", fmt("%1%", v.integer())));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nBool:
|
case nBool:
|
||||||
doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false"));
|
doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean() ? "true" : "false"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nString:
|
case nString:
|
||||||
|
@ -89,18 +84,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
if (state.isDerivation(v)) {
|
if (state.isDerivation(v)) {
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(state.symbols.create("derivation"));
|
|
||||||
|
|
||||||
Path drvPath;
|
Path drvPath;
|
||||||
a = v.attrs->find(state.sDrvPath);
|
if (auto a = v.attrs()->get(state.sDrvPath)) {
|
||||||
if (a != v.attrs->end()) {
|
|
||||||
if (strict) state.forceValue(*a->value, a->pos);
|
if (strict) state.forceValue(*a->value, a->pos);
|
||||||
if (a->value->type() == nString)
|
if (a->value->type() == nString)
|
||||||
xmlAttrs["drvPath"] = drvPath = a->value->c_str();
|
xmlAttrs["drvPath"] = drvPath = a->value->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
a = v.attrs->find(state.sOutPath);
|
if (auto a = v.attrs()->get(state.sOutPath)) {
|
||||||
if (a != v.attrs->end()) {
|
|
||||||
if (strict) state.forceValue(*a->value, a->pos);
|
if (strict) state.forceValue(*a->value, a->pos);
|
||||||
if (a->value->type() == nString)
|
if (a->value->type() == nString)
|
||||||
xmlAttrs["outPath"] = a->value->c_str();
|
xmlAttrs["outPath"] = a->value->c_str();
|
||||||
|
@ -109,14 +100,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
||||||
|
|
||||||
if (drvPath != "" && drvsSeen.insert(drvPath).second)
|
if (drvPath != "" && drvsSeen.insert(drvPath).second)
|
||||||
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
showAttrs(state, strict, location, *v.attrs(), doc, context, drvsSeen);
|
||||||
else
|
else
|
||||||
doc.writeEmptyElement("repeated");
|
doc.writeEmptyElement("repeated");
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
XMLOpenElement _(doc, "attrs");
|
XMLOpenElement _(doc, "attrs");
|
||||||
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
showAttrs(state, strict, location, *v.attrs(), doc, context, drvsSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -135,28 +126,28 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
if (location) posToXML(state, xmlAttrs, state.positions[v.lambda.fun->pos]);
|
if (location) posToXML(state, xmlAttrs, state.positions[v.payload.lambda.fun->pos]);
|
||||||
XMLOpenElement _(doc, "function", xmlAttrs);
|
XMLOpenElement _(doc, "function", xmlAttrs);
|
||||||
|
|
||||||
if (v.lambda.fun->hasFormals()) {
|
if (v.payload.lambda.fun->hasFormals()) {
|
||||||
XMLAttrs attrs;
|
XMLAttrs attrs;
|
||||||
if (v.lambda.fun->arg) attrs["name"] = state.symbols[v.lambda.fun->arg];
|
if (v.payload.lambda.fun->arg) attrs["name"] = state.symbols[v.payload.lambda.fun->arg];
|
||||||
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
if (v.payload.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
||||||
XMLOpenElement _(doc, "attrspat", attrs);
|
XMLOpenElement _(doc, "attrspat", attrs);
|
||||||
for (auto & i : v.lambda.fun->formals->lexicographicOrder(state.symbols))
|
for (auto & i : v.payload.lambda.fun->formals->lexicographicOrder(state.symbols))
|
||||||
doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name]));
|
doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name]));
|
||||||
} else
|
} else
|
||||||
doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.lambda.fun->arg]));
|
doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.payload.lambda.fun->arg]));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case nExternal:
|
case nExternal:
|
||||||
v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen, pos);
|
v.external()->printValueAsXML(state, strict, location, doc, context, drvsSeen, pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nFloat:
|
case nFloat:
|
||||||
doc.writeEmptyElement("float", singletonAttrs("value", fmt("%1%", v.fpoint)));
|
doc.writeEmptyElement("float", singletonAttrs("value", fmt("%1%", v.fpoint())));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nThunk:
|
case nThunk:
|
||||||
|
|
|
@ -234,14 +234,14 @@ public:
|
||||||
ExprLambda * fun;
|
ExprLambda * fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
union
|
using Payload = union
|
||||||
{
|
{
|
||||||
NixInt integer;
|
NixInt integer;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
|
|
||||||
StringWithContext string;
|
StringWithContext string;
|
||||||
|
|
||||||
Path _path;
|
Path path;
|
||||||
|
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
|
@ -258,6 +258,8 @@ public:
|
||||||
NixFloat fpoint;
|
NixFloat fpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Payload payload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the normal type of a Value. This only returns nThunk if
|
* Returns the normal type of a Value. This only returns nThunk if
|
||||||
* the Value hasn't been forceValue'd
|
* the Value hasn't been forceValue'd
|
||||||
|
@ -286,34 +288,25 @@ public:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
inline void finishValue(InternalType newType, Payload newPayload)
|
||||||
* After overwriting an app node, be sure to clear pointers in the
|
|
||||||
* Value to ensure that the target isn't kept alive unnecessarily.
|
|
||||||
*/
|
|
||||||
inline void clearValue()
|
|
||||||
{
|
{
|
||||||
app.left = app.right = 0;
|
payload = newPayload;
|
||||||
|
internalType = newType;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkInt(NixInt n)
|
inline void mkInt(NixInt n)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tInt, { .integer = n });
|
||||||
internalType = tInt;
|
|
||||||
integer = n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkBool(bool b)
|
inline void mkBool(bool b)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tBool, { .boolean = b });
|
||||||
internalType = tBool;
|
|
||||||
boolean = b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkString(const char * s, const char * * context = 0)
|
inline void mkString(const char * s, const char * * context = 0)
|
||||||
{
|
{
|
||||||
internalType = tString;
|
finishValue(tString, { .string = { .c_str = s, .context = context } });
|
||||||
string.c_str = s;
|
|
||||||
string.context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkString(std::string_view s);
|
void mkString(std::string_view s);
|
||||||
|
@ -332,63 +325,44 @@ public:
|
||||||
|
|
||||||
inline void mkPath(InputAccessor * accessor, const char * path)
|
inline void mkPath(InputAccessor * accessor, const char * path)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tPath, { .path = { .accessor = accessor, .path = path } });
|
||||||
internalType = tPath;
|
|
||||||
_path.accessor = accessor;
|
|
||||||
_path.path = path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkNull()
|
inline void mkNull()
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tNull, {});
|
||||||
internalType = tNull;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkAttrs(Bindings * a)
|
inline void mkAttrs(Bindings * a)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tAttrs, { .attrs = a });
|
||||||
internalType = tAttrs;
|
|
||||||
attrs = a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value & mkAttrs(BindingsBuilder & bindings);
|
Value & mkAttrs(BindingsBuilder & bindings);
|
||||||
|
|
||||||
void mkList(const ListBuilder & builder)
|
void mkList(const ListBuilder & builder)
|
||||||
{
|
{
|
||||||
clearValue();
|
if (builder.size == 1)
|
||||||
if (builder.size == 1) {
|
finishValue(tList1, { .smallList = { builder.inlineElems[0] } });
|
||||||
smallList[0] = builder.inlineElems[0];
|
else if (builder.size == 2)
|
||||||
internalType = tList1;
|
finishValue(tList2, { .smallList = { builder.inlineElems[0], builder.inlineElems[1] } });
|
||||||
} else if (builder.size == 2) {
|
else
|
||||||
smallList[0] = builder.inlineElems[0];
|
finishValue(tListN, { .bigList = { .size = builder.size, .elems = builder.elems } });
|
||||||
smallList[1] = builder.inlineElems[1];
|
|
||||||
internalType = tList2;
|
|
||||||
} else {
|
|
||||||
bigList.size = builder.size;
|
|
||||||
bigList.elems = builder.elems;
|
|
||||||
internalType = tListN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkThunk(Env * e, Expr * ex)
|
inline void mkThunk(Env * e, Expr * ex)
|
||||||
{
|
{
|
||||||
internalType = tThunk;
|
finishValue(tThunk, { .thunk = { .env = e, .expr = ex } });
|
||||||
thunk.env = e;
|
|
||||||
thunk.expr = ex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkApp(Value * l, Value * r)
|
inline void mkApp(Value * l, Value * r)
|
||||||
{
|
{
|
||||||
internalType = tApp;
|
finishValue(tApp, { .app = { .left = l, .right = r } });
|
||||||
app.left = l;
|
|
||||||
app.right = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkLambda(Env * e, ExprLambda * f)
|
inline void mkLambda(Env * e, ExprLambda * f)
|
||||||
{
|
{
|
||||||
internalType = tLambda;
|
finishValue(tLambda, { .lambda = { .env = e, .fun = f } });
|
||||||
lambda.env = e;
|
|
||||||
lambda.fun = f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkBlackhole();
|
inline void mkBlackhole();
|
||||||
|
@ -397,28 +371,22 @@ public:
|
||||||
|
|
||||||
inline void mkPrimOpApp(Value * l, Value * r)
|
inline void mkPrimOpApp(Value * l, Value * r)
|
||||||
{
|
{
|
||||||
internalType = tPrimOpApp;
|
finishValue(tPrimOpApp, { .primOpApp = { .left = l, .right = r } });
|
||||||
primOpApp.left = l;
|
|
||||||
primOpApp.right = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a `tPrimOpApp` value, get the original `PrimOp` value.
|
* For a `tPrimOpApp` value, get the original `PrimOp` value.
|
||||||
*/
|
*/
|
||||||
PrimOp * primOpAppPrimOp() const;
|
const PrimOp * primOpAppPrimOp() const;
|
||||||
|
|
||||||
inline void mkExternal(ExternalValueBase * e)
|
inline void mkExternal(ExternalValueBase * e)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tExternal, { .external = e });
|
||||||
internalType = tExternal;
|
|
||||||
external = e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkFloat(NixFloat n)
|
inline void mkFloat(NixFloat n)
|
||||||
{
|
{
|
||||||
clearValue();
|
finishValue(tFloat, { .fpoint = n });
|
||||||
internalType = tFloat;
|
|
||||||
fpoint = n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isList() const
|
bool isList() const
|
||||||
|
@ -428,7 +396,7 @@ public:
|
||||||
|
|
||||||
Value * const * listElems()
|
Value * const * listElems()
|
||||||
{
|
{
|
||||||
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
|
return internalType == tList1 || internalType == tList2 ? payload.smallList : payload.bigList.elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::span<Value * const> listItems() const
|
std::span<Value * const> listItems() const
|
||||||
|
@ -439,12 +407,12 @@ public:
|
||||||
|
|
||||||
Value * const * listElems() const
|
Value * const * listElems() const
|
||||||
{
|
{
|
||||||
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
|
return internalType == tList1 || internalType == tList2 ? payload.smallList : payload.bigList.elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t listSize() const
|
size_t listSize() const
|
||||||
{
|
{
|
||||||
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
|
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : payload.bigList.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
PosIdx determinePos(const PosIdx pos) const;
|
PosIdx determinePos(const PosIdx pos) const;
|
||||||
|
@ -460,26 +428,44 @@ public:
|
||||||
{
|
{
|
||||||
assert(internalType == tPath);
|
assert(internalType == tPath);
|
||||||
return SourcePath(
|
return SourcePath(
|
||||||
ref(_path.accessor->shared_from_this()),
|
ref(payload.path.accessor->shared_from_this()),
|
||||||
CanonPath(CanonPath::unchecked_t(), _path.path));
|
CanonPath(CanonPath::unchecked_t(), payload.path.path));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view string_view() const
|
std::string_view string_view() const
|
||||||
{
|
{
|
||||||
assert(internalType == tString);
|
assert(internalType == tString);
|
||||||
return std::string_view(string.c_str);
|
return std::string_view(payload.string.c_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * const c_str() const
|
const char * const c_str() const
|
||||||
{
|
{
|
||||||
assert(internalType == tString);
|
assert(internalType == tString);
|
||||||
return string.c_str;
|
return payload.string.c_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * * context() const
|
const char * * context() const
|
||||||
{
|
{
|
||||||
return string.context;
|
return payload.string.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalValueBase * external() const
|
||||||
|
{ return payload.external; }
|
||||||
|
|
||||||
|
const Bindings * attrs() const
|
||||||
|
{ return payload.attrs; }
|
||||||
|
|
||||||
|
const PrimOp * primOp() const
|
||||||
|
{ return payload.primOp; }
|
||||||
|
|
||||||
|
bool boolean() const
|
||||||
|
{ return payload.boolean; }
|
||||||
|
|
||||||
|
NixInt integer() const
|
||||||
|
{ return payload.integer; }
|
||||||
|
|
||||||
|
NixFloat fpoint() const
|
||||||
|
{ return payload.fpoint; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -487,13 +473,12 @@ extern ExprBlackHole eBlackHole;
|
||||||
|
|
||||||
bool Value::isBlackhole() const
|
bool Value::isBlackhole() const
|
||||||
{
|
{
|
||||||
return internalType == tThunk && thunk.expr == (Expr*) &eBlackHole;
|
return internalType == tThunk && payload.thunk.expr == (Expr*) &eBlackHole;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::mkBlackhole()
|
void Value::mkBlackhole()
|
||||||
{
|
{
|
||||||
internalType = tThunk;
|
mkThunk(nullptr, (Expr *) &eBlackHole);
|
||||||
thunk.expr = (Expr*) &eBlackHole;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -333,8 +333,8 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool add = false;
|
bool add = false;
|
||||||
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
if (v.type() == nFunction && v.payload.lambda.fun->hasFormals()) {
|
||||||
for (auto & i : v.lambda.fun->formals->formals) {
|
for (auto & i : v.payload.lambda.fun->formals->formals) {
|
||||||
if (state->symbols[i.name] == "inNixShell") {
|
if (state->symbols[i.name] == "inNixShell") {
|
||||||
add = true;
|
add = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1238,15 +1238,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type() == nInt) {
|
} else if (v->type() == nInt) {
|
||||||
attrs2["type"] = "int";
|
attrs2["type"] = "int";
|
||||||
attrs2["value"] = fmt("%1%", v->integer);
|
attrs2["value"] = fmt("%1%", v->integer());
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type() == nFloat) {
|
} else if (v->type() == nFloat) {
|
||||||
attrs2["type"] = "float";
|
attrs2["type"] = "float";
|
||||||
attrs2["value"] = fmt("%1%", v->fpoint);
|
attrs2["value"] = fmt("%1%", v->fpoint());
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type() == nBool) {
|
} else if (v->type() == nBool) {
|
||||||
attrs2["type"] = "bool";
|
attrs2["type"] = "bool";
|
||||||
attrs2["value"] = v->boolean ? "true" : "false";
|
attrs2["value"] = v->boolean() ? "true" : "false";
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type() == nList) {
|
} else if (v->type() == nList) {
|
||||||
attrs2["type"] = "strings";
|
attrs2["type"] = "strings";
|
||||||
|
@ -1260,13 +1260,11 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
} else if (v->type() == nAttrs) {
|
} else if (v->type() == nAttrs) {
|
||||||
attrs2["type"] = "strings";
|
attrs2["type"] = "strings";
|
||||||
XMLOpenElement m(xml, "meta", attrs2);
|
XMLOpenElement m(xml, "meta", attrs2);
|
||||||
Bindings & attrs = *v->attrs;
|
for (auto & i : *v->attrs()) {
|
||||||
for (auto &i : attrs) {
|
if (i.value->type() != nString) continue;
|
||||||
Attr & a(*attrs.find(i.name));
|
|
||||||
if(a.value->type() != nString) continue;
|
|
||||||
XMLAttrs attrs3;
|
XMLAttrs attrs3;
|
||||||
attrs3["type"] = globals.state->symbols[i.name];
|
attrs3["type"] = globals.state->symbols[i.name];
|
||||||
attrs3["value"] = a.value->c_str();
|
attrs3["value"] = i.value->c_str();
|
||||||
xml.writeEmptyElement("string", attrs3);
|
xml.writeEmptyElement("string", attrs3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,9 +138,9 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
|
||||||
debug("evaluating user environment builder");
|
debug("evaluating user environment builder");
|
||||||
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
auto & aDrvPath(*topLevel.attrs()->find(state.sDrvPath));
|
||||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
||||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
auto & aOutPath(*topLevel.attrs()->find(state.sOutPath));
|
||||||
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
|
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
|
||||||
|
|
||||||
/* Realise the resulting store expression. */
|
/* Realise the resulting store expression. */
|
||||||
|
|
|
@ -93,14 +93,14 @@ struct CmdBundle : InstallableValueCommand
|
||||||
if (!evalState->isDerivation(*vRes))
|
if (!evalState->isDerivation(*vRes))
|
||||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||||
|
|
||||||
auto attr1 = vRes->attrs->get(evalState->sDrvPath);
|
auto attr1 = vRes->attrs()->get(evalState->sDrvPath);
|
||||||
if (!attr1)
|
if (!attr1)
|
||||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||||
|
|
||||||
NixStringContext context2;
|
NixStringContext context2;
|
||||||
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
|
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
|
||||||
|
|
||||||
auto attr2 = vRes->attrs->get(evalState->sOutPath);
|
auto attr2 = vRes->attrs()->get(evalState->sOutPath);
|
||||||
if (!attr2)
|
if (!attr2)
|
||||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ struct CmdBundle : InstallableValueCommand
|
||||||
auto outPathS = store->printStorePath(outPath);
|
auto outPathS = store->printStorePath(outPath);
|
||||||
|
|
||||||
if (!outLink) {
|
if (!outLink) {
|
||||||
auto * attr = vRes->attrs->get(evalState->sName);
|
auto * attr = vRes->attrs()->get(evalState->sName);
|
||||||
if (!attr)
|
if (!attr)
|
||||||
throw Error("attribute 'name' missing");
|
throw Error("attribute 'name' missing");
|
||||||
outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, "");
|
outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, "");
|
||||||
|
|
|
@ -89,7 +89,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
|
||||||
else if (v.type() == nAttrs) {
|
else if (v.type() == nAttrs) {
|
||||||
if (mkdir(path.c_str(), 0777) == -1)
|
if (mkdir(path.c_str(), 0777) == -1)
|
||||||
throw SysError("creating directory '%s'", path);
|
throw SysError("creating directory '%s'", path);
|
||||||
for (auto & attr : *v.attrs) {
|
for (auto & attr : *v.attrs()) {
|
||||||
std::string_view name = state->symbols[attr.name];
|
std::string_view name = state->symbols[attr.name];
|
||||||
try {
|
try {
|
||||||
if (name == "." || name == "..")
|
if (name == "." || name == "..")
|
||||||
|
|
|
@ -169,7 +169,7 @@ static void enumerateOutputs(EvalState & state, Value & vFlake,
|
||||||
auto pos = vFlake.determinePos(noPos);
|
auto pos = vFlake.determinePos(noPos);
|
||||||
state.forceAttrs(vFlake, pos, "while evaluating a flake to get its outputs");
|
state.forceAttrs(vFlake, pos, "while evaluating a flake to get its outputs");
|
||||||
|
|
||||||
auto aOutputs = vFlake.attrs->get(state.symbols.create("outputs"));
|
auto aOutputs = vFlake.attrs()->get(state.symbols.create("outputs"));
|
||||||
assert(aOutputs);
|
assert(aOutputs);
|
||||||
|
|
||||||
state.forceAttrs(*aOutputs->value, pos, "while evaluating the outputs of a flake");
|
state.forceAttrs(*aOutputs->value, pos, "while evaluating the outputs of a flake");
|
||||||
|
@ -179,10 +179,10 @@ static void enumerateOutputs(EvalState & state, Value & vFlake,
|
||||||
/* Hack: ensure that hydraJobs is evaluated before anything
|
/* Hack: ensure that hydraJobs is evaluated before anything
|
||||||
else. This way we can disable IFD for hydraJobs and then enable
|
else. This way we can disable IFD for hydraJobs and then enable
|
||||||
it for other outputs. */
|
it for other outputs. */
|
||||||
if (auto attr = aOutputs->value->attrs->get(sHydraJobs))
|
if (auto attr = aOutputs->value->attrs()->get(sHydraJobs))
|
||||||
callback(state.symbols[attr->name], *attr->value, attr->pos);
|
callback(state.symbols[attr->name], *attr->value, attr->pos);
|
||||||
|
|
||||||
for (auto & attr : *aOutputs->value->attrs) {
|
for (auto & attr : *aOutputs->value->attrs()) {
|
||||||
if (attr.name != sHydraJobs)
|
if (attr.name != sHydraJobs)
|
||||||
callback(state.symbols[attr.name], *attr.value, attr.pos);
|
callback(state.symbols[attr.name], *attr.value, attr.pos);
|
||||||
}
|
}
|
||||||
|
@ -451,10 +451,10 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
if (!v.isLambda()) {
|
if (!v.isLambda()) {
|
||||||
throw Error("overlay is not a function, but %s instead", showType(v));
|
throw Error("overlay is not a function, but %s instead", showType(v));
|
||||||
}
|
}
|
||||||
if (v.lambda.fun->hasFormals()
|
if (v.payload.lambda.fun->hasFormals()
|
||||||
|| !argHasName(v.lambda.fun->arg, "final"))
|
|| !argHasName(v.payload.lambda.fun->arg, "final"))
|
||||||
throw Error("overlay does not take an argument named 'final'");
|
throw Error("overlay does not take an argument named 'final'");
|
||||||
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
|
auto body = dynamic_cast<ExprLambda *>(v.payload.lambda.fun->body);
|
||||||
if (!body
|
if (!body
|
||||||
|| body->hasFormals()
|
|| body->hasFormals()
|
||||||
|| !argHasName(body->arg, "prev"))
|
|| !argHasName(body->arg, "prev"))
|
||||||
|
@ -489,7 +489,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
if (state->isDerivation(v))
|
if (state->isDerivation(v))
|
||||||
throw Error("jobset should not be a derivation at top-level");
|
throw Error("jobset should not be a derivation at top-level");
|
||||||
|
|
||||||
for (auto & attr : *v.attrs) {
|
for (auto & attr : *v.attrs()) {
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]);
|
auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]);
|
||||||
if (state->isDerivation(*attr.value)) {
|
if (state->isDerivation(*attr.value)) {
|
||||||
|
@ -528,7 +528,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
state->forceAttrs(v, pos, "");
|
state->forceAttrs(v, pos, "");
|
||||||
|
|
||||||
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
|
if (auto attr = v.attrs()->get(state->symbols.create("path"))) {
|
||||||
if (attr->name == state->symbols.create("path")) {
|
if (attr->name == state->symbols.create("path")) {
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
|
auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
|
||||||
|
@ -539,12 +539,12 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
} else
|
} else
|
||||||
throw Error("template '%s' lacks attribute 'path'", attrPath);
|
throw Error("template '%s' lacks attribute 'path'", attrPath);
|
||||||
|
|
||||||
if (auto attr = v.attrs->get(state->symbols.create("description")))
|
if (auto attr = v.attrs()->get(state->symbols.create("description")))
|
||||||
state->forceStringNoCtx(*attr->value, attr->pos, "");
|
state->forceStringNoCtx(*attr->value, attr->pos, "");
|
||||||
else
|
else
|
||||||
throw Error("template '%s' lacks attribute 'description'", attrPath);
|
throw Error("template '%s' lacks attribute 'description'", attrPath);
|
||||||
|
|
||||||
for (auto & attr : *v.attrs) {
|
for (auto & attr : *v.attrs()) {
|
||||||
std::string_view name(state->symbols[attr.name]);
|
std::string_view name(state->symbols[attr.name]);
|
||||||
if (name != "path" && name != "description" && name != "welcomeText")
|
if (name != "path" && name != "description" && name != "welcomeText")
|
||||||
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
|
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
|
||||||
|
@ -600,12 +600,12 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
if (name == "checks") {
|
if (name == "checks") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
for (auto & attr2 : *attr.value->attrs) {
|
for (auto & attr2 : *attr.value->attrs()) {
|
||||||
auto drvPath = checkDerivation(
|
auto drvPath = checkDerivation(
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
*attr2.value, attr2.pos);
|
*attr2.value, attr2.pos);
|
||||||
|
@ -622,7 +622,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "formatter") {
|
else if (name == "formatter") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
|
@ -635,12 +635,12 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "packages" || name == "devShells") {
|
else if (name == "packages" || name == "devShells") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
for (auto & attr2 : *attr.value->attrs)
|
for (auto & attr2 : *attr.value->attrs())
|
||||||
checkDerivation(
|
checkDerivation(
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
*attr2.value, attr2.pos);
|
*attr2.value, attr2.pos);
|
||||||
|
@ -650,12 +650,12 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "apps") {
|
else if (name == "apps") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
for (auto & attr2 : *attr.value->attrs)
|
for (auto & attr2 : *attr.value->attrs())
|
||||||
checkApp(
|
checkApp(
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
*attr2.value, attr2.pos);
|
*attr2.value, attr2.pos);
|
||||||
|
@ -665,7 +665,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "defaultPackage" || name == "devShell") {
|
else if (name == "defaultPackage" || name == "devShell") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
|
@ -678,7 +678,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "defaultApp") {
|
else if (name == "defaultApp") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos) ) {
|
if (checkSystemType(attr_name, attr.pos) ) {
|
||||||
|
@ -691,7 +691,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "legacyPackages") {
|
else if (name == "legacyPackages") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
checkSystemName(state->symbols[attr.name], attr.pos);
|
checkSystemName(state->symbols[attr.name], attr.pos);
|
||||||
checkSystemType(state->symbols[attr.name], attr.pos);
|
checkSystemType(state->symbols[attr.name], attr.pos);
|
||||||
// FIXME: do getDerivations?
|
// FIXME: do getDerivations?
|
||||||
|
@ -703,7 +703,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "overlays") {
|
else if (name == "overlays") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs())
|
||||||
checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]),
|
checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]),
|
||||||
*attr.value, attr.pos);
|
*attr.value, attr.pos);
|
||||||
}
|
}
|
||||||
|
@ -713,14 +713,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "nixosModules") {
|
else if (name == "nixosModules") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs())
|
||||||
checkModule(fmt("%s.%s", name, state->symbols[attr.name]),
|
checkModule(fmt("%s.%s", name, state->symbols[attr.name]),
|
||||||
*attr.value, attr.pos);
|
*attr.value, attr.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (name == "nixosConfigurations") {
|
else if (name == "nixosConfigurations") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs())
|
||||||
checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]),
|
checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]),
|
||||||
*attr.value, attr.pos);
|
*attr.value, attr.pos);
|
||||||
}
|
}
|
||||||
|
@ -733,14 +733,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "templates") {
|
else if (name == "templates") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs())
|
||||||
checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]),
|
checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]),
|
||||||
*attr.value, attr.pos);
|
*attr.value, attr.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (name == "defaultBundler") {
|
else if (name == "defaultBundler") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
|
@ -753,12 +753,12 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
else if (name == "bundlers") {
|
else if (name == "bundlers") {
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs()) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
if (checkSystemType(attr_name, attr.pos)) {
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
for (auto & attr2 : *attr.value->attrs) {
|
for (auto & attr2 : *attr.value->attrs()) {
|
||||||
checkBundler(
|
checkBundler(
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
*attr2.value, attr2.pos);
|
*attr2.value, attr2.pos);
|
||||||
|
|
|
@ -260,7 +260,7 @@ static void showHelp(std::vector<std::string> subcommand, NixArgs & toplevel)
|
||||||
state.callFunction(*vGenerateManpage, state.getBuiltin("false"), *vRes, noPos);
|
state.callFunction(*vGenerateManpage, state.getBuiltin("false"), *vRes, noPos);
|
||||||
state.callFunction(*vRes, *vDump, *vRes, noPos);
|
state.callFunction(*vRes, *vDump, *vRes, noPos);
|
||||||
|
|
||||||
auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
|
auto attr = vRes->attrs()->get(state.symbols.create(mdName + ".md"));
|
||||||
if (!attr)
|
if (!attr)
|
||||||
throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand));
|
throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand));
|
||||||
|
|
||||||
|
@ -406,11 +406,10 @@ void mainWrapped(int argc, char * * argv)
|
||||||
auto res = nlohmann::json::object();
|
auto res = nlohmann::json::object();
|
||||||
res["builtins"] = ({
|
res["builtins"] = ({
|
||||||
auto builtinsJson = nlohmann::json::object();
|
auto builtinsJson = nlohmann::json::object();
|
||||||
auto builtins = state.baseEnv.values[0]->attrs;
|
for (auto & builtin : *state.baseEnv.values[0]->attrs()) {
|
||||||
for (auto & builtin : *builtins) {
|
|
||||||
auto b = nlohmann::json::object();
|
auto b = nlohmann::json::object();
|
||||||
if (!builtin.value->isPrimOp()) continue;
|
if (!builtin.value->isPrimOp()) continue;
|
||||||
auto primOp = builtin.value->primOp;
|
auto primOp = builtin.value->primOp();
|
||||||
if (!primOp->doc) continue;
|
if (!primOp->doc) continue;
|
||||||
b["arity"] = primOp->arity;
|
b["arity"] = primOp->arity;
|
||||||
b["args"] = primOp->args;
|
b["args"] = primOp->args;
|
||||||
|
|
|
@ -36,8 +36,8 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url)
|
||||||
vMirrors);
|
vMirrors);
|
||||||
state.forceAttrs(vMirrors, noPos, "while evaluating the set of all mirrors");
|
state.forceAttrs(vMirrors, noPos, "while evaluating the set of all mirrors");
|
||||||
|
|
||||||
auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
|
auto mirrorList = vMirrors.attrs()->get(state.symbols.create(mirrorName));
|
||||||
if (mirrorList == vMirrors.attrs->end())
|
if (!mirrorList)
|
||||||
throw Error("unknown mirror name '%s'", mirrorName);
|
throw Error("unknown mirror name '%s'", mirrorName);
|
||||||
state.forceList(*mirrorList->value, noPos, "while evaluating one mirror configuration");
|
state.forceList(*mirrorList->value, noPos, "while evaluating one mirror configuration");
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
||||||
state->forceAttrs(v, noPos, "while evaluating the source attribute to prefetch");
|
state->forceAttrs(v, noPos, "while evaluating the source attribute to prefetch");
|
||||||
|
|
||||||
/* Extract the URL. */
|
/* Extract the URL. */
|
||||||
auto * attr = v.attrs->get(state->symbols.create("urls"));
|
auto * attr = v.attrs()->get(state->symbols.create("urls"));
|
||||||
if (!attr)
|
if (!attr)
|
||||||
throw Error("attribute 'urls' missing");
|
throw Error("attribute 'urls' missing");
|
||||||
state->forceList(*attr->value, noPos, "while evaluating the urls to prefetch");
|
state->forceList(*attr->value, noPos, "while evaluating the urls to prefetch");
|
||||||
|
@ -223,7 +223,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
||||||
url = state->forceString(*attr->value->listElems()[0], noPos, "while evaluating the first url from the urls list");
|
url = state->forceString(*attr->value->listElems()[0], noPos, "while evaluating the first url from the urls list");
|
||||||
|
|
||||||
/* Extract the hash mode. */
|
/* Extract the hash mode. */
|
||||||
auto attr2 = v.attrs->get(state->symbols.create("outputHashMode"));
|
auto attr2 = v.attrs()->get(state->symbols.create("outputHashMode"));
|
||||||
if (!attr2)
|
if (!attr2)
|
||||||
printInfo("warning: this does not look like a fetchurl call");
|
printInfo("warning: this does not look like a fetchurl call");
|
||||||
else
|
else
|
||||||
|
@ -231,7 +231,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
||||||
|
|
||||||
/* Extract the name. */
|
/* Extract the name. */
|
||||||
if (!name) {
|
if (!name) {
|
||||||
auto attr3 = v.attrs->get(state->symbols.create("name"));
|
auto attr3 = v.attrs()->get(state->symbols.create("name"));
|
||||||
if (!attr3)
|
if (!attr3)
|
||||||
name = state->forceString(*attr3->value, noPos, "while evaluating the name of the source to prefetch");
|
name = state->forceString(*attr3->value, noPos, "while evaluating the name of the source to prefetch");
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,28 +80,28 @@ namespace nix {
|
||||||
if (arg.type() != nInt) {
|
if (arg.type() != nInt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return arg.integer == v;
|
return arg.integer() == v;
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) {
|
MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) {
|
||||||
if (arg.type() != nFloat) {
|
if (arg.type() != nFloat) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return arg.fpoint == v;
|
return arg.fpoint() == v;
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER(IsTrue, "") {
|
MATCHER(IsTrue, "") {
|
||||||
if (arg.type() != nBool) {
|
if (arg.type() != nBool) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return arg.boolean == true;
|
return arg.boolean() == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER(IsFalse, "") {
|
MATCHER(IsFalse, "") {
|
||||||
if (arg.type() != nBool) {
|
if (arg.type() != nBool) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return arg.boolean == false;
|
return arg.boolean() == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) {
|
MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) {
|
||||||
|
@ -134,8 +134,8 @@ namespace nix {
|
||||||
if (arg.type() != nAttrs) {
|
if (arg.type() != nAttrs) {
|
||||||
*result_listener << "Expected set got " << arg.type();
|
*result_listener << "Expected set got " << arg.type();
|
||||||
return false;
|
return false;
|
||||||
} else if (arg.attrs->size() != (size_t)n) {
|
} else if (arg.attrs()->size() != (size_t) n) {
|
||||||
*result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs->size();
|
*result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs()->size();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace nix {
|
||||||
auto v = eval("builtins.tryEval (throw \"\")");
|
auto v = eval("builtins.tryEval (throw \"\")");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
auto s = createSymbol("success");
|
auto s = createSymbol("success");
|
||||||
auto p = v.attrs->get(s);
|
auto p = v.attrs()->get(s);
|
||||||
ASSERT_NE(p, nullptr);
|
ASSERT_NE(p, nullptr);
|
||||||
ASSERT_THAT(*p->value, IsFalse());
|
ASSERT_THAT(*p->value, IsFalse());
|
||||||
}
|
}
|
||||||
|
@ -81,11 +81,11 @@ namespace nix {
|
||||||
auto v = eval("builtins.tryEval 123");
|
auto v = eval("builtins.tryEval 123");
|
||||||
ASSERT_THAT(v, IsAttrs());
|
ASSERT_THAT(v, IsAttrs());
|
||||||
auto s = createSymbol("success");
|
auto s = createSymbol("success");
|
||||||
auto p = v.attrs->get(s);
|
auto p = v.attrs()->get(s);
|
||||||
ASSERT_NE(p, nullptr);
|
ASSERT_NE(p, nullptr);
|
||||||
ASSERT_THAT(*p->value, IsTrue());
|
ASSERT_THAT(*p->value, IsTrue());
|
||||||
s = createSymbol("value");
|
s = createSymbol("value");
|
||||||
p = v.attrs->get(s);
|
p = v.attrs()->get(s);
|
||||||
ASSERT_NE(p, nullptr);
|
ASSERT_NE(p, nullptr);
|
||||||
ASSERT_THAT(*p->value, IsIntEq(123));
|
ASSERT_THAT(*p->value, IsIntEq(123));
|
||||||
}
|
}
|
||||||
|
@ -157,18 +157,18 @@ namespace nix {
|
||||||
auto v = eval(expr);
|
auto v = eval(expr);
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(3));
|
ASSERT_THAT(v, IsAttrsOfSize(3));
|
||||||
|
|
||||||
auto file = v.attrs->find(createSymbol("file"));
|
auto file = v.attrs()->find(createSymbol("file"));
|
||||||
ASSERT_NE(file, nullptr);
|
ASSERT_NE(file, nullptr);
|
||||||
ASSERT_THAT(*file->value, IsString());
|
ASSERT_THAT(*file->value, IsString());
|
||||||
auto s = baseNameOf(file->value->string_view());
|
auto s = baseNameOf(file->value->string_view());
|
||||||
ASSERT_EQ(s, "foo.nix");
|
ASSERT_EQ(s, "foo.nix");
|
||||||
|
|
||||||
auto line = v.attrs->find(createSymbol("line"));
|
auto line = v.attrs()->find(createSymbol("line"));
|
||||||
ASSERT_NE(line, nullptr);
|
ASSERT_NE(line, nullptr);
|
||||||
state.forceValue(*line->value, noPos);
|
state.forceValue(*line->value, noPos);
|
||||||
ASSERT_THAT(*line->value, IsIntEq(4));
|
ASSERT_THAT(*line->value, IsIntEq(4));
|
||||||
|
|
||||||
auto column = v.attrs->find(createSymbol("column"));
|
auto column = v.attrs()->find(createSymbol("column"));
|
||||||
ASSERT_NE(column, nullptr);
|
ASSERT_NE(column, nullptr);
|
||||||
state.forceValue(*column->value, noPos);
|
state.forceValue(*column->value, noPos);
|
||||||
ASSERT_THAT(*column->value, IsIntEq(3));
|
ASSERT_THAT(*column->value, IsIntEq(3));
|
||||||
|
@ -202,14 +202,14 @@ namespace nix {
|
||||||
TEST_F(PrimOpTest, removeAttrsRetains) {
|
TEST_F(PrimOpTest, removeAttrsRetains) {
|
||||||
auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]");
|
auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||||
ASSERT_NE(v.attrs->find(createSymbol("y")), nullptr);
|
ASSERT_NE(v.attrs()->find(createSymbol("y")), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PrimOpTest, listToAttrsEmptyList) {
|
TEST_F(PrimOpTest, listToAttrsEmptyList) {
|
||||||
auto v = eval("builtins.listToAttrs []");
|
auto v = eval("builtins.listToAttrs []");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(0));
|
ASSERT_THAT(v, IsAttrsOfSize(0));
|
||||||
ASSERT_EQ(v.type(), nAttrs);
|
ASSERT_EQ(v.type(), nAttrs);
|
||||||
ASSERT_EQ(v.attrs->size(), 0);
|
ASSERT_EQ(v.attrs()->size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PrimOpTest, listToAttrsNotFieldName) {
|
TEST_F(PrimOpTest, listToAttrsNotFieldName) {
|
||||||
|
@ -219,7 +219,7 @@ namespace nix {
|
||||||
TEST_F(PrimOpTest, listToAttrs) {
|
TEST_F(PrimOpTest, listToAttrs) {
|
||||||
auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]");
|
auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||||
auto key = v.attrs->find(createSymbol("key"));
|
auto key = v.attrs()->find(createSymbol("key"));
|
||||||
ASSERT_NE(key, nullptr);
|
ASSERT_NE(key, nullptr);
|
||||||
ASSERT_THAT(*key->value, IsIntEq(123));
|
ASSERT_THAT(*key->value, IsIntEq(123));
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ namespace nix {
|
||||||
TEST_F(PrimOpTest, intersectAttrs) {
|
TEST_F(PrimOpTest, intersectAttrs) {
|
||||||
auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }");
|
auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||||
auto b = v.attrs->find(createSymbol("b"));
|
auto b = v.attrs()->find(createSymbol("b"));
|
||||||
ASSERT_NE(b, nullptr);
|
ASSERT_NE(b, nullptr);
|
||||||
ASSERT_THAT(*b->value, IsIntEq(3));
|
ASSERT_THAT(*b->value, IsIntEq(3));
|
||||||
}
|
}
|
||||||
|
@ -243,11 +243,11 @@ namespace nix {
|
||||||
auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)");
|
auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
|
|
||||||
auto x = v.attrs->find(createSymbol("x"));
|
auto x = v.attrs()->find(createSymbol("x"));
|
||||||
ASSERT_NE(x, nullptr);
|
ASSERT_NE(x, nullptr);
|
||||||
ASSERT_THAT(*x->value, IsFalse());
|
ASSERT_THAT(*x->value, IsFalse());
|
||||||
|
|
||||||
auto y = v.attrs->find(createSymbol("y"));
|
auto y = v.attrs()->find(createSymbol("y"));
|
||||||
ASSERT_NE(y, nullptr);
|
ASSERT_NE(y, nullptr);
|
||||||
ASSERT_THAT(*y->value, IsTrue());
|
ASSERT_THAT(*y->value, IsTrue());
|
||||||
}
|
}
|
||||||
|
@ -256,13 +256,13 @@ namespace nix {
|
||||||
auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }");
|
auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
|
|
||||||
auto a = v.attrs->find(createSymbol("a"));
|
auto a = v.attrs()->find(createSymbol("a"));
|
||||||
ASSERT_NE(a, nullptr);
|
ASSERT_NE(a, nullptr);
|
||||||
ASSERT_THAT(*a->value, IsThunk());
|
ASSERT_THAT(*a->value, IsThunk());
|
||||||
state.forceValue(*a->value, noPos);
|
state.forceValue(*a->value, noPos);
|
||||||
ASSERT_THAT(*a->value, IsIntEq(10));
|
ASSERT_THAT(*a->value, IsIntEq(10));
|
||||||
|
|
||||||
auto b = v.attrs->find(createSymbol("b"));
|
auto b = v.attrs()->find(createSymbol("b"));
|
||||||
ASSERT_NE(b, nullptr);
|
ASSERT_NE(b, nullptr);
|
||||||
ASSERT_THAT(*b->value, IsThunk());
|
ASSERT_THAT(*b->value, IsThunk());
|
||||||
state.forceValue(*b->value, noPos);
|
state.forceValue(*b->value, noPos);
|
||||||
|
@ -410,13 +410,13 @@ namespace nix {
|
||||||
auto v = eval("builtins.partition (x: x > 10) [1 23 9 3 42]");
|
auto v = eval("builtins.partition (x: x > 10) [1 23 9 3 42]");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
|
|
||||||
auto right = v.attrs->get(createSymbol("right"));
|
auto right = v.attrs()->get(createSymbol("right"));
|
||||||
ASSERT_NE(right, nullptr);
|
ASSERT_NE(right, nullptr);
|
||||||
ASSERT_THAT(*right->value, IsListOfSize(2));
|
ASSERT_THAT(*right->value, IsListOfSize(2));
|
||||||
ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23));
|
ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23));
|
||||||
ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42));
|
ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42));
|
||||||
|
|
||||||
auto wrong = v.attrs->get(createSymbol("wrong"));
|
auto wrong = v.attrs()->get(createSymbol("wrong"));
|
||||||
ASSERT_NE(wrong, nullptr);
|
ASSERT_NE(wrong, nullptr);
|
||||||
ASSERT_EQ(wrong->value->type(), nList);
|
ASSERT_EQ(wrong->value->type(), nList);
|
||||||
ASSERT_EQ(wrong->value->listSize(), 3);
|
ASSERT_EQ(wrong->value->listSize(), 3);
|
||||||
|
@ -641,14 +641,14 @@ namespace nix {
|
||||||
auto v = eval("derivation");
|
auto v = eval("derivation");
|
||||||
ASSERT_EQ(v.type(), nFunction);
|
ASSERT_EQ(v.type(), nFunction);
|
||||||
ASSERT_TRUE(v.isLambda());
|
ASSERT_TRUE(v.isLambda());
|
||||||
ASSERT_NE(v.lambda.fun, nullptr);
|
ASSERT_NE(v.payload.lambda.fun, nullptr);
|
||||||
ASSERT_TRUE(v.lambda.fun->hasFormals());
|
ASSERT_TRUE(v.payload.lambda.fun->hasFormals());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PrimOpTest, currentTime) {
|
TEST_F(PrimOpTest, currentTime) {
|
||||||
auto v = eval("builtins.currentTime");
|
auto v = eval("builtins.currentTime");
|
||||||
ASSERT_EQ(v.type(), nInt);
|
ASSERT_EQ(v.type(), nInt);
|
||||||
ASSERT_TRUE(v.integer > 0);
|
ASSERT_TRUE(v.integer() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PrimOpTest, splitVersion) {
|
TEST_F(PrimOpTest, splitVersion) {
|
||||||
|
@ -709,11 +709,11 @@ namespace nix {
|
||||||
auto v = eval(expr);
|
auto v = eval(expr);
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
|
|
||||||
auto name = v.attrs->find(createSymbol("name"));
|
auto name = v.attrs()->find(createSymbol("name"));
|
||||||
ASSERT_TRUE(name);
|
ASSERT_TRUE(name);
|
||||||
ASSERT_THAT(*name->value, IsStringEq(expectedName));
|
ASSERT_THAT(*name->value, IsStringEq(expectedName));
|
||||||
|
|
||||||
auto version = v.attrs->find(createSymbol("version"));
|
auto version = v.attrs()->find(createSymbol("version"));
|
||||||
ASSERT_TRUE(version);
|
ASSERT_TRUE(version);
|
||||||
ASSERT_THAT(*version->value, IsStringEq(expectedVersion));
|
ASSERT_THAT(*version->value, IsStringEq(expectedVersion));
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,11 +62,11 @@ namespace nix {
|
||||||
TEST_F(TrivialExpressionTest, updateAttrs) {
|
TEST_F(TrivialExpressionTest, updateAttrs) {
|
||||||
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
|
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||||
auto a = v.attrs->find(createSymbol("a"));
|
auto a = v.attrs()->find(createSymbol("a"));
|
||||||
ASSERT_NE(a, nullptr);
|
ASSERT_NE(a, nullptr);
|
||||||
ASSERT_THAT(*a->value, IsIntEq(3));
|
ASSERT_THAT(*a->value, IsIntEq(3));
|
||||||
|
|
||||||
auto b = v.attrs->find(createSymbol("b"));
|
auto b = v.attrs()->find(createSymbol("b"));
|
||||||
ASSERT_NE(b, nullptr);
|
ASSERT_NE(b, nullptr);
|
||||||
ASSERT_THAT(*b->value, IsIntEq(2));
|
ASSERT_THAT(*b->value, IsIntEq(2));
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ namespace nix {
|
||||||
auto v = eval(expr);
|
auto v = eval(expr);
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||||
|
|
||||||
auto a = v.attrs->find(createSymbol("a"));
|
auto a = v.attrs()->find(createSymbol("a"));
|
||||||
ASSERT_NE(a, nullptr);
|
ASSERT_NE(a, nullptr);
|
||||||
|
|
||||||
ASSERT_THAT(*a->value, IsThunk());
|
ASSERT_THAT(*a->value, IsThunk());
|
||||||
|
@ -159,11 +159,11 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
|
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
|
||||||
|
|
||||||
auto b = a->value->attrs->find(createSymbol("b"));
|
auto b = a->value->attrs()->find(createSymbol("b"));
|
||||||
ASSERT_NE(b, nullptr);
|
ASSERT_NE(b, nullptr);
|
||||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||||
|
|
||||||
auto c = a->value->attrs->find(createSymbol("c"));
|
auto c = a->value->attrs()->find(createSymbol("c"));
|
||||||
ASSERT_NE(c, nullptr);
|
ASSERT_NE(c, nullptr);
|
||||||
ASSERT_THAT(*c->value, IsIntEq(2));
|
ASSERT_THAT(*c->value, IsIntEq(2));
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ namespace nix {
|
||||||
TEST_F(TrivialExpressionTest, bindOr) {
|
TEST_F(TrivialExpressionTest, bindOr) {
|
||||||
auto v = eval("{ or = 1; }");
|
auto v = eval("{ or = 1; }");
|
||||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||||
auto b = v.attrs->find(createSymbol("or"));
|
auto b = v.attrs()->find(createSymbol("or"));
|
||||||
ASSERT_NE(b, nullptr);
|
ASSERT_NE(b, nullptr);
|
||||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue