From 9151dbff88fa765496e970aee2db5a8ce640b3a4 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 10:26:46 -0600 Subject: [PATCH 1/7] ignore-try flag --- src/libcmd/command.cc | 11 ++++++++++- src/libcmd/command.hh | 1 + src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 7f8072d75..940fd5b23 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -91,6 +91,12 @@ EvalCommand::EvalCommand() .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); + + addFlag({ + .longName = "ignore-try", + .description = "ignore exceptions in try clauses during debug", + .handler = {&ignoreExceptionsDuringTry, true}, + }); } EvalCommand::~EvalCommand() @@ -120,7 +126,10 @@ ref EvalCommand::getEvalState() ; if (startReplOnEvalErrors) { - evalState->debugRepl = &runRepl; + evalState->debugRepl = &runRepl; + }; + if (ignoreExceptionsDuringTry) { + evalState->ignoreTry = ignoreExceptionsDuringTry; }; } return ref(evalState); diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 8982f21d0..2c930dcb7 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -58,6 +58,7 @@ struct CopyCommand : virtual StoreCommand struct EvalCommand : virtual StoreCommand, MixEvalArgs { bool startReplOnEvalErrors = false; + bool ignoreExceptionsDuringTry = false; EvalCommand(); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 40462afdf..c35527992 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,6 +467,7 @@ EvalState::EvalState( , debugRepl(0) , debugStop(false) , debugQuit(false) + , ignoreTry(false) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 7b8732169..3c3dddd1e 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,6 +130,7 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; + bool ignoreTry; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea274301..772898932 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -851,6 +851,15 @@ static RegisterPrimOp primop_floor({ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; + if (state.debugRepl && state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } + try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -859,6 +868,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } + + // restore the debugRepl pointer if we saved it earlier. + if (savedDebugRepl) + state.debugRepl = savedDebugRepl; + v.mkAttrs(attrs); } From bc0d41e9baa19c10977dd38f4bb255c14bd6554d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:17:28 -0600 Subject: [PATCH 2/7] print message with exceptions in a try clause --- src/libexpr/eval.cc | 12 ++++++++++-- src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 15 +++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c35527992..60214453a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -464,10 +464,11 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) - , debugRepl(0) + , debugRepl(nullptr) , debugStop(false) , debugQuit(false) , ignoreTry(false) + , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) @@ -833,7 +834,14 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & : 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()); + { + printError("%s\n\n", error->what()); + + if (trylevel > 0 && error->info().level != lvlInfo) + printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); + + printError(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) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3c3dddd1e..9aff77042 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -131,6 +131,7 @@ public: bool debugStop; bool debugQuit; bool ignoreTry; + int trylevel; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 772898932..e4fd8f650 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -853,11 +853,15 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl) { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; + state.trylevel++; + if (state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } } try { @@ -873,6 +877,9 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; + if (state.debugRepl) + state.trylevel--; + v.mkAttrs(attrs); } From 8cf6ae86648336bd67a1555302b21576b790c368 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:29:38 -0600 Subject: [PATCH 3/7] use Counter class to count tryEval levels --- src/libexpr/primops.cc | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e4fd8f650..ecc1c136a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,22 +846,30 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); +class Counter +{ + private: + int &counter; + public: + Counter(int &counter) :counter(counter) { counter++; } + ~Counter() { counter--; } +}; + /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + /* increment state.trylevel, and decrement it when this function returns. */ + Counter trylevel(state.trylevel); + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl) + if (state.debugRepl && state.ignoreTry) { - state.trylevel++; - if (state.ignoreTry) - { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; - } + /* to prevent starting the repl from exceptions withing a tryEval, null it. */ + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; } try { @@ -877,9 +885,6 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; - if (state.debugRepl) - state.trylevel--; - v.mkAttrs(attrs); } From 49ff4ef6373f4aaeb6194fb4a195d3037c74312e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 10 Jun 2022 12:22:36 -0600 Subject: [PATCH 4/7] remove unused parameter --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 60214453a..28256ec5c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -840,7 +840,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & if (trylevel > 0 && error->info().level != lvlInfo) printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); - printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } auto se = getStaticEnv(expr); From 69ea265fd26e6b503bb52566ce6f5f12e0a75661 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:12 -0600 Subject: [PATCH 5/7] 'tryEval' not 'try clause' --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 28256ec5c..956c4b474 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -838,7 +838,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & printError("%s\n\n", error->what()); if (trylevel > 0 && error->info().level != lvlInfo) - printError("This exception occurred in a try clause. 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"); printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } From 6ac8200ff5d21d7c4464b4b3a2d3716fa4b942fd Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:40 -0600 Subject: [PATCH 6/7] use util.hh class instead of local --- src/libexpr/primops.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ecc1c136a..3a07e43a7 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,15 +846,6 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); -class Counter -{ - private: - int &counter; - public: - Counter(int &counter) :counter(counter) { counter++; } - ~Counter() { counter--; } -}; - /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) @@ -862,7 +853,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); /* increment state.trylevel, and decrement it when this function returns. */ - Counter trylevel(state.trylevel); + MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; if (state.debugRepl && state.ignoreTry) From a3629ab0ccd40a4492ac99424d84b3649df8b057 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:47:09 -0600 Subject: [PATCH 7/7] move ignore-try to EvalSettings --- src/libcmd/command.cc | 9 --------- src/libexpr/eval.cc | 1 - src/libexpr/eval.hh | 8 +++++++- src/libexpr/primops.cc | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 940fd5b23..14bb27936 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -91,12 +91,6 @@ EvalCommand::EvalCommand() .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); - - addFlag({ - .longName = "ignore-try", - .description = "ignore exceptions in try clauses during debug", - .handler = {&ignoreExceptionsDuringTry, true}, - }); } EvalCommand::~EvalCommand() @@ -128,9 +122,6 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) { evalState->debugRepl = &runRepl; }; - if (ignoreExceptionsDuringTry) { - evalState->ignoreTry = ignoreExceptionsDuringTry; - }; } return ref(evalState); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 956c4b474..f485e2fed 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,7 +467,6 @@ EvalState::EvalState( , debugRepl(nullptr) , debugStop(false) , debugQuit(false) - , ignoreTry(false) , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9aff77042..b8903c06c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,7 +130,6 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; - bool ignoreTry; int trylevel; std::list debugTraces; std::map> exprEnvs; @@ -648,6 +647,13 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting ignoreExceptionsDuringTry{this, false, "ignore-try", + R"( + If set to true, ignore exceptions inside 'tryEval' calls when evaluating nix expressions in + debug mode (using the --debugger flag). By default the debugger will pause on all exceptions. + )"}; + }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3a07e43a7..2201ca0c4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -856,7 +856,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry) { /* to prevent starting the repl from exceptions withing a tryEval, null it. */ savedDebugRepl = state.debugRepl;