libexpr: move debug repl state into own struct

just to keep debug-related state closer together. eventually this will
also allow us to not allocate debugger state altogether unless needed.

Change-Id: Id83fea75d96d0ecbe21683cb1b57dd5b11b13535
This commit is contained in:
eldritch horrors 2024-11-27 02:09:08 +01:00
parent e635db77e3
commit 003883306d
7 changed files with 116 additions and 113 deletions

View file

@ -118,7 +118,7 @@ ref<EvalState> EvalCommand::getEvalState()
evalState->repair = repair; evalState->repair = repair;
if (startReplOnEvalErrors) { if (startReplOnEvalErrors) {
evalState->debugRepl = &AbstractNixRepl::runSimple; evalState->debug.repl = &AbstractNixRepl::runSimple;
}; };
} }
return ref<EvalState>(evalState); return ref<EvalState>(evalState);

View file

@ -285,7 +285,7 @@ ReplExitStatus NixRepl::mainLoop()
{ {
if (isFirstRepl) { if (isFirstRepl) {
std::string_view debuggerNotice = ""; std::string_view debuggerNotice = "";
if (state.debugRepl) { if (state.debug.repl) {
debuggerNotice = " debugger"; debuggerNotice = " debugger";
} }
notice("Lix %1%%2%\nType :? for help.", nixVersion, debuggerNotice); notice("Lix %1%%2%\nType :? for help.", nixVersion, debuggerNotice);
@ -310,7 +310,7 @@ ReplExitStatus NixRepl::mainLoop()
// number of chars as the prompt. // number of chars as the prompt.
if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) { if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
// Ctrl-D should exit the debugger. // Ctrl-D should exit the debugger.
state.debugStop = false; state.debug.stop = false;
logger->cout(""); logger->cout("");
// TODO: Should Ctrl-D exit just the current debugger session or // TODO: Should Ctrl-D exit just the current debugger session or
// the entire program? // the entire program?
@ -366,7 +366,7 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
} }
} }
if (state.debugRepl) { if (state.debug.repl) {
for (auto const & colonCmd : this->DEBUG_COMMANDS) { for (auto const & colonCmd : this->DEBUG_COMMANDS) {
if (colonCmd.starts_with(prefix)) { if (colonCmd.starts_with(prefix)) {
completions.insert(std::string(colonCmd)); completions.insert(std::string(colonCmd));
@ -416,9 +416,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
} }
} else { } else {
/* Temporarily disable the debugger, to avoid re-entering readline. */ /* Temporarily disable the debugger, to avoid re-entering readline. */
auto debug_repl = state.debugRepl; auto debug_repl = state.debug.repl;
state.debugRepl = nullptr; state.debug.repl = nullptr;
Finally restoreDebug([&]() { state.debugRepl = debug_repl; }); Finally restoreDebug([&]() { state.debug.repl = debug_repl; });
try { try {
/* This is an expression that should evaluate to an /* This is an expression that should evaluate to an
attribute set. Evaluate it to get the names of the attribute set. Evaluate it to get the names of the
@ -485,7 +485,7 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt)
{ {
initEnv(); initEnv();
auto se = state.getStaticEnv(dt.expr); auto se = state.debug.staticEnvFor(dt.expr);
if (se) { if (se) {
auto vm = mapStaticEnvBindings(state.symbols, *se.get(), dt.env); auto vm = mapStaticEnvBindings(state.symbols, *se.get(), dt.env);
@ -541,7 +541,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
<< " errors\n" << " errors\n"
<< " :?, :help Brings up this help menu\n" << " :?, :help Brings up this help menu\n"
; ;
if (state.debugRepl) { if (state.debug.repl) {
std::cout std::cout
<< "\n" << "\n"
<< " Debug mode commands\n" << " Debug mode commands\n"
@ -556,15 +556,15 @@ ProcessLineResult NixRepl::processLine(std::string line)
} }
else if (state.debugRepl && (command == ":bt" || command == ":backtrace")) { else if (state.debug.repl && (command == ":bt" || command == ":backtrace")) {
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state.debug.traces)) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state.positions, i); showDebugTrace(std::cout, state.positions, i);
} }
} }
else if (state.debugRepl && (command == ":env")) { else if (state.debug.repl && (command == ":env")) {
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state.debug.traces)) {
if (idx == debugTraceIndex) { if (idx == debugTraceIndex) {
printEnvBindings(state, i.expr, i.env); printEnvBindings(state, i.expr, i.env);
break; break;
@ -572,13 +572,13 @@ ProcessLineResult NixRepl::processLine(std::string line)
} }
} }
else if (state.debugRepl && (command == ":st")) { else if (state.debug.repl && (command == ":st")) {
try { try {
// change the DebugTrace index. // change the DebugTrace index.
debugTraceIndex = stoi(arg); debugTraceIndex = stoi(arg);
} catch (...) { } } catch (...) { }
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state.debug.traces)) {
if (idx == debugTraceIndex) { if (idx == debugTraceIndex) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state.positions, i); showDebugTrace(std::cout, state.positions, i);
@ -590,15 +590,15 @@ ProcessLineResult NixRepl::processLine(std::string line)
} }
} }
else if (state.debugRepl && (command == ":s" || command == ":step")) { else if (state.debug.repl && (command == ":s" || command == ":step")) {
// set flag to stop at next DebugTrace; exit repl. // set flag to stop at next DebugTrace; exit repl.
state.debugStop = true; state.debug.stop = true;
return ProcessLineResult::Continue; return ProcessLineResult::Continue;
} }
else if (state.debugRepl && (command == ":c" || command == ":continue")) { else if (state.debug.repl && (command == ":c" || command == ":continue")) {
// set flag to run to next breakpoint or end of program; exit repl. // set flag to run to next breakpoint or end of program; exit repl.
state.debugStop = false; state.debug.stop = false;
return ProcessLineResult::Continue; return ProcessLineResult::Continue;
} }
@ -771,7 +771,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
} }
else if (command == ":q" || command == ":quit") { else if (command == ":q" || command == ":quit") {
state.debugStop = false; state.debug.stop = false;
return ProcessLineResult::Quit; return ProcessLineResult::Quit;
} }

View file

@ -45,7 +45,7 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrame(const Env & env, const Expr
// NOTE: This is abusing side-effects. // NOTE: This is abusing side-effects.
// TODO: check compatibility with nested debugger calls. // TODO: check compatibility with nested debugger calls.
// TODO: What side-effects?? // TODO: What side-effects??
error.state.debugTraces.push_front(DebugTrace{ error.state.debug.traces.push_front(DebugTrace{
.pos = error.state.positions[expr.getPos()], .pos = error.state.positions[expr.getPos()],
.expr = expr, .expr = expr,
.env = env, .env = env,
@ -74,11 +74,11 @@ EvalErrorBuilder<T>::addTrace(PosIdx pos, std::string_view formatString, const A
template<class T> template<class T>
void EvalErrorBuilder<T>::debugThrow() void EvalErrorBuilder<T>::debugThrow()
{ {
if (error.state.debugRepl && !error.state.debugTraces.empty()) { if (error.state.debug.repl && !error.state.debug.traces.empty()) {
const DebugTrace & last = error.state.debugTraces.front(); const DebugTrace & last = error.state.debug.traces.front();
const Env * env = &last.env; const Env * env = &last.env;
const Expr * expr = &last.expr; const Expr * expr = &last.expr;
error.state.runDebugRepl(&error, *env, *expr); error.state.debug.runDebugRepl(error.state, &error, *env, *expr);
} }
// `EvalState` is the only class that can construct an `EvalErrorBuilder`, // `EvalState` is the only class that can construct an `EvalErrorBuilder`,

View file

@ -262,9 +262,6 @@ EvalState::EvalState(
, derivationInternal(rootPath(CanonPath("/builtin/derivation.nix"))) , derivationInternal(rootPath(CanonPath("/builtin/derivation.nix")))
, store(store) , store(store)
, buildStore(buildStore ? buildStore : store) , buildStore(buildStore ? buildStore : store)
, debugRepl(nullptr)
, debugStop(false)
, trylevel(0)
, regexCache(makeRegexCache()) , regexCache(makeRegexCache())
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr)) , valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
@ -590,7 +587,7 @@ void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env &
void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env) void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env)
{ {
// just print the names for now // just print the names for now
auto se = es.getStaticEnv(expr); auto se = es.debug.staticEnvFor(expr);
if (se) if (se)
printEnvBindings(es.symbols, *se, env, 0); printEnvBindings(es.symbols, *se, env, 0);
} }
@ -639,18 +636,20 @@ public:
} }
}; };
void EvalState::runDebugRepl(const EvalError * error, const Env & env, const Expr & expr) void DebugState::runDebugRepl(
EvalState & evalState, const EvalError * error, const Env & env, const Expr & expr
)
{ {
// Make sure we have a debugger to run and we're not already in a debugger. // Make sure we have a debugger to run and we're not already in a debugger.
if (!debugRepl || inDebugger) if (!repl || inDebugger)
return; return;
auto dts = auto dts =
error && expr.getPos() error && expr.getPos()
? std::make_unique<DebugTraceStacker>( ? std::make_unique<DebugTraceStacker>(
*this, evalState,
DebugTrace { DebugTrace {
.pos = error->info().pos ? error->info().pos : positions[expr.getPos()], .pos = error->info().pos ? error->info().pos : evalState.positions[expr.getPos()],
.expr = expr, .expr = expr,
.env = env, .env = env,
.hint = error->info().msg, .hint = error->info().msg,
@ -666,11 +665,11 @@ void EvalState::runDebugRepl(const EvalError * error, const Env & env, const Exp
printError("This exception occurred in a 'tryEval' call. Use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); printError("This exception occurred in a 'tryEval' call. Use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n");
} }
auto se = getStaticEnv(expr); auto se = staticEnvFor(expr);
if (se) { if (se) {
auto vm = mapStaticEnvBindings(symbols, *se.get(), env); auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env);
DebuggerGuard _guard(inDebugger); DebuggerGuard _guard(inDebugger);
auto exitStatus = (debugRepl)(*this, *vm); auto exitStatus = repl(evalState, *vm);
switch (exitStatus) { switch (exitStatus) {
case ReplExitStatus::QuitAll: case ReplExitStatus::QuitAll:
if (error) if (error)
@ -718,9 +717,9 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t)
: evalState(evalState) : evalState(evalState)
, trace(std::move(t)) , trace(std::move(t))
{ {
evalState.debugTraces.push_front(trace); evalState.debug.traces.push_front(trace);
if (evalState.debugStop && evalState.debugRepl) if (evalState.debug.stop && evalState.debug.repl)
evalState.runDebugRepl(nullptr, trace.env, trace.expr); evalState.debug.runDebugRepl(evalState, nullptr, trace.env, trace.expr);
} }
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
@ -955,7 +954,7 @@ void EvalState::cacheFile(
fileParseCache[resolvedPath] = e; fileParseCache[resolvedPath] = e;
try { try {
auto dts = debugRepl auto dts = debug.repl
? makeDebugTraceStacker( ? makeDebugTraceStacker(
*this, *this,
*e, *e,
@ -1173,7 +1172,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
*i.second.chooseByKind(&env2, &env, inheritEnv)); *i.second.chooseByKind(&env2, &env, inheritEnv));
} }
auto dts = state.debugRepl auto dts = state.debug.repl
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -1258,7 +1257,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} }
try { try {
auto dts = state.debugRepl auto dts = state.debug.repl
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -1576,7 +1575,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
/* Evaluate the body. */ /* Evaluate the body. */
try { try {
auto dts = debugRepl auto dts = debug.repl
? makeDebugTraceStacker( ? makeDebugTraceStacker(
*this, *lambda.body, env2, positions[lambda.pos], *this, *lambda.body, env2, positions[lambda.pos],
"while calling %s", "while calling %s",
@ -1715,7 +1714,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
void ExprCall::eval(EvalState & state, Env & env, Value & v) void ExprCall::eval(EvalState & state, Env & env, Value & v)
{ {
auto dts = state.debugRepl auto dts = state.debug.repl
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -2088,7 +2087,7 @@ void EvalState::forceValueDeep(Value & v)
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 = debug.repl && i.value->isThunk()
? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos], ? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos],
"while evaluating the attribute '%1%'", symbols[i.name]) "while evaluating the attribute '%1%'", symbols[i.name])
: nullptr; : nullptr;

View file

@ -152,6 +152,28 @@ struct DebugTrace {
bool isError; bool isError;
}; };
struct DebugState
{
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> repl;
bool stop = false;
bool inDebugger = false;
std::list<DebugTrace> traces;
std::map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
int trylevel = 0;
void runDebugRepl(
EvalState & evalState, const EvalError * error, const Env & env, const Expr & expr
);
const std::shared_ptr<const StaticEnv> staticEnvFor(const Expr & expr) const
{
if (auto i = exprEnvs.find(&expr); i != exprEnvs.end()) {
return i->second;
}
return nullptr;
}
};
struct StaticSymbols struct StaticSymbols
{ {
@ -202,25 +224,7 @@ public:
RootValue vCallFlake = nullptr; RootValue vCallFlake = nullptr;
RootValue vImportedDrvToDerivation = nullptr; RootValue vImportedDrvToDerivation = nullptr;
/** DebugState debug;
* Debugger
*/
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl;
bool debugStop;
bool inDebugger = false;
int trylevel;
std::list<DebugTrace> debugTraces;
std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs;
const std::shared_ptr<const StaticEnv> getStaticEnv(const Expr & expr) const
{
auto i = exprEnvs.find(&expr);
if (i != exprEnvs.end())
return i->second;
else
return std::shared_ptr<const StaticEnv>();;
}
void runDebugRepl(const EvalError * error, const Env & env, const Expr & expr);
template<class T, typename... Args> template<class T, typename... Args>
[[nodiscard, gnu::noinline]] [[nodiscard, gnu::noinline]]
@ -760,7 +764,7 @@ struct DebugTraceStacker {
DebugTraceStacker(EvalState & evalState, DebugTrace t); DebugTraceStacker(EvalState & evalState, DebugTrace t);
~DebugTraceStacker() ~DebugTraceStacker()
{ {
evalState.debugTraces.pop_front(); evalState.debug.traces.pop_front();
} }
EvalState & evalState; EvalState & evalState;
DebugTrace trace; DebugTrace trace;

View file

@ -302,32 +302,32 @@ void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env
void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }
void ExprFloat::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprFloat::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }
void ExprString::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprString::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }
void ExprPath::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprPath::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }
void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
fromWith = nullptr; fromWith = nullptr;
@ -364,14 +364,14 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
void ExprInheritFrom::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprInheritFrom::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }
void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
e->bindVars(es, env); e->bindVars(es, env);
if (def) def->bindVars(es, env); if (def) def->bindVars(es, env);
@ -382,8 +382,8 @@ void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
e->bindVars(es, env); e->bindVars(es, env);
for (auto & i : attrPath) for (auto & i : attrPath)
@ -414,8 +414,8 @@ std::shared_ptr<const StaticEnv> ExprAttrs::bindInheritSources(
void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
if (recursive) { if (recursive) {
auto newEnv = [&] () -> std::shared_ptr<const StaticEnv> { auto newEnv = [&] () -> std::shared_ptr<const StaticEnv> {
@ -453,8 +453,8 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
void ExprList::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprList::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
for (auto & i : elems) for (auto & i : elems)
i->bindVars(es, env); i->bindVars(es, env);
@ -462,8 +462,8 @@ void ExprList::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
auto newEnv = std::make_shared<StaticEnv>( auto newEnv = std::make_shared<StaticEnv>(
nullptr, env.get(), nullptr, env.get(),
@ -489,8 +489,8 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
fun->bindVars(es, env); fun->bindVars(es, env);
for (auto & e : args) for (auto & e : args)
@ -514,16 +514,16 @@ void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
for (auto & i : attrs->attrs) for (auto & i : attrs->attrs)
i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv)); i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv));
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
body->bindVars(es, newEnv); body->bindVars(es, newEnv);
} }
void ExprWith::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprWith::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
parentWith = nullptr; parentWith = nullptr;
for (auto * e = env.get(); e && !parentWith; e = e->up) for (auto * e = env.get(); e && !parentWith; e = e->up)
@ -548,8 +548,8 @@ void ExprWith::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
void ExprIf::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprIf::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
cond->bindVars(es, env); cond->bindVars(es, env);
then->bindVars(es, env); then->bindVars(es, env);
@ -558,8 +558,8 @@ void ExprIf::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & e
void ExprAssert::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprAssert::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
cond->bindVars(es, env); cond->bindVars(es, env);
body->bindVars(es, env); body->bindVars(es, env);
@ -567,16 +567,16 @@ void ExprAssert::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
e->bindVars(es, env); e->bindVars(es, env);
} }
void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
for (auto & i : this->es) for (auto & i : this->es)
i.second->bindVars(es, env); i.second->bindVars(es, env);
@ -584,8 +584,8 @@ void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const Sta
void ExprPos::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprPos::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
if (es.debugRepl) if (es.debug.repl)
es.exprEnvs.insert(std::make_pair(this, env)); es.debug.exprEnvs.insert(std::make_pair(this, env));
} }

View file

@ -566,15 +566,15 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
static void prim_break(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_break(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
if (state.debugRepl && !state.debugTraces.empty()) { if (state.debug.repl && !state.debug.traces.empty()) {
auto error = EvalError(state, ErrorInfo { auto error = EvalError(state, ErrorInfo {
.level = lvlInfo, .level = lvlInfo,
.msg = HintFmt("breakpoint reached"), .msg = HintFmt("breakpoint reached"),
.pos = state.positions[pos], .pos = state.positions[pos],
}); });
auto & dt = state.debugTraces.front(); auto & dt = state.debug.traces.front();
state.runDebugRepl(&error, dt.env, dt.expr); state.debug.runDebugRepl(state, &error, dt.env, dt.expr);
} }
// Return the value we were passed. // Return the value we were passed.
@ -638,14 +638,14 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
auto attrs = state.buildBindings(2); auto attrs = state.buildBindings(2);
/* increment state.trylevel, and decrement it when this function returns. */ /* increment state.trylevel, and decrement it when this function returns. */
MaintainCount trylevel(state.trylevel); MaintainCount trylevel(state.debug.trylevel);
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> savedDebugRepl; std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> savedDebugRepl;
if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry) if (state.debug.repl && evalSettings.ignoreExceptionsDuringTry)
{ {
/* to prevent starting the repl from exceptions withing a tryEval, null it. */ /* to prevent starting the repl from exceptions withing a tryEval, null it. */
savedDebugRepl = state.debugRepl; savedDebugRepl = state.debug.repl;
state.debugRepl = nullptr; state.debug.repl = nullptr;
} }
try { try {
@ -659,7 +659,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
// restore the debugRepl pointer if we saved it earlier. // restore the debugRepl pointer if we saved it earlier.
if (savedDebugRepl) if (savedDebugRepl)
state.debugRepl = savedDebugRepl; state.debug.repl = savedDebugRepl;
v.mkAttrs(attrs); v.mkAttrs(attrs);
} }
@ -697,9 +697,9 @@ static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Valu
printError("trace: %1%", args[0]->string.s); printError("trace: %1%", args[0]->string.s);
else else
printError("trace: %1%", ValuePrinter(state, *args[0])); printError("trace: %1%", ValuePrinter(state, *args[0]));
if (evalSettings.builtinsTraceDebugger && state.debugRepl && !state.debugTraces.empty()) { if (evalSettings.builtinsTraceDebugger && state.debug.repl && !state.debug.traces.empty()) {
const DebugTrace & last = state.debugTraces.front(); const DebugTrace & last = state.debug.traces.front();
state.runDebugRepl(nullptr, last.env, last.expr); state.debug.runDebugRepl(state, nullptr, last.env, last.expr);
} }
state.forceValue(*args[1], pos); state.forceValue(*args[1], pos);
v = *args[1]; v = *args[1];