Skip to content

Commit

Permalink
:quit in the debugger should quit the whole program
Browse files Browse the repository at this point in the history
  • Loading branch information
9999years committed Feb 3, 2024
1 parent 081dc5d commit 3bee459
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 44 deletions.
63 changes: 47 additions & 16 deletions src/libcmd/repl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,27 @@ extern "C" {

namespace nix {

/**
* Returned by `NixRepl::processLine`.
*/
enum class ProcessLineResult {
/**
* The user exited with `:quit`. The REPL should exit. The surrounding
* program or evaluation (e.g., if the REPL was acting as the debugger)
* should also exit.
*/
QuitAll,
/**
* The user exited with `:continue`. The REPL should exit, but the program
* should continue running.
*/
QuitOnce,
/**
* The user did not exit. The REPL should request another line of input.
*/
Continue,
};

struct NixRepl
: AbstractNixRepl
#if HAVE_BOEHMGC
Expand All @@ -75,13 +96,13 @@ struct NixRepl
std::function<AnnotatedValues()> getValues);
virtual ~NixRepl();

void mainLoop() override;
ReplExitStatus mainLoop() override;
void initEnv() override;

StringSet completePrefix(const std::string & prefix);
bool getLine(std::string & input, const std::string & prompt);
StorePath getDerivationPath(Value & v);
bool processLine(std::string line);
ProcessLineResult processLine(std::string line);

void loadFile(const Path & path);
void loadFlake(const std::string & flakeRef);
Expand Down Expand Up @@ -243,7 +264,7 @@ static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positi
return out;
}

void NixRepl::mainLoop()
ReplExitStatus NixRepl::mainLoop()
{
std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n");
Expand Down Expand Up @@ -277,15 +298,25 @@ void NixRepl::mainLoop()
// When continuing input from previous lines, don't print a prompt, just align to the same
// number of chars as the prompt.
if (!getLine(input, input.empty() ? "nix-repl> " : " ")) {
// ctrl-D should exit the debugger.
// Ctrl-D should exit the debugger.
state->debugStop = false;
state->debugQuit = true;
logger->cout("");
break;
// TODO: Should Ctrl-D exit just the current debugger session or
// the entire program?
return ReplExitStatus::QuitAll;
}
logger->resume();
try {
if (!removeWhitespace(input).empty() && !processLine(input)) return;
switch (processLine(input)) {
case ProcessLineResult::QuitAll:
return ReplExitStatus::QuitAll;
case ProcessLineResult::QuitOnce:
return ReplExitStatus::Continue;
case ProcessLineResult::Continue:
break;
default:
abort();
}
} catch (ParseError & e) {
if (e.msg().find("unexpected end of file") != std::string::npos) {
// For parse errors on incomplete input, we continue waiting for the next line of
Expand Down Expand Up @@ -475,10 +506,11 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt)
}
}

bool NixRepl::processLine(std::string line)
ProcessLineResult NixRepl::processLine(std::string line)
{
line = trim(line);
if (line == "") return true;
if (line.empty())
return ProcessLineResult::Continue;

_isInterrupted = false;

Expand Down Expand Up @@ -573,13 +605,13 @@ bool NixRepl::processLine(std::string line)
else if (state->debugRepl && (command == ":s" || command == ":step")) {
// set flag to stop at next DebugTrace; exit repl.
state->debugStop = true;
return false;
return ProcessLineResult::QuitOnce;
}

else if (state->debugRepl && (command == ":c" || command == ":continue")) {
// set flag to run to next breakpoint or end of program; exit repl.
state->debugStop = false;
return false;
return ProcessLineResult::QuitOnce;
}

else if (command == ":a" || command == ":add") {
Expand Down Expand Up @@ -722,8 +754,7 @@ bool NixRepl::processLine(std::string line)

else if (command == ":q" || command == ":quit") {
state->debugStop = false;
state->debugQuit = true;
return false;
return ProcessLineResult::QuitAll;
}

else if (command == ":doc") {
Expand Down Expand Up @@ -784,7 +815,7 @@ bool NixRepl::processLine(std::string line)
}
}

return true;
return ProcessLineResult::Continue;
}

void NixRepl::loadFile(const Path & path)
Expand Down Expand Up @@ -915,7 +946,7 @@ std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
}


void AbstractNixRepl::runSimple(
ReplExitStatus AbstractNixRepl::runSimple(
ref<EvalState> evalState,
const ValMap & extraEnv)
{
Expand All @@ -937,7 +968,7 @@ void AbstractNixRepl::runSimple(
for (auto & [name, value] : extraEnv)
repl->addVarToScope(repl->state->symbols.create(name), *value);

repl->mainLoop();
return repl->mainLoop();
}

}
4 changes: 2 additions & 2 deletions src/libcmd/repl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ struct AbstractNixRepl
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
std::function<AnnotatedValues()> getValues);

