back to ref<EvalState> in NixRepl

This commit is contained in:
Ben Burdette 2022-05-25 10:21:20 -06:00
parent 91b7d5373a
commit b4c24a29c6
4 changed files with 82 additions and 83 deletions

View file

@ -274,6 +274,6 @@ void printClosureDiff(
void runRepl( void runRepl(
EvalState & evalState, ref<EvalState> evalState,
const ValMap & extraEnv); const ValMap & extraEnv);
} }

View file

@ -48,7 +48,7 @@ struct NixRepl
#endif #endif
{ {
std::string curDir; std::string curDir;
EvalState & state; ref<EvalState> state;
Bindings * autoArgs; Bindings * autoArgs;
size_t debugTraceIndex; size_t debugTraceIndex;
@ -63,7 +63,7 @@ struct NixRepl
const Path historyFile; const Path historyFile;
NixRepl(EvalState & state); NixRepl(ref<EvalState> state);
~NixRepl(); ~NixRepl();
void mainLoop(const std::vector<std::string> & files); void mainLoop(const std::vector<std::string> & files);
StringSet completePrefix(const std::string & prefix); StringSet completePrefix(const std::string & prefix);
@ -96,10 +96,10 @@ std::string removeWhitespace(std::string s)
} }
NixRepl::NixRepl(EvalState & state) NixRepl::NixRepl(ref<EvalState> state)
: state(state) : state(state)
, debugTraceIndex(0) , debugTraceIndex(0)
, staticEnv(new StaticEnv(false, state.staticBaseEnv.get())) , staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
, historyFile(getDataDir() + "/nix/repl-history") , historyFile(getDataDir() + "/nix/repl-history")
{ {
curDir = absPath("."); curDir = absPath(".");
@ -261,8 +261,8 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
// number of chars as the prompt. // number of chars as the prompt.
if (!getLine(input, input.empty() ? "nix-repl> " : " ")) { if (!getLine(input, input.empty() ? "nix-repl> " : " ")) {
// ctrl-D should exit the debugger. // ctrl-D should exit the debugger.
state.debugStop = false; state->debugStop = false;
state.debugQuit = true; state->debugQuit = true;
break; break;
} }
try { try {
@ -279,8 +279,8 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
// in debugger mode, an EvalError should trigger another repl session. // 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; // when that session returns the exception will land here. No need to show it again;
// show the error for this repl session instead. // show the error for this repl session instead.
if (state.debugRepl && !state.debugTraces.empty()) if (state->debugRepl && !state->debugTraces.empty())
showDebugTrace(std::cout, state.positions, state.debugTraces.front()); showDebugTrace(std::cout, state->positions, state->debugTraces.front());
else else
printMsg(lvlError, e.msg()); printMsg(lvlError, e.msg());
} catch (Error & e) { } catch (Error & e) {
@ -386,11 +386,11 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
Expr * e = parseString(expr); Expr * e = parseString(expr);
Value v; Value v;
e->eval(state, *env, v); e->eval(*state, *env, v);
state.forceAttrs(v, noPos); state->forceAttrs(v, noPos);
for (auto & i : *v.attrs) { for (auto & i : *v.attrs) {
std::string_view name = state.symbols[i.name]; std::string_view name = state->symbols[i.name];
if (name.substr(0, cur2.size()) != cur2) continue; if (name.substr(0, cur2.size()) != cur2) continue;
completions.insert(concatStrings(prev, expr, ".", name)); completions.insert(concatStrings(prev, expr, ".", name));
} }
@ -426,14 +426,14 @@ static bool isVarName(std::string_view s)
StorePath NixRepl::getDerivationPath(Value & v) { StorePath NixRepl::getDerivationPath(Value & v) {
auto drvInfo = getDerivation(state, v, false); auto drvInfo = getDerivation(*state, v, false);
if (!drvInfo) if (!drvInfo)
throw Error("expression does not evaluate to a derivation, so I can't build it"); throw Error("expression does not evaluate to a derivation, so I can't build it");
auto drvPath = drvInfo->queryDrvPath(); auto drvPath = drvInfo->queryDrvPath();
if (!drvPath) if (!drvPath)
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)"); throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
if (!state.store->isValidPath(*drvPath)) if (!state->store->isValidPath(*drvPath))
throw Error("expression evaluated to invalid derivation '%s'", state.store->printStorePath(*drvPath)); throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
return *drvPath; return *drvPath;
} }
@ -441,13 +441,13 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt)
{ {
initEnv(); initEnv();
auto se = state.getStaticEnv(dt.expr); auto se = state->getStaticEnv(dt.expr);
if (se) { if (se) {
auto vm = mapStaticEnvBindings(state.symbols, *se.get(), dt.env); auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env);
// add staticenv vars. // add staticenv vars.
for (auto & [name, value] : *(vm.get())) for (auto & [name, value] : *(vm.get()))
addVarToScope(state.symbols.create(name), *value); addVarToScope(state->symbols.create(name), *value);
} }
} }
@ -492,7 +492,7 @@ bool NixRepl::processLine(std::string line)
<< " :log <expr> Show logs for a derivation\n" << " :log <expr> Show logs for a derivation\n"
<< " :te [bool] Enable, disable or toggle showing traces for errors\n" << " :te [bool] Enable, disable or toggle showing traces for errors\n"
; ;
if (state.debugRepl) { if (state->debugRepl) {
std::cout std::cout
<< "\n" << "\n"
<< " Debug mode commands\n" << " Debug mode commands\n"
@ -507,49 +507,49 @@ bool NixRepl::processLine(std::string line)
} }
else if (state.debugRepl && (command == ":bt" || command == ":backtrace")) { else if (state->debugRepl && (command == ":bt" || command == ":backtrace")) {
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state->debugTraces)) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state.positions, i); showDebugTrace(std::cout, state->positions, i);
} }
} }
else if (state.debugRepl && (command == ":env")) { else if (state->debugRepl && (command == ":env")) {
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state->debugTraces)) {
if (idx == debugTraceIndex) { if (idx == debugTraceIndex) {
printEnvBindings(state, i.expr, i.env); printEnvBindings(*state, i.expr, i.env);
break; break;
} }
} }
} }
else if (state.debugRepl && (command == ":st")) { else if (state->debugRepl && (command == ":st")) {
try { try {
// change the DebugTrace index. // change the DebugTrace index.
debugTraceIndex = stoi(arg); debugTraceIndex = stoi(arg);
} catch (...) { } } catch (...) { }
for (const auto & [idx, i] : enumerate(state.debugTraces)) { for (const auto & [idx, i] : enumerate(state->debugTraces)) {
if (idx == debugTraceIndex) { if (idx == debugTraceIndex) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state.positions, i); showDebugTrace(std::cout, state->positions, i);
std::cout << std::endl; std::cout << std::endl;
printEnvBindings(state, i.expr, i.env); printEnvBindings(*state, i.expr, i.env);
loadDebugTraceEnv(i); loadDebugTraceEnv(i);
break; break;
} }
} }
} }
else if (state.debugRepl && (command == ":s" || command == ":step")) { else if (state->debugRepl && (command == ":s" || command == ":step")) {
// set flag to stop at next DebugTrace; exit repl. // set flag to stop at next DebugTrace; exit repl.
state.debugStop = true; state->debugStop = true;
return false; return false;
} }
else if (state.debugRepl && (command == ":c" || command == ":continue")) { else if (state->debugRepl && (command == ":c" || command == ":continue")) {
// set flag to run to next breakpoint or end of program; exit repl. // set flag to run to next breakpoint or end of program; exit repl.
state.debugStop = false; state->debugStop = false;
return false; return false;
} }
@ -560,7 +560,7 @@ bool NixRepl::processLine(std::string line)
} }
else if (command == ":l" || command == ":load") { else if (command == ":l" || command == ":load") {
state.resetFileCache(); state->resetFileCache();
loadFile(arg); loadFile(arg);
} }
@ -569,7 +569,7 @@ bool NixRepl::processLine(std::string line)
} }
else if (command == ":r" || command == ":reload") { else if (command == ":r" || command == ":reload") {
state.resetFileCache(); state->resetFileCache();
reloadFiles(); reloadFiles();
} }
@ -580,15 +580,15 @@ bool NixRepl::processLine(std::string line)
const auto [file, line] = [&] () -> std::pair<std::string, uint32_t> { const auto [file, line] = [&] () -> std::pair<std::string, uint32_t> {
if (v.type() == nPath || v.type() == nString) { if (v.type() == nPath || v.type() == nString) {
PathSet context; PathSet context;
auto filename = state.coerceToString(noPos, v, context).toOwned(); auto filename = state->coerceToString(noPos, v, context).toOwned();
state.symbols.create(filename); state->symbols.create(filename);
return {filename, 0}; return {filename, 0};
} else if (v.isLambda()) { } else if (v.isLambda()) {
auto pos = state.positions[v.lambda.fun->pos]; auto pos = state->positions[v.lambda.fun->pos];
return {pos.file, pos.line}; return {pos.file, pos.line};
} else { } else {
// assume it's a derivation // assume it's a derivation
return findPackageFilename(state, v, arg); return findPackageFilename(*state, v, arg);
} }
}(); }();
@ -602,7 +602,7 @@ bool NixRepl::processLine(std::string line)
runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }); runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args });
// Reload right after exiting the editor // Reload right after exiting the editor
state.resetFileCache(); state->resetFileCache();
reloadFiles(); reloadFiles();
} }
@ -616,30 +616,30 @@ bool NixRepl::processLine(std::string line)
Value v, f, result; Value v, f, result;
evalString(arg, v); evalString(arg, v);
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
state.callFunction(f, v, result, PosIdx()); state->callFunction(f, v, result, PosIdx());
StorePath drvPath = getDerivationPath(result); StorePath drvPath = getDerivationPath(result);
runNix("nix-shell", {state.store->printStorePath(drvPath)}); runNix("nix-shell", {state->store->printStorePath(drvPath)});
} }
else if (command == ":b" || command == ":bl" || command == ":i" || command == ":sh" || command == ":log") { else if (command == ":b" || command == ":bl" || command == ":i" || command == ":sh" || command == ":log") {
Value v; Value v;
evalString(arg, v); evalString(arg, v);
StorePath drvPath = getDerivationPath(v); StorePath drvPath = getDerivationPath(v);
Path drvPathRaw = state.store->printStorePath(drvPath); Path drvPathRaw = state->store->printStorePath(drvPath);
if (command == ":b" || command == ":bl") { if (command == ":b" || command == ":bl") {
state.store->buildPaths({DerivedPath::Built{drvPath}}); state->store->buildPaths({DerivedPath::Built{drvPath}});
auto drv = state.store->readDerivation(drvPath); auto drv = state->store->readDerivation(drvPath);
logger->cout("\nThis derivation produced the following outputs:"); logger->cout("\nThis derivation produced the following outputs:");
for (auto & [outputName, outputPath] : state.store->queryDerivationOutputMap(drvPath)) { for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) {
auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>(); auto localStore = state->store.dynamic_pointer_cast<LocalFSStore>();
if (localStore && command == ":bl") { if (localStore && command == ":bl") {
std::string symlink = "repl-result-" + outputName; std::string symlink = "repl-result-" + outputName;
localStore->addPermRoot(outputPath, absPath(symlink)); localStore->addPermRoot(outputPath, absPath(symlink));
logger->cout(" ./%s -> %s", symlink, state.store->printStorePath(outputPath)); logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath));
} else { } else {
logger->cout(" %s -> %s", outputName, state.store->printStorePath(outputPath)); logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
} }
} }
} else if (command == ":i") { } else if (command == ":i") {
@ -651,7 +651,7 @@ bool NixRepl::processLine(std::string line)
}); });
auto subs = getDefaultSubstituters(); auto subs = getDefaultSubstituters();
subs.push_front(state.store); subs.push_front(state->store);
bool foundLog = false; bool foundLog = false;
RunPager pager; RunPager pager;
@ -684,15 +684,15 @@ bool NixRepl::processLine(std::string line)
} }
else if (command == ":q" || command == ":quit") { else if (command == ":q" || command == ":quit") {
state.debugStop = false; state->debugStop = false;
state.debugQuit = true; state->debugQuit = true;
return false; return false;
} }
else if (command == ":doc") { else if (command == ":doc") {
Value v; Value v;
evalString(arg, v); evalString(arg, v);
if (auto doc = state.getDoc(v)) { if (auto doc = state->getDoc(v)) {
std::string markdown; std::string markdown;
if (!doc->args.empty() && doc->name) { if (!doc->args.empty() && doc->name) {
@ -736,9 +736,9 @@ bool NixRepl::processLine(std::string line)
isVarName(name = removeWhitespace(line.substr(0, p)))) isVarName(name = removeWhitespace(line.substr(0, p))))
{ {
Expr * e = parseString(line.substr(p + 1)); Expr * e = parseString(line.substr(p + 1));
Value & v(*state.allocValue()); Value & v(*state->allocValue());
v.mkThunk(env, e); v.mkThunk(env, e);
addVarToScope(state.symbols.create(name), v); addVarToScope(state->symbols.create(name), v);
} else { } else {
Value v; Value v;
evalString(line, v); evalString(line, v);
@ -755,8 +755,8 @@ void NixRepl::loadFile(const Path & path)
loadedFiles.remove(path); loadedFiles.remove(path);
loadedFiles.push_back(path); loadedFiles.push_back(path);
Value v, v2; Value v, v2;
state.evalFile(lookupFileArg(state, path), v); state->evalFile(lookupFileArg(*state, path), v);
state.autoCallFunction(*autoArgs, v, v2); state->autoCallFunction(*autoArgs, v, v2);
addAttrsToScope(v2); addAttrsToScope(v2);
} }
@ -771,8 +771,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
Value v; Value v;
flake::callFlake(state, flake::callFlake(*state,
flake::lockFlake(state, flakeRef, flake::lockFlake(*state, flakeRef,
flake::LockFlags { flake::LockFlags {
.updateLockFile = false, .updateLockFile = false,
.useRegistries = !evalSettings.pureEval, .useRegistries = !evalSettings.pureEval,
@ -785,14 +785,14 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
void NixRepl::initEnv() void NixRepl::initEnv()
{ {
env = &state.allocEnv(envSize); env = &state->allocEnv(envSize);
env->up = &state.baseEnv; env->up = &state->baseEnv;
displ = 0; displ = 0;
staticEnv->vars.clear(); staticEnv->vars.clear();
varNames.clear(); varNames.clear();
for (auto & i : state.staticBaseEnv->vars) for (auto & i : state->staticBaseEnv->vars)
varNames.emplace(state.symbols[i.first]); varNames.emplace(state->symbols[i.first]);
} }
@ -821,14 +821,14 @@ void NixRepl::loadFiles()
void NixRepl::addAttrsToScope(Value & attrs) void NixRepl::addAttrsToScope(Value & attrs)
{ {
state.forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }); state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); });
if (displ + attrs.attrs->size() >= envSize) if (displ + attrs.attrs->size() >= envSize)
throw Error("environment full; cannot add more variables"); throw Error("environment full; cannot add more variables");
for (auto & i : *attrs.attrs) { for (auto & i : *attrs.attrs) {
staticEnv->vars.emplace_back(i.name, displ); staticEnv->vars.emplace_back(i.name, displ);
env->values[displ++] = i.value; env->values[displ++] = i.value;
varNames.emplace(state.symbols[i.name]); varNames.emplace(state->symbols[i.name]);
} }
staticEnv->sort(); staticEnv->sort();
staticEnv->deduplicate(); staticEnv->deduplicate();
@ -845,13 +845,13 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
staticEnv->vars.emplace_back(name, displ); staticEnv->vars.emplace_back(name, displ);
staticEnv->sort(); staticEnv->sort();
env->values[displ++] = &v; env->values[displ++] = &v;
varNames.emplace(state.symbols[name]); varNames.emplace(state->symbols[name]);
} }
Expr * NixRepl::parseString(std::string s) Expr * NixRepl::parseString(std::string s)
{ {
Expr * e = state.parseExprFromString(std::move(s), curDir, staticEnv); Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv);
return e; return e;
} }
@ -859,8 +859,8 @@ Expr * NixRepl::parseString(std::string s)
void NixRepl::evalString(std::string s, Value & v) void NixRepl::evalString(std::string s, Value & v)
{ {
Expr * e = parseString(s); Expr * e = parseString(s);
e->eval(state, *env, v); e->eval(*state, *env, v);
state.forceValue(v, [&]() { return v.determinePos(noPos); }); state->forceValue(v, [&]() { return v.determinePos(noPos); });
} }
@ -890,7 +890,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
str.flush(); str.flush();
checkInterrupt(); checkInterrupt();
state.forceValue(v, [&]() { return v.determinePos(noPos); }); state->forceValue(v, [&]() { return v.determinePos(noPos); });
switch (v.type()) { switch (v.type()) {
@ -919,14 +919,14 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
case nAttrs: { case nAttrs: {
seen.insert(&v); seen.insert(&v);
bool isDrv = state.isDerivation(v); bool isDrv = state->isDerivation(v);
if (isDrv) { if (isDrv) {
str << "«derivation "; str << "«derivation ";
Bindings::iterator i = v.attrs->find(state.sDrvPath); Bindings::iterator i = v.attrs->find(state->sDrvPath);
PathSet context; PathSet context;
if (i != v.attrs->end()) if (i != v.attrs->end())
str << state.store->printStorePath(state.coerceToStorePath(i->pos, *i->value, context)); str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context));
else else
str << "???"; str << "???";
str << "»"; str << "»";
@ -938,7 +938,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
typedef std::map<std::string, Value *> Sorted; typedef std::map<std::string, Value *> Sorted;
Sorted sorted; Sorted sorted;
for (auto & i : *v.attrs) for (auto & i : *v.attrs)
sorted.emplace(state.symbols[i.name], i.value); sorted.emplace(state->symbols[i.name], i.value);
for (auto & i : sorted) { for (auto & i : sorted) {
if (isVarName(i.first)) if (isVarName(i.first))
@ -988,7 +988,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
case nFunction: case nFunction:
if (v.isLambda()) { if (v.isLambda()) {
std::ostringstream s; std::ostringstream s;
s << state.positions[v.lambda.fun->pos]; s << state->positions[v.lambda.fun->pos];
str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL;
} else if (v.isPrimOp()) { } else if (v.isPrimOp()) {
str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; str << ANSI_MAGENTA "«primop»" ANSI_NORMAL;
@ -1012,7 +1012,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
} }
void runRepl( void runRepl(
EvalState &evalState, ref<EvalState>evalState,
const ValMap & extraEnv) const ValMap & extraEnv)
{ {
auto repl = std::make_unique<NixRepl>(evalState); auto repl = std::make_unique<NixRepl>(evalState);
@ -1021,7 +1021,7 @@ void runRepl(
// add 'extra' vars. // add 'extra' vars.
for (auto & [name, value] : extraEnv) for (auto & [name, value] : extraEnv)
repl->addVarToScope(repl->state.symbols.create(name), *value); repl->addVarToScope(repl->state->symbols.create(name), *value);
repl->mainLoop({}); repl->mainLoop({});
} }
@ -1057,8 +1057,8 @@ struct CmdRepl : StoreCommand, MixEvalArgs
auto evalState = make_ref<EvalState>(searchPath, store); auto evalState = make_ref<EvalState>(searchPath, store);
auto repl = std::make_unique<NixRepl>(*evalState); auto repl = std::make_unique<NixRepl>(evalState);
repl->autoArgs = getAutoArgs(repl->state); repl->autoArgs = getAutoArgs(*repl->state);
repl->initEnv(); repl->initEnv();
repl->mainLoop(files); repl->mainLoop(files);
} }

View file

@ -836,7 +836,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
auto se = getStaticEnv(expr); auto se = getStaticEnv(expr);
if (se) { if (se) {
auto vm = mapStaticEnvBindings(symbols, *se.get(), env); auto vm = mapStaticEnvBindings(symbols, *se.get(), env);
(debugRepl)(*this, *vm); (debugRepl)(ref<EvalState>(shared_from_this()), *vm);
} }
} }

View file

@ -13,7 +13,6 @@
#include <unordered_map> #include <unordered_map>
#include <mutex> #include <mutex>
namespace nix { namespace nix {
@ -88,7 +87,7 @@ struct DebugTrace {
void debugError(Error * e, Env & env, Expr & expr); void debugError(Error * e, Env & env, Expr & expr);
class EvalState class EvalState : public std::enable_shared_from_this<EvalState>
{ {
public: public:
SymbolTable symbols; SymbolTable symbols;
@ -127,7 +126,7 @@ public:
RootValue vImportedDrvToDerivation = nullptr; RootValue vImportedDrvToDerivation = nullptr;
/* Debugger */ /* Debugger */
void (* debugRepl)(EvalState & es, const ValMap & extraEnv); void (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
bool debugStop; bool debugStop;
bool debugQuit; bool debugQuit;
std::list<DebugTrace> debugTraces; std::list<DebugTrace> debugTraces;