libexpr: abstract DebugState from EvalState
this is necessary to share a debug state between multiple eval states.
while doings so makes little sense at present it will be necessary for
async io support since eval states must be async io roots, which means
we must create them as needed from a shared evaluation context object.
Change-Id: Id9d4b37aae40706f65c741e3b961855582e035ab
This commit is contained in:
parent
0bfa58ff53
commit
ef1d62ec6c
5 changed files with 37 additions and 25 deletions
|
@ -106,14 +106,11 @@ ref<eval_cache::CachingEvalState> EvalCommand::getEvalState()
|
||||||
{
|
{
|
||||||
if (!evalState) {
|
if (!evalState) {
|
||||||
evalState = std::allocate_shared<eval_cache::CachingEvalState>(
|
evalState = std::allocate_shared<eval_cache::CachingEvalState>(
|
||||||
TraceableAllocator<EvalState>(), searchPath, getEvalStore(), getStore()
|
TraceableAllocator<EvalState>(), searchPath, getEvalStore(), getStore(),
|
||||||
|
startReplOnEvalErrors ? AbstractNixRepl::runSimple : nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
evalState->repair = repair;
|
evalState->repair = repair;
|
||||||
|
|
||||||
if (startReplOnEvalErrors) {
|
|
||||||
evalState->debug = std::make_unique<DebugState>(&AbstractNixRepl::runSimple);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return ref<eval_cache::CachingEvalState>(evalState);
|
return ref<eval_cache::CachingEvalState>(evalState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ void EvalErrorBuilder<T>::debugThrow()
|
||||||
if (auto last = state.debug->traces().next()) {
|
if (auto last = state.debug->traces().next()) {
|
||||||
const Env * env = &(*last)->env;
|
const Env * env = &(*last)->env;
|
||||||
const Expr * expr = &(*last)->expr;
|
const Expr * expr = &(*last)->expr;
|
||||||
state.debug->runDebugRepl(state, &error, *env, *expr);
|
state.debug->onEvalError(&error, *env, *expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,7 +274,8 @@ EvalBuiltins::EvalBuiltins(
|
||||||
EvalState::EvalState(
|
EvalState::EvalState(
|
||||||
const SearchPath & _searchPath,
|
const SearchPath & _searchPath,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
std::shared_ptr<Store> buildStore)
|
std::shared_ptr<Store> buildStore,
|
||||||
|
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl)
|
||||||
: s(symbols)
|
: s(symbols)
|
||||||
, searchPath([&] {
|
, searchPath([&] {
|
||||||
SearchPath searchPath;
|
SearchPath searchPath;
|
||||||
|
@ -290,6 +291,14 @@ EvalState::EvalState(
|
||||||
, repair(NoRepair)
|
, repair(NoRepair)
|
||||||
, store(store)
|
, store(store)
|
||||||
, buildStore(buildStore ? buildStore : store)
|
, buildStore(buildStore ? buildStore : store)
|
||||||
|
, debug{
|
||||||
|
debugRepl ? std::make_unique<DebugState>(
|
||||||
|
positions,
|
||||||
|
symbols,
|
||||||
|
[this, debugRepl](const ValMap & extraEnv) { return debugRepl(*this, extraEnv); }
|
||||||
|
)
|
||||||
|
: nullptr
|
||||||
|
}
|
||||||
{
|
{
|
||||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||||
|
|
||||||
|
@ -637,9 +646,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void DebugState::runDebugRepl(
|
void DebugState::onEvalError(const EvalError * error, const Env & env, const Expr & expr)
|
||||||
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 (inDebugger)
|
if (inDebugger)
|
||||||
|
@ -648,7 +655,7 @@ void DebugState::runDebugRepl(
|
||||||
auto dts =
|
auto dts =
|
||||||
error && expr.getPos()
|
error && expr.getPos()
|
||||||
? addTrace(DebugTrace {
|
? addTrace(DebugTrace {
|
||||||
.pos = error->info().pos ? error->info().pos : evalState.positions[expr.getPos()],
|
.pos = error->info().pos ? error->info().pos : positions[expr.getPos()],
|
||||||
.expr = expr,
|
.expr = expr,
|
||||||
.env = env,
|
.env = env,
|
||||||
.hint = error->info().msg,
|
.hint = error->info().msg,
|
||||||
|
@ -666,9 +673,9 @@ void DebugState::runDebugRepl(
|
||||||
|
|
||||||
auto se = staticEnvFor(expr);
|
auto se = staticEnvFor(expr);
|
||||||
if (se) {
|
if (se) {
|
||||||
auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env);
|
auto vm = mapStaticEnvBindings(symbols, *se.get(), env);
|
||||||
DebuggerGuard _guard(inDebugger);
|
DebuggerGuard _guard(inDebugger);
|
||||||
auto exitStatus = repl(evalState, *vm);
|
auto exitStatus = errorCallback(*vm);
|
||||||
switch (exitStatus) {
|
switch (exitStatus) {
|
||||||
case ReplExitStatus::QuitAll:
|
case ReplExitStatus::QuitAll:
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -718,8 +725,8 @@ static DebugState::TraceFrame makeDebugTraceStacker(
|
||||||
.hint = HintFmt(formatArgs...),
|
.hint = HintFmt(formatArgs...),
|
||||||
.isError = false,
|
.isError = false,
|
||||||
});
|
});
|
||||||
if (state.debug->stop && state.debug->repl)
|
if (state.debug->stop && state.debug->errorCallback)
|
||||||
state.debug->runDebugRepl(state, nullptr, env, expr);
|
state.debug->onEvalError(nullptr, env, expr);
|
||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,23 +143,29 @@ struct DebugState
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::weak_ptr<const DebugTrace> latestTrace;
|
std::weak_ptr<const DebugTrace> latestTrace;
|
||||||
|
const PosTable & positions;
|
||||||
|
const SymbolTable & symbols;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> repl;
|
std::function<ReplExitStatus(ValMap const & extraEnv)> errorCallback;
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
bool inDebugger = false;
|
bool inDebugger = false;
|
||||||
std::map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
std::map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
||||||
int trylevel = 0;
|
int trylevel = 0;
|
||||||
|
|
||||||
explicit DebugState(std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> repl)
|
explicit DebugState(
|
||||||
: repl(repl)
|
const PosTable & positions,
|
||||||
|
const SymbolTable & symbols,
|
||||||
|
std::function<ReplExitStatus(ValMap const & extraEnv)> errorCallback
|
||||||
|
)
|
||||||
|
: positions(positions)
|
||||||
|
, symbols(symbols)
|
||||||
|
, errorCallback(errorCallback)
|
||||||
{
|
{
|
||||||
assert(repl);
|
assert(errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runDebugRepl(
|
void onEvalError(const EvalError * error, const Env & env, const Expr & expr);
|
||||||
EvalState & evalState, const EvalError * error, const Env & env, const Expr & expr
|
|
||||||
);
|
|
||||||
|
|
||||||
const std::shared_ptr<const StaticEnv> staticEnvFor(const Expr & expr) const
|
const std::shared_ptr<const StaticEnv> staticEnvFor(const Expr & expr) const
|
||||||
{
|
{
|
||||||
|
@ -409,7 +415,9 @@ public:
|
||||||
EvalState(
|
EvalState(
|
||||||
const SearchPath & _searchPath,
|
const SearchPath & _searchPath,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
std::shared_ptr<Store> buildStore = nullptr);
|
std::shared_ptr<Store> buildStore = nullptr,
|
||||||
|
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl = nullptr
|
||||||
|
);
|
||||||
~EvalState();
|
~EvalState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -579,7 +579,7 @@ static void prim_break(EvalState & state, const PosIdx pos, Value * * args, Valu
|
||||||
.pos = state.positions[pos],
|
.pos = state.positions[pos],
|
||||||
});
|
});
|
||||||
|
|
||||||
state.debug->runDebugRepl(state, &error, (*trace)->env, (*trace)->expr);
|
state.debug->onEvalError(&error, (*trace)->env, (*trace)->expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the value we were passed.
|
// Return the value we were passed.
|
||||||
|
@ -705,7 +705,7 @@ static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Valu
|
||||||
? state.debug->traces().next()
|
? state.debug->traces().next()
|
||||||
: std::nullopt)
|
: std::nullopt)
|
||||||
{
|
{
|
||||||
state.debug->runDebugRepl(state, nullptr, (*last)->env, (*last)->expr);
|
state.debug->onEvalError(nullptr, (*last)->env, (*last)->expr);
|
||||||
}
|
}
|
||||||
state.forceValue(*args[1], pos);
|
state.forceValue(*args[1], pos);
|
||||||
v = *args[1];
|
v = *args[1];
|
||||||
|
|
Loading…
Reference in a new issue