aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Burdette <bburdette@protonmail.com>2022-05-19 17:01:23 -0600
committerBen Burdette <bburdette@protonmail.com>2022-05-19 17:01:23 -0600
commit0600df86b8bc59633457f7ceb79e84c8ea3fed17 (patch)
treea369026f39acc3b3a63bb0fc67c18934f7c9974a
parent7ddef73d026d79adc0c4f3fd1518d88d1331c38c (diff)
'debugMode'
-rw-r--r--src/libcmd/command.cc53
-rw-r--r--src/libcmd/repl.cc14
-rw-r--r--src/libexpr/eval.cc38
-rw-r--r--src/libexpr/eval.hh19
-rw-r--r--src/libexpr/nixexpr.cc40
-rw-r--r--src/libexpr/nixexpr.hh2
-rw-r--r--src/libexpr/primops.cc10
7 files changed, 105 insertions, 71 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<EvalState> 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>(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<DebugTraceStacker>(
- 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());
-
- auto se = evalState.getStaticEnv(expr);
- if (se) {
- auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env);
- runRepl(evalState, *vm);
- }
- };
+ // if (startReplOnEvalErrors)
+
+ // // debuggerHook = [evalState{ref<EvalState>(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<DebugTraceStacker>(
+ // 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());
+
+ // auto se = evalState.getStaticEnv(expr);
+ // if (se) {
+ // auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env);
+ // runRepl(evalState, *vm);
+ // }
+ // };
}
return ref<EvalState>(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<std::string> & 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 <expr> 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<ValMap> 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<DebugTraceStacker>(
+ *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> 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<ValMap> 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<DebugTrace> debugTraces;
@@ -140,13 +143,14 @@ public:
return std::shared_ptr<const StaticEnv>();;
}
+ void debugRepl(const Error * error, const Env & env, const Expr & expr);
template<class E>
[[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<void(EvalState & evalState,const Error * error, const Env & env, const Expr & expr)> debuggerHook;
+// std::function<void(EvalState & evalState,const Error * error, const Env & env, const Expr & expr)> debuggerHook;
/* Displaying abstract syntax trees. */
@@ -303,31 +303,31 @@ void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env
void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
}
void ExprFloat::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
}
void ExprString::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
}
void ExprPath::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
}
void ExprVar::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv> &
void ExprSelect::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv>
void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticE
void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv>
void ExprList::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv> &
void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
auto newEnv = std::make_shared<StaticEnv>(
@@ -455,7 +455,7 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv> &
void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{
- if (debuggerHook)
+ if (es.debugMode)
es.exprEnvs.insert(std::make_pair(this, env));
auto newEnv = std::make_shared<StaticEnv>(false, env.get(), attrs->attrs.size());
@@ -484,7 +484,7 @@ void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
void ExprWith::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv> &
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<const StaticEnv> &
void ExprIf::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv> & e
void ExprAssert::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv>
void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const StaticEnv>
void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<const Sta
void ExprPos::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & 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<void(EvalState & evalState, const Error * error, const Env & env, const Expr & expr)> debuggerHook;
+// extern std::function<void(EvalState & evalState, const Error * error, const Env & env, const Expr & expr)> 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);
}