static void runSimple(
static ReplExitStatus runSimple(
ref<EvalState> evalState,
const ValMap & extraEnv);

virtual void initEnv() = 0;

virtual void mainLoop() = 0;
virtual ReplExitStatus mainLoop() = 0;
};

}
12 changes: 10 additions & 2 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "hash.hh"
#include "primops.hh"
#include "print-options.hh"
#include "shared.hh"
#include "types.hh"
#include "util.hh"
#include "store-api.hh"
Expand Down Expand Up @@ -456,7 +457,6 @@ EvalState::EvalState(
, buildStore(buildStore ? buildStore : store)
, debugRepl(nullptr)
, debugStop(false)
, debugQuit(false)
, trylevel(0)
, regexCache(makeRegexCache())
#if HAVE_BOEHMGC
Expand Down Expand Up @@ -832,7 +832,15 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
auto se = getStaticEnv(expr);
if (se) {
auto vm = mapStaticEnvBindings(symbols, *se.get(), env);
(debugRepl)(ref<EvalState>(shared_from_this()), *vm);
auto exitStatus = (debugRepl)(ref<EvalState>(shared_from_this()), *vm);
switch (exitStatus) {
case ReplExitStatus::QuitAll:
throw Exit(0);
case ReplExitStatus::Continue:
break;
default:
abort();
}
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/libexpr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "experimental-features.hh"
#include "input-accessor.hh"
#include "search-path.hh"
#include "repl-exit-status.hh"

#include <map>
#include <optional>
Expand Down Expand Up @@ -257,9 +258,8 @@ public:
/**
* Debugger
*/
void (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
ReplExitStatus (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
bool debugStop;
bool debugQuit;
int trylevel;
std::list<DebugTrace> debugTraces;
std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs;
Expand Down Expand Up @@ -819,7 +819,6 @@ struct DebugTraceStacker {
DebugTraceStacker(EvalState & evalState, DebugTrace t);
~DebugTraceStacker()
{
// assert(evalState.debugTraces.front() == trace);
evalState.debugTraces.pop_front();
}
EvalState & evalState;
Expand Down
11 changes: 1 addition & 10 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -763,15 +763,6 @@ static RegisterPrimOp primop_break({

auto & dt = state.debugTraces.front();
state.runDebugRepl(&error, dt.env, dt.expr);

if (state.debugQuit) {
// If the user elects to quit the repl, throw an exception.
throw Error(ErrorInfo{
.level = lvlInfo,
.msg = hintfmt("quit the debugger"),
.errPos = nullptr,
});
}
}

// Return the value we were passed.
Expand Down Expand Up @@ -882,7 +873,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
/* increment state.trylevel, and decrement it when this function returns. */
MaintainCount trylevel(state.trylevel);

void (* savedDebugRepl)(ref<EvalState> es, const ValMap & extraEnv) = nullptr;
ReplExitStatus (* savedDebugRepl)(ref<EvalState> es, const ValMap & extraEnv) = nullptr;
if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry)
{
/* to prevent starting the repl from exceptions withing a tryEval, null it. */
Expand Down
20 changes: 20 additions & 0 deletions src/libexpr/repl-exit-status.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

namespace nix {

/**
* Exit status returned from the REPL.
*/
enum class ReplExitStatus {
/**
* The user exited with `:quit`. The program (e.g., if the REPL was acting
* as the debugger) should exit.
*/
QuitAll,
/**
* The user exited with `:continue`. The program should continue running.
*/
Continue,
};

}
2 changes: 0 additions & 2 deletions src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,4 @@ PrintFreed::~PrintFreed()
showBytes(results.bytesFreed));
}

Exit::~Exit() { }

}
10 changes: 1 addition & 9 deletions src/libmain/shared.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "common-args.hh"
#include "path.hh"
#include "derived-path.hh"
#include "exit.hh"

#include <signal.h>

Expand All @@ -15,15 +16,6 @@

namespace nix {

class Exit : public std::exception
{
public:
int status;
Exit() : status(0) { }
Exit(int status) : status(status) { }
virtual ~Exit();
};

int handleExceptions(const std::string & programName, std::function<void()> fun);

/**
Expand Down
7 changes: 7 additions & 0 deletions src/libutil/exit.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "exit.hh"

namespace nix {

Exit::~Exit() {}

}
19 changes: 19 additions & 0 deletions src/libutil/exit.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <exception>

namespace nix {

/**
* Exit the program with a given exit code.
*/
class Exit : public std::exception
{
public:
int status;
Exit() : status(0) { }
Exit(int status) : status(status) { }
virtual ~Exit();
};

}

0 comments on commit 3bee459

Please sign in to comment.