libexpr: pass Exprs as references, not pointers
almost all places where Exprs are passed as pointers expect the pointers to be non-null. pass them as references to encode this constraint in the type system as well (and also communicate that Exprs must not be freed). Change-Id: Ia98f166fec3c23151f906e13acb4a0954a5980a2
This commit is contained in:
parent
b8f49a8eaf
commit
ad5366c2ad
14 changed files with 85 additions and 75 deletions
|
@ -214,7 +214,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||||
|
|
||||||
evalSettings.pureEval = false;
|
evalSettings.pureEval = false;
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
Expr *e = state->parseExprFromFile(
|
Expr & e = state->parseExprFromFile(
|
||||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -434,13 +434,13 @@ Installables SourceExprCommand::parseInstallables(
|
||||||
auto vFile = state->allocValue();
|
auto vFile = state->allocValue();
|
||||||
|
|
||||||
if (file == "-") {
|
if (file == "-") {
|
||||||
auto e = state->parseStdin();
|
auto & e = state->parseStdin();
|
||||||
state->eval(e, *vFile);
|
state->eval(e, *vFile);
|
||||||
}
|
}
|
||||||
else if (file)
|
else if (file)
|
||||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||||
else {
|
else {
|
||||||
auto e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
|
auto & e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
|
||||||
state->eval(e, *vFile);
|
state->eval(e, *vFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ struct NixRepl
|
||||||
void reloadFiles();
|
void reloadFiles();
|
||||||
void addAttrsToScope(Value & attrs);
|
void addAttrsToScope(Value & attrs);
|
||||||
void addVarToScope(const Symbol name, Value & v);
|
void addVarToScope(const Symbol name, Value & v);
|
||||||
Expr * parseString(std::string s);
|
Expr & parseString(std::string s);
|
||||||
void evalString(std::string s, Value & v);
|
void evalString(std::string s, Value & v);
|
||||||
void loadDebugTraceEnv(DebugTrace & dt);
|
void loadDebugTraceEnv(DebugTrace & dt);
|
||||||
|
|
||||||
|
@ -428,9 +428,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||||
auto expr = cur.substr(0, dot);
|
auto expr = cur.substr(0, dot);
|
||||||
auto cur2 = cur.substr(dot + 1);
|
auto cur2 = cur.substr(dot + 1);
|
||||||
|
|
||||||
Expr * e = parseString(expr);
|
Expr & e = parseString(expr);
|
||||||
Value v;
|
Value v;
|
||||||
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) {
|
||||||
|
@ -821,7 +821,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||||
line[p + 1] != '=' &&
|
line[p + 1] != '=' &&
|
||||||
isVarName(name = removeWhitespace(line.substr(0, p))))
|
isVarName(name = removeWhitespace(line.substr(0, p))))
|
||||||
{
|
{
|
||||||
Expr * e = parseString(line.substr(p + 1));
|
Expr & e = parseString(line.substr(p + 1));
|
||||||
Value & v(*state->allocValue());
|
Value & v(*state->allocValue());
|
||||||
v.mkThunk(env, e);
|
v.mkThunk(env, e);
|
||||||
addVarToScope(state->symbols.create(name), v);
|
addVarToScope(state->symbols.create(name), v);
|
||||||
|
@ -946,7 +946,7 @@ Value * NixRepl::getReplOverlaysEvalFunction()
|
||||||
auto code =
|
auto code =
|
||||||
#include "repl-overlays.nix.gen.hh"
|
#include "repl-overlays.nix.gen.hh"
|
||||||
;
|
;
|
||||||
auto expr = state->parseExprFromString(
|
auto & expr = state->parseExprFromString(
|
||||||
code,
|
code,
|
||||||
SourcePath(evalReplInitFilesPath),
|
SourcePath(evalReplInitFilesPath),
|
||||||
state->staticBaseEnv
|
state->staticBaseEnv
|
||||||
|
@ -1054,7 +1054,7 @@ Value * NixRepl::bindingsToAttrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * NixRepl::parseString(std::string s)
|
Expr & NixRepl::parseString(std::string s)
|
||||||
{
|
{
|
||||||
return state->parseExprFromString(std::move(s), state->rootPath(CanonPath::fromCwd()), staticEnv);
|
return state->parseExprFromString(std::move(s), state->rootPath(CanonPath::fromCwd()), staticEnv);
|
||||||
}
|
}
|
||||||
|
@ -1062,16 +1062,16 @@ Expr * NixRepl::parseString(std::string s)
|
||||||
|
|
||||||
void NixRepl::evalString(std::string s, Value & v)
|
void NixRepl::evalString(std::string s, Value & v)
|
||||||
{
|
{
|
||||||
Expr * e = parseString(s);
|
Expr & e = parseString(s);
|
||||||
e->eval(*state, *env, v);
|
e.eval(*state, *env, v);
|
||||||
state->forceValue(v, v.determinePos(noPos));
|
state->forceValue(v, v.determinePos(noPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * NixRepl::evalFile(SourcePath & path)
|
Value * NixRepl::evalFile(SourcePath & path)
|
||||||
{
|
{
|
||||||
auto expr = state->parseExprFromFile(path, staticEnv);
|
auto & expr = state->parseExprFromFile(path, staticEnv);
|
||||||
Value * result(state->allocValue());
|
Value * result(state->allocValue());
|
||||||
expr->eval(*state, *env, *result);
|
expr.eval(*state, *env, *result);
|
||||||
state->forceValue(*result, result->determinePos(noPos));
|
state->forceValue(*result, result->determinePos(noPos));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,11 +86,11 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||||
{
|
{
|
||||||
if (v.isThunk()) {
|
if (v.isThunk()) {
|
||||||
Env * env = v.thunk.env;
|
Env * env = v.thunk.env;
|
||||||
Expr * expr = v.thunk.expr;
|
Expr & expr = *v.thunk.expr;
|
||||||
try {
|
try {
|
||||||
v.mkBlackhole();
|
v.mkBlackhole();
|
||||||
//checkInterrupt();
|
//checkInterrupt();
|
||||||
expr->eval(*this, *env, v);
|
expr.eval(*this, *env, v);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
v.mkThunk(env, expr);
|
v.mkThunk(env, expr);
|
||||||
tryFixupBlackHolePos(v, pos);
|
tryFixupBlackHolePos(v, pos);
|
||||||
|
|
|
@ -950,14 +950,14 @@ void EvalState::mkList(Value & v, size_t size)
|
||||||
|
|
||||||
unsigned long nrThunks = 0;
|
unsigned long nrThunks = 0;
|
||||||
|
|
||||||
static inline void mkThunk(Value & v, Env & env, Expr * expr)
|
static inline void mkThunk(Value & v, Env & env, Expr & expr)
|
||||||
{
|
{
|
||||||
v.mkThunk(&env, expr);
|
v.mkThunk(&env, expr);
|
||||||
nrThunks++;
|
nrThunks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::mkThunk_(Value & v, Expr * expr)
|
void EvalState::mkThunk_(Value & v, Expr & expr)
|
||||||
{
|
{
|
||||||
mkThunk(v, baseEnv, expr);
|
mkThunk(v, baseEnv, expr);
|
||||||
}
|
}
|
||||||
|
@ -1058,7 +1058,7 @@ void EvalState::mkSingleDerivedPathString(
|
||||||
Value * Expr::maybeThunk(EvalState & state, Env & env)
|
Value * Expr::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
Value * v = state.allocValue();
|
Value * v = state.allocValue();
|
||||||
mkThunk(*v, env, this);
|
mkThunk(*v, env, *this);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,7 +1122,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial
|
||||||
e = j->second;
|
e = j->second;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
e = parseExprFromFile(checkSourcePath(resolvedPath));
|
e = &parseExprFromFile(checkSourcePath(resolvedPath));
|
||||||
|
|
||||||
cacheFile(path, resolvedPath, e, v, mustBeTrivial);
|
cacheFile(path, resolvedPath, e, v, mustBeTrivial);
|
||||||
}
|
}
|
||||||
|
@ -1159,7 +1159,7 @@ void EvalState::cacheFile(
|
||||||
if (mustBeTrivial &&
|
if (mustBeTrivial &&
|
||||||
!(dynamic_cast<ExprAttrs *>(e)))
|
!(dynamic_cast<ExprAttrs *>(e)))
|
||||||
error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
|
error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
|
||||||
eval(e, v);
|
eval(*e, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
|
addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
|
||||||
throw;
|
throw;
|
||||||
|
@ -1170,23 +1170,23 @@ void EvalState::cacheFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::eval(Expr * e, Value & v)
|
void EvalState::eval(Expr & e, Value & v)
|
||||||
{
|
{
|
||||||
e->eval(*this, baseEnv, v);
|
e.eval(*this, baseEnv, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos, std::string_view errorCtx)
|
inline bool EvalState::evalBool(Env & env, Expr & e, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Value v;
|
Value v;
|
||||||
e->eval(*this, env, v);
|
e.eval(*this, env, v);
|
||||||
if (v.type() != nBool)
|
if (v.type() != nBool)
|
||||||
error<TypeError>(
|
error<TypeError>(
|
||||||
"expected a Boolean but found %1%: %2%",
|
"expected a Boolean but found %1%: %2%",
|
||||||
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);
|
||||||
|
@ -1195,16 +1195,16 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos, std::stri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const PosIdx pos, std::string_view errorCtx)
|
inline void EvalState::evalAttrs(Env & env, Expr & e, Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
e->eval(*this, env, v);
|
e.eval(*this, env, v);
|
||||||
if (v.type() != nAttrs)
|
if (v.type() != nAttrs)
|
||||||
error<TypeError>(
|
error<TypeError>(
|
||||||
"expected a set but found %1%: %2%",
|
"expected a set but found %1%: %2%",
|
||||||
showType(v),
|
showType(v),
|
||||||
ValuePrinter(*this, v, errorPrintOptions)
|
ValuePrinter(*this, v, errorPrintOptions)
|
||||||
).withFrame(env, *e).debugThrow();
|
).withFrame(env, e).debugThrow();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(positions[pos], errorCtx);
|
e.addTrace(positions[pos], errorCtx);
|
||||||
throw;
|
throw;
|
||||||
|
@ -1277,7 +1277,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
Value * vAttr;
|
Value * vAttr;
|
||||||
if (hasOverrides && i.second.kind != AttrDef::Kind::Inherited) {
|
if (hasOverrides && i.second.kind != AttrDef::Kind::Inherited) {
|
||||||
vAttr = state.allocValue();
|
vAttr = state.allocValue();
|
||||||
mkThunk(*vAttr, *i.second.chooseByKind(&env2, &env, inheritEnv), i.second.e);
|
mkThunk(*vAttr, *i.second.chooseByKind(&env2, &env, inheritEnv), *i.second.e);
|
||||||
} 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;
|
||||||
|
@ -1868,13 +1868,13 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
// We cheat in the parser, and pass the position of the condition as the position of the if itself.
|
// We cheat in the parser, and pass the position of the condition as the position of the if itself.
|
||||||
(state.evalBool(env, cond, pos, "while evaluating a branch condition") ? then : else_)->eval(state, env, v);
|
(state.evalBool(env, *cond, pos, "while evaluating a branch condition") ? *then : *else_).eval(state, env, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
if (!state.evalBool(env, cond, pos, "in the condition of the assert statement")) {
|
if (!state.evalBool(env, *cond, pos, "in the condition of the assert statement")) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
cond->show(state.symbols, out);
|
cond->show(state.symbols, out);
|
||||||
state.error<AssertionError>("assertion '%1%' failed", out.str()).atPos(pos).withFrame(env, *this).debugThrow();
|
state.error<AssertionError>("assertion '%1%' failed", out.str()).atPos(pos).withFrame(env, *this).debugThrow();
|
||||||
|
@ -1885,7 +1885,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
v.mkBool(!state.evalBool(env, e, getPos(), "in the argument of the not operator")); // XXX: FIXME: !
|
v.mkBool(!state.evalBool(env, *e, getPos(), "in the argument of the not operator")); // XXX: FIXME: !
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1907,27 +1907,27 @@ void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
v.mkBool(state.evalBool(env, e1, pos, "in the left operand of the AND (&&) operator") && state.evalBool(env, e2, pos, "in the right operand of the AND (&&) operator"));
|
v.mkBool(state.evalBool(env, *e1, pos, "in the left operand of the AND (&&) operator") && state.evalBool(env, *e2, pos, "in the right operand of the AND (&&) operator"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
v.mkBool(state.evalBool(env, e1, pos, "in the left operand of the OR (||) operator") || state.evalBool(env, e2, pos, "in the right operand of the OR (||) operator"));
|
v.mkBool(state.evalBool(env, *e1, pos, "in the left operand of the OR (||) operator") || state.evalBool(env, *e2, pos, "in the right operand of the OR (||) operator"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
v.mkBool(!state.evalBool(env, e1, pos, "in the left operand of the IMPL (->) operator") || state.evalBool(env, e2, pos, "in the right operand of the IMPL (->) operator"));
|
v.mkBool(!state.evalBool(env, *e1, pos, "in the left operand of the IMPL (->) operator") || state.evalBool(env, *e2, pos, "in the right operand of the IMPL (->) operator"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1, v2;
|
Value v1, v2;
|
||||||
state.evalAttrs(env, e1, v1, pos, "in the left operand of the update (//) operator");
|
state.evalAttrs(env, *e1, v1, pos, "in the left operand of the update (//) operator");
|
||||||
state.evalAttrs(env, e2, v2, pos, "in the right operand of the update (//) operator");
|
state.evalAttrs(env, *e2, v2, pos, "in the right operand of the update (//) operator");
|
||||||
|
|
||||||
state.nrOpUpdates++;
|
state.nrOpUpdates++;
|
||||||
|
|
||||||
|
@ -2748,39 +2748,39 @@ SourcePath resolveExprPath(SourcePath path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromFile(const SourcePath & path)
|
Expr & EvalState::parseExprFromFile(const SourcePath & path)
|
||||||
{
|
{
|
||||||
return parseExprFromFile(path, staticBaseEnv);
|
return parseExprFromFile(path, staticBaseEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv)
|
Expr & EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv)
|
||||||
{
|
{
|
||||||
auto buffer = path.readFile();
|
auto buffer = path.readFile();
|
||||||
// readFile hopefully have left some extra space for terminators
|
// readFile hopefully have left some extra space for terminators
|
||||||
buffer.append("\0\0", 2);
|
buffer.append("\0\0", 2);
|
||||||
return parse(buffer.data(), buffer.size(), Pos::Origin(path), path.parent(), staticEnv);
|
return *parse(buffer.data(), buffer.size(), Pos::Origin(path), path.parent(), staticEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
|
Expr & EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
|
||||||
{
|
{
|
||||||
// NOTE this method (and parseStdin) must take care to *fully copy* their input
|
// NOTE this method (and parseStdin) must take care to *fully copy* their input
|
||||||
// into their respective Pos::Origin until the parser stops overwriting its input
|
// into their respective Pos::Origin until the parser stops overwriting its input
|
||||||
// data.
|
// data.
|
||||||
auto s = make_ref<std::string>(s_);
|
auto s = make_ref<std::string>(s_);
|
||||||
s_.append("\0\0", 2);
|
s_.append("\0\0", 2);
|
||||||
return parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv);
|
return *parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
|
Expr & EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
|
||||||
{
|
{
|
||||||
return parseExprFromString(std::move(s), basePath, staticBaseEnv);
|
return parseExprFromString(std::move(s), basePath, staticBaseEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseStdin()
|
Expr & EvalState::parseStdin()
|
||||||
{
|
{
|
||||||
// NOTE this method (and parseExprFromString) must take care to *fully copy* their
|
// NOTE this method (and parseExprFromString) must take care to *fully copy* their
|
||||||
// input into their respective Pos::Origin until the parser stops overwriting its
|
// input into their respective Pos::Origin until the parser stops overwriting its
|
||||||
|
@ -2790,7 +2790,7 @@ Expr * EvalState::parseStdin()
|
||||||
// drainFD should have left some extra space for terminators
|
// drainFD should have left some extra space for terminators
|
||||||
auto s = make_ref<std::string>(buffer);
|
auto s = make_ref<std::string>(buffer);
|
||||||
buffer.append("\0\0", 2);
|
buffer.append("\0\0", 2);
|
||||||
return parse(buffer.data(), buffer.size(), Pos::Stdin{.source = s}, rootPath(CanonPath::fromCwd()), staticBaseEnv);
|
return *parse(buffer.data(), buffer.size(), Pos::Stdin{.source = s}, rootPath(CanonPath::fromCwd()), staticBaseEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -340,16 +340,16 @@ public:
|
||||||
/**
|
/**
|
||||||
* Parse a Nix expression from the specified file.
|
* Parse a Nix expression from the specified file.
|
||||||
*/
|
*/
|
||||||
Expr * parseExprFromFile(const SourcePath & path);
|
Expr & parseExprFromFile(const SourcePath & path);
|
||||||
Expr * parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv);
|
Expr & parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a Nix expression from the specified string.
|
* Parse a Nix expression from the specified string.
|
||||||
*/
|
*/
|
||||||
Expr * parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv);
|
Expr & parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv);
|
||||||
Expr * parseExprFromString(std::string s, const SourcePath & basePath);
|
Expr & parseExprFromString(std::string s, const SourcePath & basePath);
|
||||||
|
|
||||||
Expr * parseStdin();
|
Expr & parseStdin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate an expression read from the given file to normal
|
* Evaluate an expression read from the given file to normal
|
||||||
|
@ -390,15 +390,15 @@ public:
|
||||||
*
|
*
|
||||||
* @param [out] v The resulting is stored here.
|
* @param [out] v The resulting is stored here.
|
||||||
*/
|
*/
|
||||||
void eval(Expr * e, Value & v);
|
void eval(Expr & e, Value & v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluation the expression, then verify that it has the expected
|
* Evaluation the expression, then verify that it has the expected
|
||||||
* type.
|
* type.
|
||||||
*/
|
*/
|
||||||
inline bool evalBool(Env & env, Expr * e);
|
inline bool evalBool(Env & env, Expr & e);
|
||||||
inline bool evalBool(Env & env, Expr * e, const PosIdx pos, std::string_view errorCtx);
|
inline bool evalBool(Env & env, Expr & e, const PosIdx pos, std::string_view errorCtx);
|
||||||
inline void evalAttrs(Env & env, Expr * e, Value & v, const PosIdx pos, std::string_view errorCtx);
|
inline void evalAttrs(Env & env, Expr & e, Value & v, const PosIdx pos, std::string_view errorCtx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If `v` is a thunk, enter it and overwrite `v` with the result
|
* If `v` is a thunk, enter it and overwrite `v` with the result
|
||||||
|
@ -619,7 +619,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkList(Value & v, size_t length);
|
void mkList(Value & v, size_t length);
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr & expr);
|
||||||
void mkPos(Value & v, PosIdx pos);
|
void mkPos(Value & v, PosIdx pos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,12 +42,21 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath)
|
||||||
|
|
||||||
struct Expr
|
struct Expr
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
Expr(Expr &&) = default;
|
||||||
|
Expr & operator=(Expr &&) = default;
|
||||||
|
|
||||||
|
public:
|
||||||
struct AstSymbols {
|
struct AstSymbols {
|
||||||
Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
|
Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Expr() = default;
|
||||||
|
Expr(const Expr &) = delete;
|
||||||
|
Expr & operator=(const Expr &) = delete;
|
||||||
virtual ~Expr() { };
|
virtual ~Expr() { };
|
||||||
|
|
||||||
virtual void show(const SymbolTable & symbols, std::ostream & str) const;
|
virtual void show(const SymbolTable & symbols, std::ostream & str) const;
|
||||||
virtual void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env);
|
virtual void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env);
|
||||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||||
|
|
|
@ -244,9 +244,9 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||||
// args[0]->attrs is already sorted.
|
// args[0]->attrs is already sorted.
|
||||||
|
|
||||||
debug("evaluating file '%1%'", path);
|
debug("evaluating file '%1%'", path);
|
||||||
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
|
Expr & e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
|
||||||
|
|
||||||
e->eval(state, *env, v);
|
e.eval(state, *env, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,13 +390,13 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
auto output = runProgram(program, true, commandArgs);
|
auto output = runProgram(program, true, commandArgs);
|
||||||
Expr * parsed;
|
Expr * parsed;
|
||||||
try {
|
try {
|
||||||
parsed = state.parseExprFromString(std::move(output), state.rootPath(CanonPath::root));
|
parsed = &state.parseExprFromString(std::move(output), state.rootPath(CanonPath::root));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(state.positions[pos], "while parsing the output from '%1%'", program);
|
e.addTrace(state.positions[pos], "while parsing the output from '%1%'", program);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
state.eval(parsed, v);
|
state.eval(*parsed, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(state.positions[pos], "while evaluating the output from '%1%'", program);
|
e.addTrace(state.positions[pos], "while evaluating the output from '%1%'", program);
|
||||||
throw;
|
throw;
|
||||||
|
@ -4494,7 +4494,7 @@ void EvalState::createBaseEnv()
|
||||||
// the parser needs two NUL bytes as terminators; one of them
|
// the parser needs two NUL bytes as terminators; one of them
|
||||||
// is implied by being a C string.
|
// is implied by being a C string.
|
||||||
"\0";
|
"\0";
|
||||||
eval(parse(code, sizeof(code), derivationInternal, {CanonPath::root}, staticBaseEnv), *vDerivation);
|
eval(*parse(code, sizeof(code), derivationInternal, {CanonPath::root}, staticBaseEnv), *vDerivation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -323,11 +323,11 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkThunk(Env * e, Expr * ex)
|
inline void mkThunk(Env * e, Expr & ex)
|
||||||
{
|
{
|
||||||
internalType = tThunk;
|
internalType = tThunk;
|
||||||
thunk.env = e;
|
thunk.env = e;
|
||||||
thunk.expr = ex;
|
thunk.expr = &ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkApp(Value * l, Value * r)
|
inline void mkApp(Value * l, Value * r)
|
||||||
|
|
|
@ -234,7 +234,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
DrvInfos drvs;
|
DrvInfos drvs;
|
||||||
|
|
||||||
/* Parse the expressions. */
|
/* Parse the expressions. */
|
||||||
std::vector<Expr *> exprs;
|
std::vector<std::reference_wrapper<Expr>> exprs;
|
||||||
|
|
||||||
if (readStdin)
|
if (readStdin)
|
||||||
exprs = {state->parseStdin()};
|
exprs = {state->parseStdin()};
|
||||||
|
@ -337,7 +337,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto expr = state->parseExprFromString(
|
auto & expr = state->parseExprFromString(
|
||||||
"(import <nixpkgs> {}).bashInteractive",
|
"(import <nixpkgs> {}).bashInteractive",
|
||||||
state->rootPath(CanonPath::fromCwd()));
|
state->rootPath(CanonPath::fromCwd()));
|
||||||
|
|
||||||
|
|
|
@ -413,7 +413,7 @@ static void queryInstSources(EvalState & state,
|
||||||
loadSourceExpr(state, *instSource.nixExprPath, vArg);
|
loadSourceExpr(state, *instSource.nixExprPath, vArg);
|
||||||
|
|
||||||
for (auto & i : args) {
|
for (auto & i : args) {
|
||||||
Expr * eFun = state.parseExprFromString(i, state.rootPath(CanonPath::fromCwd()));
|
Expr & eFun = state.parseExprFromString(i, state.rootPath(CanonPath::fromCwd()));
|
||||||
Value vFun, vTmp;
|
Value vFun, vTmp;
|
||||||
state.eval(eFun, vFun);
|
state.eval(eFun, vFun);
|
||||||
vTmp.mkApp(&vFun, &vArg);
|
vTmp.mkApp(&vFun, &vArg);
|
||||||
|
|
|
@ -27,10 +27,10 @@ enum OutputKind { okPlain, okXML, okJSON };
|
||||||
|
|
||||||
void processExpr(EvalState & state, const Strings & attrPaths,
|
void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
bool parseOnly, bool strict, Bindings & autoArgs,
|
bool parseOnly, bool strict, Bindings & autoArgs,
|
||||||
bool evalOnly, OutputKind output, bool location, Expr * e)
|
bool evalOnly, OutputKind output, bool location, Expr & e)
|
||||||
{
|
{
|
||||||
if (parseOnly) {
|
if (parseOnly) {
|
||||||
e->show(state.symbols, std::cout);
|
e.show(state.symbols, std::cout);
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,14 +175,14 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readStdin) {
|
if (readStdin) {
|
||||||
Expr * e = state->parseStdin();
|
Expr & e = state->parseStdin();
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
} else if (files.empty() && !fromArgs)
|
} else if (files.empty() && !fromArgs)
|
||||||
files.push_back("./default.nix");
|
files.push_back("./default.nix");
|
||||||
|
|
||||||
for (auto & i : files) {
|
for (auto & i : files) {
|
||||||
Expr * e = fromArgs
|
Expr & e = fromArgs
|
||||||
? state->parseExprFromString(i, state->rootPath(CanonPath::fromCwd()))
|
? state->parseExprFromString(i, state->rootPath(CanonPath::fromCwd()))
|
||||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
|
|
|
@ -234,7 +234,7 @@ static void showHelp(std::vector<std::string> subcommand, NixArgs & toplevel)
|
||||||
auto vUtils = state.allocValue();
|
auto vUtils = state.allocValue();
|
||||||
state.cacheFile(
|
state.cacheFile(
|
||||||
CanonPath("/utils.nix"), CanonPath("/utils.nix"),
|
CanonPath("/utils.nix"), CanonPath("/utils.nix"),
|
||||||
state.parseExprFromString(
|
&state.parseExprFromString(
|
||||||
#include "utils.nix.gen.hh"
|
#include "utils.nix.gen.hh"
|
||||||
, CanonPath::root),
|
, CanonPath::root),
|
||||||
*vUtils);
|
*vUtils);
|
||||||
|
|
|
@ -28,8 +28,7 @@ namespace nix {
|
||||||
}
|
}
|
||||||
Value eval(std::string input, bool forceValue = true) {
|
Value eval(std::string input, bool forceValue = true) {
|
||||||
Value v;
|
Value v;
|
||||||
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
|
Expr & e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
|
||||||
assert(e);
|
|
||||||
state.eval(e, v);
|
state.eval(e, v);
|
||||||
if (forceValue)
|
if (forceValue)
|
||||||
state.forceValue(v, noPos);
|
state.forceValue(v, noPos);
|
||||||
|
|
|
@ -91,7 +91,8 @@ TEST_F(ValuePrintingTests, tList)
|
||||||
TEST_F(ValuePrintingTests, vThunk)
|
TEST_F(ValuePrintingTests, vThunk)
|
||||||
{
|
{
|
||||||
Value vThunk;
|
Value vThunk;
|
||||||
vThunk.mkThunk(nullptr, nullptr);
|
ExprInt e(0);
|
||||||
|
vThunk.mkThunk(nullptr, e);
|
||||||
|
|
||||||
test(vThunk, "«thunk»");
|
test(vThunk, "«thunk»");
|
||||||
}
|
}
|
||||||
|
@ -521,7 +522,7 @@ TEST_F(ValuePrintingTests, ansiColorsAssert)
|
||||||
ExprAssert expr(noPos, &eFalse, &eInt);
|
ExprAssert expr(noPos, &eFalse, &eInt);
|
||||||
|
|
||||||
Value v;
|
Value v;
|
||||||
state.mkThunk_(v, &expr);
|
state.mkThunk_(v, expr);
|
||||||
|
|
||||||
test(v,
|
test(v,
|
||||||
ANSI_RED "«error: assertion 'false' failed»" ANSI_NORMAL,
|
ANSI_RED "«error: assertion 'false' failed»" ANSI_NORMAL,
|
||||||
|
@ -621,7 +622,8 @@ TEST_F(ValuePrintingTests, ansiColorsPrimOpApp)
|
||||||
TEST_F(ValuePrintingTests, ansiColorsThunk)
|
TEST_F(ValuePrintingTests, ansiColorsThunk)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
v.mkThunk(nullptr, nullptr);
|
ExprInt e(0);
|
||||||
|
v.mkThunk(nullptr, e);
|
||||||
|
|
||||||
test(v,
|
test(v,
|
||||||
ANSI_MAGENTA "«thunk»" ANSI_NORMAL,
|
ANSI_MAGENTA "«thunk»" ANSI_NORMAL,
|
||||||
|
|
Loading…
Reference in a new issue