diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index e66cf4430..5c14c7d3e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -439,7 +439,11 @@ bool NixRepl::processLine(string line) << " :d Debug mode commands\n" << " :d stack Show call stack\n" << " :d env Show env stack\n" - << " :d error Show current error\n"; + << " :d error Show current error\n" + << " :d go Go until end of program, exception, or builtins.break().\n" + << " :d step Go one step\n" + ; + } else if (command == ":d" || command == ":debug") { @@ -476,6 +480,16 @@ bool NixRepl::processLine(string line) notice("error information not available"); } } + else if (arg == "step") { + // set flag and exit repl. + state->debugStop = true; + return false; + } + else if (arg == "go") { + // set flag and exit repl. + state->debugStop = false; + return false; + } } else if (command == ":a" || command == ":add") { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7b3745e52..426cff2d3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -417,6 +417,7 @@ EvalState::EvalState( , repair(NoRepair) , store(store) , buildStore(buildStore ? buildStore : store) + , debugStop(true) , regexCache(makeRegexCache()) , baseEnv(allocEnv(128)) , staticBaseEnv(new StaticEnv(false, 0)) @@ -930,7 +931,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState &evalState, DebugTrace t) :evalState(evalState), trace(t) { evalState.debugTraces.push_front(t); - if (debuggerHook) + if (evalState.debugStop && debuggerHook) debuggerHook(0, t.env, t.expr); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1a097ab8c..649fda778 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -115,6 +115,7 @@ public: RootValue vCallFlake = nullptr; RootValue vImportedDrvToDerivation = nullptr; + bool debugStop; std::list debugTraces; private: diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 66265f917..3a54e1490 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -710,6 +710,28 @@ static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { .fun = prim_genericClosure, }); +static RegisterPrimOp primop_break({ + .name = "break", + .args = {}, + .doc = R"( + In debug mode, pause Nix expression evaluation and enter the repl. + )", + .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) + { + // PathSet context; + // string s = state.coerceToString(pos, *args[0], context); + if (debuggerHook && !state.debugTraces.empty()) + { + auto &dt = state.debugTraces.front(); + // std::optional pos; + // const Expr &expr; + // const Env &env; + // hintformat hint; + debuggerHook(nullptr, dt.env, dt.expr); + } + } +}); + static RegisterPrimOp primop_abort({ .name = "abort", .args = {"s"},