libexpr: migrate Expr::eval to return a Value, take 2
This is a rebase of CL 1626 after the performance problems that blocked that change are no longer an issue. Change-Id: I4a17f7606c5fdc9a924933a860eb401f6a6a6964
This commit is contained in:
+5
-9
@@ -504,8 +504,7 @@ StringSet NixRepl::completePrefix(const std::string &prefix)
|
||||
auto cur2 = cur.substr(dot + 1);
|
||||
|
||||
Expr & e = parseString(expr);
|
||||
Value v;
|
||||
e.eval(state, *env, v);
|
||||
Value v = e.eval(state, *env);
|
||||
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()) {
|
||||
@@ -656,8 +655,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
overloaded{
|
||||
[&](ExprReplBindings & b) {
|
||||
for (auto & [name, e] : b.symbols) {
|
||||
Value v;
|
||||
e->eval(state, *env, v);
|
||||
Value v = e->eval(state, *env);
|
||||
// NONEXTLINE(bugprone-unused-return-value): leak because of thunk
|
||||
// references
|
||||
(void) e.release();
|
||||
@@ -665,8 +663,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
}
|
||||
},
|
||||
[&](std::unique_ptr<Expr> & e) {
|
||||
Value v;
|
||||
e->eval(state, *env, v);
|
||||
Value v = e->eval(state, *env);
|
||||
// NONEXTLINE(bugprone-unused-return-value): leak because of thunk references
|
||||
(void) e.release();
|
||||
state.forceValue(v, noPos);
|
||||
@@ -1590,15 +1587,14 @@ std::variant<std::unique_ptr<Expr>, ExprReplBindings> NixRepl::parseReplString(s
|
||||
void NixRepl::evalString(std::string s, Value & v)
|
||||
{
|
||||
Expr & e = parseString(s);
|
||||
e.eval(state, *env, v);
|
||||
v = e.eval(state, *env);
|
||||
state.forceValue(v, noPos);
|
||||
}
|
||||
|
||||
Value NixRepl::evalFile(SourcePath & path)
|
||||
{
|
||||
auto & expr = evaluator.parseExprFromFile(evaluator.paths.checkSourcePath(path), staticEnv);
|
||||
Value result;
|
||||
expr.eval(state, *env, result);
|
||||
Value result = expr.eval(state, *env);
|
||||
state.forceValue(result, noPos);
|
||||
return result;
|
||||
}
|
||||
|
||||
+89
-110
@@ -1,5 +1,4 @@
|
||||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "primops.hh"
|
||||
#include "gc-small-vector.hh"
|
||||
|
||||
@@ -47,21 +46,21 @@ Value ExprList::maybeThunk(EvalState & state, Env & env)
|
||||
return Expr::maybeThunk(state, env);
|
||||
}
|
||||
|
||||
void Expr::eval(EvalState & state, Env & env, Value & v)
|
||||
Value Expr::eval(EvalState & state, Env & env)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void ExprLiteral::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprLiteral::eval(EvalState & state, Env & env)
|
||||
{
|
||||
v = this->v;
|
||||
return this->v;
|
||||
}
|
||||
|
||||
void ExprInheritFrom::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprInheritFrom::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value & v2 = env.values[displ];
|
||||
state.forceValue(v2, pos);
|
||||
v = v2;
|
||||
return v2;
|
||||
}
|
||||
|
||||
Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
|
||||
@@ -77,10 +76,10 @@ Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
|
||||
return &inheritEnv;
|
||||
}
|
||||
|
||||
void ExprSet::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprSet::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Bindings::Size capacity = attrs.size() + dynamicAttrs.size();
|
||||
v = {NewValueAs::attrs, state.ctx.buildBindings(capacity).finish()};
|
||||
Value v = {NewValueAs::attrs, state.ctx.buildBindings(capacity).finish()};
|
||||
auto dynamicEnv = &env;
|
||||
|
||||
if (recursive) {
|
||||
@@ -167,7 +166,7 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
KJ_DEFER(v = vBackup);
|
||||
v = Value{NewValueAs::blackhole};
|
||||
i.nameExpr->eval(state, *dynamicEnv, nameVal);
|
||||
nameVal = i.nameExpr->eval(state, *dynamicEnv);
|
||||
state.forceValue(nameVal, i.pos);
|
||||
if (nameVal.type() == nNull) {
|
||||
continue;
|
||||
@@ -195,9 +194,10 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
|
||||
v.attrs()->pos = pos;
|
||||
return v;
|
||||
}
|
||||
|
||||
void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprLet::eval(EvalState & state, Env & env)
|
||||
{
|
||||
/* Create a new environment that contains the attributes in this
|
||||
`let'. */
|
||||
@@ -214,19 +214,20 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||
env2.values[displ++] = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
|
||||
}
|
||||
|
||||
body->eval(state, env2, v);
|
||||
return body->eval(state, env2);
|
||||
}
|
||||
|
||||
void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprList::eval(EvalState & state, Env & env)
|
||||
{
|
||||
auto result = state.ctx.mem.newList(elems.size());
|
||||
v = {NewValueAs::list, result};
|
||||
Value v = {NewValueAs::list, result};
|
||||
for (auto && [n, v2] : enumerate(result->span())) {
|
||||
v2 = elems[n]->maybeThunk(state, env);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprVar::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value * v2 = state.lookupVar(&env, *this, false);
|
||||
try {
|
||||
@@ -238,123 +239,103 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
v = *v2;
|
||||
return *v2;
|
||||
}
|
||||
|
||||
void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprWith::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Env & env2(state.ctx.mem.allocEnv(1));
|
||||
env2.up = &env;
|
||||
env2.values[0] = attrs->maybeThunk(state, env);
|
||||
|
||||
body->eval(state, env2, v);
|
||||
return body->eval(state, env2);
|
||||
}
|
||||
|
||||
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprIf::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value vCond;
|
||||
cond->eval(state, env, vCond);
|
||||
(state.checkBool(vCond, env, *cond) ? *then : *else_).eval(state, env, v);
|
||||
Value vCond = cond->eval(state, env);
|
||||
return (state.checkBool(vCond, env, *cond) ? *then : *else_).eval(state, env);
|
||||
}
|
||||
|
||||
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprAssert::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value vCond;
|
||||
cond->eval(state, env, vCond);
|
||||
Value vCond = cond->eval(state, env);
|
||||
if (!state.checkBool(vCond, env, *cond)) {
|
||||
state.ctx.errors.make<AssertionError>("assertion failed")
|
||||
.atPos(pos)
|
||||
.withFrame(env, *this)
|
||||
.debugThrow();
|
||||
}
|
||||
body->eval(state, env, v);
|
||||
return body->eval(state, env);
|
||||
}
|
||||
|
||||
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpNot::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value vInner;
|
||||
e->eval(state, env, vInner);
|
||||
v = {NewValueAs::boolean, !state.checkBool(vInner, env, *e)};
|
||||
Value vInner = e->eval(state, env);
|
||||
return {NewValueAs::boolean, !state.checkBool(vInner, env, *e)};
|
||||
}
|
||||
|
||||
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpEq::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
v = {NewValueAs::boolean, state.eqValues(v1, v2, pos, "while testing two values for equality")};
|
||||
Value v1 = e1->eval(state, env);
|
||||
Value v2 = e2->eval(state, env);
|
||||
return {NewValueAs::boolean, state.eqValues(v1, v2, pos, "while testing two values for equality")};
|
||||
}
|
||||
|
||||
void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpNEq::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
v = {NewValueAs::boolean, !state.eqValues(v1, v2, pos, "while testing two values for inequality")};
|
||||
Value v1 = e1->eval(state, env);
|
||||
Value v2 = e2->eval(state, env);
|
||||
return {NewValueAs::boolean, !state.eqValues(v1, v2, pos, "while testing two values for inequality")};
|
||||
}
|
||||
|
||||
void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpAnd::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v1 = e1->eval(state, env);
|
||||
/* Explicitly short-circuit */
|
||||
if (!state.checkBool(v1, env, *e1)) {
|
||||
v = {NewValueAs::boolean, false};
|
||||
return;
|
||||
return {NewValueAs::boolean, false};
|
||||
}
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
v = {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
Value v2 = e2->eval(state, env);
|
||||
return {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
}
|
||||
|
||||
void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpOr::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v1 = e1->eval(state, env);
|
||||
/* Explicitly short-circuit */
|
||||
if (state.checkBool(v1, env, *e1)) {
|
||||
v = {NewValueAs::boolean, true};
|
||||
return;
|
||||
return {NewValueAs::boolean, true};
|
||||
}
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
v = {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
Value v2 = e2->eval(state, env);
|
||||
return {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
}
|
||||
|
||||
void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpImpl::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v1 = e1->eval(state, env);
|
||||
/* Explicitly short-circuit (ex falso quodlibet) */
|
||||
if (!state.checkBool(v1, env, *e1)) {
|
||||
v = {NewValueAs::boolean, true};
|
||||
return;
|
||||
return {NewValueAs::boolean, true};
|
||||
}
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
v = {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
Value v2 = e2->eval(state, env);
|
||||
return {NewValueAs::boolean, state.checkBool(v2, env, *e2)};
|
||||
}
|
||||
|
||||
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpUpdate::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v1 = e1->eval(state, env);
|
||||
state.checkAttrs(v1, env, *e1);
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
Value v2 = e2->eval(state, env);
|
||||
state.checkAttrs(v2, env, *e2);
|
||||
|
||||
state.ctx.stats.nrOpUpdates++;
|
||||
|
||||
if (v1.attrs()->size() == 0) {
|
||||
v = v2;
|
||||
return;
|
||||
return v2;
|
||||
}
|
||||
if (v2.attrs()->size() == 0) {
|
||||
v = v1;
|
||||
return;
|
||||
return v1;
|
||||
}
|
||||
|
||||
auto attrs = state.ctx.buildBindings(v1.attrs()->size() + v2.attrs()->size());
|
||||
@@ -383,40 +364,39 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||
attrs.insert(*j++);
|
||||
}
|
||||
|
||||
v = {NewValueAs::attrs, attrs.alreadySorted()};
|
||||
Value v = {NewValueAs::attrs, attrs.alreadySorted()};
|
||||
|
||||
state.ctx.stats.nrOpUpdateValuesCopied += v.attrs()->size();
|
||||
return v;
|
||||
}
|
||||
|
||||
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpConcatLists::eval(EvalState & state, Env & env)
|
||||
{
|
||||
state.ctx.stats.nrListConcats++;
|
||||
|
||||
/* We don't call into `concatLists` as that loses the position information of the expressions. */
|
||||
|
||||
Value v1;
|
||||
e1->eval(state, env, v1);
|
||||
Value v1 = e1->eval(state, env);
|
||||
state.checkList(v1, env, *e1);
|
||||
Value v2;
|
||||
e2->eval(state, env, v2);
|
||||
Value v2 = e2->eval(state, env);
|
||||
state.checkList(v2, env, *e2);
|
||||
|
||||
size_t l1 = v1.listSize(), l2 = v2.listSize(), len = l1 + l2;
|
||||
|
||||
if (l1 == 0) {
|
||||
v = v2;
|
||||
return v2;
|
||||
} else if (l2 == 0) {
|
||||
v = v1;
|
||||
return v1;
|
||||
} else {
|
||||
auto list = state.ctx.mem.newList(len);
|
||||
v = {NewValueAs::list, list};
|
||||
auto out = list->elems;
|
||||
std::copy(v1.listElems(), v1.listElems() + l1, out);
|
||||
std::copy(v2.listElems(), v2.listElems() + l2, out + l1);
|
||||
return {NewValueAs::list, list};
|
||||
}
|
||||
}
|
||||
|
||||
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprConcatStrings::eval(EvalState & state, Env & env)
|
||||
{
|
||||
NixStringContext context;
|
||||
std::vector<BackedStringView> s;
|
||||
@@ -454,7 +434,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
for (auto & [i_pos, i] : es) {
|
||||
Value & vTmp = *vTmpP++;
|
||||
i->eval(state, env, vTmp);
|
||||
vTmp = i->eval(state, env);
|
||||
|
||||
/* If the first element is a path, then the result will also
|
||||
be a path, we don't copy anything (yet - that's done later,
|
||||
@@ -528,9 +508,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
|
||||
if (firstType == nInt) {
|
||||
v = {NewValueAs::integer, n};
|
||||
return {NewValueAs::integer, n};
|
||||
} else if (firstType == nFloat) {
|
||||
v = {NewValueAs::floating, nf};
|
||||
return {NewValueAs::floating, nf};
|
||||
} else if (firstType == nPath) {
|
||||
if (!context.empty()) {
|
||||
state.ctx.errors
|
||||
@@ -539,26 +519,28 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
.withFrame(env, *this)
|
||||
.debugThrow();
|
||||
}
|
||||
v = {NewValueAs::path, CanonPath(canonPath(str()))};
|
||||
return {NewValueAs::path, CanonPath(canonPath(str()))};
|
||||
} else {
|
||||
v = {NewValueAs::string, gcStr(), context};
|
||||
return {NewValueAs::string, gcStr(), context};
|
||||
}
|
||||
}
|
||||
|
||||
void ExprPos::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprPos::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value v;
|
||||
state.mkPos(v, pos);
|
||||
return v;
|
||||
}
|
||||
|
||||
void ExprBlackHole::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprBlackHole::eval(EvalState & state, Env & env)
|
||||
{
|
||||
state.ctx.errors.make<InfiniteRecursionError>("infinite recursion encountered").debugThrow();
|
||||
}
|
||||
|
||||
void ExprDebugFrame::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprDebugFrame::eval(EvalState & state, Env & env)
|
||||
{
|
||||
auto dts = makeDebugTraceStacker(state, *inner, env, state.ctx.positions[pos], message);
|
||||
inner->eval(state, env, v);
|
||||
return inner->eval(state, env);
|
||||
}
|
||||
|
||||
/** Returns `nullptr` if we should be using a default instead. */
|
||||
@@ -630,7 +612,7 @@ ExprSelect::selectSingleAttr(EvalState & state, Env & env, AttrName const & attr
|
||||
return attrIt;
|
||||
}
|
||||
|
||||
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprSelect::eval(EvalState & state, Env & env)
|
||||
{
|
||||
// Position for the current attrset Value in this select chain.
|
||||
PosIdx posCurrent;
|
||||
@@ -640,7 +622,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
Value baseSelectee;
|
||||
try {
|
||||
// Evaluate the original thing we're selecting on.
|
||||
e->eval(state, env, baseSelectee);
|
||||
baseSelectee = e->eval(state, env);
|
||||
} catch (Error & e) {
|
||||
// clang-format off
|
||||
e.addTrace(state.ctx.positions[getPos()], HintFmt(
|
||||
@@ -663,7 +645,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
if (!attr) {
|
||||
// Use default.
|
||||
try {
|
||||
this->def->eval(state, env, v);
|
||||
return this->def->eval(state, env);
|
||||
} catch (Error & err) {
|
||||
err.addTrace(
|
||||
state.ctx.positions[this->def->pos],
|
||||
@@ -672,7 +654,6 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
);
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The selection worked. If we have another iteration, then we use `attr->value`
|
||||
@@ -689,7 +670,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
state.forceValue(curSelectee.get(), posCurrent ? posCurrent : posCurrentSyntax);
|
||||
|
||||
v = curSelectee.get();
|
||||
return curSelectee.get();
|
||||
|
||||
} catch (Error & err) {
|
||||
auto const & lastPos = state.ctx.positions[posCurrent];
|
||||
@@ -701,37 +682,33 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
}
|
||||
|
||||
void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprOpHasAttr::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value vTmp;
|
||||
Value vTmp = e->eval(state, env);
|
||||
Value * vAttrs = &vTmp;
|
||||
|
||||
e->eval(state, env, vTmp);
|
||||
|
||||
for (auto & i : attrPath) {
|
||||
state.forceValue(*vAttrs, getPos());
|
||||
const Attr * j;
|
||||
auto name = getName(i, state, env);
|
||||
if (vAttrs->type() != nAttrs || (j = vAttrs->attrs()->get(name)) == nullptr) {
|
||||
v = {NewValueAs::boolean, false};
|
||||
return;
|
||||
return {NewValueAs::boolean, false};
|
||||
} else {
|
||||
vAttrs = &j->value;
|
||||
}
|
||||
}
|
||||
|
||||
v = {NewValueAs::boolean, true};
|
||||
return {NewValueAs::boolean, true};
|
||||
}
|
||||
|
||||
void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprLambda::eval(EvalState & state, Env & env)
|
||||
{
|
||||
v = {NewValueAs::lambda, state.ctx.mem, env, *this};
|
||||
return {NewValueAs::lambda, state.ctx.mem, env, *this};
|
||||
}
|
||||
|
||||
void ExprCall::eval(EvalState & state, Env & env, Value & v)
|
||||
Value ExprCall::eval(EvalState & state, Env & env)
|
||||
{
|
||||
Value vFun;
|
||||
fun->eval(state, env, vFun);
|
||||
Value vFun = fun->eval(state, env);
|
||||
|
||||
// Empirical arity of Nixpkgs lambdas by regex e.g. ([a-zA-Z]+:(\s|(/\*.*\/)|(#.*\n))*){5}
|
||||
// 2: over 4000
|
||||
@@ -745,7 +722,9 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v)
|
||||
vArgs[i] = args[i]->maybeThunk(state, env);
|
||||
}
|
||||
|
||||
Value v;
|
||||
state.callFunction(vFun, vArgs, v, pos);
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||
Expr & expr = *thunk.expr;
|
||||
thunk = Value::blackHole;
|
||||
try {
|
||||
expr.eval(*this, *env, v);
|
||||
v = expr.eval(*this, *env);
|
||||
thunk.resolve(v);
|
||||
} catch (...) {
|
||||
thunk = backup;
|
||||
|
||||
+3
-4
@@ -166,8 +166,7 @@ Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
||||
if (name.symbol) {
|
||||
return name.symbol;
|
||||
} else {
|
||||
Value nameValue;
|
||||
name.expr->eval(state, env, nameValue);
|
||||
Value nameValue = name.expr->eval(state, env);
|
||||
state.forceStringNoCtx(nameValue, name.expr->getPos(), "while evaluating an attribute name");
|
||||
return state.ctx.symbols.create(nameValue.str());
|
||||
}
|
||||
@@ -976,7 +975,7 @@ void EvalState::resetFileCache()
|
||||
|
||||
void EvalState::eval(Expr & e, Value & v)
|
||||
{
|
||||
e.eval(*this, ctx.builtins.env, v);
|
||||
v = e.eval(*this, ctx.builtins.env);
|
||||
}
|
||||
|
||||
std::string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath)
|
||||
@@ -1168,7 +1167,7 @@ void EvalState::callFunction(Value & fun, std::span<Value> args, Value & vRes, c
|
||||
|
||||
/* Evaluate the body. */
|
||||
try {
|
||||
lambda.body->eval(*this, env2, vCur);
|
||||
vCur = lambda.body->eval(*this, env2);
|
||||
} catch (Error & e) {
|
||||
if (loggerSettings.showTrace.get()) {
|
||||
e.addTrace(
|
||||
|
||||
+29
-27
@@ -128,7 +128,7 @@ public:
|
||||
|
||||
virtual JSON toJSON(const SymbolTable & symbols) const;
|
||||
virtual void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) = 0;
|
||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||
virtual Value eval(EvalState & state, Env & env);
|
||||
virtual Value maybeThunk(EvalState & state, Env & env);
|
||||
virtual void setName(Symbol name);
|
||||
PosIdx getPos() const { return pos; }
|
||||
@@ -167,7 +167,7 @@ struct ExprDebugFrame : Expr
|
||||
{
|
||||
return inner->toJSON(symbols);
|
||||
}
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -179,7 +179,7 @@ protected:
|
||||
public:
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -267,7 +267,7 @@ struct ExprVar : Expr
|
||||
ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : Expr(pos), name(name), needsRoot(needsRoot) { };
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -287,7 +287,7 @@ struct ExprInheritFrom : Expr
|
||||
}
|
||||
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -309,7 +309,7 @@ struct ExprSelect : Expr
|
||||
ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath, std::unique_ptr<Expr> def) : Expr(pos), e(std::move(e)), def(std::move(def)), attrPath(std::move(attrPath)) { };
|
||||
ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, const PosIdx namePos, Symbol name) : Expr(pos), e(std::move(e)) { attrPath.push_back(AttrName(namePos, name)); };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
|
||||
private:
|
||||
@@ -322,7 +322,7 @@ struct ExprOpHasAttr : Expr
|
||||
AttrPath attrPath;
|
||||
ExprOpHasAttr(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath) : Expr(pos), e(std::move(e)), attrPath(std::move(attrPath)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -392,7 +392,7 @@ struct ExprSet : Expr, ExprAttrs {
|
||||
ExprSet(const PosIdx &pos, bool recursive = false) : Expr(pos), recursive(recursive) { };
|
||||
ExprSet() { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -410,7 +410,7 @@ struct ExprList : Expr
|
||||
std::vector<std::unique_ptr<Expr>> elems;
|
||||
ExprList(PosIdx pos) : Expr(pos) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
Value maybeThunk(EvalState & state, Env & env) override;
|
||||
};
|
||||
@@ -528,7 +528,7 @@ struct ExprLambda : Expr
|
||||
}
|
||||
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -540,7 +540,7 @@ struct ExprCall : Expr
|
||||
: Expr(pos), fun(std::move(fun)), args(std::move(args))
|
||||
{ }
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -548,7 +548,7 @@ struct ExprLet : Expr, ExprAttrs
|
||||
{
|
||||
std::unique_ptr<Expr> body;
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -559,7 +559,7 @@ struct ExprWith : Expr
|
||||
ExprWith * parentWith;
|
||||
ExprWith(const PosIdx & pos, std::unique_ptr<Expr> attrs, std::unique_ptr<Expr> body) : Expr(pos), attrs(std::move(attrs)), body(std::move(body)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -568,7 +568,7 @@ struct ExprIf : Expr
|
||||
std::unique_ptr<Expr> cond, then, else_;
|
||||
ExprIf(const PosIdx & pos, std::unique_ptr<Expr> cond, std::unique_ptr<Expr> then, std::unique_ptr<Expr> else_) : Expr(pos), cond(std::move(cond)), then(std::move(then)), else_(std::move(else_)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -577,7 +577,7 @@ struct ExprAssert : Expr
|
||||
std::unique_ptr<Expr> cond, body;
|
||||
ExprAssert(const PosIdx & pos, std::unique_ptr<Expr> cond, std::unique_ptr<Expr> body) : Expr(pos), cond(std::move(cond)), body(std::move(body)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -586,7 +586,7 @@ struct ExprOpNot : Expr
|
||||
std::unique_ptr<Expr> e;
|
||||
ExprOpNot(const PosIdx & pos, std::unique_ptr<Expr> e) : Expr(pos), e(std::move(e)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -595,17 +595,19 @@ struct ExprOpNot : Expr
|
||||
{ \
|
||||
std::unique_ptr<Expr> e1, e2; \
|
||||
name(std::unique_ptr<Expr> e1, std::unique_ptr<Expr> e2) : e1(std::move(e1)), e2(std::move(e2)) {}; \
|
||||
name(const PosIdx & pos, std::unique_ptr<Expr> e1, std::unique_ptr<Expr> e2) : Expr(pos), e1(std::move(e1)), e2(std::move(e2)) { }; \
|
||||
name(const PosIdx & pos, std::unique_ptr<Expr> e1, std::unique_ptr<Expr> e2) \
|
||||
: Expr(pos) \
|
||||
, e1(std::move(e1)) \
|
||||
, e2(std::move(e2)) {}; \
|
||||
JSON toJSON(const SymbolTable & symbols) const override \
|
||||
{ \
|
||||
return { \
|
||||
{"_type", #name}, \
|
||||
{"e1", e1->toJSON(symbols)}, \
|
||||
{"e2", e2->toJSON(symbols)} \
|
||||
};\
|
||||
return {{"_type", #name}, {"e1", e1->toJSON(symbols)}, {"e2", e2->toJSON(symbols)}}; \
|
||||
} \
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); } \
|
||||
void eval(EvalState & state, Env & env, Value & v) override; \
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override \
|
||||
{ \
|
||||
ev.visit(*this, ptr); \
|
||||
} \
|
||||
Value eval(EvalState & state, Env & env) override; \
|
||||
};
|
||||
|
||||
MakeBinOp(ExprOpEq, "==")
|
||||
@@ -623,7 +625,7 @@ struct ExprConcatStrings : Expr
|
||||
ExprConcatStrings(const PosIdx & pos, bool isInterpolation, std::vector<std::pair<PosIdx, std::unique_ptr<Expr>>> es)
|
||||
: Expr(pos), isInterpolation(isInterpolation), es(std::move(es)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
@@ -631,14 +633,14 @@ struct ExprPos : Expr
|
||||
{
|
||||
ExprPos(const PosIdx & pos) : Expr(pos) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
/* only used to mark thunks as black holes. */
|
||||
struct ExprBlackHole : Expr
|
||||
{
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
Value eval(EvalState & state, Env & env) override;
|
||||
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
|
||||
};
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v)
|
||||
debug("evaluating file '%1%'", path);
|
||||
Expr & e = state.ctx.parseExprFromFile(state.ctx.paths.resolveExprPath(path), staticEnv);
|
||||
|
||||
e.eval(state, *env, v);
|
||||
v = e.eval(state, *env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user