From 0600df86b8bc59633457f7ceb79e84c8ea3fed17 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 19 May 2022 17:01:23 -0600 Subject: [PATCH] 'debugMode' --- src/libcmd/command.cc | 49 ++++++++++++++++++++++-------------------- src/libcmd/repl.cc | 14 ++++++------ src/libexpr/eval.cc | 38 ++++++++++++++++++++++++++------ src/libexpr/eval.hh | 19 ++++++++++------ src/libexpr/nixexpr.cc | 40 +++++++++++++++++----------------- src/libexpr/nixexpr.hh | 2 +- src/libexpr/primops.cc | 10 ++++----- 7 files changed, 103 insertions(+), 69 deletions(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index a7d7bfb17..a4ea5bc33 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -118,32 +118,35 @@ ref EvalCommand::getEvalState() searchPath, getEvalStore(), getStore()) #endif ; + + evalState->debugMode = startReplOnEvalErrors; // TODO move this somewhere else. Its only here to get the evalState ptr! - if (startReplOnEvalErrors) - // debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { - debuggerHook = [](EvalState & evalState, const Error * error, const Env & env, const Expr & expr) { - auto dts = - error && expr.getPos() - ? std::make_unique( - evalState, - DebugTrace { - .pos = error->info().errPos ? *error->info().errPos : evalState.positions[expr.getPos()], - .expr = expr, - .env = env, - .hint = error->info().msg, - .isError = true - }) - : nullptr; + // if (startReplOnEvalErrors) + + // // debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { + // debuggerHook = [](EvalState & evalState, const Error * error, const Env & env, const Expr & expr) { + // auto dts = + // error && expr.getPos() + // ? std::make_unique( + // evalState, + // DebugTrace { + // .pos = error->info().errPos ? *error->info().errPos : evalState.positions[expr.getPos()], + // .expr = expr, + // .env = env, + // .hint = error->info().msg, + // .isError = true + // }) + // : nullptr; - if (error) - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + // if (error) + // printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); - auto se = evalState.getStaticEnv(expr); - if (se) { - auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env); - runRepl(evalState, *vm); - } - }; + // auto se = evalState.getStaticEnv(expr); + // if (se) { + // auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env); + // runRepl(evalState, *vm); + // } + // }; } return ref(evalState); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 5aecf3ac3..6bf23cc61 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -280,7 +280,7 @@ void NixRepl::mainLoop(const std::vector & files) // in debugger mode, an EvalError should trigger another repl session. // when that session returns the exception will land here. No need to show it again; // show the error for this repl session instead. - if (debuggerHook && !state->debugTraces.empty()) + if (state->debugMode && !state->debugTraces.empty()) showDebugTrace(std::cout, state->positions, state->debugTraces.front()); else printMsg(lvlError, e.msg()); @@ -493,7 +493,7 @@ bool NixRepl::processLine(std::string line) << " :log Show logs for a derivation\n" << " :te [bool] Enable, disable or toggle showing traces for errors\n" ; - if (debuggerHook) { + if (state->debugMode) { std::cout << "\n" << " Debug mode commands\n" @@ -508,14 +508,14 @@ bool NixRepl::processLine(std::string line) } - else if (debuggerHook && (command == ":bt" || command == ":backtrace")) { + else if (state->debugMode && (command == ":bt" || command == ":backtrace")) { for (const auto & [idx, i] : enumerate(state->debugTraces)) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, state->positions, i); } } - else if (debuggerHook && (command == ":env")) { + else if (state->debugMode && (command == ":env")) { for (const auto & [idx, i] : enumerate(state->debugTraces)) { if (idx == debugTraceIndex) { printEnvBindings(*state, i.expr, i.env); @@ -524,7 +524,7 @@ bool NixRepl::processLine(std::string line) } } - else if (debuggerHook && (command == ":st")) { + else if (state->debugMode && (command == ":st")) { try { // change the DebugTrace index. debugTraceIndex = stoi(arg); @@ -542,13 +542,13 @@ bool NixRepl::processLine(std::string line) } } - else if (debuggerHook && (command == ":s" || command == ":step")) { + else if (state->debugMode && (command == ":s" || command == ":step")) { // set flag to stop at next DebugTrace; exit repl. state->debugStop = true; return false; } - else if (debuggerHook && (command == ":c" || command == ":continue")) { + else if (state->debugMode && (command == ":c" || command == ":continue")) { // set flag to run to next breakpoint or end of program; exit repl. state->debugStop = false; return false; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f95ff4931..1cde4a9ab 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -463,6 +463,7 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) + , debugMode(false) , debugStop(false) , debugQuit(false) , regexCache(makeRegexCache()) @@ -810,6 +811,31 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati return vm; } +void EvalState::debugRepl(const Error * error, const Env & env, const Expr & expr) +{ + auto dts = + error && expr.getPos() + ? std::make_unique( + *this, + DebugTrace { + .pos = error->info().errPos ? *error->info().errPos : positions[expr.getPos()], + .expr = expr, + .env = env, + .hint = error->info().msg, + .isError = true + }) + : nullptr; + + if (error) + printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + + auto se = getStaticEnv(expr); + if (se) { + auto vm = mapStaticEnvBindings(symbols, *se.get(), env); + runRepl(*this, *vm); + } +} + /* Every "format" object (even temporary) takes up a few hundred bytes of stack space, which is a real killer in the recursive evaluator. So here are some helper functions for throwing @@ -1043,8 +1069,8 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) , trace(std::move(t)) { evalState.debugTraces.push_front(trace); - if (evalState.debugStop && debuggerHook) - debuggerHook(evalState, nullptr, trace.env, trace.expr); + if (evalState.debugStop && evalState.debugMode) + evalState.debugRepl(nullptr, trace.env, trace.expr); } void Value::mkString(std::string_view s) @@ -1241,7 +1267,7 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { - auto dts = debuggerHook + auto dts = debugMode ? makeDebugTraceStacker( *this, *e, @@ -1475,7 +1501,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - auto dts = debuggerHook + auto dts = state.debugMode ? makeDebugTraceStacker( state, *this, @@ -1644,7 +1670,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { - auto dts = debuggerHook + auto dts = debugMode ? makeDebugTraceStacker( *this, *lambda.body, env2, positions[lambda.pos], "while evaluating %s", @@ -2072,7 +2098,7 @@ void EvalState::forceValueDeep(Value & v) for (auto & i : *v.attrs) try { // If the value is a thunk, we're evaling. Otherwise no trace necessary. - auto dts = debuggerHook && i.value->isThunk() + auto dts = debugMode && i.value->isThunk() ? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos], "while evaluating the attribute '%1%'", symbols[i.name]) : nullptr; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 763150dae..711a4d6be 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,9 +25,6 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); -void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env); -void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, int lvl = 0); - struct PrimOp { PrimOpFun fun; @@ -51,6 +48,11 @@ struct Env Value * values[0]; }; +extern void runRepl(ref evalState, const ValMap & extraEnv); + +void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env); +void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, int lvl = 0); + std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env); void copyContext(const Value & v, PathSet & context); @@ -127,6 +129,7 @@ public: RootValue vImportedDrvToDerivation = nullptr; /* Debugger */ + bool debugMode; bool debugStop; bool debugQuit; std::list debugTraces; @@ -140,13 +143,14 @@ public: return std::shared_ptr();; } + void debugRepl(const Error * error, const Env & env, const Expr & expr); template [[gnu::noinline, gnu::noreturn]] void debugThrow(const E &error, const Env & env, const Expr & expr) { - if (debuggerHook) - debuggerHook(*this, &error, env, expr); + if (debugMode) + debugRepl(&error, env, expr); throw error; } @@ -158,14 +162,15 @@ public: // Call this in the situation where Expr and Env are inaccessible. // The debugger will start in the last context that's in the // DebugTrace stack. - if (debuggerHook && !debugTraces.empty()) { + if (debugMode && !debugTraces.empty()) { const DebugTrace & last = debugTraces.front(); - debuggerHook(*this, &e, last.env, last.expr); + debugRepl(&e, last.env, last.expr); } throw e; } + private: SrcToStore srcToStore; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 21b71d7c9..b40791694 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -10,7 +10,7 @@ namespace nix { /* Launch the nix debugger */ -std::function debuggerHook; +// std::function debuggerHook; /* Displaying abstract syntax trees. */ @@ -303,31 +303,31 @@ void Expr::bindVars(EvalState & es, const std::shared_ptr & env void ExprInt::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprFloat::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprString::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprPath::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprVar::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); /* Check whether the variable appears in the environment. If so, @@ -363,7 +363,7 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr & void ExprSelect::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -375,7 +375,7 @@ void ExprSelect::bindVars(EvalState & es, const std::shared_ptr void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -386,7 +386,7 @@ void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); if (recursive) { @@ -419,7 +419,7 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr void ExprList::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : elems) @@ -428,7 +428,7 @@ void ExprList::bindVars(EvalState & es, const std::shared_ptr & void ExprLambda::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared( @@ -455,7 +455,7 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr void ExprCall::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); fun->bindVars(es, env); @@ -465,7 +465,7 @@ void ExprCall::bindVars(EvalState & es, const std::shared_ptr & void ExprLet::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared(false, env.get(), attrs->attrs.size()); @@ -484,7 +484,7 @@ void ExprLet::bindVars(EvalState & es, const std::shared_ptr & void ExprWith::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); /* Does this `with' have an enclosing `with'? If so, record its @@ -499,7 +499,7 @@ void ExprWith::bindVars(EvalState & es, const std::shared_ptr & break; } - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); attrs->bindVars(es, env); @@ -509,7 +509,7 @@ void ExprWith::bindVars(EvalState & es, const std::shared_ptr & void ExprIf::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); @@ -519,7 +519,7 @@ void ExprIf::bindVars(EvalState & es, const std::shared_ptr & e void ExprAssert::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); @@ -528,7 +528,7 @@ void ExprAssert::bindVars(EvalState & es, const std::shared_ptr void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -536,7 +536,7 @@ void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : *this->es) @@ -545,7 +545,7 @@ void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr & env) { - if (debuggerHook) + if (es.debugMode) es.exprEnvs.insert(std::make_pair(this, env)); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index fdafb1711..6a5d02ed1 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -22,7 +22,7 @@ MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); MakeError(RestrictedPathError, Error); -extern std::function debuggerHook; +// extern std::function debuggerHook; /* Position objects. */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e56e6314b..f7429197a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -757,7 +757,7 @@ static RegisterPrimOp primop_break({ )", .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { - if (debuggerHook && !state.debugTraces.empty()) { + if (state.debugMode && !state.debugTraces.empty()) { auto error = Error(ErrorInfo { .level = lvlInfo, .msg = hintfmt("breakpoint reached"), @@ -765,7 +765,7 @@ static RegisterPrimOp primop_break({ }); auto & dt = state.debugTraces.front(); - debuggerHook(state, &error, dt.env, dt.expr); + state.debugRepl(&error, dt.env, dt.expr); if (state.debugQuit) { // If the user elects to quit the repl, throw an exception. @@ -879,8 +879,8 @@ static RegisterPrimOp primop_floor({ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); - auto saveDebuggerHook = debuggerHook; - debuggerHook = nullptr; + auto saveDebugMode = state.debugMode; + state.debugMode = false; try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -889,7 +889,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } - debuggerHook = saveDebuggerHook; + state.debugMode = saveDebugMode; v.mkAttrs(attrs); }