From e5662ba6525c27248d57d8265e9c6c3a46f95c7e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 5 Aug 2020 21:26:17 +0200 Subject: Add a flag to start the REPL on evaluation errors This allows interactively inspecting the state of the evaluator at the point of failure. Example: $ nix eval path:///home/eelco/Dev/nix/flake2#modules.hello-closure._final --start-repl-on-eval-errors error: --- TypeError -------------------------------------------------------------------------------------------------------------------------------------------------------------------- nix at: (20:53) in file: /nix/store/4264z41dxfdiqr95svmpnxxxwhfplhy0-source/flake.nix 19| 20| _final = builtins.foldl' (xs: mod: xs // (mod._module.config { config = _final; })) _defaults _allModules; | ^ 21| }; attempt to call something which is not a function but a set Starting REPL to allow you to inspect the current state of the evaluator. The following extra variables are in scope: arg, fun Welcome to Nix version 2.4. Type :? for help. nix-repl> fun error: --- EvalError -------------------------------------------------------------------------------------------------------------------------------------------------------------------- nix at: (150:28) in file: /nix/store/4264z41dxfdiqr95svmpnxxxwhfplhy0-source/flake.nix 149| 150| tarballClosure = (module { | ^ 151| extends = [ self.modules.derivation ]; attribute 'derivation' missing nix-repl> :t fun a set nix-repl> builtins.attrNames fun [ "tarballClosure" ] nix-repl> --- src/libexpr/eval.cc | 13 +++++++-- src/nix/command.cc | 24 +++++++++++++++++ src/nix/command.hh | 8 ++++++ src/nix/installables.cc | 7 ----- src/nix/repl.cc | 71 +++++++++++++++++++++++++++++++++---------------- 5 files changed, 91 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0123070d1..5d71e5466 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1171,6 +1171,8 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) } } +std::function & env)> debuggerHook; + void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos) { auto trace = evalSettings.traceFunctionCalls ? std::make_unique(pos) : nullptr; @@ -1198,8 +1200,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po } } - if (fun.type != tLambda) - throwTypeError(pos, "attempt to call something which is not a function but %1%", fun); + if (fun.type != tLambda) { + auto error = TypeError({ + .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), + .errPos = pos + }); + if (debuggerHook) + debuggerHook(error, {{"fun", &fun}, {"arg", &arg}}); + throw error; + } ExprLambda & lambda(*fun.lambda.fun); diff --git a/src/nix/command.cc b/src/nix/command.cc index af36dda89..8b69948b6 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -31,6 +31,30 @@ void StoreCommand::run() run(getStore()); } +EvalCommand::EvalCommand() +{ + addFlag({ + .longName = "start-repl-on-eval-errors", + .description = "start an interactive environment if evaluation fails", + .handler = {&startReplOnEvalErrors, true}, + }); +} + +extern std::function & env)> debuggerHook; + +ref EvalCommand::getEvalState() +{ + if (!evalState) { + evalState = std::make_shared(searchPath, getStore()); + if (startReplOnEvalErrors) + debuggerHook = [evalState{ref(evalState)}](const Error & error, const std::map & env) { + printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + runRepl(evalState, env); + }; + } + return ref(evalState); +} + StorePathsCommand::StorePathsCommand(bool recursive) : recursive(recursive) { diff --git a/src/nix/command.hh b/src/nix/command.hh index bc46a2028..fe1cd2799 100644 --- a/src/nix/command.hh +++ b/src/nix/command.hh @@ -36,8 +36,12 @@ private: struct EvalCommand : virtual StoreCommand, MixEvalArgs { + bool startReplOnEvalErrors = false; + ref getEvalState(); + EvalCommand(); + std::shared_ptr evalState; }; @@ -251,4 +255,8 @@ void printClosureDiff( const StorePath & afterPath, std::string_view indent); +void runRepl( + ref evalState, + const std::map & extraEnv); + } diff --git a/src/nix/installables.cc b/src/nix/installables.cc index 59b52ce95..926cac2f8 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -234,13 +234,6 @@ void completeFlakeRefWithFragment( completeFlakeRef(evalState->store, prefix); } -ref EvalCommand::getEvalState() -{ - if (!evalState) - evalState = std::make_shared(searchPath, getStore()); - return ref(evalState); -} - void completeFlakeRef(ref store, std::string_view prefix) { if (prefix == "") diff --git a/src/nix/repl.cc b/src/nix/repl.cc index fb9050d0d..8409c7574 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -41,7 +41,7 @@ namespace nix { struct NixRepl : gc { string curDir; - std::unique_ptr state; + ref state; Bindings * autoArgs; Strings loadedFiles; @@ -54,7 +54,7 @@ struct NixRepl : gc const Path historyFile; - NixRepl(const Strings & searchPath, nix::ref store); + NixRepl(ref state); ~NixRepl(); void mainLoop(const std::vector & files); StringSet completePrefix(string prefix); @@ -65,13 +65,13 @@ struct NixRepl : gc void initEnv(); void reloadFiles(); void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value & v); + void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); void evalString(string s, Value & v); typedef set ValuesSeen; - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); }; @@ -84,8 +84,8 @@ string removeWhitespace(string s) } -NixRepl::NixRepl(const Strings & searchPath, nix::ref store) - : state(std::make_unique(searchPath, store)) +NixRepl::NixRepl(ref state) + : state(state) , staticEnv(false, &state->staticBaseEnv) , historyFile(getDataDir() + "/nix/repl-history") { @@ -176,11 +176,13 @@ void NixRepl::mainLoop(const std::vector & files) string error = ANSI_RED "error:" ANSI_NORMAL " "; std::cout << "Welcome to Nix version " << nixVersion << ". Type :? for help." << std::endl << std::endl; - for (auto & i : files) - loadedFiles.push_back(i); + if (!files.empty()) { + for (auto & i : files) + loadedFiles.push_back(i); - reloadFiles(); - if (!loadedFiles.empty()) std::cout << std::endl; + reloadFiles(); + if (!loadedFiles.empty()) std::cout << std::endl; + } // Allow nix-repl specific settings in .inputrc rl_readline_name = "nix-repl"; @@ -516,10 +518,10 @@ bool NixRepl::processLine(string line) isVarName(name = removeWhitespace(string(line, 0, p)))) { Expr * e = parseString(string(line, p + 1)); - Value & v(*state->allocValue()); - v.type = tThunk; - v.thunk.env = env; - v.thunk.expr = e; + auto v = state->allocValue(); + v->type = tThunk; + v->thunk.env = env; + v->thunk.expr = e; addVarToScope(state->symbols.create(name), v); } else { Value v; @@ -577,17 +579,17 @@ void NixRepl::addAttrsToScope(Value & attrs) { state->forceAttrs(attrs); for (auto & i : *attrs.attrs) - addVarToScope(i.name, *i.value); + addVarToScope(i.name, i.value); std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; } -void NixRepl::addVarToScope(const Symbol & name, Value & v) +void NixRepl::addVarToScope(const Symbol & name, Value * v) { if (displ >= envSize) throw Error("environment full; cannot add more variables"); staticEnv.vars[name] = displ; - env->values[displ++] = &v; + env->values[displ++] = v; varNames.insert((string) name); } @@ -754,6 +756,26 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } +void runRepl( + ref evalState, + const std::map & extraEnv) +{ + auto repl = std::make_unique(evalState); + + repl->initEnv(); + + std::set names; + + for (auto & [name, value] : extraEnv) { + names.insert(ANSI_BOLD + name + ANSI_NORMAL); + repl->addVarToScope(repl->state->symbols.create(name), value); + } + + printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); + + repl->mainLoop({}); +} + struct CmdRepl : StoreCommand, MixEvalArgs { std::vector files; @@ -775,17 +797,20 @@ struct CmdRepl : StoreCommand, MixEvalArgs Examples examples() override { return { - Example{ - "Display all special commands within the REPL:", - "nix repl\n nix-repl> :?" - } + { + "Display all special commands within the REPL:", + "nix repl\n nix-repl> :?" + } }; } void run(ref store) override { evalSettings.pureEval = false; - auto repl = std::make_unique(searchPath, openStore()); + + auto evalState = make_ref(searchPath, store); + + auto repl = std::make_unique(evalState); repl->autoArgs = getAutoArgs(*repl->state); repl->mainLoop(files); } -- cgit v1.2.3 From e486996cef871337ef14991e709d7f2cc6611e4e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 1 Feb 2021 15:50:58 +0100 Subject: Rename to --debugger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Domen Kožar --- src/nix/command.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nix/command.cc b/src/nix/command.cc index 8b69948b6..c2bd5b13c 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -34,7 +34,7 @@ void StoreCommand::run() EvalCommand::EvalCommand() { addFlag({ - .longName = "start-repl-on-eval-errors", + .longName = "debugger", .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); -- cgit v1.2.3 From 57c2dd5d8581f37392df369493b00794b619304e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 28 Apr 2021 09:55:08 -0600 Subject: fixes --- src/libexpr/eval.cc | 2 +- src/nix/repl.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index a92adc3c0..37fb6ed18 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1278,7 +1278,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po if (!fun.isLambda()) { auto error = TypeError({ // .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), - .hint = hintfmt("attempt to call something which is not a function but %1%", fun), + .msg = hintfmt("attempt to call something which is not a function but %1%", fun), .errPos = pos }); if (debuggerHook) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index bb067e935..b1f250e73 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -537,8 +537,8 @@ bool NixRepl::processLine(string line) isVarName(name = removeWhitespace(string(line, 0, p)))) { Expr * e = parseString(string(line, p + 1)); - Value & v(*state->allocValue()); - v.mkThunk(env, e); + Value *v = new Value(*state->allocValue()); + v->mkThunk(env, e); addVarToScope(state->symbols.create(name), v); } else { Value v; -- cgit v1.2.3 From f32c687f03e9764e55831d894b719fdf0104cf25 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 28 Apr 2021 15:50:11 -0600 Subject: move repl.cc to libcmd for linkage --- src/libcmd/command.cc | 37 +++ src/libcmd/local.mk | 6 +- src/libcmd/repl.cc | 832 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/nix/repl.cc | 832 -------------------------------------------------- 4 files changed, 872 insertions(+), 835 deletions(-) create mode 100644 src/libcmd/repl.cc delete mode 100644 src/nix/repl.cc (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 644c9c3b0..d790bb51d 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -54,6 +54,7 @@ void StoreCommand::run() run(getStore()); } +/* EvalCommand::EvalCommand() { addFlag({ @@ -77,6 +78,42 @@ ref EvalCommand::getEvalState() } return ref(evalState); } +*/ +EvalCommand::EvalCommand() +{ + addFlag({ + .longName = "debugger", + .description = "start an interactive environment if evaluation fails", + .handler = {&startReplOnEvalErrors, true}, + }); +} +// ref EvalCommand::getEvalState() +// { +// if (!evalState) +// evalState = std::make_shared(searchPath, getStore()); +// return ref(evalState); +// } +extern std::function & env)> debuggerHook; + +ref EvalCommand::getEvalState() +{ + if (!evalState) { + evalState = std::make_shared(searchPath, getStore()); + if (startReplOnEvalErrors) + debuggerHook = [evalState{ref(evalState)}](const Error & error, const std::map & env) { + printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + runRepl(evalState, env); + }; + } + return ref(evalState); +} + +EvalCommand::~EvalCommand() +{ + if (evalState) + evalState->printStats(); +} + RealisedPathsCommand::RealisedPathsCommand(bool recursive) : recursive(recursive) diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index ab0e0e43d..c282499b1 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -6,10 +6,10 @@ libcmd_DIR := $(d) libcmd_SOURCES := $(wildcard $(d)/*.cc) -libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers +libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix -libcmd_LDFLAGS = -llowdown +libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -libcmd_LIBS = libstore libutil libexpr libmain libfetchers +libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix libwut $(eval $(call install-file-in, $(d)/nix-cmd.pc, $(prefix)/lib/pkgconfig, 0644)) diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc new file mode 100644 index 000000000..b1f250e73 --- /dev/null +++ b/src/libcmd/repl.cc @@ -0,0 +1,832 @@ +#include +#include +#include +#include + +#include + +#ifdef READLINE +#include +#include +#else +// editline < 1.15.2 don't wrap their API for C++ usage +// (added in https://github.com/troglobit/editline/commit/91398ceb3427b730995357e9d120539fb9bb7461). +// This results in linker errors due to to name-mangling of editline C symbols. +// For compatibility with these versions, we wrap the API here +// (wrapping multiple times on newer versions is no problem). +extern "C" { +#include +} +#endif + +#include "ansicolor.hh" +#include "shared.hh" +#include "eval.hh" +#include "eval-inline.hh" +#include "attr-path.hh" +#include "store-api.hh" +#include "common-eval-args.hh" +#include "get-drvs.hh" +#include "derivations.hh" +#include "affinity.hh" +#include "globals.hh" +#include "command.hh" +#include "finally.hh" +#include "markdown.hh" + +#if HAVE_BOEHMGC +#define GC_INCLUDE_NEW +#include +#endif + +namespace nix { + +struct NixRepl + #if HAVE_BOEHMGC + : gc + #endif +{ + string curDir; + ref state; + Bindings * autoArgs; + + Strings loadedFiles; + + const static int envSize = 32768; + StaticEnv staticEnv; + Env * env; + int displ; + StringSet varNames; + + const Path historyFile; + + NixRepl(ref state); + ~NixRepl(); + void mainLoop(const std::vector & files); + StringSet completePrefix(string prefix); + bool getLine(string & input, const std::string &prompt); + StorePath getDerivationPath(Value & v); + bool processLine(string line); + void loadFile(const Path & path); + void initEnv(); + void reloadFiles(); + void addAttrsToScope(Value & attrs); + void addVarToScope(const Symbol & name, Value * v); + Expr * parseString(string s); + void evalString(string s, Value & v); + + typedef set ValuesSeen; + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); +}; + + +string removeWhitespace(string s) +{ + s = chomp(s); + size_t n = s.find_first_not_of(" \n\r\t"); + if (n != string::npos) s = string(s, n); + return s; +} + + +NixRepl::NixRepl(ref state) + : state(state) + , staticEnv(false, &state->staticBaseEnv) + , historyFile(getDataDir() + "/nix/repl-history") +{ + curDir = absPath("."); +} + + +NixRepl::~NixRepl() +{ + write_history(historyFile.c_str()); +} + +static NixRepl * curRepl; // ugly + +static char * completionCallback(char * s, int *match) { + auto possible = curRepl->completePrefix(s); + if (possible.size() == 1) { + *match = 1; + auto *res = strdup(possible.begin()->c_str() + strlen(s)); + if (!res) throw Error("allocation failure"); + return res; + } else if (possible.size() > 1) { + auto checkAllHaveSameAt = [&](size_t pos) { + auto &first = *possible.begin(); + for (auto &p : possible) { + if (p.size() <= pos || p[pos] != first[pos]) + return false; + } + return true; + }; + size_t start = strlen(s); + size_t len = 0; + while (checkAllHaveSameAt(start + len)) ++len; + if (len > 0) { + *match = 1; + auto *res = strdup(std::string(*possible.begin(), start, len).c_str()); + if (!res) throw Error("allocation failure"); + return res; + } + } + + *match = 0; + return nullptr; +} + +static int listPossibleCallback(char *s, char ***avp) { + auto possible = curRepl->completePrefix(s); + + if (possible.size() > (INT_MAX / sizeof(char*))) + throw Error("too many completions"); + + int ac = 0; + char **vp = nullptr; + + auto check = [&](auto *p) { + if (!p) { + if (vp) { + while (--ac >= 0) + free(vp[ac]); + free(vp); + } + throw Error("allocation failure"); + } + return p; + }; + + vp = check((char **)malloc(possible.size() * sizeof(char*))); + + for (auto & p : possible) + vp[ac++] = check(strdup(p.c_str())); + + *avp = vp; + + return ac; +} + +namespace { + // Used to communicate to NixRepl::getLine whether a signal occurred in ::readline. + volatile sig_atomic_t g_signal_received = 0; + + void sigintHandler(int signo) { + g_signal_received = signo; + } +} + +void NixRepl::mainLoop(const std::vector & files) +{ + string error = ANSI_RED "error:" ANSI_NORMAL " "; + std::cout << "Welcome to Nix version " << nixVersion << ". Type :? for help." << std::endl << std::endl; + + if (!files.empty()) { + for (auto & i : files) + loadedFiles.push_back(i); + + reloadFiles(); + if (!loadedFiles.empty()) std::cout << std::endl; + } + + // Allow nix-repl specific settings in .inputrc + rl_readline_name = "nix-repl"; + createDirs(dirOf(historyFile)); +#ifndef READLINE + el_hist_size = 1000; +#endif + read_history(historyFile.c_str()); + curRepl = this; +#ifndef READLINE + rl_set_complete_func(completionCallback); + rl_set_list_possib_func(listPossibleCallback); +#endif + + std::string input; + + while (true) { + // 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> " : " ")) + break; + + try { + if (!removeWhitespace(input).empty() && !processLine(input)) return; + } 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 + // input without clearing the input so far. + continue; + } else { + printMsg(lvlError, e.msg()); + } + } catch (Error & e) { + printMsg(lvlError, e.msg()); + } catch (Interrupted & e) { + printMsg(lvlError, e.msg()); + } + + // We handled the current input fully, so we should clear it + // and read brand new input. + input.clear(); + std::cout << std::endl; + } +} + + +bool NixRepl::getLine(string & input, const std::string &prompt) +{ + struct sigaction act, old; + sigset_t savedSignalMask, set; + + auto setupSignals = [&]() { + act.sa_handler = sigintHandler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGINT, &act, &old)) + throw SysError("installing handler for SIGINT"); + + sigemptyset(&set); + sigaddset(&set, SIGINT); + if (sigprocmask(SIG_UNBLOCK, &set, &savedSignalMask)) + throw SysError("unblocking SIGINT"); + }; + auto restoreSignals = [&]() { + if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr)) + throw SysError("restoring signals"); + + if (sigaction(SIGINT, &old, 0)) + throw SysError("restoring handler for SIGINT"); + }; + + setupSignals(); + char * s = readline(prompt.c_str()); + Finally doFree([&]() { free(s); }); + restoreSignals(); + + if (g_signal_received) { + g_signal_received = 0; + input.clear(); + return true; + } + + if (!s) + return false; + input += s; + input += '\n'; + return true; +} + + +StringSet NixRepl::completePrefix(string prefix) +{ + StringSet completions; + + size_t start = prefix.find_last_of(" \n\r\t(){}[]"); + std::string prev, cur; + if (start == std::string::npos) { + prev = ""; + cur = prefix; + } else { + prev = std::string(prefix, 0, start + 1); + cur = std::string(prefix, start + 1); + } + + size_t slash, dot; + + if ((slash = cur.rfind('/')) != string::npos) { + try { + auto dir = std::string(cur, 0, slash); + auto prefix2 = std::string(cur, slash + 1); + for (auto & entry : readDirectory(dir == "" ? "/" : dir)) { + if (entry.name[0] != '.' && hasPrefix(entry.name, prefix2)) + completions.insert(prev + dir + "/" + entry.name); + } + } catch (Error &) { + } + } else if ((dot = cur.rfind('.')) == string::npos) { + /* This is a variable name; look it up in the current scope. */ + StringSet::iterator i = varNames.lower_bound(cur); + while (i != varNames.end()) { + if (string(*i, 0, cur.size()) != cur) break; + completions.insert(prev + *i); + i++; + } + } else { + try { + /* This is an expression that should evaluate to an + attribute set. Evaluate it to get the names of the + attributes. */ + string expr(cur, 0, dot); + string cur2 = string(cur, dot + 1); + + Expr * e = parseString(expr); + Value v; + e->eval(*state, *env, v); + state->forceAttrs(v); + + for (auto & i : *v.attrs) { + string name = i.name; + if (string(name, 0, cur2.size()) != cur2) continue; + completions.insert(prev + expr + "." + name); + } + + } catch (ParseError & e) { + // Quietly ignore parse errors. + } catch (EvalError & e) { + // Quietly ignore evaluation errors. + } catch (UndefinedVarError & e) { + // Quietly ignore undefined variable errors. + } + } + + return completions; +} + + +bool isVarName(const string & s) +{ + if (s.size() == 0) return false; + char c = s[0]; + if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false; + for (auto & i : s) + if (!((i >= 'a' && i <= 'z') || + (i >= 'A' && i <= 'Z') || + (i >= '0' && i <= '9') || + i == '_' || i == '-' || i == '\'')) + return false; + return true; +} + + +StorePath NixRepl::getDerivationPath(Value & v) { + auto drvInfo = getDerivation(*state, v, false); + if (!drvInfo) + throw Error("expression does not evaluate to a derivation, so I can't build it"); + Path drvPathRaw = drvInfo->queryDrvPath(); + if (drvPathRaw == "") + throw Error("expression did not evaluate to a valid derivation (no drv path)"); + StorePath drvPath = state->store->parseStorePath(drvPathRaw); + if (!state->store->isValidPath(drvPath)) + throw Error("expression did not evaluate to a valid derivation (invalid drv path)"); + return drvPath; +} + + +bool NixRepl::processLine(string line) +{ + if (line == "") return true; + + string command, arg; + + if (line[0] == ':') { + size_t p = line.find_first_of(" \n\r\t"); + command = string(line, 0, p); + if (p != string::npos) arg = removeWhitespace(string(line, p)); + } else { + arg = line; + } + + if (command == ":?" || command == ":help") { + // FIXME: convert to Markdown, include in the 'nix repl' manpage. + std::cout + << "The following commands are available:\n" + << "\n" + << " Evaluate and print expression\n" + << " = Bind expression to variable\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build derivation\n" + << " :e Open the derivation in $EDITOR\n" + << " :i Build derivation, then install result into current profile\n" + << " :l Load Nix expression and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :q Exit nix-repl\n" + << " :r Reload all files\n" + << " :s Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n" + << " :u Build derivation, then start nix-shell\n" + << " :doc Show documentation of a builtin function\n"; + } + + else if (command == ":a" || command == ":add") { + Value v; + evalString(arg, v); + addAttrsToScope(v); + } + + else if (command == ":l" || command == ":load") { + state->resetFileCache(); + loadFile(arg); + } + + else if (command == ":r" || command == ":reload") { + state->resetFileCache(); + reloadFiles(); + } + + else if (command == ":e" || command == ":edit") { + Value v; + evalString(arg, v); + + Pos pos; + + if (v.type() == nPath || v.type() == nString) { + PathSet context; + auto filename = state->coerceToString(noPos, v, context); + pos.file = state->symbols.create(filename); + } else if (v.isLambda()) { + pos = v.lambda.fun->pos; + } else { + // assume it's a derivation + pos = findDerivationFilename(*state, v, arg); + } + + // Open in EDITOR + auto args = editorFor(pos); + auto editor = args.front(); + args.pop_front(); + runProgram(editor, true, args); + + // Reload right after exiting the editor + state->resetFileCache(); + reloadFiles(); + } + + else if (command == ":t") { + Value v; + evalString(arg, v); + std::cout << showType(v) << std::endl; + + } else if (command == ":u") { + Value v, f, result; + evalString(arg, v); + evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); + state->callFunction(f, v, result, Pos()); + + StorePath drvPath = getDerivationPath(result); + runProgram(settings.nixBinDir + "/nix-shell", true, {state->store->printStorePath(drvPath)}); + } + + else if (command == ":b" || command == ":i" || command == ":s") { + Value v; + evalString(arg, v); + StorePath drvPath = getDerivationPath(v); + Path drvPathRaw = state->store->printStorePath(drvPath); + + if (command == ":b") { + /* We could do the build in this process using buildPaths(), + but doing it in a child makes it easier to recover from + problems / SIGINT. */ + try { + runProgram(settings.nixBinDir + "/nix", true, {"build", "--no-link", drvPathRaw}); + auto drv = state->store->readDerivation(drvPath); + std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; + for (auto & i : drv.outputsAndOptPaths(*state->store)) + std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(*i.second.second)); + } catch (ExecError &) { + } + } else if (command == ":i") { + runProgram(settings.nixBinDir + "/nix-env", true, {"-i", drvPathRaw}); + } else { + runProgram(settings.nixBinDir + "/nix-shell", true, {drvPathRaw}); + } + } + + else if (command == ":p" || command == ":print") { + Value v; + evalString(arg, v); + printValue(std::cout, v, 1000000000) << std::endl; + } + + else if (command == ":q" || command == ":quit") + return false; + + else if (command == ":doc") { + Value v; + evalString(arg, v); + if (auto doc = state->getDoc(v)) { + std::string markdown; + + if (!doc->args.empty() && doc->name) { + auto args = doc->args; + for (auto & arg : args) + arg = "*" + arg + "*"; + + markdown += + "**Synopsis:** `builtins." + (std::string) (*doc->name) + "` " + + concatStringsSep(" ", args) + "\n\n"; + } + + markdown += trim(stripIndentation(doc->doc)); + + std::cout << renderMarkdownToTerminal(markdown); + } else + throw Error("value does not have documentation"); + } + + else if (command != "") + throw Error("unknown command '%1%'", command); + + else { + size_t p = line.find('='); + string name; + if (p != string::npos && + p < line.size() && + line[p + 1] != '=' && + isVarName(name = removeWhitespace(string(line, 0, p)))) + { + Expr * e = parseString(string(line, p + 1)); + Value *v = new Value(*state->allocValue()); + v->mkThunk(env, e); + addVarToScope(state->symbols.create(name), v); + } else { + Value v; + evalString(line, v); + printValue(std::cout, v, 1) << std::endl; + } + } + + return true; +} + + +void NixRepl::loadFile(const Path & path) +{ + loadedFiles.remove(path); + loadedFiles.push_back(path); + Value v, v2; + state->evalFile(lookupFileArg(*state, path), v); + state->autoCallFunction(*autoArgs, v, v2); + addAttrsToScope(v2); +} + + +void NixRepl::initEnv() +{ + env = &state->allocEnv(envSize); + env->up = &state->baseEnv; + displ = 0; + staticEnv.vars.clear(); + + varNames.clear(); + for (auto & i : state->staticBaseEnv.vars) + varNames.insert(i.first); +} + + +void NixRepl::reloadFiles() +{ + initEnv(); + + Strings old = loadedFiles; + loadedFiles.clear(); + + bool first = true; + for (auto & i : old) { + if (!first) std::cout << std::endl; + first = false; + std::cout << format("Loading '%1%'...") % i << std::endl; + loadFile(i); + } +} + + +void NixRepl::addAttrsToScope(Value & attrs) +{ + state->forceAttrs(attrs); + for (auto & i : *attrs.attrs) + addVarToScope(i.name, i.value); + std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; +} + + +void NixRepl::addVarToScope(const Symbol & name, Value * v) +{ + if (displ >= envSize) + throw Error("environment full; cannot add more variables"); + staticEnv.vars[name] = displ; + env->values[displ++] = v; + varNames.insert((string) name); +} + + +Expr * NixRepl::parseString(string s) +{ + Expr * e = state->parseExprFromString(s, curDir, staticEnv); + return e; +} + + +void NixRepl::evalString(string s, Value & v) +{ + Expr * e = parseString(s); + e->eval(*state, *env, v); + state->forceValue(v); +} + + +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) +{ + ValuesSeen seen; + return printValue(str, v, maxDepth, seen); +} + + +std::ostream & printStringValue(std::ostream & str, const char * string) { + str << "\""; + for (const char * i = string; *i; i++) + if (*i == '\"' || *i == '\\') str << "\\" << *i; + else if (*i == '\n') str << "\\n"; + else if (*i == '\r') str << "\\r"; + else if (*i == '\t') str << "\\t"; + else str << *i; + str << "\""; + return str; +} + + +// FIXME: lot of cut&paste from Nix's eval.cc. +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen) +{ + str.flush(); + checkInterrupt(); + + state->forceValue(v); + + switch (v.type()) { + + case nInt: + str << ANSI_CYAN << v.integer << ANSI_NORMAL; + break; + + case nBool: + str << ANSI_CYAN << (v.boolean ? "true" : "false") << ANSI_NORMAL; + break; + + case nString: + str << ANSI_YELLOW; + printStringValue(str, v.string.s); + str << ANSI_NORMAL; + break; + + case nPath: + str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping? + break; + + case nNull: + str << ANSI_CYAN "null" ANSI_NORMAL; + break; + + case nAttrs: { + seen.insert(&v); + + bool isDrv = state->isDerivation(v); + + if (isDrv) { + str << "«derivation "; + Bindings::iterator i = v.attrs->find(state->sDrvPath); + PathSet context; + Path drvPath = i != v.attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "???"; + str << drvPath << "»"; + } + + else if (maxDepth > 0) { + str << "{ "; + + typedef std::map Sorted; + Sorted sorted; + for (auto & i : *v.attrs) + sorted[i.name] = i.value; + + for (auto & i : sorted) { + if (isVarName(i.first)) + str << i.first; + else + printStringValue(str, i.first.c_str()); + str << " = "; + if (seen.find(i.second) != seen.end()) + str << "«repeated»"; + else + try { + printValue(str, *i.second, maxDepth - 1, seen); + } catch (AssertionError & e) { + str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL; + } + str << "; "; + } + + str << "}"; + } else + str << "{ ... }"; + + break; + } + + case nList: + seen.insert(&v); + + str << "[ "; + if (maxDepth > 0) + for (unsigned int n = 0; n < v.listSize(); ++n) { + if (seen.find(v.listElems()[n]) != seen.end()) + str << "«repeated»"; + else + try { + printValue(str, *v.listElems()[n], maxDepth - 1, seen); + } catch (AssertionError & e) { + str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL; + } + str << " "; + } + else + str << "... "; + str << "]"; + break; + + case nFunction: + if (v.isLambda()) { + std::ostringstream s; + s << v.lambda.fun->pos; + str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; + } else if (v.isPrimOp()) { + str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; + } else if (v.isPrimOpApp()) { + str << ANSI_BLUE "«primop-app»" ANSI_NORMAL; + } else { + abort(); + } + break; + + case nFloat: + str << v.fpoint; + break; + + default: + str << ANSI_RED "«unknown»" ANSI_NORMAL; + break; + } + + return str; +} + +void runRepl( + ref evalState, + const std::map & extraEnv) +{ + auto repl = std::make_unique(evalState); + + repl->initEnv(); + + std::set names; + + for (auto & [name, value] : extraEnv) { + names.insert(ANSI_BOLD + name + ANSI_NORMAL); + repl->addVarToScope(repl->state->symbols.create(name), value); + } + + printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); + + repl->mainLoop({}); +} + +struct CmdRepl : StoreCommand, MixEvalArgs +{ + std::vector files; + + CmdRepl() + { + expectArgs({ + .label = "files", + .handler = {&files}, + .completer = completePath + }); + } + + std::string description() override + { + return "start an interactive environment for evaluating Nix expressions"; + } + + std::string doc() override + { + return + #include "repl.md" + ; + } + + void run(ref store) override + { + evalSettings.pureEval = false; + + auto evalState = make_ref(searchPath, store); + + auto repl = std::make_unique(evalState); + repl->autoArgs = getAutoArgs(*repl->state); + repl->mainLoop(files); + } +}; + +static auto rCmdRepl = registerCommand("repl"); + +} diff --git a/src/nix/repl.cc b/src/nix/repl.cc deleted file mode 100644 index b1f250e73..000000000 --- a/src/nix/repl.cc +++ /dev/null @@ -1,832 +0,0 @@ -#include -#include -#include -#include - -#include - -#ifdef READLINE -#include -#include -#else -// editline < 1.15.2 don't wrap their API for C++ usage -// (added in https://github.com/troglobit/editline/commit/91398ceb3427b730995357e9d120539fb9bb7461). -// This results in linker errors due to to name-mangling of editline C symbols. -// For compatibility with these versions, we wrap the API here -// (wrapping multiple times on newer versions is no problem). -extern "C" { -#include -} -#endif - -#include "ansicolor.hh" -#include "shared.hh" -#include "eval.hh" -#include "eval-inline.hh" -#include "attr-path.hh" -#include "store-api.hh" -#include "common-eval-args.hh" -#include "get-drvs.hh" -#include "derivations.hh" -#include "affinity.hh" -#include "globals.hh" -#include "command.hh" -#include "finally.hh" -#include "markdown.hh" - -#if HAVE_BOEHMGC -#define GC_INCLUDE_NEW -#include -#endif - -namespace nix { - -struct NixRepl - #if HAVE_BOEHMGC - : gc - #endif -{ - string curDir; - ref state; - Bindings * autoArgs; - - Strings loadedFiles; - - const static int envSize = 32768; - StaticEnv staticEnv; - Env * env; - int displ; - StringSet varNames; - - const Path historyFile; - - NixRepl(ref state); - ~NixRepl(); - void mainLoop(const std::vector & files); - StringSet completePrefix(string prefix); - bool getLine(string & input, const std::string &prompt); - StorePath getDerivationPath(Value & v); - bool processLine(string line); - void loadFile(const Path & path); - void initEnv(); - void reloadFiles(); - void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value * v); - Expr * parseString(string s); - void evalString(string s, Value & v); - - typedef set ValuesSeen; - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); -}; - - -string removeWhitespace(string s) -{ - s = chomp(s); - size_t n = s.find_first_not_of(" \n\r\t"); - if (n != string::npos) s = string(s, n); - return s; -} - - -NixRepl::NixRepl(ref state) - : state(state) - , staticEnv(false, &state->staticBaseEnv) - , historyFile(getDataDir() + "/nix/repl-history") -{ - curDir = absPath("."); -} - - -NixRepl::~NixRepl() -{ - write_history(historyFile.c_str()); -} - -static NixRepl * curRepl; // ugly - -static char * completionCallback(char * s, int *match) { - auto possible = curRepl->completePrefix(s); - if (possible.size() == 1) { - *match = 1; - auto *res = strdup(possible.begin()->c_str() + strlen(s)); - if (!res) throw Error("allocation failure"); - return res; - } else if (possible.size() > 1) { - auto checkAllHaveSameAt = [&](size_t pos) { - auto &first = *possible.begin(); - for (auto &p : possible) { - if (p.size() <= pos || p[pos] != first[pos]) - return false; - } - return true; - }; - size_t start = strlen(s); - size_t len = 0; - while (checkAllHaveSameAt(start + len)) ++len; - if (len > 0) { - *match = 1; - auto *res = strdup(std::string(*possible.begin(), start, len).c_str()); - if (!res) throw Error("allocation failure"); - return res; - } - } - - *match = 0; - return nullptr; -} - -static int listPossibleCallback(char *s, char ***avp) { - auto possible = curRepl->completePrefix(s); - - if (possible.size() > (INT_MAX / sizeof(char*))) - throw Error("too many completions"); - - int ac = 0; - char **vp = nullptr; - - auto check = [&](auto *p) { - if (!p) { - if (vp) { - while (--ac >= 0) - free(vp[ac]); - free(vp); - } - throw Error("allocation failure"); - } - return p; - }; - - vp = check((char **)malloc(possible.size() * sizeof(char*))); - - for (auto & p : possible) - vp[ac++] = check(strdup(p.c_str())); - - *avp = vp; - - return ac; -} - -namespace { - // Used to communicate to NixRepl::getLine whether a signal occurred in ::readline. - volatile sig_atomic_t g_signal_received = 0; - - void sigintHandler(int signo) { - g_signal_received = signo; - } -} - -void NixRepl::mainLoop(const std::vector & files) -{ - string error = ANSI_RED "error:" ANSI_NORMAL " "; - std::cout << "Welcome to Nix version " << nixVersion << ". Type :? for help." << std::endl << std::endl; - - if (!files.empty()) { - for (auto & i : files) - loadedFiles.push_back(i); - - reloadFiles(); - if (!loadedFiles.empty()) std::cout << std::endl; - } - - // Allow nix-repl specific settings in .inputrc - rl_readline_name = "nix-repl"; - createDirs(dirOf(historyFile)); -#ifndef READLINE - el_hist_size = 1000; -#endif - read_history(historyFile.c_str()); - curRepl = this; -#ifndef READLINE - rl_set_complete_func(completionCallback); - rl_set_list_possib_func(listPossibleCallback); -#endif - - std::string input; - - while (true) { - // 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> " : " ")) - break; - - try { - if (!removeWhitespace(input).empty() && !processLine(input)) return; - } 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 - // input without clearing the input so far. - continue; - } else { - printMsg(lvlError, e.msg()); - } - } catch (Error & e) { - printMsg(lvlError, e.msg()); - } catch (Interrupted & e) { - printMsg(lvlError, e.msg()); - } - - // We handled the current input fully, so we should clear it - // and read brand new input. - input.clear(); - std::cout << std::endl; - } -} - - -bool NixRepl::getLine(string & input, const std::string &prompt) -{ - struct sigaction act, old; - sigset_t savedSignalMask, set; - - auto setupSignals = [&]() { - act.sa_handler = sigintHandler; - sigfillset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGINT, &act, &old)) - throw SysError("installing handler for SIGINT"); - - sigemptyset(&set); - sigaddset(&set, SIGINT); - if (sigprocmask(SIG_UNBLOCK, &set, &savedSignalMask)) - throw SysError("unblocking SIGINT"); - }; - auto restoreSignals = [&]() { - if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr)) - throw SysError("restoring signals"); - - if (sigaction(SIGINT, &old, 0)) - throw SysError("restoring handler for SIGINT"); - }; - - setupSignals(); - char * s = readline(prompt.c_str()); - Finally doFree([&]() { free(s); }); - restoreSignals(); - - if (g_signal_received) { - g_signal_received = 0; - input.clear(); - return true; - } - - if (!s) - return false; - input += s; - input += '\n'; - return true; -} - - -StringSet NixRepl::completePrefix(string prefix) -{ - StringSet completions; - - size_t start = prefix.find_last_of(" \n\r\t(){}[]"); - std::string prev, cur; - if (start == std::string::npos) { - prev = ""; - cur = prefix; - } else { - prev = std::string(prefix, 0, start + 1); - cur = std::string(prefix, start + 1); - } - - size_t slash, dot; - - if ((slash = cur.rfind('/')) != string::npos) { - try { - auto dir = std::string(cur, 0, slash); - auto prefix2 = std::string(cur, slash + 1); - for (auto & entry : readDirectory(dir == "" ? "/" : dir)) { - if (entry.name[0] != '.' && hasPrefix(entry.name, prefix2)) - completions.insert(prev + dir + "/" + entry.name); - } - } catch (Error &) { - } - } else if ((dot = cur.rfind('.')) == string::npos) { - /* This is a variable name; look it up in the current scope. */ - StringSet::iterator i = varNames.lower_bound(cur); - while (i != varNames.end()) { - if (string(*i, 0, cur.size()) != cur) break; - completions.insert(prev + *i); - i++; - } - } else { - try { - /* This is an expression that should evaluate to an - attribute set. Evaluate it to get the names of the - attributes. */ - string expr(cur, 0, dot); - string cur2 = string(cur, dot + 1); - - Expr * e = parseString(expr); - Value v; - e->eval(*state, *env, v); - state->forceAttrs(v); - - for (auto & i : *v.attrs) { - string name = i.name; - if (string(name, 0, cur2.size()) != cur2) continue; - completions.insert(prev + expr + "." + name); - } - - } catch (ParseError & e) { - // Quietly ignore parse errors. - } catch (EvalError & e) { - // Quietly ignore evaluation errors. - } catch (UndefinedVarError & e) { - // Quietly ignore undefined variable errors. - } - } - - return completions; -} - - -bool isVarName(const string & s) -{ - if (s.size() == 0) return false; - char c = s[0]; - if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false; - for (auto & i : s) - if (!((i >= 'a' && i <= 'z') || - (i >= 'A' && i <= 'Z') || - (i >= '0' && i <= '9') || - i == '_' || i == '-' || i == '\'')) - return false; - return true; -} - - -StorePath NixRepl::getDerivationPath(Value & v) { - auto drvInfo = getDerivation(*state, v, false); - if (!drvInfo) - throw Error("expression does not evaluate to a derivation, so I can't build it"); - Path drvPathRaw = drvInfo->queryDrvPath(); - if (drvPathRaw == "") - throw Error("expression did not evaluate to a valid derivation (no drv path)"); - StorePath drvPath = state->store->parseStorePath(drvPathRaw); - if (!state->store->isValidPath(drvPath)) - throw Error("expression did not evaluate to a valid derivation (invalid drv path)"); - return drvPath; -} - - -bool NixRepl::processLine(string line) -{ - if (line == "") return true; - - string command, arg; - - if (line[0] == ':') { - size_t p = line.find_first_of(" \n\r\t"); - command = string(line, 0, p); - if (p != string::npos) arg = removeWhitespace(string(line, p)); - } else { - arg = line; - } - - if (command == ":?" || command == ":help") { - // FIXME: convert to Markdown, include in the 'nix repl' manpage. - std::cout - << "The following commands are available:\n" - << "\n" - << " Evaluate and print expression\n" - << " = Bind expression to variable\n" - << " :a Add attributes from resulting set to scope\n" - << " :b Build derivation\n" - << " :e Open the derivation in $EDITOR\n" - << " :i Build derivation, then install result into current profile\n" - << " :l Load Nix expression and add it to scope\n" - << " :p Evaluate and print expression recursively\n" - << " :q Exit nix-repl\n" - << " :r Reload all files\n" - << " :s Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n" - << " :u Build derivation, then start nix-shell\n" - << " :doc Show documentation of a builtin function\n"; - } - - else if (command == ":a" || command == ":add") { - Value v; - evalString(arg, v); - addAttrsToScope(v); - } - - else if (command == ":l" || command == ":load") { - state->resetFileCache(); - loadFile(arg); - } - - else if (command == ":r" || command == ":reload") { - state->resetFileCache(); - reloadFiles(); - } - - else if (command == ":e" || command == ":edit") { - Value v; - evalString(arg, v); - - Pos pos; - - if (v.type() == nPath || v.type() == nString) { - PathSet context; - auto filename = state->coerceToString(noPos, v, context); - pos.file = state->symbols.create(filename); - } else if (v.isLambda()) { - pos = v.lambda.fun->pos; - } else { - // assume it's a derivation - pos = findDerivationFilename(*state, v, arg); - } - - // Open in EDITOR - auto args = editorFor(pos); - auto editor = args.front(); - args.pop_front(); - runProgram(editor, true, args); - - // Reload right after exiting the editor - state->resetFileCache(); - reloadFiles(); - } - - else if (command == ":t") { - Value v; - evalString(arg, v); - std::cout << showType(v) << std::endl; - - } else if (command == ":u") { - Value v, f, result; - evalString(arg, v); - evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); - state->callFunction(f, v, result, Pos()); - - StorePath drvPath = getDerivationPath(result); - runProgram(settings.nixBinDir + "/nix-shell", true, {state->store->printStorePath(drvPath)}); - } - - else if (command == ":b" || command == ":i" || command == ":s") { - Value v; - evalString(arg, v); - StorePath drvPath = getDerivationPath(v); - Path drvPathRaw = state->store->printStorePath(drvPath); - - if (command == ":b") { - /* We could do the build in this process using buildPaths(), - but doing it in a child makes it easier to recover from - problems / SIGINT. */ - try { - runProgram(settings.nixBinDir + "/nix", true, {"build", "--no-link", drvPathRaw}); - auto drv = state->store->readDerivation(drvPath); - std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; - for (auto & i : drv.outputsAndOptPaths(*state->store)) - std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(*i.second.second)); - } catch (ExecError &) { - } - } else if (command == ":i") { - runProgram(settings.nixBinDir + "/nix-env", true, {"-i", drvPathRaw}); - } else { - runProgram(settings.nixBinDir + "/nix-shell", true, {drvPathRaw}); - } - } - - else if (command == ":p" || command == ":print") { - Value v; - evalString(arg, v); - printValue(std::cout, v, 1000000000) << std::endl; - } - - else if (command == ":q" || command == ":quit") - return false; - - else if (command == ":doc") { - Value v; - evalString(arg, v); - if (auto doc = state->getDoc(v)) { - std::string markdown; - - if (!doc->args.empty() && doc->name) { - auto args = doc->args; - for (auto & arg : args) - arg = "*" + arg + "*"; - - markdown += - "**Synopsis:** `builtins." + (std::string) (*doc->name) + "` " - + concatStringsSep(" ", args) + "\n\n"; - } - - markdown += trim(stripIndentation(doc->doc)); - - std::cout << renderMarkdownToTerminal(markdown); - } else - throw Error("value does not have documentation"); - } - - else if (command != "") - throw Error("unknown command '%1%'", command); - - else { - size_t p = line.find('='); - string name; - if (p != string::npos && - p < line.size() && - line[p + 1] != '=' && - isVarName(name = removeWhitespace(string(line, 0, p)))) - { - Expr * e = parseString(string(line, p + 1)); - Value *v = new Value(*state->allocValue()); - v->mkThunk(env, e); - addVarToScope(state->symbols.create(name), v); - } else { - Value v; - evalString(line, v); - printValue(std::cout, v, 1) << std::endl; - } - } - - return true; -} - - -void NixRepl::loadFile(const Path & path) -{ - loadedFiles.remove(path); - loadedFiles.push_back(path); - Value v, v2; - state->evalFile(lookupFileArg(*state, path), v); - state->autoCallFunction(*autoArgs, v, v2); - addAttrsToScope(v2); -} - - -void NixRepl::initEnv() -{ - env = &state->allocEnv(envSize); - env->up = &state->baseEnv; - displ = 0; - staticEnv.vars.clear(); - - varNames.clear(); - for (auto & i : state->staticBaseEnv.vars) - varNames.insert(i.first); -} - - -void NixRepl::reloadFiles() -{ - initEnv(); - - Strings old = loadedFiles; - loadedFiles.clear(); - - bool first = true; - for (auto & i : old) { - if (!first) std::cout << std::endl; - first = false; - std::cout << format("Loading '%1%'...") % i << std::endl; - loadFile(i); - } -} - - -void NixRepl::addAttrsToScope(Value & attrs) -{ - state->forceAttrs(attrs); - for (auto & i : *attrs.attrs) - addVarToScope(i.name, i.value); - std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; -} - - -void NixRepl::addVarToScope(const Symbol & name, Value * v) -{ - if (displ >= envSize) - throw Error("environment full; cannot add more variables"); - staticEnv.vars[name] = displ; - env->values[displ++] = v; - varNames.insert((string) name); -} - - -Expr * NixRepl::parseString(string s) -{ - Expr * e = state->parseExprFromString(s, curDir, staticEnv); - return e; -} - - -void NixRepl::evalString(string s, Value & v) -{ - Expr * e = parseString(s); - e->eval(*state, *env, v); - state->forceValue(v); -} - - -std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) -{ - ValuesSeen seen; - return printValue(str, v, maxDepth, seen); -} - - -std::ostream & printStringValue(std::ostream & str, const char * string) { - str << "\""; - for (const char * i = string; *i; i++) - if (*i == '\"' || *i == '\\') str << "\\" << *i; - else if (*i == '\n') str << "\\n"; - else if (*i == '\r') str << "\\r"; - else if (*i == '\t') str << "\\t"; - else str << *i; - str << "\""; - return str; -} - - -// FIXME: lot of cut&paste from Nix's eval.cc. -std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen) -{ - str.flush(); - checkInterrupt(); - - state->forceValue(v); - - switch (v.type()) { - - case nInt: - str << ANSI_CYAN << v.integer << ANSI_NORMAL; - break; - - case nBool: - str << ANSI_CYAN << (v.boolean ? "true" : "false") << ANSI_NORMAL; - break; - - case nString: - str << ANSI_YELLOW; - printStringValue(str, v.string.s); - str << ANSI_NORMAL; - break; - - case nPath: - str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping? - break; - - case nNull: - str << ANSI_CYAN "null" ANSI_NORMAL; - break; - - case nAttrs: { - seen.insert(&v); - - bool isDrv = state->isDerivation(v); - - if (isDrv) { - str << "«derivation "; - Bindings::iterator i = v.attrs->find(state->sDrvPath); - PathSet context; - Path drvPath = i != v.attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "???"; - str << drvPath << "»"; - } - - else if (maxDepth > 0) { - str << "{ "; - - typedef std::map Sorted; - Sorted sorted; - for (auto & i : *v.attrs) - sorted[i.name] = i.value; - - for (auto & i : sorted) { - if (isVarName(i.first)) - str << i.first; - else - printStringValue(str, i.first.c_str()); - str << " = "; - if (seen.find(i.second) != seen.end()) - str << "«repeated»"; - else - try { - printValue(str, *i.second, maxDepth - 1, seen); - } catch (AssertionError & e) { - str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL; - } - str << "; "; - } - - str << "}"; - } else - str << "{ ... }"; - - break; - } - - case nList: - seen.insert(&v); - - str << "[ "; - if (maxDepth > 0) - for (unsigned int n = 0; n < v.listSize(); ++n) { - if (seen.find(v.listElems()[n]) != seen.end()) - str << "«repeated»"; - else - try { - printValue(str, *v.listElems()[n], maxDepth - 1, seen); - } catch (AssertionError & e) { - str << ANSI_RED "«error: " << e.msg() << "»" ANSI_NORMAL; - } - str << " "; - } - else - str << "... "; - str << "]"; - break; - - case nFunction: - if (v.isLambda()) { - std::ostringstream s; - s << v.lambda.fun->pos; - str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; - } else if (v.isPrimOp()) { - str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; - } else if (v.isPrimOpApp()) { - str << ANSI_BLUE "«primop-app»" ANSI_NORMAL; - } else { - abort(); - } - break; - - case nFloat: - str << v.fpoint; - break; - - default: - str << ANSI_RED "«unknown»" ANSI_NORMAL; - break; - } - - return str; -} - -void runRepl( - ref evalState, - const std::map & extraEnv) -{ - auto repl = std::make_unique(evalState); - - repl->initEnv(); - - std::set names; - - for (auto & [name, value] : extraEnv) { - names.insert(ANSI_BOLD + name + ANSI_NORMAL); - repl->addVarToScope(repl->state->symbols.create(name), value); - } - - printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); - - repl->mainLoop({}); -} - -struct CmdRepl : StoreCommand, MixEvalArgs -{ - std::vector files; - - CmdRepl() - { - expectArgs({ - .label = "files", - .handler = {&files}, - .completer = completePath - }); - } - - std::string description() override - { - return "start an interactive environment for evaluating Nix expressions"; - } - - std::string doc() override - { - return - #include "repl.md" - ; - } - - void run(ref store) override - { - evalSettings.pureEval = false; - - auto evalState = make_ref(searchPath, store); - - auto repl = std::make_unique(evalState); - repl->autoArgs = getAutoArgs(*repl->state); - repl->mainLoop(files); - } -}; - -static auto rCmdRepl = registerCommand("repl"); - -} -- cgit v1.2.3 From 2dd61411af903e374566e0cf5d06257ad240662e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 3 May 2021 14:37:33 -0600 Subject: debugger on autoCallFunction error --- src/libcmd/command.cc | 16 ++++++++++------ src/libexpr/eval.cc | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index d790bb51d..51a071d25 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -79,24 +79,28 @@ ref EvalCommand::getEvalState() return ref(evalState); } */ +// ref EvalCommand::getEvalState() +// { +// if (!evalState) +// evalState = std::make_shared(searchPath, getStore()); +// return ref(evalState); +// } + + EvalCommand::EvalCommand() { + // std::cout << "EvalCommand::EvalCommand()" << std::endl; addFlag({ .longName = "debugger", .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); } -// ref EvalCommand::getEvalState() -// { -// if (!evalState) -// evalState = std::make_shared(searchPath, getStore()); -// return ref(evalState); -// } extern std::function & env)> debuggerHook; ref EvalCommand::getEvalState() { + std::cout << " EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; if (!evalState) { evalState = std::make_shared(searchPath, getStore()); if (startReplOnEvalErrors) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 37fb6ed18..51feef923 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1398,12 +1398,28 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) if (j != args.end()) { actualArgs->attrs->push_back(*j); } else if (!i.def) { - throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%') + auto error = MissingArgumentError({ + .msg = hintfmt(R"(cannot evaluate a function that has an argument without a value ('%1%') Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", i.name); +https://nixos.org/manual/nix/stable/#ss-functions.)", i.name), + .errPos = i.pos + }); + +// throwMissingArgumentError(i.pos +// , R"(cannot evaluate a function that has an argument without a value ('%1%') + +// Nix attempted to evaluate a function as a top level expression; in +// this case it must have its arguments supplied either by default +// values, or passed explicitly with '--arg' or '--argstr'. See +// https://nixos.org/manual/nix/stable/#ss-functions.)", i.name); + + if (debuggerHook) + debuggerHook(error, {{"fun", &fun}}); + + throw error; } } -- cgit v1.2.3 From a8fef9a6b10c34e450d4251f7e9808c906e2f488 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 10 May 2021 18:36:57 -0600 Subject: throwTypeError with debugger/env --- src/libexpr/eval.cc | 123 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 51feef923..a48c38e0d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -35,6 +36,7 @@ namespace nix { +std::function & env)> debuggerHook; static char * dupString(const char * s) { @@ -615,7 +617,6 @@ std::optional EvalState::getDoc(Value & v) return {}; } - /* 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 @@ -656,22 +657,46 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s)) +// #define valmap(x) std::optional> + +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const std::optional> & env)) { - throw TypeError({ + auto error = TypeError({ .msg = hintfmt(s), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, const std::optional> & env)) { - throw TypeError({ + auto error = TypeError({ + .msg = hintfmt(s, v), + .errPos = pos + }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; +} + +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, const std::optional> & env)) +{ + auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } + + LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1)) { throw AssertionError({ @@ -688,12 +713,16 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, const std::optional> & env)) { - throw MissingArgumentError({ + auto error = MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInline(void addErrorTrace(Error & e, const char * s, const string & s2)) @@ -1246,7 +1275,6 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) } } -std::function & env)> debuggerHook; void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos) { @@ -1276,14 +1304,20 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po } if (!fun.isLambda()) { - auto error = TypeError({ - // .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), - .msg = hintfmt("attempt to call something which is not a function but %1%", fun), - .errPos = pos - }); - if (debuggerHook) - debuggerHook(error, {{"fun", &fun}, {"arg", &arg}}); - throw error; + throwTypeError( + pos, + "attempt to call something which is not a function but %1%", + fun, + std::optional>({{"fun", &fun}, {"arg", &arg}})); + + // auto error = TypeError({ + // // .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), + // .msg = hintfmt("attempt to call something which is not a function but %1%", fun), + // .errPos = pos + // }); + // if (debuggerHook) + // debuggerHook(error, {{"fun", &fun}, {"arg", &arg}}); + // throw error; } ExprLambda & lambda(*fun.lambda.fun); @@ -1312,8 +1346,13 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po for (auto & i : lambda.formals->formals) { Bindings::iterator j = arg.attrs->find(i.name); if (j == arg.attrs->end()) { - if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'", - lambda, i.name); + if (!i.def) + throwTypeError( + pos, + "%1% called without required argument '%2%'", + lambda, + i.name, + std::optional>({{"fun", &fun}, {"arg", &arg}})); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1328,7 +1367,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po user. */ for (auto & i : *arg.attrs) if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end()) - throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name); + throwTypeError(pos, + "%1% called with unexpected argument '%2%'", + lambda, + i.name, + std::optional>({{"fun", &fun}, {"arg", &arg}})); abort(); // can't happen } } @@ -1398,16 +1441,14 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) if (j != args.end()) { actualArgs->attrs->push_back(*j); } else if (!i.def) { - auto error = MissingArgumentError({ - .msg = hintfmt(R"(cannot evaluate a function that has an argument without a value ('%1%') + throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%') Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", i.name), - .errPos = i.pos - }); - +https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, + std::optional>({{"fun", &fun}})); // todo add bindings. + // throwMissingArgumentError(i.pos // , R"(cannot evaluate a function that has an argument without a value ('%1%') @@ -1416,10 +1457,11 @@ https://nixos.org/manual/nix/stable/#ss-functions.)", i.name), // values, or passed explicitly with '--arg' or '--argstr'. See // https://nixos.org/manual/nix/stable/#ss-functions.)", i.name); - if (debuggerHook) - debuggerHook(error, {{"fun", &fun}}); + // if (debuggerHook) + // // debuggerHook(error, args); + // debuggerHook(error, {{"fun", &fun}}); - throw error; + // throw error; } } @@ -1673,7 +1715,8 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nInt) - throwTypeError(pos, "value is %1% while an integer was expected", v); + throwTypeError(pos, "value is %1% while an integer was expected", v, + std::optional>({{"value", &v}})); return v.integer; } @@ -1684,7 +1727,8 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) if (v.type() == nInt) return v.integer; else if (v.type() != nFloat) - throwTypeError(pos, "value is %1% while a float was expected", v); + throwTypeError(pos, "value is %1% while a float was expected", v, + std::optional>({{"value", &v}})); return v.fpoint; } @@ -1693,7 +1737,8 @@ bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v); + throwTypeError(pos, "value is %1% while a Boolean was expected", v, + std::optional>({{"value", &v}})); return v.boolean; } @@ -1708,7 +1753,8 @@ void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) - throwTypeError(pos, "value is %1% while a function was expected", v); + throwTypeError(pos, "value is %1% while a function was expected", v, + std::optional>({{"value", &v}})); } @@ -1716,10 +1762,8 @@ string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nString) { - if (pos) - throwTypeError(pos, "value is %1% while a string was expected", v); - else - throwTypeError("value is %1% while a string was expected", v); + throwTypeError(pos, "value is %1% while a string was expected", v, + std::optional>({{"value", &v}})); } return string(v.string.s); } @@ -1826,7 +1870,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, return *maybeString; } auto i = v.attrs->find(sOutPath); - if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string"); + if (i == v.attrs->end()) + throwTypeError(pos, "cannot coerce a set to a string", + std::optional>({{"value", &v}})); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -1857,7 +1903,8 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } } - throwTypeError(pos, "cannot coerce %1% to a string", v); + throwTypeError(pos, "cannot coerce %1% to a string", v, + std::optional>({{"value", &v}})); } -- cgit v1.2.3 From e7847ad7a1268bbe6962a36a29b044ee841f1874 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 11 May 2021 15:38:49 -0600 Subject: map1/2 for stack usage --- src/libexpr/eval.cc | 56 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index a48c38e0d..f8391cd77 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -617,6 +616,19 @@ std::optional EvalState::getDoc(Value & v) return {}; } +static std::optional> map1(const char *name, Value *v) __attribute__((noinline)); +std::optional> map1(const char *name, Value *v) +{ + return std::optional>({{name, v}}); +} + + +static std::optional> map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); +std::optional> map2(const char *name1, Value *v1, const char *name2, Value *v2) +{ + return std::optional>({{name1, v1},{name2, v2}}); +} + /* 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 @@ -657,8 +669,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); } -// #define valmap(x) std::optional> - LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const std::optional> & env)) { auto error = TypeError({ @@ -1308,7 +1318,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po pos, "attempt to call something which is not a function but %1%", fun, - std::optional>({{"fun", &fun}, {"arg", &arg}})); + map2("fun", &fun, "arg", &arg)); // auto error = TypeError({ // // .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), @@ -1352,7 +1362,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - std::optional>({{"fun", &fun}, {"arg", &arg}})); + map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1371,7 +1381,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called with unexpected argument '%2%'", lambda, i.name, - std::optional>({{"fun", &fun}, {"arg", &arg}})); + map2("fun", &fun, "arg", &arg)); abort(); // can't happen } } @@ -1446,23 +1456,9 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - std::optional>({{"fun", &fun}})); // todo add bindings. - -// throwMissingArgumentError(i.pos -// , R"(cannot evaluate a function that has an argument without a value ('%1%') - -// Nix attempted to evaluate a function as a top level expression; in -// this case it must have its arguments supplied either by default -// values, or passed explicitly with '--arg' or '--argstr'. See -// https://nixos.org/manual/nix/stable/#ss-functions.)", i.name); - - // if (debuggerHook) - // // debuggerHook(error, args); - // debuggerHook(error, {{"fun", &fun}}); - - // throw error; - +https://nixos.org/manual/nix/stable/#ss-functions.)", + i.name, + map1("fun", &fun)); // todo add bindings. } } } @@ -1716,7 +1712,7 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v, - std::optional>({{"value", &v}})); + map1("value", &v)); return v.integer; } @@ -1728,7 +1724,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) return v.integer; else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v, - std::optional>({{"value", &v}})); + map1("value", &v)); return v.fpoint; } @@ -1738,7 +1734,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v, - std::optional>({{"value", &v}})); + map1("value", &v)); return v.boolean; } @@ -1754,7 +1750,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v, - std::optional>({{"value", &v}})); + map1("value", &v)); } @@ -1763,7 +1759,7 @@ string EvalState::forceString(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nString) { throwTypeError(pos, "value is %1% while a string was expected", v, - std::optional>({{"value", &v}})); + map1("value", &v)); } return string(v.string.s); } @@ -1872,7 +1868,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string", - std::optional>({{"value", &v}})); + map1("value", &v)); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -1904,7 +1900,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } throwTypeError(pos, "cannot coerce %1% to a string", v, - std::optional>({{"value", &v}})); + map1("value", &v)); } -- cgit v1.2.3 From 0c2265da85bd094376279aea5e282974784218b3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 12 May 2021 09:43:58 -0600 Subject: unique_ptr for valmap --- src/libexpr/eval.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f8391cd77..531e3f752 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -616,17 +616,21 @@ std::optional EvalState::getDoc(Value & v) return {}; } -static std::optional> map1(const char *name, Value *v) __attribute__((noinline)); -std::optional> map1(const char *name, Value *v) +// typedef std::optional> valmap; +typedef const std::map valmap; + +static std::unique_ptr map1(const char *name, Value *v) __attribute__((noinline)); +std::unique_ptr map1(const char *name, Value *v) { - return std::optional>({{name, v}}); + // return new valmap({{name, v}}); + return std::unique_ptr(new valmap({{name, v}})); } -static std::optional> map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); -std::optional> map2(const char *name1, Value *v1, const char *name2, Value *v2) +static std::unique_ptr map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); +std::unique_ptr map2(const char *name1, Value *v1, const char *name2, Value *v2) { - return std::optional>({{name1, v1},{name2, v2}}); + return std::unique_ptr(new valmap({{name1, v1}, {name2, v2}})); } /* Every "format" object (even temporary) takes up a few hundred bytes @@ -669,7 +673,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const std::optional> & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, std::unique_ptr env)) { auto error = TypeError({ .msg = hintfmt(s), @@ -681,7 +685,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, const std::optional> & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, std::unique_ptr env)) { auto error = TypeError({ .msg = hintfmt(s, v), @@ -693,7 +697,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, const std::optional> & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, std::unique_ptr env)) { auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), @@ -723,7 +727,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, const std::optional> & env)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, std::unique_ptr env)) { auto error = MissingArgumentError({ .msg = hintfmt(s, s1), -- cgit v1.2.3 From 459bccc750616f07c9d55d6c12211e07c2369f1a Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 12 May 2021 11:33:31 -0600 Subject: plain env pointer --- src/libexpr/eval.cc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 531e3f752..3f73c24a1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -619,18 +619,18 @@ std::optional EvalState::getDoc(Value & v) // typedef std::optional> valmap; typedef const std::map valmap; -static std::unique_ptr map1(const char *name, Value *v) __attribute__((noinline)); -std::unique_ptr map1(const char *name, Value *v) +static valmap* map1(const char *name, Value *v) __attribute__((noinline)); +valmap* map1(const char *name, Value *v) { // return new valmap({{name, v}}); - return std::unique_ptr(new valmap({{name, v}})); + return new valmap({{name, v}}); } -static std::unique_ptr map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); -std::unique_ptr map2(const char *name1, Value *v1, const char *name2, Value *v2) +static valmap* map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); +valmap* map2(const char *name1, Value *v1, const char *name2, Value *v2) { - return std::unique_ptr(new valmap({{name1, v1}, {name2, v2}})); + return new valmap({{name1, v1}, {name2, v2}}); } /* Every "format" object (even temporary) takes up a few hundred bytes @@ -673,8 +673,9 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, std::unique_ptr env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valmap* env)) { + auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s), .errPos = pos @@ -685,8 +686,9 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, std:: throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, std::unique_ptr env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, valmap* env)) { + auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos @@ -697,8 +699,9 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, std::unique_ptr env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, valmap* env)) { + auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), .errPos = pos @@ -727,7 +730,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, std::unique_ptr env)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, valmap* env)) { auto error = MissingArgumentError({ .msg = hintfmt(s, s1), -- cgit v1.2.3 From ab19d1685dd67a19c91eb3af346b9ac86f34b7d1 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 13 May 2021 16:00:48 -0600 Subject: throwEvalError; mapBindings --- src/libexpr/eval.cc | 79 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3f73c24a1..29b2721fe 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -617,20 +617,43 @@ std::optional EvalState::getDoc(Value & v) } // typedef std::optional> valmap; -typedef const std::map valmap; +typedef std::map valmap; -static valmap* map1(const char *name, Value *v) __attribute__((noinline)); -valmap* map1(const char *name, Value *v) +static valmap * map0() __attribute__((noinline)); +valmap * map0() { - // return new valmap({{name, v}}); - return new valmap({{name, v}}); + return new valmap(); +} + +static valmap * map1(const char *name, Value *v) __attribute__((noinline)); +valmap * map1(const char *name, Value *v) +{ + // return new valmap({{name, v}}); + return new valmap({{name, v}}); } -static valmap* map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); -valmap* map2(const char *name1, Value *v1, const char *name2, Value *v2) +static valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); +valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2) { - return new valmap({{name1, v1}, {name2, v2}}); + return new valmap({{name1, v1}, {name2, v2}}); +} + +static valmap * mapBindings(Bindings *b) __attribute__((noinline)); +valmap * mapBindings(Bindings *b) +{ + auto map = new valmap(); + + // auto v = new Value; + + for (auto i = b->begin(); i != b->end(); ++i) + { + std::string s = i->name; + (*map)[s] = i->value; + // map->insert({std::string("wat"), v}); + } + + return map; } /* Every "format" object (even temporary) takes up a few hundred bytes @@ -638,17 +661,27 @@ valmap* map2(const char *name1, Value *v1, const char *name2, Value *v2) evaluator. So here are some helper functions for throwing exceptions. */ -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, valmap * env)) { - throw EvalError(s, s2); + auto delenv = std::unique_ptr(env); + auto error = EvalError(s, s2); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, valmap * env)) { - throw EvalError({ + auto delenv = std::unique_ptr(env); + auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3)) @@ -673,7 +706,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valmap* env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valmap * env)) { auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -686,7 +719,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valma throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, valmap* env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, valmap * env)) { auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -699,7 +732,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, valmap* env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, valmap * env)) { auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -730,7 +763,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, valmap* env)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, valmap * env)) { auto error = MissingArgumentError({ .msg = hintfmt(s, s1), @@ -1198,7 +1231,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } else { state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError(pos, "attribute '%1%' missing", name); + throwEvalError(pos, "attribute '%1%' missing", name, mapBindings(vAttrs->attrs)); } vAttrs = j->value; pos2 = j->pos; @@ -1463,7 +1496,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", +https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, map1("fun", &fun)); // todo add bindings. } @@ -1651,14 +1684,14 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) nf = n; nf += vTmp.fpoint; } else - throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp)); + throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), map0()); } else if (firstType == nFloat) { if (vTmp.type() == nInt) { nf += vTmp.integer; } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else - throwEvalError(pos, "cannot add %1% to a float", showType(vTmp)); + throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), map0()); } else s << state.coerceToString(pos, vTmp, context, false, firstType == nString); } @@ -1914,7 +1947,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) - throwEvalError("file names are not allowed to end in '%1%'", drvExtension); + throwEvalError("file names are not allowed to end in '%1%'", + drvExtension, + map0()); Path dstPath; auto i = srcToStore.find(path); @@ -1938,7 +1973,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) { string path = coerceToString(pos, v, context, false, false); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, map1("value", &v)); return path; } -- cgit v1.2.3 From 989a4181a8f3fb830bae5018c18a13dc535b395a Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 11:06:20 -0600 Subject: throwEvalError form 2 --- src/libexpr/eval.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 29b2721fe..1ae88ea1f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -684,9 +684,14 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, valmap * env)) { - throw EvalError(s, s2, s3); + auto delenv = std::unique_ptr(env); + auto error = EvalError(s, s2, s3); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3)) @@ -1498,7 +1503,7 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - map1("fun", &fun)); // todo add bindings. + map1("fun", &fun)); // todo add bindings + fun } } } @@ -1850,10 +1855,10 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0]); + v.string.s, v.string.context[0]); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0]); + v.string.s, v.string.context[0], map1("value", &v)); } return s; } @@ -2052,7 +2057,8 @@ bool EvalState::eqValues(Value & v1, Value & v2) return v1.fpoint == v2.fpoint; default: - throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2)); + throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), + map2("value1", &v1, "value2", &v2)); } } -- cgit v1.2.3 From ed74eaa07f6f7b5e87a1b96eff94990551ff488e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 11:09:18 -0600 Subject: throwEvalError form 3 --- src/libexpr/eval.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 1ae88ea1f..592f89fdf 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -694,12 +694,17 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, valmap * env)) { - throw EvalError({ + auto delenv = std::unique_ptr(env); + auto error = EvalError({ .msg = hintfmt(s, s2, s3), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2)) @@ -1855,7 +1860,7 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0]); + v.string.s, v.string.context[0], map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], map1("value", &v)); -- cgit v1.2.3 From d041dd874eddef8e56822ecb0806ad53db1fdacc Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 11:15:24 -0600 Subject: throwEvalError form 4 --- src/libexpr/eval.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 592f89fdf..8c96b6ba2 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -707,13 +707,18 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, valmap * env)) { // p1 is where the error occurred; p2 is a position mentioned in the message. - throw EvalError({ + auto delenv = std::unique_ptr(env); + auto error = EvalError({ .msg = hintfmt(s, sym, p2), .errPos = p1 }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valmap * env)) @@ -1151,7 +1156,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Symbol nameSym = state.symbols.create(nameVal.string.s); Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) - throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos); + throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, + map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ -- cgit v1.2.3 From 17af7dc3260216aa279a1bb6f506b537aaef7bc3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 11:29:26 -0600 Subject: throwAssertionError, throwUndefinedError -> valmap-ized --- src/libexpr/eval.cc | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 8c96b6ba2..671b07dcd 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -760,26 +760,35 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } - - -LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1)) +LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, valmap * env)) { - throw AssertionError({ + auto delenv = std::unique_ptr(env); + auto error = AssertionError({ .msg = hintfmt(s, s1), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } -LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1)) +LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, valmap * env)) { - throw UndefinedVarError({ + auto delenv = std::unique_ptr(env); + auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; } LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, valmap * env)) { + auto delenv = std::unique_ptr(env); auto error = MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = pos @@ -848,7 +857,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, map0()); // TODO: env.attrs? for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1548,7 +1557,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) if (!state.evalBool(env, cond, pos)) { std::ostringstream out; cond->show(out); - throwAssertionError(pos, "assertion '%1%' failed", out.str()); + throwAssertionError(pos, "assertion '%1%' failed", out.str(), map0()); } body->eval(state, env, v); } -- cgit v1.2.3 From 644567cf7ea810f86bd8e0328567b39c4757bc14 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 13:40:00 -0600 Subject: clean up w LocalNoInline macro --- src/libexpr/eval.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 671b07dcd..897444360 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -619,28 +619,24 @@ std::optional EvalState::getDoc(Value & v) // typedef std::optional> valmap; typedef std::map valmap; -static valmap * map0() __attribute__((noinline)); -valmap * map0() +LocalNoInline(valmap * map0()) { return new valmap(); } -static valmap * map1(const char *name, Value *v) __attribute__((noinline)); -valmap * map1(const char *name, Value *v) +LocalNoInline(valmap * map1(const char *name, Value *v)) { // return new valmap({{name, v}}); return new valmap({{name, v}}); } -static valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2) __attribute__((noinline)); -valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2) +LocalNoInline(valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2)) { return new valmap({{name1, v1}, {name2, v2}}); } -static valmap * mapBindings(Bindings *b) __attribute__((noinline)); -valmap * mapBindings(Bindings *b) +LocalNoInline(valmap * mapBindings(Bindings *b)) { auto map = new valmap(); -- cgit v1.2.3 From 99304334caa833b32712ad02e04f1a0e9c8322fe Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 14 May 2021 18:09:30 -0600 Subject: showType(fun) --- src/libexpr/eval.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 897444360..9bb43f522 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1378,17 +1378,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po throwTypeError( pos, "attempt to call something which is not a function but %1%", - fun, + showType(fun), map2("fun", &fun, "arg", &arg)); - - // auto error = TypeError({ - // // .hint = hintfmt("attempt to call something which is not a function but %1%", showType(fun)), - // .msg = hintfmt("attempt to call something which is not a function but %1%", fun), - // .errPos = pos - // }); - // if (debuggerHook) - // debuggerHook(error, {{"fun", &fun}, {"arg", &arg}}); - // throw error; } ExprLambda & lambda(*fun.lambda.fun); -- cgit v1.2.3 From ff2e72054f741f51c07e737d82c8eff920342488 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 8 Jun 2021 14:44:41 -0600 Subject: another throwTypeError form --- src/libexpr/eval.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 9bb43f522..f296550d0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -743,6 +743,19 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const char * t, valmap * env)) +{ + auto delenv = std::unique_ptr(env); + auto error = TypeError({ + .msg = hintfmt(s, t), + .errPos = pos + }); + + if (debuggerHook) + debuggerHook(error, *env); + throw error; +} + LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, valmap * env)) { auto delenv = std::unique_ptr(env); @@ -1378,7 +1391,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po throwTypeError( pos, "attempt to call something which is not a function but %1%", - showType(fun), + showType(fun).c_str(), map2("fun", &fun, "arg", &arg)); } -- cgit v1.2.3 From a8df23975293a9c0b4d7a55b46d0047f955e0f1c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 8 Jun 2021 14:44:53 -0600 Subject: highlight the extra vars --- src/libcmd/repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index b1f250e73..29be71e13 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -785,7 +785,7 @@ void runRepl( repl->addVarToScope(repl->state->symbols.create(name), value); } - printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); + printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); repl->mainLoop({}); } -- cgit v1.2.3 From ebf530d31ecc2e01238737be8cf41c9d80962c99 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 8 Jun 2021 18:17:58 -0600 Subject: line endings --- src/libexpr/eval.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f296550d0..cef0f0bc3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -642,9 +642,9 @@ LocalNoInline(valmap * mapBindings(Bindings *b)) // auto v = new Value; - for (auto i = b->begin(); i != b->end(); ++i) + for (auto i = b->begin(); i != b->end(); ++i) { - std::string s = i->name; + std::string s = i->name; (*map)[s] = i->value; // map->insert({std::string("wat"), v}); } @@ -1174,7 +1174,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Symbol nameSym = state.symbols.create(nameVal.string.s); Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) - throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, + throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); @@ -2077,7 +2077,7 @@ bool EvalState::eqValues(Value & v1, Value & v2) return v1.fpoint == v2.fpoint; default: - throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), + throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), map2("value1", &v1, "value2", &v2)); } } -- cgit v1.2.3 From 93ca9381dac7b95cdab005e653f3051c74968d51 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 8 Jun 2021 18:37:28 -0600 Subject: formatting; string arg for throwTypeError --- src/libexpr/eval.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index cef0f0bc3..85bff6ee5 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -743,11 +743,11 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const char * t, valmap * env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, valmap * env)) { auto delenv = std::unique_ptr(env); auto error = TypeError({ - .msg = hintfmt(s, t), + .msg = hintfmt(s, s2), .errPos = pos }); @@ -1516,7 +1516,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) if (j != args.end()) { actualArgs->attrs->push_back(*j); } else if (!i.def) { - throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%') + throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%') Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default @@ -1965,7 +1965,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } throwTypeError(pos, "cannot coerce %1% to a string", v, - map1("value", &v)); + map1("value", &v)); } @@ -2077,8 +2077,10 @@ bool EvalState::eqValues(Value & v1, Value & v2) return v1.fpoint == v2.fpoint; default: - throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), - map2("value1", &v1, "value2", &v2)); + throwEvalError("cannot compare %1% with %2%", + showType(v1), + showType(v2), + map2("value1", &v1, "value2", &v2)); } } -- cgit v1.2.3 From d22de1dd0c060971cb2cbeb9e49cae84c8d395cb Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 9 Jun 2021 15:38:08 -0600 Subject: remove dead code --- src/libexpr/eval.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 85bff6ee5..f8fe0f309 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -616,7 +616,6 @@ std::optional EvalState::getDoc(Value & v) return {}; } -// typedef std::optional> valmap; typedef std::map valmap; LocalNoInline(valmap * map0()) @@ -626,7 +625,6 @@ LocalNoInline(valmap * map0()) LocalNoInline(valmap * map1(const char *name, Value *v)) { - // return new valmap({{name, v}}); return new valmap({{name, v}}); } @@ -640,13 +638,10 @@ LocalNoInline(valmap * mapBindings(Bindings *b)) { auto map = new valmap(); - // auto v = new Value; - for (auto i = b->begin(); i != b->end(); ++i) { std::string s = i->name; (*map)[s] = i->value; - // map->insert({std::string("wat"), v}); } return map; @@ -866,7 +861,8 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, map0()); // TODO: env.attrs? + // TODO: env.attrs? + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, map0()); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } -- cgit v1.2.3 From 129dd760e63d1be33e99d847e759d8a1e4c2dee7 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 11 Jun 2021 18:55:15 -0600 Subject: mapEnvBindings --- src/libexpr/eval.cc | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f8fe0f309..6dcdbb2bd 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -618,6 +618,15 @@ std::optional EvalState::getDoc(Value & v) typedef std::map valmap; +/*void addEnv(Value * v, valmap &vmap) +{ + if (v.isThunk()) { + Env * env = v.thunk.env; + + Expr * expr = v.thunk.expr; + +} +*/ LocalNoInline(valmap * map0()) { return new valmap(); @@ -628,17 +637,16 @@ LocalNoInline(valmap * map1(const char *name, Value *v)) return new valmap({{name, v}}); } - LocalNoInline(valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2)) { return new valmap({{name1, v1}, {name2, v2}}); } -LocalNoInline(valmap * mapBindings(Bindings *b)) +LocalNoInline(valmap * mapBindings(Bindings &b)) { auto map = new valmap(); - for (auto i = b->begin(); i != b->end(); ++i) + for (auto i = b.begin(); i != b.end(); ++i) { std::string s = i->name; (*map)[s] = i->value; @@ -647,6 +655,15 @@ LocalNoInline(valmap * mapBindings(Bindings *b)) return map; } +LocalNoInline(valmap * mapEnvBindings(Env &env)) +{ + if (env.values[0]->type() == nAttrs) { + return mapBindings(*env.values[0]->attrs); + } else { + return map0(); + } +} + /* 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 @@ -813,13 +830,11 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con e.addTrace(pos, s, s2); } - void mkString(Value & v, const char * s) { v.mkString(dupString(s)); } - Value & mkString(Value & v, std::string_view s, const PathSet & context) { v.mkString(dupStringWithLen(s.data(), s.size())); @@ -862,7 +877,8 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) } if (!env->prevWith) // TODO: env.attrs? - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, map0()); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, + mapEnvBindings(*env)); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1171,7 +1187,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, - map1("value", &v)); // TODO dynamicAttrs to env? + mapEnvBindings(env)); + // map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ @@ -1261,7 +1278,9 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } else { state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError(pos, "attribute '%1%' missing", name, mapBindings(vAttrs->attrs)); + throwEvalError(pos, "attribute '%1%' missing", name, + mapEnvBindings(env)); + // mapBindings(*vAttrs->attrs)); } vAttrs = j->value; pos2 = j->pos; @@ -1519,7 +1538,8 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - map1("fun", &fun)); // todo add bindings + fun + mapBindings(args)); + // map1("fun", &fun)); // todo add bindings + fun } } } @@ -1704,15 +1724,20 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) firstType = nFloat; nf = n; nf += vTmp.fpoint; - } else - throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), map0()); + } else { + std::cerr << "envtype: " << showType(env.values[0]->type()) << std::endl; + + throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), + mapEnvBindings(env)); + } } else if (firstType == nFloat) { if (vTmp.type() == nInt) { nf += vTmp.integer; } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else - throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), map0()); + throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), + mapEnvBindings(env)); } else s << state.coerceToString(pos, vTmp, context, false, firstType == nString); } @@ -1871,10 +1896,10 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], map1("value", &v)); + v.string.s, v.string.context[0], map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], map1("value", &v)); + v.string.s, v.string.context[0], map1("value", &v)); } return s; } -- cgit v1.2.3 From edb5a280243974c2094ed62cec104b55b97add43 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 11 Jun 2021 18:55:40 -0600 Subject: hintfmt for eye searing varnames --- src/libcmd/repl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 29be71e13..57174bf0e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -781,11 +781,13 @@ void runRepl( std::set names; for (auto & [name, value] : extraEnv) { - names.insert(ANSI_BOLD + name + ANSI_NORMAL); + // names.insert(ANSI_BOLD + name + ANSI_NORMAL); + names.insert(name); repl->addVarToScope(repl->state->symbols.create(name), value); } printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); + // printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); repl->mainLoop({}); } -- cgit v1.2.3 From 89264d20e63effa8d10f84a5f989d962f5df36f5 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 6 Aug 2021 11:09:27 -0600 Subject: move valmap to hh; add to env --- src/libexpr/eval.cc | 168 ++++++++++++++++++++++++++++++++++++++++++---------- src/libexpr/eval.hh | 3 + src/nix/flake.cc | 1 + 3 files changed, 142 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6dcdbb2bd..48bff8dce 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -78,6 +78,8 @@ void printValue(std::ostream & str, std::set & active, const Valu return; } + str << "internal type: " << v.internalType << std::endl; + switch (v.internalType) { case tInt: str << v.integer; @@ -404,7 +406,7 @@ EvalState::EvalState(const Strings & _searchPath, ref store) assert(gcInitialised); - static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); + static_assert(sizeof(Env) <= 16 + sizeof(std::unique_ptr), "environment must be <= 16 bytes"); /* Initialise the Nix expression search path. */ if (!evalSettings.pureEval) { @@ -616,7 +618,7 @@ std::optional EvalState::getDoc(Value & v) return {}; } -typedef std::map valmap; +// typedef std::map valmap; /*void addEnv(Value * v, valmap &vmap) { @@ -655,13 +657,44 @@ LocalNoInline(valmap * mapBindings(Bindings &b)) return map; } +LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) +{ + for (auto i = b.begin(); i != b.end(); ++i) + { + std::string s = prefix; + s += i->name; + valmap[s] = i->value; + } +} + LocalNoInline(valmap * mapEnvBindings(Env &env)) { - if (env.values[0]->type() == nAttrs) { - return mapBindings(*env.values[0]->attrs); - } else { - return map0(); + // NOT going to use this + if (env.staticEnv) { + std::cout << "got static env" << std::endl; } + +// std::cout << "envsize: " << env.values.size() << std::endl; + + // std::cout << "size_t size: " << sizeof(size_t) << std::endl; + // std::cout << "envsize: " << env.size << std::endl; + // std::cout << "envup: " << env.up << std::endl; + + valmap *vm = env.up ? mapEnvBindings(*env.up) : new valmap(); + + /* + size_t i=0; + do { + std::cout << "env: " << i << " value: " << showType(*env.values[i]) << std::endl; + // std::cout << *env.values[i] << std::endl; + ++i; + } while(i < (std::min(env.size, (size_t)100))); + + + if (env.values[0]->type() == nAttrs) + addBindings(std::to_string((int)env.size), *env.values[0]->attrs, *vm); + */ + return vm; } /* Every "format" object (even temporary) takes up a few hundred bytes @@ -876,7 +909,6 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - // TODO: env.attrs? throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, mapEnvBindings(*env)); for (size_t l = env->prevWith; l; --l, env = env->up) ; @@ -902,14 +934,28 @@ Value * EvalState::allocValue() Env & EvalState::allocEnv(size_t size) { + nrEnvs++; nrValuesInEnvs += size; - Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); - env->type = Env::Plain; + // if (debuggerHook) + // { + // Env * env = (Env *) allocBytes(sizeof(DebugEnv) + size * sizeof(Value *)); + // // Env * env = new DebugEnv; + // env->type = Env::Plain; + // /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ + + // return *env; + // } else { + Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); + env->type = Env::Plain; + // env->size = size; - /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ + /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ - return *env; + return *env; + // } + + } @@ -1126,6 +1172,11 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) env2.up = &env; dynamicEnv = &env2; + // TODO; deal with the below overrides or whatever + if (debuggerHook) { + env2.valuemap = mapBindings(attrs); + } + AttrDefs::iterator overrides = attrs.find(state.sOverrides); bool hasOverrides = overrides != attrs.end(); @@ -1207,6 +1258,9 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) Env & env2(state.allocEnv(attrs->attrs.size())); env2.up = &env; + if (debuggerHook) { + env2.valuemap = mapBindings(attrs); + } /* The recursive attributes are evaluated in the new environment, while the inherited attributes are evaluated in the original environment. */ @@ -1420,9 +1474,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po size_t displ = 0; - if (!lambda.matchAttrs) + if (!lambda.matchAttrs){ + // TODO: what is this arg? empty argument? + // add empty valmap here? env2.values[displ++] = &arg; - + } else { forceAttrs(arg, pos); @@ -1432,23 +1488,51 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po /* For each formal argument, get the actual argument. If there is no matching actual argument but the formal argument has a default, use the default. */ - size_t attrsUsed = 0; - for (auto & i : lambda.formals->formals) { - Bindings::iterator j = arg.attrs->find(i.name); - if (j == arg.attrs->end()) { - if (!i.def) - throwTypeError( - pos, - "%1% called without required argument '%2%'", - lambda, - i.name, - map2("fun", &fun, "arg", &arg)); - env2.values[displ++] = i.def->maybeThunk(*this, env2); - } else { - attrsUsed++; - env2.values[displ++] = j->value; + if (debuggerHook) { + size_t attrsUsed = 0; + for (auto & i : lambda.formals->formals) { + Bindings::iterator j = arg.attrs->find(i.name); + if (j == arg.attrs->end()) { + if (!i.def) + throwTypeError( + pos, + "%1% called without required argument '%2%'", + lambda, + i.name, + map2("fun", &fun, "arg", &arg)); + env2.values[displ++] = i.def->maybeThunk(*this, env2); + } else { + attrsUsed++; + env2.values[displ++] = j->value; + } } } + else { + auto map = new valmap(); + + size_t attrsUsed = 0; + for (auto & i : lambda.formals->formals) { + Bindings::iterator j = arg.attrs->find(i.name); + if (j == arg.attrs->end()) { + if (!i.def) + throwTypeError( + pos, + "%1% called without required argument '%2%'", + lambda, + i.name, + map2("fun", &fun, "arg", &arg)); + env2.values[displ++] = i.def->maybeThunk(*this, env2); + } else { + attrsUsed++; + env2.values[displ++] = j->value; + + // add to debugger name-value map + std::string s = i->name; + (*map)[s] = i->value; + } + } + env2.valuemap = map; + } /* Check that each actual argument is listed as a formal argument (unless the attribute match specifies a `...'). */ @@ -1558,6 +1642,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.type = Env::HasWithExpr; env2.values[0] = (Value *) attrs; + env2.valuemap = mapBindings(attrs) + body->eval(state, env2, v); } @@ -1896,14 +1982,36 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], map1("value", &v)); + v.string.s, v.string.context[0], + // b.has_value() ? mapBindings(*b.get()) : map0()); + map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], map1("value", &v)); + v.string.s, v.string.context[0], + // b.has_value() ? mapBindings(*b.get()) : map0()); + map1("value", &v)); } return s; } +/*string EvalState::forceStringNoCtx(std::optional b, Value & v, const Pos & pos) +{ + string s = forceString(v, pos); + if (v.string.context) { + if (pos) + throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", + v.string.s, v.string.context[0], + b.has_value() ? mapBindings(*b.get()) : map0()); + // map1("value", &v)); + else + throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", + v.string.s, v.string.context[0], + b.has_value() ? mapBindings(*b.get()) : map0()); + // map1("value", &v)); + } + return s; +}*/ + bool EvalState::isDerivation(Value & v) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e3eaed6d3..448f41def 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -33,12 +33,14 @@ struct PrimOp const char * doc = nullptr; }; +typedef std::map valmap; struct Env { Env * up; unsigned short prevWith:14; // nr of levels up to next `with' environment enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2; + std::unique_ptr valuemap; // TODO: rename Value * values[0]; }; @@ -204,6 +206,7 @@ public: string forceString(Value & v, const Pos & pos = noPos); string forceString(Value & v, PathSet & context, const Pos & pos = noPos); string forceStringNoCtx(Value & v, const Pos & pos = noPos); + // string forceStringNoCtx(std::optional b, Value & v, const Pos & pos = noPos); /* Return true iff the value `v' denotes a derivation (i.e. a set with attribute `type = "derivation"'). */ diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 62a413e27..6af052008 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -408,6 +408,7 @@ struct CmdFlakeCheck : FlakeCommand if (auto attr = v.attrs->get(state->symbols.create("description"))) state->forceStringNoCtx(*attr->value, *attr->pos); + // state->forceStringNoCtx(std::optional(v.attrs), *attr->value, *attr->pos); else throw Error("template '%s' lacks attribute 'description'", attrPath); -- cgit v1.2.3 From 030271184fecbbe9dd871b71d92c61e163254646 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 9 Aug 2021 14:30:47 -0600 Subject: trying env args; but unecessary? --- src/libcmd/command.cc | 3 +- src/libexpr/eval.cc | 148 ++++++++++++++++++++++++-------------------------- 2 files changed, 74 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 51a071d25..86b6f37f8 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -96,7 +96,8 @@ EvalCommand::EvalCommand() .handler = {&startReplOnEvalErrors, true}, }); } -extern std::function & env)> debuggerHook; +// extern std::function & env)> debuggerHook; +extern std::function debuggerHook; ref EvalCommand::getEvalState() { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 48bff8dce..464022372 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -35,7 +35,8 @@ namespace nix { -std::function & env)> debuggerHook; +// std::function & env)> debuggerHook; +std::function debuggerHook; static char * dupString(const char * s) { @@ -667,189 +668,189 @@ LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) } } -LocalNoInline(valmap * mapEnvBindings(Env &env)) -{ - // NOT going to use this - if (env.staticEnv) { - std::cout << "got static env" << std::endl; - } +// LocalNoInline(valmap * mapEnvBindings(Env &env)) +// { +// // NOT going to use this +// if (env.valuemap) { +// std::cout << "got static env" << std::endl; +// } -// std::cout << "envsize: " << env.values.size() << std::endl; +// // std::cout << "envsize: " << env.values.size() << std::endl; - // std::cout << "size_t size: " << sizeof(size_t) << std::endl; - // std::cout << "envsize: " << env.size << std::endl; - // std::cout << "envup: " << env.up << std::endl; +// // std::cout << "size_t size: " << sizeof(size_t) << std::endl; +// // std::cout << "envsize: " << env.size << std::endl; +// // std::cout << "envup: " << env.up << std::endl; - valmap *vm = env.up ? mapEnvBindings(*env.up) : new valmap(); +// valmap *vm = env.up ? mapEnvBindings(*env.up) : new valmap(); - /* - size_t i=0; - do { - std::cout << "env: " << i << " value: " << showType(*env.values[i]) << std::endl; - // std::cout << *env.values[i] << std::endl; - ++i; - } while(i < (std::min(env.size, (size_t)100))); +// /* +// size_t i=0; +// do { +// std::cout << "env: " << i << " value: " << showType(*env.values[i]) << std::endl; +// // std::cout << *env.values[i] << std::endl; +// ++i; +// } while(i < (std::min(env.size, (size_t)100))); - if (env.values[0]->type() == nAttrs) - addBindings(std::to_string((int)env.size), *env.values[0]->attrs, *vm); - */ - return vm; -} +// if (env.values[0]->type() == nAttrs) +// addBindings(std::to_string((int)env.size), *env.values[0]->attrs, *vm); +// */ +// return 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 exceptions. */ -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, valmap * env)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, valmap * env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, valmap * env)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2, s3); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, valmap * env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, s2, s3), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, valmap * env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env)) { // p1 is where the error occurred; p2 is a position mentioned in the message. - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, sym, p2), .errPos = p1 }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, valmap * env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, valmap * env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, valmap * env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, s2), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, valmap * env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, valmap * env)) +LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = AssertionError({ .msg = hintfmt(s, s1), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, valmap * env)) +LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, valmap * env)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env)) { - auto delenv = std::unique_ptr(env); + // auto delenv = std::unique_ptr(env); auto error = MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = pos }); if (debuggerHook) - debuggerHook(error, *env); + debuggerHook(error, env); throw error; } @@ -909,8 +910,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, - mapEnvBindings(*env)); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1238,7 +1238,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, - mapEnvBindings(env)); + env); // map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); @@ -1332,8 +1332,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } else { state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError(pos, "attribute '%1%' missing", name, - mapEnvBindings(env)); + throwEvalError(pos, "attribute '%1%' missing", name, env); // mapBindings(*vAttrs->attrs)); } vAttrs = j->value; @@ -1622,7 +1621,8 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - mapBindings(args)); + fun.lambda.env); + // mapBindings(args)); // map1("fun", &fun)); // todo add bindings + fun } } @@ -1642,7 +1642,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.type = Env::HasWithExpr; env2.values[0] = (Value *) attrs; - env2.valuemap = mapBindings(attrs) + env2.valuemap = mapBindings(*attrs) body->eval(state, env2, v); } @@ -1813,8 +1813,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else { std::cerr << "envtype: " << showType(env.values[0]->type()) << std::endl; - throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), - mapEnvBindings(env)); + throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), env); } } else if (firstType == nFloat) { if (vTmp.type() == nInt) { @@ -1822,8 +1821,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else - throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), - mapEnvBindings(env)); + throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), env); } else s << state.coerceToString(pos, vTmp, context, false, firstType == nString); } @@ -2061,8 +2059,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", - map1("value", &v)); + throwTypeError(pos, "cannot coerce a set to a string", map1("value", &v)); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2093,12 +2090,11 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } } - throwTypeError(pos, "cannot coerce %1% to a string", v, - map1("value", &v)); + throwTypeError(pos, "cannot coerce %1% to a string", v, map1("value", &v)); } -string EvalState::copyPathToStore(PathSet & context, const Path & path) +string EvalState::copyPathToStore(Env &env, PathSet & context, const Path & path) { if (nix::isDerivation(path)) throwEvalError("file names are not allowed to end in '%1%'", -- cgit v1.2.3 From b6eb38016b9d16cf206f3f2b0cd4bce4dea40345 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 17 Aug 2021 14:39:50 -0600 Subject: moving towards env in exceptions --- src/libcmd/command.cc | 2 +- src/libexpr/eval.cc | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 86b6f37f8..59ab1f874 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -105,7 +105,7 @@ ref EvalCommand::getEvalState() if (!evalState) { evalState = std::make_shared(searchPath, getStore()); if (startReplOnEvalErrors) - debuggerHook = [evalState{ref(evalState)}](const Error & error, const std::map & env) { + debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); runRepl(evalState, env); }; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 464022372..f799ee7db 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1172,11 +1172,6 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) env2.up = &env; dynamicEnv = &env2; - // TODO; deal with the below overrides or whatever - if (debuggerHook) { - env2.valuemap = mapBindings(attrs); - } - AttrDefs::iterator overrides = attrs.find(state.sOverrides); bool hasOverrides = overrides != attrs.end(); @@ -1195,6 +1190,11 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos)); } + // TODO; deal with the below overrides or whatever + if (debuggerHook) { + env2.valuemap.reset(mapBindings(*v.attrs)); + } + /* If the rec contains an attribute called `__overrides', then evaluate it, and add the attributes in that set to the rec. This allows overriding of recursive attributes, which is @@ -1258,9 +1258,6 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) Env & env2(state.allocEnv(attrs->attrs.size())); env2.up = &env; - if (debuggerHook) { - env2.valuemap = mapBindings(attrs); - } /* The recursive attributes are evaluated in the new environment, while the inherited attributes are evaluated in the original environment. */ @@ -1268,6 +1265,18 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) for (auto & i : attrs->attrs) env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2); + if (debuggerHook) { + auto map = new valmap(); + + displ = 0; + for (auto & i : attrs->attrs) + { + // std::string s = i->name; + (*map)[i.first] = env2.values[displ++]; + } + env2.valuemap.reset(map); + } + body->eval(state, env2, v); } @@ -1460,6 +1469,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po pos, "attempt to call something which is not a function but %1%", showType(fun).c_str(), + // fun.env); map2("fun", &fun, "arg", &arg)); } @@ -1498,7 +1508,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - map2("fun", &fun, "arg", &arg)); + fun.lambda.env); + // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1519,18 +1530,19 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - map2("fun", &fun, "arg", &arg)); + fun.env); + // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; env2.values[displ++] = j->value; // add to debugger name-value map - std::string s = i->name; - (*map)[s] = i->value; + std::string s = i.name; + (*map)[s] = i.value; } } - env2.valuemap = map; + env2.valuemap.reset(map); } /* Check that each actual argument is listed as a formal @@ -1544,7 +1556,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called with unexpected argument '%2%'", lambda, i.name, - map2("fun", &fun, "arg", &arg)); + fun.env); + // map2("fun", &fun, "arg", &arg)); abort(); // can't happen } } @@ -1621,7 +1634,7 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - fun.lambda.env); + *fun.lambda.env); // mapBindings(args)); // map1("fun", &fun)); // todo add bindings + fun } -- cgit v1.2.3 From e82cf13b1e94a27b2d6402ff6850a5a11d18fb92 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 18 Aug 2021 17:53:10 -0600 Subject: switch to fakeenvs --- src/libexpr/eval.cc | 68 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f799ee7db..48546e8ad 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -958,6 +958,16 @@ Env & EvalState::allocEnv(size_t size) } +Env & fakeEnv(size_t size) +{ + // making a fake Env so we'll have one to pass to exception ftns. + // a placeholder until we can pass real envs everywhere they're needed. + Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); + env->type = Env::Plain; + + return *env; +} + void EvalState::mkList(Value & v, size_t size) { @@ -1469,8 +1479,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po pos, "attempt to call something which is not a function but %1%", showType(fun).c_str(), + fakeEnv(1)); // fun.env); - map2("fun", &fun, "arg", &arg)); + // map2("fun", &fun, "arg", &arg)); } ExprLambda & lambda(*fun.lambda.fun); @@ -1508,7 +1519,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - fun.lambda.env); + *fun.lambda.env); // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { @@ -1530,7 +1541,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - fun.env); + *fun.lambda.env); // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { @@ -1539,7 +1550,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po // add to debugger name-value map std::string s = i.name; - (*map)[s] = i.value; + (*map)[s] = j->value; } } env2.valuemap.reset(map); @@ -1556,7 +1567,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called with unexpected argument '%2%'", lambda, i.name, - fun.env); + *fun.lambda.env); // map2("fun", &fun, "arg", &arg)); abort(); // can't happen } @@ -1655,7 +1666,11 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.type = Env::HasWithExpr; env2.values[0] = (Value *) attrs; - env2.valuemap = mapBindings(*attrs) + if (debuggerHook) { + forceAttrs(attrs); + env2.valuemap = mapBindings(attrs->attrs); + } + body->eval(state, env2, v); } @@ -1672,7 +1687,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) if (!state.evalBool(env, cond, pos)) { std::ostringstream out; cond->show(out); - throwAssertionError(pos, "assertion '%1%' failed", out.str(), map0()); + throwAssertionError(pos, "assertion '%1%' failed", out.str(), env); } body->eval(state, env, v); } @@ -1895,7 +1910,8 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v, - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); return v.integer; } @@ -1907,7 +1923,8 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) return v.integer; else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v, - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); return v.fpoint; } @@ -1916,8 +1933,9 @@ bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, - map1("value", &v)); + throwTypeError(pos, "value is %1% while a Boolean was expected", v, + fakeEnv(1)); + // map1("value", &v)); return v.boolean; } @@ -1933,7 +1951,8 @@ void EvalState::forceFunction(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v, - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); } @@ -1942,7 +1961,8 @@ string EvalState::forceString(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nString) { throwTypeError(pos, "value is %1% while a string was expected", v, - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); } return string(v.string.s); } @@ -1995,12 +2015,14 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], // b.has_value() ? mapBindings(*b.get()) : map0()); - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], // b.has_value() ? mapBindings(*b.get()) : map0()); - map1("value", &v)); + fakeEnv(1)); + // map1("value", &v)); } return s; } @@ -2072,7 +2094,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", map1("value", &v)); + throwTypeError(pos, "cannot coerce a set to a string", + fakeEnv(1)); + // map1("value", &v)); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2080,7 +2104,6 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, return v.external->coerceToString(pos, context, coerceMore, copyToStore); if (coerceMore) { - /* Note that `false' is represented as an empty string for shell scripting convenience, just like `null'. */ if (v.type() == nBool && v.boolean) return "1"; @@ -2103,7 +2126,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } } - throwTypeError(pos, "cannot coerce %1% to a string", v, map1("value", &v)); + throwTypeError(pos, "cannot coerce %1% to a string", v, + fakeEnv(1)); + // map1("value", &v)); } @@ -2136,7 +2161,9 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) { string path = coerceToString(pos, v, context, false, false); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, map1("value", &v)); + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, + fakeEnv(1)); + // map1("value", &v)); return path; } @@ -2218,7 +2245,8 @@ bool EvalState::eqValues(Value & v1, Value & v2) throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), - map2("value1", &v1, "value2", &v2)); + fakeEnv(1)); + // map2("value1", &v1, "value2", &v2)); } } -- cgit v1.2.3 From 22720215366ada555f077ffb8eb810029ec93a04 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 18 Aug 2021 20:02:23 -0600 Subject: more error fixes --- src/libexpr/eval.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 48546e8ad..eef4974e5 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1667,8 +1667,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.values[0] = (Value *) attrs; if (debuggerHook) { - forceAttrs(attrs); - env2.valuemap = mapBindings(attrs->attrs); + state.forceAttrs(*env2.values[0]); + env2.valuemap.reset(mapBindings(*env2.values[0]->attrs)); } @@ -2132,12 +2132,13 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } -string EvalState::copyPathToStore(Env &env, PathSet & context, const Path & path) +string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) throwEvalError("file names are not allowed to end in '%1%'", drvExtension, - map0()); + fakeEnv(1)); + // map0()); Path dstPath; auto i = srcToStore.find(path); -- cgit v1.2.3 From 4b5f9b35f06754aaf578a2d4b3d730949964ef05 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 18 Aug 2021 21:25:26 -0600 Subject: env to bindings --- src/libcmd/command.cc | 5 ++++- src/libexpr/eval.cc | 25 +++++++++++++++++++++++-- src/libexpr/eval.hh | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 59ab1f874..a32c4a24b 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -99,6 +99,8 @@ EvalCommand::EvalCommand() // extern std::function & env)> debuggerHook; extern std::function debuggerHook; + + ref EvalCommand::getEvalState() { std::cout << " EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; @@ -107,7 +109,8 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); - runRepl(evalState, env); + auto vm = mapEnvBindings(env); + runRepl(evalState, *vm); }; } return ref(evalState); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index eef4974e5..2e885bb7c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -668,6 +668,28 @@ LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) } } + + +void mapEnvBindings(const Env &env, valmap & vm) +{ + // add bindings for the next level up first. + if (env.up) { + mapEnvBindings(*env.up, vm); + } + + // merge - and write over - higher level bindings. + vm.merge(*env.valuemap); +} + +valmap * mapEnvBindings(const Env &env) +{ + auto vm = new valmap(); + + mapEnvBindings(env, *vm); + + return vm; +} + // LocalNoInline(valmap * mapEnvBindings(Env &env)) // { // // NOT going to use this @@ -1508,8 +1530,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po /* For each formal argument, get the actual argument. If there is no matching actual argument but the formal argument has a default, use the default. */ + size_t attrsUsed = 0; if (debuggerHook) { - size_t attrsUsed = 0; for (auto & i : lambda.formals->formals) { Bindings::iterator j = arg.attrs->find(i.name); if (j == arg.attrs->end()) { @@ -1531,7 +1553,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po else { auto map = new valmap(); - size_t attrsUsed = 0; for (auto & i : lambda.formals->formals) { Bindings::iterator j = arg.attrs->find(i.name); if (j == arg.attrs->end()) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 448f41def..2d167e6eb 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -44,6 +44,7 @@ struct Env Value * values[0]; }; +valmap * mapEnvBindings(const Env &env); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet()); -- cgit v1.2.3 From bd3b5329f91e6caff387cf361a5c779468f34f88 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 24 Aug 2021 16:32:54 -0600 Subject: print env bindings --- src/libcmd/command.cc | 1 + src/libexpr/eval.cc | 74 +++++++++++++++++++++++++++++++++++++++++++++------ src/libexpr/eval.hh | 1 + 3 files changed, 68 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index a32c4a24b..1a59dff77 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -109,6 +109,7 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + printEnvBindings(env); auto vm = mapEnvBindings(env); runRepl(evalState, *vm); }; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 2e885bb7c..7fee1168c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -669,6 +669,26 @@ LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) } +void printEnvBindings(const Env &env, int lv ) +{ + if (env.values[0]->type() == nAttrs) { + Bindings::iterator j = env.values[0]->attrs->begin(); + + while (j != env.values[0]->attrs->end()) { + std::cout << lv << " env binding: " << j->name << std::endl; + // if (countCalls && j->pos) attrSelects[*j->pos]++; + // return j->value; + j++; + } + + } + + std::cout << "next env : " << env.up << std::endl; + + if (env.up) { + printEnvBindings(*env.up, ++lv); + } +} void mapEnvBindings(const Env &env, valmap & vm) { @@ -678,14 +698,38 @@ void mapEnvBindings(const Env &env, valmap & vm) } // merge - and write over - higher level bindings. - vm.merge(*env.valuemap); + if (env.valuemap) + vm.merge(*env.valuemap); } +// void mapEnvBindings(const Env &env, valmap & vm) +// { +// // add bindings for the next level up first. +// if (env.up) { +// mapEnvBindings(*env.up, vm); +// } + +// // merge - and write over - higher level bindings. +// if (env.valuemap) +// vm.merge(*env.valuemap); +// } + valmap * mapEnvBindings(const Env &env) { auto vm = new valmap(); + // segfault! + std::cout << "before mapenv" << std::endl; + if (env.valuemap) { + std::cout << "valuemap" << std::endl; + std::cout << "mapenv count" << env.valuemap->size() << std::endl; + } else + { + std::cout << "novaluemap" << std::endl; + } + mapEnvBindings(env, *vm); + std::cout << "after mapenv" << std::endl; return vm; } @@ -852,6 +896,8 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env)) { + std::cout << "throwUndefinedVarError" << std::endl; + // auto delenv = std::unique_ptr(env); auto error = UndefinedVarError({ .msg = hintfmt(s, s1), @@ -914,6 +960,8 @@ void mkPath(Value & v, const char * s) inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) { + // std::cout << " EvalState::lookupVar" << std::endl; + for (size_t l = var.level; l; --l, env = env->up) ; if (!var.fromWith) return env->values[var.displ]; @@ -931,8 +979,10 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) if (countCalls && j->pos) attrSelects[*j->pos]++; return j->value; } - if (!env->prevWith) + if (!env->prevWith) { + std::cout << "pre throwUndefinedVarError" << std::endl; throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env); + } for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1681,16 +1731,24 @@ https://nixos.org/manual/nix/stable/#ss-functions.)", void ExprWith::eval(EvalState & state, Env & env, Value & v) { + // std::cout << "ExprWith::eval" << std::endl; Env & env2(state.allocEnv(1)); env2.up = &env; env2.prevWith = prevWith; env2.type = Env::HasWithExpr; - env2.values[0] = (Value *) attrs; - - if (debuggerHook) { - state.forceAttrs(*env2.values[0]); - env2.valuemap.reset(mapBindings(*env2.values[0]->attrs)); - } + env2.values[0] = (Value *) attrs; // ok DAG nasty. just smoosh this in. + // presumably evaluate later, lazily. + // std::cout << "ExprWith::eval2" << std::endl; + + // can't load the valuemap until they've been evaled, which is not yet. + // if (debuggerHook) { + // std::cout << "ExprWith::eval3.0" << std::endl; + // std::cout << "ExprWith attrs" << *attrs << std::endl; + // state.forceAttrs(*(Value*) attrs); + // std::cout << "ExprWith::eval3.5" << std::endl; + // env2.valuemap.reset(mapBindings(*env2.values[0]->attrs)); + // std::cout << "ExprWith::eval4" << std::endl; + // } body->eval(state, env2, v); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 2d167e6eb..f5c685edf 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -44,6 +44,7 @@ struct Env Value * values[0]; }; +void printEnvBindings(const Env &env, int lv = 0); valmap * mapEnvBindings(const Env &env); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet()); -- cgit v1.2.3 From d8a977a22ebd8884124a0a80e6b1523228f70f4b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 25 Aug 2021 11:19:09 -0600 Subject: adding all the value names from env.values[0] --- src/libcmd/command.cc | 2 +- src/libexpr/eval.cc | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 1a59dff77..45665b555 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -103,7 +103,7 @@ extern std::function debuggerHook; ref EvalCommand::getEvalState() { - std::cout << " EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; + std::cout << "EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; if (!evalState) { evalState = std::make_shared(searchPath, getStore()); if (startReplOnEvalErrors) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7fee1168c..6eb7f2cb9 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -698,21 +698,19 @@ void mapEnvBindings(const Env &env, valmap & vm) } // merge - and write over - higher level bindings. - if (env.valuemap) - vm.merge(*env.valuemap); + if (env.values[0]->type() == nAttrs) { + auto map = valmap(); + + Bindings::iterator j = env.values[0]->attrs->begin(); + + while (j != env.values[0]->attrs->end()) { + map[j->name] = j->value; + j++; + } + vm.merge(map); + } } -// void mapEnvBindings(const Env &env, valmap & vm) -// { -// // add bindings for the next level up first. -// if (env.up) { -// mapEnvBindings(*env.up, vm); -// } - -// // merge - and write over - higher level bindings. -// if (env.valuemap) -// vm.merge(*env.valuemap); -// } valmap * mapEnvBindings(const Env &env) { -- cgit v1.2.3 From 310c689d317d1eb4bcf50cd11d84165fe2ffd512 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 25 Aug 2021 13:18:27 -0600 Subject: remove more explicit valmap code --- src/libexpr/eval.cc | 150 +++++++++++++++++----------------------------------- src/libexpr/eval.hh | 1 - 2 files changed, 48 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6eb7f2cb9..c6fb052f4 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -630,43 +630,43 @@ std::optional EvalState::getDoc(Value & v) } */ -LocalNoInline(valmap * map0()) -{ - return new valmap(); -} +// LocalNoInline(valmap * map0()) +// { +// return new valmap(); +// } -LocalNoInline(valmap * map1(const char *name, Value *v)) -{ - return new valmap({{name, v}}); -} +// LocalNoInline(valmap * map1(const char *name, Value *v)) +// { +// return new valmap({{name, v}}); +// } -LocalNoInline(valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2)) -{ - return new valmap({{name1, v1}, {name2, v2}}); -} +// LocalNoInline(valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2)) +// { +// return new valmap({{name1, v1}, {name2, v2}}); +// } -LocalNoInline(valmap * mapBindings(Bindings &b)) -{ - auto map = new valmap(); +// LocalNoInline(valmap * mapBindings(Bindings &b)) +// { +// auto map = new valmap(); - for (auto i = b.begin(); i != b.end(); ++i) - { - std::string s = i->name; - (*map)[s] = i->value; - } +// for (auto i = b.begin(); i != b.end(); ++i) +// { +// std::string s = i->name; +// (*map)[s] = i->value; +// } - return map; -} +// return map; +// } -LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) -{ - for (auto i = b.begin(); i != b.end(); ++i) - { - std::string s = prefix; - s += i->name; - valmap[s] = i->value; - } -} +// LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) +// { +// for (auto i = b.begin(); i != b.end(); ++i) +// { +// std::string s = prefix; +// s += i->name; +// valmap[s] = i->value; +// } +// } void printEnvBindings(const Env &env, int lv ) @@ -698,6 +698,7 @@ void mapEnvBindings(const Env &env, valmap & vm) } // merge - and write over - higher level bindings. + // note; skipping HasWithExpr that haven't been evaled yet. if (env.values[0]->type() == nAttrs) { auto map = valmap(); @@ -716,18 +717,7 @@ valmap * mapEnvBindings(const Env &env) { auto vm = new valmap(); - // segfault! - std::cout << "before mapenv" << std::endl; - if (env.valuemap) { - std::cout << "valuemap" << std::endl; - std::cout << "mapenv count" << env.valuemap->size() << std::endl; - } else - { - std::cout << "novaluemap" << std::endl; - } - mapEnvBindings(env, *vm); - std::cout << "after mapenv" << std::endl; return vm; } @@ -1270,11 +1260,6 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos)); } - // TODO; deal with the below overrides or whatever - if (debuggerHook) { - env2.valuemap.reset(mapBindings(*v.attrs)); - } - /* If the rec contains an attribute called `__overrides', then evaluate it, and add the attributes in that set to the rec. This allows overriding of recursive attributes, which is @@ -1345,18 +1330,6 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) for (auto & i : attrs->attrs) env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2); - if (debuggerHook) { - auto map = new valmap(); - - displ = 0; - for (auto & i : attrs->attrs) - { - // std::string s = i->name; - (*map)[i.first] = env2.values[displ++]; - } - env2.valuemap.reset(map); - } - body->eval(state, env2, v); } @@ -1579,52 +1552,25 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po there is no matching actual argument but the formal argument has a default, use the default. */ size_t attrsUsed = 0; - if (debuggerHook) { - for (auto & i : lambda.formals->formals) { - Bindings::iterator j = arg.attrs->find(i.name); - if (j == arg.attrs->end()) { - if (!i.def) - throwTypeError( - pos, - "%1% called without required argument '%2%'", - lambda, - i.name, - *fun.lambda.env); - // map2("fun", &fun, "arg", &arg)); - env2.values[displ++] = i.def->maybeThunk(*this, env2); - } else { - attrsUsed++; - env2.values[displ++] = j->value; - } - } - } - else { - auto map = new valmap(); - - for (auto & i : lambda.formals->formals) { - Bindings::iterator j = arg.attrs->find(i.name); - if (j == arg.attrs->end()) { - if (!i.def) - throwTypeError( - pos, - "%1% called without required argument '%2%'", - lambda, - i.name, - *fun.lambda.env); - // map2("fun", &fun, "arg", &arg)); - env2.values[displ++] = i.def->maybeThunk(*this, env2); - } else { - attrsUsed++; - env2.values[displ++] = j->value; - - // add to debugger name-value map - std::string s = i.name; - (*map)[s] = j->value; - } + for (auto & i : lambda.formals->formals) { + Bindings::iterator j = arg.attrs->find(i.name); + if (j == arg.attrs->end()) { + if (!i.def) + throwTypeError( + pos, + "%1% called without required argument '%2%'", + lambda, + i.name, + *fun.lambda.env); + // map2("fun", &fun, "arg", &arg)); + env2.values[displ++] = i.def->maybeThunk(*this, env2); + } else { + attrsUsed++; + env2.values[displ++] = j->value; } - env2.valuemap.reset(map); } + /* Check that each actual argument is listed as a formal argument (unless the attribute match specifies a `...'). */ if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index f5c685edf..ca3a7b742 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -40,7 +40,6 @@ struct Env Env * up; unsigned short prevWith:14; // nr of levels up to next `with' environment enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2; - std::unique_ptr valuemap; // TODO: rename Value * values[0]; }; -- cgit v1.2.3 From 176911102ce2c0be06bbfed9099f364d71c3c679 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 13 Sep 2021 11:57:25 -0600 Subject: printEnvPosChain --- src/libcmd/command.cc | 1 + src/libexpr/eval.cc | 34 ++++++++++++++++++++++++++++++---- src/libexpr/eval.hh | 1 + src/libutil/error.hh | 6 ++++++ 4 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 45665b555..07f4208da 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -109,6 +109,7 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + // printEnvPosChain(env); printEnvBindings(env); auto vm = mapEnvBindings(env); runRepl(evalState, *vm); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c6fb052f4..19379b876 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -648,13 +648,11 @@ std::optional EvalState::getDoc(Value & v) // LocalNoInline(valmap * mapBindings(Bindings &b)) // { // auto map = new valmap(); - // for (auto i = b.begin(); i != b.end(); ++i) // { // std::string s = i->name; // (*map)[s] = i->value; // } - // return map; // } @@ -668,12 +666,13 @@ std::optional EvalState::getDoc(Value & v) // } // } - void printEnvBindings(const Env &env, int lv ) { + std::cout << "env " << lv << " type: " << env.type << std::endl; if (env.values[0]->type() == nAttrs) { Bindings::iterator j = env.values[0]->attrs->begin(); + while (j != env.values[0]->attrs->end()) { std::cout << lv << " env binding: " << j->name << std::endl; // if (countCalls && j->pos) attrSelects[*j->pos]++; @@ -690,6 +689,33 @@ void printEnvBindings(const Env &env, int lv ) } } +void printEnvPosChain(const Env &env, int lv ) +{ + std::cout << "printEnvPosChain " << lv << std::endl; + + std::cout << "env" << env.values[0] << std::endl; + + if (env.values[0] && env.values[0]->type() == nAttrs) { + std::cout << "im in the loop" << std::endl; + std::cout << "pos " << env.values[0]->attrs->pos << std::endl; + if (env.values[0]->attrs->pos) { + ErrPos ep(*env.values[0]->attrs->pos); + auto loc = getCodeLines(ep); + if (loc) + printCodeLines(std::cout, + std::__cxx11::to_string(lv), + ep, + *loc); + } + } + + std::cout << "next env : " << env.up << std::endl; + + if (env.up) { + printEnvPosChain(*env.up, ++lv); + } +} + void mapEnvBindings(const Env &env, valmap & vm) { // add bindings for the next level up first. @@ -699,7 +725,7 @@ void mapEnvBindings(const Env &env, valmap & vm) // merge - and write over - higher level bindings. // note; skipping HasWithExpr that haven't been evaled yet. - if (env.values[0]->type() == nAttrs) { + if (env.values[0] && env.values[0]->type() == nAttrs) { auto map = valmap(); Bindings::iterator j = env.values[0]->attrs->begin(); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ca3a7b742..c96e2c726 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -45,6 +45,7 @@ struct Env void printEnvBindings(const Env &env, int lv = 0); valmap * mapEnvBindings(const Env &env); +void printEnvPosChain(const Env &env, int lv = 0); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet()); diff --git a/src/libutil/error.hh b/src/libutil/error.hh index ff58d3e00..b6670c8b2 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -100,6 +100,12 @@ struct ErrPos { } }; +std::optional getCodeLines(const ErrPos & errPos); +void printCodeLines(std::ostream & out, + const string & prefix, + const ErrPos & errPos, + const LinesOfCode & loc); + struct Trace { std::optional pos; hintformat hint; -- cgit v1.2.3 From 21071bfdeb0a5bc2b75018c91a4c2f138f233e33 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 14 Sep 2021 10:49:22 -0600 Subject: shared_ptr for StaticEnv --- src/libcmd/repl.cc | 11 +++++---- src/libexpr/eval.cc | 8 +++---- src/libexpr/eval.hh | 9 +++---- src/libexpr/nixexpr.cc | 64 +++++++++++++++++++++++++------------------------- src/libexpr/nixexpr.hh | 8 ++++--- src/libexpr/parser.y | 6 ++--- src/libexpr/primops.cc | 4 ++-- 7 files changed, 57 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 57174bf0e..e1b58cc76 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -53,7 +53,8 @@ struct NixRepl Strings loadedFiles; const static int envSize = 32768; - StaticEnv staticEnv; + std::shared_ptr staticEnv; + // StaticEnv staticEnv; Env * env; int displ; StringSet varNames; @@ -92,7 +93,7 @@ string removeWhitespace(string s) NixRepl::NixRepl(ref state) : state(state) - , staticEnv(false, &state->staticBaseEnv) + , staticEnv(new StaticEnv(false, state->staticBaseEnv.get())) , historyFile(getDataDir() + "/nix/repl-history") { curDir = absPath("."); @@ -567,10 +568,10 @@ void NixRepl::initEnv() env = &state->allocEnv(envSize); env->up = &state->baseEnv; displ = 0; - staticEnv.vars.clear(); + staticEnv->vars.clear(); varNames.clear(); - for (auto & i : state->staticBaseEnv.vars) + for (auto & i : state->staticBaseEnv->vars) varNames.insert(i.first); } @@ -605,7 +606,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v) { if (displ >= envSize) throw Error("environment full; cannot add more variables"); - staticEnv.vars[name] = displ; + staticEnv->vars[name] = displ; env->values[displ++] = v; varNames.insert((string) name); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 19379b876..69e3a4107 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -401,7 +401,7 @@ EvalState::EvalState(const Strings & _searchPath, ref store) , store(store) , regexCache(makeRegexCache()) , baseEnv(allocEnv(128)) - , staticBaseEnv(false, 0) + , staticBaseEnv(new StaticEnv(false, 0)) { countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0"; @@ -538,7 +538,7 @@ Value * EvalState::addConstant(const string & name, Value & v) { Value * v2 = allocValue(); *v2 = v; - staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; + staticBaseEnv->vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v2; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v2)); @@ -564,7 +564,7 @@ Value * EvalState::addPrimOp(const string & name, Value * v = allocValue(); v->mkPrimOp(new PrimOp { .fun = primOp, .arity = arity, .name = sym }); - staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; + staticBaseEnv->vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; baseEnv.values[0]->attrs->push_back(Attr(sym, v)); return v; @@ -590,7 +590,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) Value * v = allocValue(); v->mkPrimOp(new PrimOp(std::move(primOp))); - staticBaseEnv.vars[envName] = baseEnvDispl; + staticBaseEnv->vars[envName] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; baseEnv.values[0]->attrs->push_back(Attr(primOp.name, v)); return v; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index c96e2c726..8edc17789 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -23,6 +23,7 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); +extern std::function debuggerHook; struct PrimOp { @@ -154,10 +155,10 @@ public: /* Parse a Nix expression from the specified file. */ Expr * parseExprFromFile(const Path & path); - Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv); + Expr * parseExprFromFile(const Path & path, std::shared_ptr & staticEnv); /* Parse a Nix expression from the specified string. */ - Expr * parseExprFromString(std::string_view s, const Path & basePath, StaticEnv & staticEnv); + Expr * parseExprFromString(std::string_view s, const Path & basePath, std::shared_ptr & staticEnv); Expr * parseExprFromString(std::string_view s, const Path & basePath); Expr * parseStdin(); @@ -238,7 +239,7 @@ public: Env & baseEnv; /* The same, but used during parsing to resolve variables. */ - StaticEnv staticBaseEnv; // !!! should be private + std::shared_ptr staticBaseEnv; // !!! should be private private: @@ -277,7 +278,7 @@ private: friend struct ExprLet; Expr * parse(const char * text, FileOrigin origin, const Path & path, - const Path & basePath, StaticEnv & staticEnv); + const Path & basePath, std::shared_ptr & staticEnv); public: diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 492b819e7..218e35f33 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -237,35 +237,35 @@ Pos noPos; /* Computing levels/displacements for variables. */ -void Expr::bindVars(const StaticEnv & env) +void Expr::bindVars(const std::shared_ptr &env) { abort(); } -void ExprInt::bindVars(const StaticEnv & env) +void ExprInt::bindVars(const std::shared_ptr &env) { } -void ExprFloat::bindVars(const StaticEnv & env) +void ExprFloat::bindVars(const std::shared_ptr &env) { } -void ExprString::bindVars(const StaticEnv & env) +void ExprString::bindVars(const std::shared_ptr &env) { } -void ExprPath::bindVars(const StaticEnv & env) +void ExprPath::bindVars(const std::shared_ptr &env) { } -void ExprVar::bindVars(const StaticEnv & env) +void ExprVar::bindVars(const std::shared_ptr &env) { /* Check whether the variable appears in the environment. If so, set its level and displacement. */ const StaticEnv * curEnv; unsigned int level; int withLevel = -1; - for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) { + for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { if (curEnv->isWith) { if (withLevel == -1) withLevel = level; } else { @@ -291,7 +291,7 @@ void ExprVar::bindVars(const StaticEnv & env) this->level = withLevel; } -void ExprSelect::bindVars(const StaticEnv & env) +void ExprSelect::bindVars(const std::shared_ptr &env) { e->bindVars(env); if (def) def->bindVars(env); @@ -300,7 +300,7 @@ void ExprSelect::bindVars(const StaticEnv & env) i.expr->bindVars(env); } -void ExprOpHasAttr::bindVars(const StaticEnv & env) +void ExprOpHasAttr::bindVars(const std::shared_ptr &env) { e->bindVars(env); for (auto & i : attrPath) @@ -308,17 +308,17 @@ void ExprOpHasAttr::bindVars(const StaticEnv & env) i.expr->bindVars(env); } -void ExprAttrs::bindVars(const StaticEnv & env) +void ExprAttrs::bindVars(const std::shared_ptr &env) { - const StaticEnv * dynamicEnv = &env; - StaticEnv newEnv(false, &env); + const StaticEnv * dynamicEnv = env.get(); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? if (recursive) { - dynamicEnv = &newEnv; + dynamicEnv = newEnv.get(); unsigned int displ = 0; for (auto & i : attrs) - newEnv.vars[i.first] = i.second.displ = displ++; + newEnv->vars[i.first] = i.second.displ = displ++; for (auto & i : attrs) i.second.e->bindVars(i.second.inherited ? env : newEnv); @@ -329,28 +329,28 @@ void ExprAttrs::bindVars(const StaticEnv & env) i.second.e->bindVars(env); for (auto & i : dynamicAttrs) { - i.nameExpr->bindVars(*dynamicEnv); - i.valueExpr->bindVars(*dynamicEnv); + i.nameExpr->bindVars(newEnv); + i.valueExpr->bindVars(newEnv); } } -void ExprList::bindVars(const StaticEnv & env) +void ExprList::bindVars(const std::shared_ptr &env) { for (auto & i : elems) i->bindVars(env); } -void ExprLambda::bindVars(const StaticEnv & env) +void ExprLambda::bindVars(const std::shared_ptr &env) { - StaticEnv newEnv(false, &env); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? unsigned int displ = 0; - if (!arg.empty()) newEnv.vars[arg] = displ++; + if (!arg.empty()) newEnv->vars[arg] = displ++; if (matchAttrs) { for (auto & i : formals->formals) - newEnv.vars[i.name] = displ++; + newEnv->vars[i.name] = displ++; for (auto & i : formals->formals) if (i.def) i.def->bindVars(newEnv); @@ -359,13 +359,13 @@ void ExprLambda::bindVars(const StaticEnv & env) body->bindVars(newEnv); } -void ExprLet::bindVars(const StaticEnv & env) +void ExprLet::bindVars(const std::shared_ptr &env) { - StaticEnv newEnv(false, &env); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? unsigned int displ = 0; for (auto & i : attrs->attrs) - newEnv.vars[i.first] = i.second.displ = displ++; + newEnv->vars[i.first] = i.second.displ = displ++; for (auto & i : attrs->attrs) i.second.e->bindVars(i.second.inherited ? env : newEnv); @@ -373,7 +373,7 @@ void ExprLet::bindVars(const StaticEnv & env) body->bindVars(newEnv); } -void ExprWith::bindVars(const StaticEnv & env) +void ExprWith::bindVars(const std::shared_ptr &env) { /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous @@ -381,42 +381,42 @@ void ExprWith::bindVars(const StaticEnv & env) const StaticEnv * curEnv; unsigned int level; prevWith = 0; - for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++) + for (curEnv = env.get(), level = 1; curEnv; curEnv = curEnv->up, level++) if (curEnv->isWith) { prevWith = level; break; } attrs->bindVars(env); - StaticEnv newEnv(true, &env); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? body->bindVars(newEnv); } -void ExprIf::bindVars(const StaticEnv & env) +void ExprIf::bindVars(const std::shared_ptr &env) { cond->bindVars(env); then->bindVars(env); else_->bindVars(env); } -void ExprAssert::bindVars(const StaticEnv & env) +void ExprAssert::bindVars(const std::shared_ptr &env) { cond->bindVars(env); body->bindVars(env); } -void ExprOpNot::bindVars(const StaticEnv & env) +void ExprOpNot::bindVars(const std::shared_ptr &env) { e->bindVars(env); } -void ExprConcatStrings::bindVars(const StaticEnv & env) +void ExprConcatStrings::bindVars(const std::shared_ptr &env) { for (auto & i : *es) i->bindVars(env); } -void ExprPos::bindVars(const StaticEnv & env) +void ExprPos::bindVars(const std::shared_ptr &env) { } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 51a14cd59..4c55cb64b 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -79,10 +79,12 @@ struct Expr { virtual ~Expr() { }; virtual void show(std::ostream & str) const; - virtual void bindVars(const StaticEnv & env); + virtual void bindVars(const std::shared_ptr & env); virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol & name); + + std::shared_ptr staticenv; }; std::ostream & operator << (std::ostream & str, const Expr & e); @@ -90,7 +92,7 @@ std::ostream & operator << (std::ostream & str, const Expr & e); #define COMMON_METHODS \ void show(std::ostream & str) const; \ void eval(EvalState & state, Env & env, Value & v); \ - void bindVars(const StaticEnv & env); + void bindVars(const std::shared_ptr & env); struct ExprInt : Expr { @@ -301,7 +303,7 @@ struct ExprOpNot : Expr { \ str << "(" << *e1 << " " s " " << *e2 << ")"; \ } \ - void bindVars(const StaticEnv & env) \ + void bindVars(const std::shared_ptr & env) \ { \ e1->bindVars(env); e2->bindVars(env); \ } \ diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index f948dde47..d1e898677 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -570,7 +570,7 @@ namespace nix { Expr * EvalState::parse(const char * text, FileOrigin origin, - const Path & path, const Path & basePath, StaticEnv & staticEnv) + const Path & path, const Path & basePath, std::shared_ptr & staticEnv) { yyscan_t scanner; ParseData data(*this); @@ -633,13 +633,13 @@ Expr * EvalState::parseExprFromFile(const Path & path) } -Expr * EvalState::parseExprFromFile(const Path & path, StaticEnv & staticEnv) +Expr * EvalState::parseExprFromFile(const Path & path, std::shared_ptr & staticEnv) { return parse(readFile(path).c_str(), foFile, path, dirOf(path), staticEnv); } -Expr * EvalState::parseExprFromString(std::string_view s, const Path & basePath, StaticEnv & staticEnv) +Expr * EvalState::parseExprFromString(std::string_view s, const Path & basePath, std::shared_ptr & staticEnv) { return parse(s.data(), foString, "", basePath, staticEnv); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index fc4afaab8..0400c8942 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -186,11 +186,11 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS Env * env = &state.allocEnv(vScope->attrs->size()); env->up = &state.baseEnv; - StaticEnv staticEnv(false, &state.staticBaseEnv); + auto staticEnv = std::shared_ptr(new StaticEnv(false, state.staticBaseEnv.get())); unsigned int displ = 0; for (auto & attr : *vScope->attrs) { - staticEnv.vars[attr.name] = displ; + staticEnv->vars[attr.name] = displ; env->values[displ++] = attr.value; } -- cgit v1.2.3 From cd8c232b554776031f61cee5f70a8825c60fbfdb Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 15 Sep 2021 16:16:53 -0600 Subject: add cout debugging --- src/libcmd/command.cc | 2 -- src/libexpr/eval.cc | 2 ++ src/libexpr/nixexpr.cc | 42 ++++++++++++++++++++++++++++++++++-------- src/libexpr/nixexpr.hh | 1 + src/libexpr/parser.y | 11 +++++++++++ src/libexpr/primops.cc | 4 ++++ 6 files changed, 52 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 07f4208da..55f6ffd00 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -99,8 +99,6 @@ EvalCommand::EvalCommand() // extern std::function & env)> debuggerHook; extern std::function debuggerHook; - - ref EvalCommand::getEvalState() { std::cout << "EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 69e3a4107..bcef2008f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -918,6 +918,8 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * .errPos = pos }); + std::cout << "pre debuggerHook" << std::endl; + if (debuggerHook) debuggerHook(error, env); throw error; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 218e35f33..f8ded2157 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -3,7 +3,7 @@ #include "util.hh" #include - +#include namespace nix { @@ -283,6 +283,7 @@ void ExprVar::bindVars(const std::shared_ptr &env) enclosing `with'. If there is no `with', then we can issue an "undefined variable" error now. */ if (withLevel == -1) + std::cout << " throw UndefinedVarError({" << std::endl; throw UndefinedVarError({ .msg = hintfmt("undefined variable '%1%'", name), .errPos = pos @@ -310,11 +311,12 @@ void ExprOpHasAttr::bindVars(const std::shared_ptr &env) void ExprAttrs::bindVars(const std::shared_ptr &env) { - const StaticEnv * dynamicEnv = env.get(); - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + std::cout << "ExprAttrs::bindVars" << std::endl; + // auto dynamicEnv(env); if (recursive) { - dynamicEnv = newEnv.get(); + // dynamicEnv = newEnv.get(); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? unsigned int displ = 0; for (auto & i : attrs) @@ -322,16 +324,25 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) for (auto & i : attrs) i.second.e->bindVars(i.second.inherited ? env : newEnv); + + for (auto & i : dynamicAttrs) { + i.nameExpr->bindVars(newEnv); + i.valueExpr->bindVars(newEnv); + } } - else + else { for (auto & i : attrs) i.second.e->bindVars(env); - for (auto & i : dynamicAttrs) { - i.nameExpr->bindVars(newEnv); - i.valueExpr->bindVars(newEnv); + for (auto & i : dynamicAttrs) { + i.nameExpr->bindVars(env); + i.valueExpr->bindVars(env); + } } + + std::cout << "ExprAttrs::bindVars end" << std::endl; + } void ExprList::bindVars(const std::shared_ptr &env) @@ -375,6 +386,7 @@ void ExprLet::bindVars(const std::shared_ptr &env) void ExprWith::bindVars(const std::shared_ptr &env) { + std::cout << " ExprWith::bindVars " << std::endl; /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous `with' if this one doesn't contain the desired attribute. */ @@ -387,9 +399,23 @@ void ExprWith::bindVars(const std::shared_ptr &env) break; } + std::cout << " ExprWith::bindVars 1" << std::endl; + attrs->show(std::cout); + std::cout << std::endl; attrs->bindVars(env); auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + std::cout << " ExprWith::bindVars 2" << std::endl; + std::cout << " body: " << std::endl; + body->show(std::cout); + std::cout << std::endl; + + std::cout << "ExprWith::newenv: " << newEnv->vars.size() << std::endl; + for (auto i = newEnv->vars.begin(); i != newEnv->vars.end(); ++i) + std::cout << "EvalState::parse newEnv " << i->first << std::endl; + + body->bindVars(newEnv); + std::cout << " ExprWith::bindVars 3" << std::endl; } void ExprIf::bindVars(const std::shared_ptr &env) diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 4c55cb64b..ce3ee9f4d 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -20,6 +20,7 @@ MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); MakeError(RestrictedPathError, Error); +extern std::function debuggerHook; /* Position objects. */ diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d1e898677..a3432eb32 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -22,6 +22,8 @@ #include "eval.hh" #include "globals.hh" +#include + namespace nix { struct ParseData @@ -572,6 +574,10 @@ namespace nix { Expr * EvalState::parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, std::shared_ptr & staticEnv) { + std::cout << "EvalState::parse " << std::endl; + for (auto i = staticEnv->vars.begin(); i != staticEnv->vars.end(); ++i) + std::cout << "EvalState::parse staticEnv " << i->first << std::endl; + yyscan_t scanner; ParseData data(*this); data.origin = origin; @@ -595,8 +601,13 @@ Expr * EvalState::parse(const char * text, FileOrigin origin, if (res) throw ParseError(data.error.value()); + + std::cout << "EvalState::parse pre bindvars " << std::endl; + data.result->bindVars(staticEnv); + std::cout << "EvalState::parse post bindVars " << std::endl; + return data.result; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 0400c8942..7a277a7f5 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -110,6 +110,8 @@ static void mkOutputString(EvalState & state, Value & v, argument. */ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v) { + std::cout << " import " << std::endl; + PathSet context; Path path = state.coerceToPath(pos, vPath, context); @@ -194,6 +196,8 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS env->values[displ++] = attr.value; } + std::cout << "import staticenv: {} " << staticEnv << std::endl; + printTalkative("evaluating file '%1%'", realPath); Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv); -- cgit v1.2.3 From c7e3d830c1f305797b7a4c8b8199ba913d6b8a02 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 22 Sep 2021 16:22:53 -0600 Subject: more debug stuff --- src/libcmd/installables.cc | 4 ++++ src/libexpr/nixexpr.cc | 41 +++++++++++++++++++++++++++++++++++++---- src/libexpr/parser.y | 2 +- src/libexpr/primops.cc | 3 +++ 4 files changed, 45 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index fd3e5cbba..bce666de5 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -619,6 +619,10 @@ std::vector> SourceExprCommand::parseInstallables( state->evalFile(lookupFileArg(*state, *file), *vFile); else { auto e = state->parseExprFromString(*expr, absPath(".")); + + int x = 5; + std::cout << "x =" << x << std::endl; + state->eval(e, *vFile); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index f8ded2157..6db047bf7 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -315,12 +315,16 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) // auto dynamicEnv(env); if (recursive) { + std::cout << "recursive" << std::endl; // dynamicEnv = newEnv.get(); - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + // also make shared_ptr? + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); unsigned int displ = 0; - for (auto & i : attrs) + for (auto & i : attrs) { + std::cout << "newenvvar: " << i.first << std::endl; newEnv->vars[i.first] = i.second.displ = displ++; + } for (auto & i : attrs) i.second.e->bindVars(i.second.inherited ? env : newEnv); @@ -330,8 +334,8 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) i.valueExpr->bindVars(newEnv); } } - else { + std::cout << "NOT recursive" << std::endl; for (auto & i : attrs) i.second.e->bindVars(env); @@ -409,7 +413,7 @@ void ExprWith::bindVars(const std::shared_ptr &env) body->show(std::cout); std::cout << std::endl; - std::cout << "ExprWith::newenv: " << newEnv->vars.size() << std::endl; + std::cout << "ExprWith::newenv: (iswith, size); (" << newEnv->isWith << ", " << newEnv->vars.size() << ") " << std::endl; for (auto i = newEnv->vars.begin(); i != newEnv->vars.end(); ++i) std::cout << "EvalState::parse newEnv " << i->first << std::endl; @@ -418,6 +422,35 @@ void ExprWith::bindVars(const std::shared_ptr &env) std::cout << " ExprWith::bindVars 3" << std::endl; } +/* +void ExprWith::bindVars(const StaticEnv & env) +{ + // Does this `with' have an enclosing `with'? If so, record its + // level so that `lookupVar' can look up variables in the previous + // `with' if this one doesn't contain the desired attribute. + const StaticEnv * curEnv; + unsigned int level; + prevWith = 0; + for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++) + if (curEnv->isWith) { + prevWith = level; + break; + } + + attrs->bindVars(env); + std::cout << "ExprWith::bindVars env: " << env.vars.size(); // add std::endl; + for (auto i = env.vars.begin(); i != env.vars.end(); ++i) + { + std::cout << i->first << std::endl; + } + + StaticEnv newEnv(true, &env); + body->bindVars(newEnv); +} +*/ + + + void ExprIf::bindVars(const std::shared_ptr &env) { cond->bindVars(env); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index a3432eb32..f10e73cda 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -574,7 +574,7 @@ namespace nix { Expr * EvalState::parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, std::shared_ptr & staticEnv) { - std::cout << "EvalState::parse " << std::endl; + std::cout << "EvalState::parse " << text << std::endl; for (auto i = staticEnv->vars.begin(); i != staticEnv->vars.end(); ++i) std::cout << "EvalState::parse staticEnv " << i->first << std::endl; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 7a277a7f5..246a3140b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -110,6 +110,9 @@ static void mkOutputString(EvalState & state, Value & v, argument. */ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v) { + std::cout << " IMPORT " << std::endl; + std::cout << " import " << std::endl; + std::cout << " IMPORT " << std::endl; std::cout << " import " << std::endl; PathSet context; -- cgit v1.2.3 From c07edb1932b0f747b563aceaecc5550f5ce192fb Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 22 Sep 2021 18:14:57 -0600 Subject: staticenv should be With --- src/libexpr/eval.cc | 2 +- src/libexpr/nixexpr.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bcef2008f..53a5c5bd2 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -976,7 +976,7 @@ void mkPath(Value & v, const char * s) inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) { - // std::cout << " EvalState::lookupVar" << std::endl; + std::cout << " EvalState::lookupVar" << var << std::endl; for (size_t l = var.level; l; --l, env = env->up) ; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 6db047bf7..8b883e185 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -407,7 +407,7 @@ void ExprWith::bindVars(const std::shared_ptr &env) attrs->show(std::cout); std::cout << std::endl; attrs->bindVars(env); - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); // also make shared_ptr? std::cout << " ExprWith::bindVars 2" << std::endl; std::cout << " body: " << std::endl; body->show(std::cout); -- cgit v1.2.3 From b9d08b98da4ab18f0c1c8bee30bd4ad934a5cdcf Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 23 Sep 2021 13:02:39 -0600 Subject: ok was unconditoinally throwing on any With var --- src/libcmd/installables.cc | 4 +-- src/libexpr/nixexpr.cc | 69 +++++++++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index bce666de5..f85bd4c13 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -618,10 +618,10 @@ std::vector> SourceExprCommand::parseInstallables( if (file) state->evalFile(lookupFileArg(*state, *file), *vFile); else { + std::cout << "pre parseExprFromString" << std::endl; auto e = state->parseExprFromString(*expr, absPath(".")); - int x = 5; - std::cout << "x =" << x << std::endl; + std::cout << "pre eval" << std::endl; state->eval(e, *vFile); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 8b883e185..6ca0de72b 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -262,34 +262,52 @@ void ExprVar::bindVars(const std::shared_ptr &env) { /* Check whether the variable appears in the environment. If so, set its level and displacement. */ - const StaticEnv * curEnv; - unsigned int level; - int withLevel = -1; - for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { - if (curEnv->isWith) { - if (withLevel == -1) withLevel = level; - } else { - StaticEnv::Vars::const_iterator i = curEnv->vars.find(name); - if (i != curEnv->vars.end()) { - fromWith = false; - this->level = level; - displ = i->second; - return; + + std::cout << "ExprVar::bindVars " << name << std::endl; + + int a = 10; + if (name == "callPackage") { + a++; // try to make code that I can put a breakpoint on... + std::cout << "meh" << a + 10 << std::endl; + int withLevel = -1; + fromWith = true; + // this->level = withLevel; + } + + { + + const StaticEnv * curEnv; + unsigned int level; + int withLevel = -1; + for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { + if (curEnv->isWith) { + if (withLevel == -1) withLevel = level; + } else { + StaticEnv::Vars::const_iterator i = curEnv->vars.find(name); + if (i != curEnv->vars.end()) { + fromWith = false; + this->level = level; + displ = i->second; + return; + } } } + + + /* Otherwise, the variable must be obtained from the nearest + enclosing `with'. If there is no `with', then we can issue an + "undefined variable" error now. */ + if (withLevel == -1) + { + std::cout << " throw UndefinedVarError({" << std::endl; + throw UndefinedVarError({ + .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), + .errPos = pos + }); + } + fromWith = true; + this->level = withLevel; } - - /* Otherwise, the variable must be obtained from the nearest - enclosing `with'. If there is no `with', then we can issue an - "undefined variable" error now. */ - if (withLevel == -1) - std::cout << " throw UndefinedVarError({" << std::endl; - throw UndefinedVarError({ - .msg = hintfmt("undefined variable '%1%'", name), - .errPos = pos - }); - fromWith = true; - this->level = withLevel; } void ExprSelect::bindVars(const std::shared_ptr &env) @@ -418,6 +436,7 @@ void ExprWith::bindVars(const std::shared_ptr &env) std::cout << "EvalState::parse newEnv " << i->first << std::endl; + std::cout << " body->bindVars(newEnv), iswith: " << newEnv->isWith << std::endl; body->bindVars(newEnv); std::cout << " ExprWith::bindVars 3" << std::endl; } -- cgit v1.2.3 From aad27143c67c863bd4886186bdf68f4796ca26c3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sat, 2 Oct 2021 13:47:36 -0600 Subject: storing staticenv bindings --- src/libexpr/eval.cc | 23 +++++++++++++++++++++++ src/libexpr/nixexpr.cc | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/libexpr/nixexpr.hh | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 53a5c5bd2..c2b6e7ea8 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -689,6 +689,29 @@ void printEnvBindings(const Env &env, int lv ) } } +void printStaticEnvBindings(const StaticEnv &se, int lvl) +{ + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) + { + std::cout << lvl << i->first << std::endl; + } + + if (se.up) { + printStaticEnvBindings(*se.up, ++lvl); + } + +} + +void printStaticEnvBindings(const Expr &expr) +{ + // just print the names for now + if (expr.staticenv) + { + printStaticEnvBindings(*expr.staticenv.get(), 0); + } + +} + void printEnvPosChain(const Env &env, int lv ) { std::cout << "printEnvPosChain " << lv << std::endl; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 6ca0de72b..85b1d5e12 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -244,22 +244,33 @@ void Expr::bindVars(const std::shared_ptr &env) void ExprInt::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; } void ExprFloat::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; } void ExprString::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; } void ExprPath::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; } void ExprVar::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + /* Check whether the variable appears in the environment. If so, set its level and displacement. */ @@ -312,6 +323,9 @@ void ExprVar::bindVars(const std::shared_ptr &env) void ExprSelect::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + e->bindVars(env); if (def) def->bindVars(env); for (auto & i : attrPath) @@ -321,6 +335,9 @@ void ExprSelect::bindVars(const std::shared_ptr &env) void ExprOpHasAttr::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + e->bindVars(env); for (auto & i : attrPath) if (!i.symbol.set()) @@ -329,6 +346,9 @@ void ExprOpHasAttr::bindVars(const std::shared_ptr &env) void ExprAttrs::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + std::cout << "ExprAttrs::bindVars" << std::endl; // auto dynamicEnv(env); @@ -369,12 +389,18 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) void ExprList::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + for (auto & i : elems) i->bindVars(env); } void ExprLambda::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? unsigned int displ = 0; @@ -394,6 +420,9 @@ void ExprLambda::bindVars(const std::shared_ptr &env) void ExprLet::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? unsigned int displ = 0; @@ -408,6 +437,9 @@ void ExprLet::bindVars(const std::shared_ptr &env) void ExprWith::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + std::cout << " ExprWith::bindVars " << std::endl; /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous @@ -472,6 +504,9 @@ void ExprWith::bindVars(const StaticEnv & env) void ExprIf::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + cond->bindVars(env); then->bindVars(env); else_->bindVars(env); @@ -479,23 +514,35 @@ void ExprIf::bindVars(const std::shared_ptr &env) void ExprAssert::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + cond->bindVars(env); body->bindVars(env); } void ExprOpNot::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + e->bindVars(env); } void ExprConcatStrings::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + for (auto & i : *es) i->bindVars(env); } void ExprPos::bindVars(const std::shared_ptr &env) { + if (debuggerHook) + staticenv = env; + } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index ce3ee9f4d..341d80b35 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -85,7 +85,7 @@ struct Expr virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol & name); - std::shared_ptr staticenv; + std::shared_ptr staticenv; }; std::ostream & operator << (std::ostream & str, const Expr & e); -- cgit v1.2.3 From 2ee1fa4afd69226f16305e792d5110fd36669c6b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Oct 2021 14:42:29 -0600 Subject: add nullable Expr argument --- src/libcmd/command.cc | 4 +- src/libexpr/eval.cc | 129 +++++++++++++++++++++++++++---------------------- src/libexpr/eval.hh | 2 +- src/libexpr/nixexpr.hh | 2 +- 4 files changed, 74 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 55f6ffd00..705b30d53 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -97,7 +97,7 @@ EvalCommand::EvalCommand() }); } // extern std::function & env)> debuggerHook; -extern std::function debuggerHook; +extern std::function debuggerHook; ref EvalCommand::getEvalState() { @@ -105,7 +105,7 @@ ref EvalCommand::getEvalState() if (!evalState) { evalState = std::make_shared(searchPath, getStore()); if (startReplOnEvalErrors) - debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env) { + debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); // printEnvPosChain(env); printEnvBindings(env); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c2b6e7ea8..76c038593 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -36,7 +36,7 @@ namespace nix { // std::function & env)> debuggerHook; -std::function debuggerHook; +std::function debuggerHook; static char * dupString(const char * s) { @@ -806,17 +806,17 @@ valmap * mapEnvBindings(const Env &env) evaluator. So here are some helper functions for throwing exceptions. */ -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env & env)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = EvalError({ @@ -824,22 +824,24 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, Env & env)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2, s3); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, Env & env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = EvalError({ @@ -847,12 +849,13 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env, Expr *expr)) { // p1 is where the error occurred; p2 is a position mentioned in the message. // auto delenv = std::unique_ptr(env); @@ -861,12 +864,13 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const .errPos = p1 }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -874,12 +878,13 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -887,12 +892,13 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -900,12 +906,13 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = TypeError({ @@ -913,12 +920,13 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env)) +LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = AssertionError({ @@ -926,12 +934,13 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env)) +LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { std::cout << "throwUndefinedVarError" << std::endl; @@ -943,12 +952,13 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * std::cout << "pre debuggerHook" << std::endl; - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { // auto delenv = std::unique_ptr(env); auto error = MissingArgumentError({ @@ -956,8 +966,9 @@ LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char .errPos = pos }); - if (debuggerHook) - debuggerHook(error, env); + if (debuggerHook && expr) + debuggerHook(error, env, *expr); + throw error; } @@ -1020,7 +1031,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) } if (!env->prevWith) { std::cout << "pre throwUndefinedVarError" << std::endl; - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, 0); } for (size_t l = env->prevWith; l; --l, env = env->up) ; } @@ -1354,7 +1365,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, - env); + env, this); // map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); @@ -1445,7 +1456,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } else { state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError(pos, "attribute '%1%' missing", name, env); + throwEvalError(pos, "attribute '%1%' missing", name, env, this); // mapBindings(*vAttrs->attrs)); } vAttrs = j->value; @@ -1573,7 +1584,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po pos, "attempt to call something which is not a function but %1%", showType(fun).c_str(), - fakeEnv(1)); + fakeEnv(1), 0); // fun.env); // map2("fun", &fun, "arg", &arg)); } @@ -1612,7 +1623,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called without required argument '%2%'", lambda, i.name, - *fun.lambda.env); + *fun.lambda.env, &lambda); // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { @@ -1633,7 +1644,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "%1% called with unexpected argument '%2%'", lambda, i.name, - *fun.lambda.env); + *fun.lambda.env, &lambda); // map2("fun", &fun, "arg", &arg)); abort(); // can't happen } @@ -1711,7 +1722,7 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - *fun.lambda.env); + *fun.lambda.env, fun.lambda.fun); // mapBindings(args)); // map1("fun", &fun)); // todo add bindings + fun } @@ -1761,7 +1772,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) if (!state.evalBool(env, cond, pos)) { std::ostringstream out; cond->show(out); - throwAssertionError(pos, "assertion '%1%' failed", out.str(), env); + throwAssertionError(pos, "assertion '%1%' failed", out.str(), env, this); } body->eval(state, env, v); } @@ -1915,7 +1926,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else { std::cerr << "envtype: " << showType(env.values[0]->type()) << std::endl; - throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), env); + throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), env, this); } } else if (firstType == nFloat) { if (vTmp.type() == nInt) { @@ -1923,7 +1934,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else - throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), env); + throwEvalError(pos, "cannot add %1% to a float", showType(vTmp), env, this); } else s << state.coerceToString(pos, vTmp, context, false, firstType == nString); } @@ -1984,7 +1995,7 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); return v.integer; } @@ -1997,7 +2008,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) return v.integer; else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); return v.fpoint; } @@ -2008,7 +2019,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); return v.boolean; } @@ -2025,7 +2036,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); } @@ -2035,7 +2046,7 @@ string EvalState::forceString(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nString) { throwTypeError(pos, "value is %1% while a string was expected", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); } return string(v.string.s); @@ -2089,13 +2100,13 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], // b.has_value() ? mapBindings(*b.get()) : map0()); - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], // b.has_value() ? mapBindings(*b.get()) : map0()); - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); } return s; @@ -2169,7 +2180,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string", - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2201,7 +2212,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } throwTypeError(pos, "cannot coerce %1% to a string", v, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); } @@ -2211,7 +2222,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path) if (nix::isDerivation(path)) throwEvalError("file names are not allowed to end in '%1%'", drvExtension, - fakeEnv(1)); + fakeEnv(1), 0); // map0()); Path dstPath; @@ -2237,7 +2248,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) string path = coerceToString(pos, v, context, false, false); if (path == "" || path[0] != '/') throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, - fakeEnv(1)); + fakeEnv(1), 0); // map1("value", &v)); return path; } @@ -2320,7 +2331,7 @@ bool EvalState::eqValues(Value & v1, Value & v2) throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), - fakeEnv(1)); + fakeEnv(1), 0); // map2("value1", &v1, "value2", &v2)); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 8edc17789..553e7861a 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -23,7 +23,7 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); -extern std::function debuggerHook; +extern std::function debuggerHook; struct PrimOp { diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 341d80b35..a78ea6215 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -20,7 +20,7 @@ MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); MakeError(RestrictedPathError, Error); -extern std::function debuggerHook; +extern std::function debuggerHook; /* Position objects. */ -- cgit v1.2.3 From 98eb13691a16d9472b822a92f32b439a6ee6e288 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Oct 2021 16:32:43 -0600 Subject: print staticenv bindings --- src/libcmd/command.cc | 12 +++++++++--- src/libexpr/eval.cc | 28 ++++++++++++++++++++++++++++ src/libexpr/eval.hh | 2 ++ 3 files changed, 39 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 705b30d53..d8e79953c 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -107,10 +107,16 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + + printStaticEnvBindings(expr); + // printEnvPosChain(env); - printEnvBindings(env); - auto vm = mapEnvBindings(env); - runRepl(evalState, *vm); + // printEnvBindings(env); + if (expr.staticenv) + { + auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); + runRepl(evalState, *vm); + } }; } return ref(evalState); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 76c038593..fba5f5031 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -712,6 +712,34 @@ void printStaticEnvBindings(const Expr &expr) } +void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) +{ + // add bindings for the next level up first. + if (env.up && se.up) { + mapStaticEnvBindings( *se.up, *env.up,vm); + } + + // iterate through staticenv bindings. + + auto map = valmap(); + for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + { + map[iter->first] = env.values[iter->second]; + } + + vm.merge(map); + +} + + +valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) +{ + auto vm = new valmap(); + mapStaticEnvBindings(se, env, *vm); + return vm; +} + + void printEnvPosChain(const Env &env, int lv ) { std::cout << "printEnvPosChain " << lv << std::endl; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 553e7861a..29599cc6c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -24,6 +24,7 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); extern std::function debuggerHook; +void printStaticEnvBindings(const Expr &expr); struct PrimOp { @@ -47,6 +48,7 @@ struct Env void printEnvBindings(const Env &env, int lv = 0); valmap * mapEnvBindings(const Env &env); void printEnvPosChain(const Env &env, int lv = 0); +valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet()); -- cgit v1.2.3 From 427fb8d1581d7b20b0f5205cc59f3857275860c1 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Oct 2021 16:48:10 -0600 Subject: comment out debugs --- src/libcmd/installables.cc | 4 ++-- src/libexpr/eval.cc | 18 +++++++++--------- src/libexpr/nixexpr.cc | 42 +++++++++++++++++++++--------------------- src/libexpr/parser.y | 10 +++++----- src/libexpr/primops.cc | 8 ++++---- 5 files changed, 41 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index f85bd4c13..c3436acf9 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -618,10 +618,10 @@ std::vector> SourceExprCommand::parseInstallables( if (file) state->evalFile(lookupFileArg(*state, *file), *vFile); else { - std::cout << "pre parseExprFromString" << std::endl; + // std::cout << "pre parseExprFromString" << std::endl; auto e = state->parseExprFromString(*expr, absPath(".")); - std::cout << "pre eval" << std::endl; + // std::cout << "pre eval" << std::endl; state->eval(e, *vFile); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index fba5f5031..12f7e8979 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -742,13 +742,13 @@ valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) void printEnvPosChain(const Env &env, int lv ) { - std::cout << "printEnvPosChain " << lv << std::endl; + // std::cout << "printEnvPosChain " << lv << std::endl; - std::cout << "env" << env.values[0] << std::endl; + // std::cout << "env" << env.values[0] << std::endl; if (env.values[0] && env.values[0]->type() == nAttrs) { - std::cout << "im in the loop" << std::endl; - std::cout << "pos " << env.values[0]->attrs->pos << std::endl; + // std::cout << "im in the loop" << std::endl; + // std::cout << "pos " << env.values[0]->attrs->pos << std::endl; if (env.values[0]->attrs->pos) { ErrPos ep(*env.values[0]->attrs->pos); auto loc = getCodeLines(ep); @@ -760,7 +760,7 @@ void printEnvPosChain(const Env &env, int lv ) } } - std::cout << "next env : " << env.up << std::endl; + // std::cout << "next env : " << env.up << std::endl; if (env.up) { printEnvPosChain(*env.up, ++lv); @@ -970,7 +970,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { - std::cout << "throwUndefinedVarError" << std::endl; + // std::cout << "throwUndefinedVarError" << std::endl; // auto delenv = std::unique_ptr(env); auto error = UndefinedVarError({ @@ -978,7 +978,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * .errPos = pos }); - std::cout << "pre debuggerHook" << std::endl; + // std::cout << "pre debuggerHook" << std::endl; if (debuggerHook && expr) debuggerHook(error, env, *expr); @@ -1038,7 +1038,7 @@ void mkPath(Value & v, const char * s) inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) { - std::cout << " EvalState::lookupVar" << var << std::endl; + // std::cout << " EvalState::lookupVar" << var << std::endl; for (size_t l = var.level; l; --l, env = env->up) ; @@ -1058,7 +1058,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) { - std::cout << "pre throwUndefinedVarError" << std::endl; + // std::cout << "pre throwUndefinedVarError" << std::endl; throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, 0); } for (size_t l = env->prevWith; l; --l, env = env->up) ; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 85b1d5e12..8f88eabd5 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -274,12 +274,12 @@ void ExprVar::bindVars(const std::shared_ptr &env) /* Check whether the variable appears in the environment. If so, set its level and displacement. */ - std::cout << "ExprVar::bindVars " << name << std::endl; + // std::cout << "ExprVar::bindVars " << name << std::endl; int a = 10; if (name == "callPackage") { a++; // try to make code that I can put a breakpoint on... - std::cout << "meh" << a + 10 << std::endl; + // std::cout << "meh" << a + 10 << std::endl; int withLevel = -1; fromWith = true; // this->level = withLevel; @@ -310,7 +310,7 @@ void ExprVar::bindVars(const std::shared_ptr &env) "undefined variable" error now. */ if (withLevel == -1) { - std::cout << " throw UndefinedVarError({" << std::endl; + // std::cout << " throw UndefinedVarError({" << std::endl; throw UndefinedVarError({ .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), .errPos = pos @@ -349,18 +349,18 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - std::cout << "ExprAttrs::bindVars" << std::endl; + // std::cout << "ExprAttrs::bindVars" << std::endl; // auto dynamicEnv(env); if (recursive) { - std::cout << "recursive" << std::endl; + // std::cout << "recursive" << std::endl; // dynamicEnv = newEnv.get(); // also make shared_ptr? auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); unsigned int displ = 0; for (auto & i : attrs) { - std::cout << "newenvvar: " << i.first << std::endl; + // std::cout << "newenvvar: " << i.first << std::endl; newEnv->vars[i.first] = i.second.displ = displ++; } @@ -373,7 +373,7 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) } } else { - std::cout << "NOT recursive" << std::endl; + // std::cout << "NOT recursive" << std::endl; for (auto & i : attrs) i.second.e->bindVars(env); @@ -383,7 +383,7 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) } } - std::cout << "ExprAttrs::bindVars end" << std::endl; + // std::cout << "ExprAttrs::bindVars end" << std::endl; } @@ -440,7 +440,7 @@ void ExprWith::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - std::cout << " ExprWith::bindVars " << std::endl; + // std::cout << " ExprWith::bindVars " << std::endl; /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous `with' if this one doesn't contain the desired attribute. */ @@ -453,24 +453,24 @@ void ExprWith::bindVars(const std::shared_ptr &env) break; } - std::cout << " ExprWith::bindVars 1" << std::endl; - attrs->show(std::cout); - std::cout << std::endl; + // std::cout << " ExprWith::bindVars 1" << std::endl; + // attrs->show(std::cout); + // std::cout << std::endl; attrs->bindVars(env); auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); // also make shared_ptr? - std::cout << " ExprWith::bindVars 2" << std::endl; - std::cout << " body: " << std::endl; - body->show(std::cout); - std::cout << std::endl; + // std::cout << " ExprWith::bindVars 2" << std::endl; + // std::cout << " body: " << std::endl; + // body->show(std::cout); + // std::cout << std::endl; - std::cout << "ExprWith::newenv: (iswith, size); (" << newEnv->isWith << ", " << newEnv->vars.size() << ") " << std::endl; - for (auto i = newEnv->vars.begin(); i != newEnv->vars.end(); ++i) - std::cout << "EvalState::parse newEnv " << i->first << std::endl; + // std::cout << "ExprWith::newenv: (iswith, size); (" << newEnv->isWith << ", " << newEnv->vars.size() << ") " << std::endl; + // for (auto i = newEnv->vars.begin(); i != newEnv->vars.end(); ++i) + // std::cout << "EvalState::parse newEnv " << i->first << std::endl; - std::cout << " body->bindVars(newEnv), iswith: " << newEnv->isWith << std::endl; + // std::cout << " body->bindVars(newEnv), iswith: " << newEnv->isWith << std::endl; body->bindVars(newEnv); - std::cout << " ExprWith::bindVars 3" << std::endl; + // std::cout << " ExprWith::bindVars 3" << std::endl; } /* diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index f10e73cda..46bbce1f6 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -574,9 +574,9 @@ namespace nix { Expr * EvalState::parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, std::shared_ptr & staticEnv) { - std::cout << "EvalState::parse " << text << std::endl; - for (auto i = staticEnv->vars.begin(); i != staticEnv->vars.end(); ++i) - std::cout << "EvalState::parse staticEnv " << i->first << std::endl; + // std::cout << "EvalState::parse " << text << std::endl; + // for (auto i = staticEnv->vars.begin(); i != staticEnv->vars.end(); ++i) + // std::cout << "EvalState::parse staticEnv " << i->first << std::endl; yyscan_t scanner; ParseData data(*this); @@ -602,11 +602,11 @@ Expr * EvalState::parse(const char * text, FileOrigin origin, if (res) throw ParseError(data.error.value()); - std::cout << "EvalState::parse pre bindvars " << std::endl; + // std::cout << "EvalState::parse pre bindvars " << std::endl; data.result->bindVars(staticEnv); - std::cout << "EvalState::parse post bindVars " << std::endl; + // std::cout << "EvalState::parse post bindVars " << std::endl; return data.result; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 246a3140b..4b8ad3e9a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -110,10 +110,10 @@ static void mkOutputString(EvalState & state, Value & v, argument. */ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v) { - std::cout << " IMPORT " << std::endl; - std::cout << " import " << std::endl; - std::cout << " IMPORT " << std::endl; - std::cout << " import " << std::endl; + // std::cout << " IMPORT " << std::endl; + // std::cout << " import " << std::endl; + // std::cout << " IMPORT " << std::endl; + // std::cout << " import " << std::endl; PathSet context; Path path = state.coerceToPath(pos, vPath, context); -- cgit v1.2.3 From 383ab600ee1f36f14677a0082473f5680193c12c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 22 Oct 2021 13:41:04 -0600 Subject: show expr on error --- src/libcmd/command.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index d8e79953c..2d86dbd61 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -110,6 +110,10 @@ ref EvalCommand::getEvalState() printStaticEnvBindings(expr); + std::cout << "expr: " << std::endl; + expr.show(std::cout); + std::cout << std::endl; + // printEnvPosChain(env); // printEnvBindings(env); if (expr.staticenv) -- cgit v1.2.3 From cbc2f0fe31576a6403e179bdbbaf9aefa113555b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 22 Oct 2021 14:02:47 -0600 Subject: remove dead code --- src/libcmd/command.cc | 36 ------------ src/libexpr/eval.cc | 157 -------------------------------------------------- src/libexpr/eval.hh | 3 - 3 files changed, 196 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 2d86dbd61..8d5098bc7 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -54,7 +54,6 @@ void StoreCommand::run() run(getStore()); } -/* EvalCommand::EvalCommand() { addFlag({ @@ -64,39 +63,6 @@ EvalCommand::EvalCommand() }); } -extern std::function & env)> debuggerHook; - -ref EvalCommand::getEvalState() -{ - if (!evalState) { - evalState = std::make_shared(searchPath, getStore()); - if (startReplOnEvalErrors) - debuggerHook = [evalState{ref(evalState)}](const Error & error, const std::map & env) { - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); - runRepl(evalState, env); - }; - } - return ref(evalState); -} -*/ -// ref EvalCommand::getEvalState() -// { -// if (!evalState) -// evalState = std::make_shared(searchPath, getStore()); -// return ref(evalState); -// } - - -EvalCommand::EvalCommand() -{ - // std::cout << "EvalCommand::EvalCommand()" << std::endl; - addFlag({ - .longName = "debugger", - .description = "start an interactive environment if evaluation fails", - .handler = {&startReplOnEvalErrors, true}, - }); -} -// extern std::function & env)> debuggerHook; extern std::function debuggerHook; ref EvalCommand::getEvalState() @@ -114,8 +80,6 @@ ref EvalCommand::getEvalState() expr.show(std::cout); std::cout << std::endl; - // printEnvPosChain(env); - // printEnvBindings(env); if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 12f7e8979..f286cbeec 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -619,75 +619,7 @@ std::optional EvalState::getDoc(Value & v) return {}; } -// typedef std::map valmap; - -/*void addEnv(Value * v, valmap &vmap) -{ - if (v.isThunk()) { - Env * env = v.thunk.env; - - Expr * expr = v.thunk.expr; - -} -*/ -// LocalNoInline(valmap * map0()) -// { -// return new valmap(); -// } - -// LocalNoInline(valmap * map1(const char *name, Value *v)) -// { -// return new valmap({{name, v}}); -// } - -// LocalNoInline(valmap * map2(const char *name1, Value *v1, const char *name2, Value *v2)) -// { -// return new valmap({{name1, v1}, {name2, v2}}); -// } - -// LocalNoInline(valmap * mapBindings(Bindings &b)) -// { -// auto map = new valmap(); -// for (auto i = b.begin(); i != b.end(); ++i) -// { -// std::string s = i->name; -// (*map)[s] = i->value; -// } -// return map; -// } - -// LocalNoInline(void addBindings(string prefix, Bindings &b, valmap &valmap)) -// { -// for (auto i = b.begin(); i != b.end(); ++i) -// { -// std::string s = prefix; -// s += i->name; -// valmap[s] = i->value; -// } -// } - -void printEnvBindings(const Env &env, int lv ) -{ - std::cout << "env " << lv << " type: " << env.type << std::endl; - if (env.values[0]->type() == nAttrs) { - Bindings::iterator j = env.values[0]->attrs->begin(); - - - while (j != env.values[0]->attrs->end()) { - std::cout << lv << " env binding: " << j->name << std::endl; - // if (countCalls && j->pos) attrSelects[*j->pos]++; - // return j->value; - j++; - } - - } - std::cout << "next env : " << env.up << std::endl; - - if (env.up) { - printEnvBindings(*env.up, ++lv); - } -} void printStaticEnvBindings(const StaticEnv &se, int lvl) { @@ -740,95 +672,6 @@ valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) } -void printEnvPosChain(const Env &env, int lv ) -{ - // std::cout << "printEnvPosChain " << lv << std::endl; - - // std::cout << "env" << env.values[0] << std::endl; - - if (env.values[0] && env.values[0]->type() == nAttrs) { - // std::cout << "im in the loop" << std::endl; - // std::cout << "pos " << env.values[0]->attrs->pos << std::endl; - if (env.values[0]->attrs->pos) { - ErrPos ep(*env.values[0]->attrs->pos); - auto loc = getCodeLines(ep); - if (loc) - printCodeLines(std::cout, - std::__cxx11::to_string(lv), - ep, - *loc); - } - } - - // std::cout << "next env : " << env.up << std::endl; - - if (env.up) { - printEnvPosChain(*env.up, ++lv); - } -} - -void mapEnvBindings(const Env &env, valmap & vm) -{ - // add bindings for the next level up first. - if (env.up) { - mapEnvBindings(*env.up, vm); - } - - // merge - and write over - higher level bindings. - // note; skipping HasWithExpr that haven't been evaled yet. - if (env.values[0] && env.values[0]->type() == nAttrs) { - auto map = valmap(); - - Bindings::iterator j = env.values[0]->attrs->begin(); - - while (j != env.values[0]->attrs->end()) { - map[j->name] = j->value; - j++; - } - vm.merge(map); - } -} - - -valmap * mapEnvBindings(const Env &env) -{ - auto vm = new valmap(); - - mapEnvBindings(env, *vm); - - return vm; -} - -// LocalNoInline(valmap * mapEnvBindings(Env &env)) -// { -// // NOT going to use this -// if (env.valuemap) { -// std::cout << "got static env" << std::endl; -// } - -// // std::cout << "envsize: " << env.values.size() << std::endl; - -// // std::cout << "size_t size: " << sizeof(size_t) << std::endl; -// // std::cout << "envsize: " << env.size << std::endl; -// // std::cout << "envup: " << env.up << std::endl; - -// valmap *vm = env.up ? mapEnvBindings(*env.up) : new valmap(); - -// /* -// size_t i=0; -// do { -// std::cout << "env: " << i << " value: " << showType(*env.values[i]) << std::endl; -// // std::cout << *env.values[i] << std::endl; -// ++i; -// } while(i < (std::min(env.size, (size_t)100))); - - -// if (env.values[0]->type() == nAttrs) -// addBindings(std::to_string((int)env.size), *env.values[0]->attrs, *vm); -// */ -// return 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 diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 29599cc6c..ae1e6ee60 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -45,9 +45,6 @@ struct Env Value * values[0]; }; -void printEnvBindings(const Env &env, int lv = 0); -valmap * mapEnvBindings(const Env &env); -void printEnvPosChain(const Env &env, int lv = 0); valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet()); -- cgit v1.2.3 From e54f17eb46bc487abc38e70dfc2f1c617fb59d32 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 22 Oct 2021 14:27:04 -0600 Subject: remove more debug code --- src/libcmd/command.cc | 3 +- src/libcmd/installables.cc | 18 --------- src/libcmd/repl.cc | 1 - src/libexpr/eval.cc | 98 ++++------------------------------------------ src/libexpr/parser.y | 9 ----- src/libexpr/primops.cc | 7 ---- src/nix/flake.cc | 1 - 7 files changed, 9 insertions(+), 128 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 8d5098bc7..8a6dd71b2 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -67,7 +67,6 @@ extern std::function EvalCommand::getEvalState() { - std::cout << "EvalCommand::getEvalState()" << startReplOnEvalErrors << std::endl; if (!evalState) { evalState = std::make_shared(searchPath, getStore()); if (startReplOnEvalErrors) @@ -80,7 +79,7 @@ ref EvalCommand::getEvalState() expr.show(std::cout); std::cout << std::endl; - if (expr.staticenv) + if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); runRepl(evalState, *vm); diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index c3436acf9..7f7a89b37 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -249,20 +249,6 @@ void completeFlakeRefWithFragment( completeFlakeRef(evalState->store, prefix); } -/* -ref EvalCommand::getEvalState() -{ - if (!evalState) - evalState = std::make_shared(searchPath, getStore()); - return ref(evalState); -} - -EvalCommand::~EvalCommand() -{ - if (evalState) - evalState->printStats(); -} -*/ void completeFlakeRef(ref store, std::string_view prefix) { @@ -618,11 +604,7 @@ std::vector> SourceExprCommand::parseInstallables( if (file) state->evalFile(lookupFileArg(*state, *file), *vFile); else { - // std::cout << "pre parseExprFromString" << std::endl; auto e = state->parseExprFromString(*expr, absPath(".")); - - // std::cout << "pre eval" << std::endl; - state->eval(e, *vFile); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index e1b58cc76..bfc131d27 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -54,7 +54,6 @@ struct NixRepl const static int envSize = 32768; std::shared_ptr staticEnv; - // StaticEnv staticEnv; Env * env; int displ; StringSet varNames; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f286cbeec..73609c3d2 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -35,7 +35,6 @@ namespace nix { -// std::function & env)> debuggerHook; std::function debuggerHook; static char * dupString(const char * s) @@ -407,7 +406,8 @@ EvalState::EvalState(const Strings & _searchPath, ref store) assert(gcInitialised); - static_assert(sizeof(Env) <= 16 + sizeof(std::unique_ptr), "environment must be <= 16 bytes"); + // static_assert(sizeof(Env) <= 16 + sizeof(std::unique_ptr), "environment must be <= 16 bytes"); + static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); /* Initialise the Nix expression search path. */ if (!evalSettings.pureEval) { @@ -646,13 +646,13 @@ void printStaticEnvBindings(const Expr &expr) void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) { - // add bindings for the next level up first. + // add bindings for the next level up first, so that the bindings for this level + // override the higher levels. if (env.up && se.up) { mapStaticEnvBindings( *se.up, *env.up,vm); } - // iterate through staticenv bindings. - + // iterate through staticenv bindings and add them. auto map = valmap(); for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) { @@ -679,7 +679,6 @@ valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2); if (debuggerHook && expr) @@ -689,7 +688,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos @@ -703,7 +701,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = EvalError(s, s2, s3); if (debuggerHook && expr) @@ -714,7 +711,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, s2, s3), .errPos = pos @@ -729,7 +725,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env, Expr *expr)) { // p1 is where the error occurred; p2 is a position mentioned in the message. - // auto delenv = std::unique_ptr(env); auto error = EvalError({ .msg = hintfmt(s, sym, p2), .errPos = p1 @@ -743,7 +738,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s), .errPos = pos @@ -757,7 +751,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos @@ -771,7 +764,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, s2), .errPos = pos @@ -785,7 +777,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), .errPos = pos @@ -799,7 +790,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = AssertionError({ .msg = hintfmt(s, s1), .errPos = pos @@ -813,16 +803,11 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { - // std::cout << "throwUndefinedVarError" << std::endl; - - // auto delenv = std::unique_ptr(env); auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); - // std::cout << "pre debuggerHook" << std::endl; - if (debuggerHook && expr) debuggerHook(error, env, *expr); @@ -831,7 +816,6 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { - // auto delenv = std::unique_ptr(env); auto error = MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = pos @@ -881,8 +865,6 @@ void mkPath(Value & v, const char * s) inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) { - // std::cout << " EvalState::lookupVar" << var << std::endl; - for (size_t l = var.level; l; --l, env = env->up) ; if (!var.fromWith) return env->values[var.displ]; @@ -901,7 +883,6 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) { - // std::cout << "pre throwUndefinedVarError" << std::endl; throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, 0); } for (size_t l = env->prevWith; l; --l, env = env->up) ; @@ -930,25 +911,9 @@ Env & EvalState::allocEnv(size_t size) nrEnvs++; nrValuesInEnvs += size; - // if (debuggerHook) - // { - // Env * env = (Env *) allocBytes(sizeof(DebugEnv) + size * sizeof(Value *)); - // // Env * env = new DebugEnv; - // env->type = Env::Plain; - // /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ - - // return *env; - // } else { - Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); - env->type = Env::Plain; - // env->size = size; - - /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ - - return *env; - // } - - + Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); + env->type = Env::Plain; + return *env; } Env & fakeEnv(size_t size) @@ -1237,7 +1202,6 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) if (j != v.attrs->end()) throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, env, this); - // map1("value", &v)); // TODO dynamicAttrs to env? i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ @@ -1594,8 +1558,6 @@ values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, *fun.lambda.env, fun.lambda.fun); - // mapBindings(args)); - // map1("fun", &fun)); // todo add bindings + fun } } } @@ -1608,25 +1570,12 @@ https://nixos.org/manual/nix/stable/#ss-functions.)", void ExprWith::eval(EvalState & state, Env & env, Value & v) { - // std::cout << "ExprWith::eval" << std::endl; Env & env2(state.allocEnv(1)); env2.up = &env; env2.prevWith = prevWith; env2.type = Env::HasWithExpr; env2.values[0] = (Value *) attrs; // ok DAG nasty. just smoosh this in. // presumably evaluate later, lazily. - // std::cout << "ExprWith::eval2" << std::endl; - - // can't load the valuemap until they've been evaled, which is not yet. - // if (debuggerHook) { - // std::cout << "ExprWith::eval3.0" << std::endl; - // std::cout << "ExprWith attrs" << *attrs << std::endl; - // state.forceAttrs(*(Value*) attrs); - // std::cout << "ExprWith::eval3.5" << std::endl; - // env2.valuemap.reset(mapBindings(*env2.values[0]->attrs)); - // std::cout << "ExprWith::eval4" << std::endl; - // } - body->eval(state, env2, v); } @@ -1867,7 +1816,6 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) if (v.type() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v, fakeEnv(1), 0); - // map1("value", &v)); return v.integer; } @@ -1880,7 +1828,6 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v, fakeEnv(1), 0); - // map1("value", &v)); return v.fpoint; } @@ -1891,7 +1838,6 @@ bool EvalState::forceBool(Value & v, const Pos & pos) if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v, fakeEnv(1), 0); - // map1("value", &v)); return v.boolean; } @@ -1908,7 +1854,6 @@ void EvalState::forceFunction(Value & v, const Pos & pos) if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v, fakeEnv(1), 0); - // map1("value", &v)); } @@ -1918,7 +1863,6 @@ string EvalState::forceString(Value & v, const Pos & pos) if (v.type() != nString) { throwTypeError(pos, "value is %1% while a string was expected", v, fakeEnv(1), 0); - // map1("value", &v)); } return string(v.string.s); } @@ -1970,37 +1914,15 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], - // b.has_value() ? mapBindings(*b.get()) : map0()); fakeEnv(1), 0); - // map1("value", &v)); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0], - // b.has_value() ? mapBindings(*b.get()) : map0()); fakeEnv(1), 0); - // map1("value", &v)); } return s; } -/*string EvalState::forceStringNoCtx(std::optional b, Value & v, const Pos & pos) -{ - string s = forceString(v, pos); - if (v.string.context) { - if (pos) - throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], - b.has_value() ? mapBindings(*b.get()) : map0()); - // map1("value", &v)); - else - throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], - b.has_value() ? mapBindings(*b.get()) : map0()); - // map1("value", &v)); - } - return s; -}*/ - bool EvalState::isDerivation(Value & v) { @@ -2084,7 +2006,6 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, throwTypeError(pos, "cannot coerce %1% to a string", v, fakeEnv(1), 0); - // map1("value", &v)); } @@ -2094,7 +2015,6 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path) throwEvalError("file names are not allowed to end in '%1%'", drvExtension, fakeEnv(1), 0); - // map0()); Path dstPath; auto i = srcToStore.find(path); @@ -2120,7 +2040,6 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) if (path == "" || path[0] != '/') throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, fakeEnv(1), 0); - // map1("value", &v)); return path; } @@ -2203,7 +2122,6 @@ bool EvalState::eqValues(Value & v1, Value & v2) showType(v1), showType(v2), fakeEnv(1), 0); - // map2("value1", &v1, "value2", &v2)); } } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 46bbce1f6..d6d5c85f5 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -574,10 +574,6 @@ namespace nix { Expr * EvalState::parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, std::shared_ptr & staticEnv) { - // std::cout << "EvalState::parse " << text << std::endl; - // for (auto i = staticEnv->vars.begin(); i != staticEnv->vars.end(); ++i) - // std::cout << "EvalState::parse staticEnv " << i->first << std::endl; - yyscan_t scanner; ParseData data(*this); data.origin = origin; @@ -601,13 +597,8 @@ Expr * EvalState::parse(const char * text, FileOrigin origin, if (res) throw ParseError(data.error.value()); - - // std::cout << "EvalState::parse pre bindvars " << std::endl; - data.result->bindVars(staticEnv); - // std::cout << "EvalState::parse post bindVars " << std::endl; - return data.result; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 4b8ad3e9a..0400c8942 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -110,11 +110,6 @@ static void mkOutputString(EvalState & state, Value & v, argument. */ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v) { - // std::cout << " IMPORT " << std::endl; - // std::cout << " import " << std::endl; - // std::cout << " IMPORT " << std::endl; - // std::cout << " import " << std::endl; - PathSet context; Path path = state.coerceToPath(pos, vPath, context); @@ -199,8 +194,6 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS env->values[displ++] = attr.value; } - std::cout << "import staticenv: {} " << staticEnv << std::endl; - printTalkative("evaluating file '%1%'", realPath); Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 6af052008..62a413e27 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -408,7 +408,6 @@ struct CmdFlakeCheck : FlakeCommand if (auto attr = v.attrs->get(state->symbols.create("description"))) state->forceStringNoCtx(*attr->value, *attr->pos); - // state->forceStringNoCtx(std::optional(v.attrs), *attr->value, *attr->pos); else throw Error("template '%s' lacks attribute 'description'", attrPath); -- cgit v1.2.3 From 71da988d47433543e70cd52dbdd6c907dd3cabda Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 22 Oct 2021 14:34:50 -0600 Subject: more debug removal --- src/libcmd/local.mk | 2 +- src/libexpr/eval.cc | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index c282499b1..df904612b 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -10,6 +10,6 @@ libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix libwut +libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix $(eval $(call install-file-in, $(d)/nix-cmd.pc, $(prefix)/lib/pkgconfig, 0644)) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 73609c3d2..719dcc1b4 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -406,7 +406,6 @@ EvalState::EvalState(const Strings & _searchPath, ref store) assert(gcInitialised); - // static_assert(sizeof(Env) <= 16 + sizeof(std::unique_ptr), "environment must be <= 16 bytes"); static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); /* Initialise the Nix expression search path. */ @@ -1574,8 +1573,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.up = &env; env2.prevWith = prevWith; env2.type = Env::HasWithExpr; - env2.values[0] = (Value *) attrs; // ok DAG nasty. just smoosh this in. - // presumably evaluate later, lazily. + env2.values[0] = (Value *) attrs; body->eval(state, env2, v); } -- cgit v1.2.3 From fb8377547bcb6d4dc6464ca34c0fe433e1cfda44 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 22 Oct 2021 14:49:58 -0600 Subject: more code cleanup --- src/libexpr/eval.cc | 7 ++- src/libexpr/nixexpr.cc | 130 +++++++++++-------------------------------------- src/libexpr/parser.y | 2 - 3 files changed, 32 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 719dcc1b4..4dde92c0a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -912,6 +912,9 @@ Env & EvalState::allocEnv(size_t size) nrValuesInEnvs += size; Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); env->type = Env::Plain; + + /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ + return *env; } @@ -925,7 +928,6 @@ Env & fakeEnv(size_t size) return *env; } - void EvalState::mkList(Value & v, size_t size) { v.mkList(size); @@ -1291,7 +1293,6 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) throwEvalError(pos, "attribute '%1%' missing", name, env, this); - // mapBindings(*vAttrs->attrs)); } vAttrs = j->value; pos2 = j->pos; @@ -1419,8 +1420,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po "attempt to call something which is not a function but %1%", showType(fun).c_str(), fakeEnv(1), 0); - // fun.env); - // map2("fun", &fun, "arg", &arg)); } ExprLambda & lambda(*fun.lambda.fun); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 8f88eabd5..65c7cac1d 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -273,52 +273,36 @@ void ExprVar::bindVars(const std::shared_ptr &env) /* Check whether the variable appears in the environment. If so, set its level and displacement. */ - - // std::cout << "ExprVar::bindVars " << name << std::endl; - - int a = 10; - if (name == "callPackage") { - a++; // try to make code that I can put a breakpoint on... - // std::cout << "meh" << a + 10 << std::endl; - int withLevel = -1; - fromWith = true; - // this->level = withLevel; + const StaticEnv * curEnv; + unsigned int level; + int withLevel = -1; + for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { + if (curEnv->isWith) { + if (withLevel == -1) withLevel = level; + } else { + StaticEnv::Vars::const_iterator i = curEnv->vars.find(name); + if (i != curEnv->vars.end()) { + fromWith = false; + this->level = level; + displ = i->second; + return; + } + } } + /* Otherwise, the variable must be obtained from the nearest + enclosing `with'. If there is no `with', then we can issue an + "undefined variable" error now. */ + if (withLevel == -1) { - - const StaticEnv * curEnv; - unsigned int level; - int withLevel = -1; - for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { - if (curEnv->isWith) { - if (withLevel == -1) withLevel = level; - } else { - StaticEnv::Vars::const_iterator i = curEnv->vars.find(name); - if (i != curEnv->vars.end()) { - fromWith = false; - this->level = level; - displ = i->second; - return; - } - } - } - - - /* Otherwise, the variable must be obtained from the nearest - enclosing `with'. If there is no `with', then we can issue an - "undefined variable" error now. */ - if (withLevel == -1) - { - // std::cout << " throw UndefinedVarError({" << std::endl; - throw UndefinedVarError({ - .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), - .errPos = pos - }); - } - fromWith = true; - this->level = withLevel; + // std::cout << " throw UndefinedVarError({" << std::endl; + throw UndefinedVarError({ + .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), + .errPos = pos + }); } + fromWith = true; + this->level = withLevel; } void ExprSelect::bindVars(const std::shared_ptr &env) @@ -349,18 +333,11 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - // std::cout << "ExprAttrs::bindVars" << std::endl; - // auto dynamicEnv(env); - if (recursive) { - // std::cout << "recursive" << std::endl; - // dynamicEnv = newEnv.get(); - // also make shared_ptr? auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); unsigned int displ = 0; for (auto & i : attrs) { - // std::cout << "newenvvar: " << i.first << std::endl; newEnv->vars[i.first] = i.second.displ = displ++; } @@ -373,7 +350,6 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) } } else { - // std::cout << "NOT recursive" << std::endl; for (auto & i : attrs) i.second.e->bindVars(env); @@ -382,9 +358,6 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) i.valueExpr->bindVars(env); } } - - // std::cout << "ExprAttrs::bindVars end" << std::endl; - } void ExprList::bindVars(const std::shared_ptr &env) @@ -401,7 +374,7 @@ void ExprLambda::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); unsigned int displ = 0; @@ -423,7 +396,7 @@ void ExprLet::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); // also make shared_ptr? + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get())); unsigned int displ = 0; for (auto & i : attrs->attrs) @@ -440,7 +413,6 @@ void ExprWith::bindVars(const std::shared_ptr &env) if (debuggerHook) staticenv = env; - // std::cout << " ExprWith::bindVars " << std::endl; /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous `with' if this one doesn't contain the desired attribute. */ @@ -453,55 +425,11 @@ void ExprWith::bindVars(const std::shared_ptr &env) break; } - // std::cout << " ExprWith::bindVars 1" << std::endl; - // attrs->show(std::cout); - // std::cout << std::endl; attrs->bindVars(env); - auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); // also make shared_ptr? - // std::cout << " ExprWith::bindVars 2" << std::endl; - // std::cout << " body: " << std::endl; - // body->show(std::cout); - // std::cout << std::endl; - - // std::cout << "ExprWith::newenv: (iswith, size); (" << newEnv->isWith << ", " << newEnv->vars.size() << ") " << std::endl; - // for (auto i = newEnv->vars.begin(); i != newEnv->vars.end(); ++i) - // std::cout << "EvalState::parse newEnv " << i->first << std::endl; - - - // std::cout << " body->bindVars(newEnv), iswith: " << newEnv->isWith << std::endl; + auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); body->bindVars(newEnv); - // std::cout << " ExprWith::bindVars 3" << std::endl; } -/* -void ExprWith::bindVars(const StaticEnv & env) -{ - // Does this `with' have an enclosing `with'? If so, record its - // level so that `lookupVar' can look up variables in the previous - // `with' if this one doesn't contain the desired attribute. - const StaticEnv * curEnv; - unsigned int level; - prevWith = 0; - for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++) - if (curEnv->isWith) { - prevWith = level; - break; - } - - attrs->bindVars(env); - std::cout << "ExprWith::bindVars env: " << env.vars.size(); // add std::endl; - for (auto i = env.vars.begin(); i != env.vars.end(); ++i) - { - std::cout << i->first << std::endl; - } - - StaticEnv newEnv(true, &env); - body->bindVars(newEnv); -} -*/ - - - void ExprIf::bindVars(const std::shared_ptr &env) { if (debuggerHook) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d6d5c85f5..d1e898677 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -22,8 +22,6 @@ #include "eval.hh" #include "globals.hh" -#include - namespace nix { struct ParseData -- cgit v1.2.3 From 885f819922d7c4b3823090ca4c9ee832f5080bde Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 9 Nov 2021 11:20:14 -0700 Subject: remove dead code --- src/libexpr/eval.cc | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 4dde92c0a..32d51ab87 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1433,8 +1433,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po size_t displ = 0; if (!lambda.matchAttrs){ - // TODO: what is this arg? empty argument? - // add empty valmap here? env2.values[displ++] = &arg; } else { @@ -1457,7 +1455,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po lambda, i.name, *fun.lambda.env, &lambda); - // map2("fun", &fun, "arg", &arg)); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1478,7 +1475,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po lambda, i.name, *fun.lambda.env, &lambda); - // map2("fun", &fun, "arg", &arg)); abort(); // can't happen } } @@ -1971,7 +1967,6 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string", fakeEnv(1), 0); - // map1("value", &v)); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } -- cgit v1.2.3 From 7e2a3db4eb663aa99aec7ebcc83d75cb948a2cb3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 9 Nov 2021 13:14:49 -0700 Subject: cleanup --- src/libexpr/eval.cc | 20 +++++++------------- src/libexpr/eval.hh | 1 - src/libexpr/nixexpr.cc | 1 - 3 files changed, 7 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 32d51ab87..8e263334a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -78,8 +78,6 @@ void printValue(std::ostream & str, std::set & active, const Valu return; } - str << "internal type: " << v.internalType << std::endl; - switch (v.internalType) { case tInt: str << v.integer; @@ -1569,7 +1567,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.prevWith = prevWith; env2.type = Env::HasWithExpr; env2.values[0] = (Value *) attrs; - + body->eval(state, env2, v); } @@ -1737,8 +1735,6 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) nf = n; nf += vTmp.fpoint; } else { - std::cerr << "envtype: " << showType(env.values[0]->type()) << std::endl; - throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp), env, this); } } else if (firstType == nFloat) { @@ -1829,7 +1825,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, + throwTypeError(pos, "value is %1% while a Boolean was expected", v, fakeEnv(1), 0); return v.boolean; } @@ -1906,12 +1902,10 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], - fakeEnv(1), 0); + v.string.s, v.string.context[0], fakeEnv(1), 0); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], - fakeEnv(1), 0); + v.string.s, v.string.context[0], fakeEnv(1), 0); } return s; } @@ -1965,7 +1959,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", + throwTypeError(pos, "cannot coerce a set to a string", fakeEnv(1), 0); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -1996,7 +1990,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } } - throwTypeError(pos, "cannot coerce %1% to a string", v, + throwTypeError(pos, "cannot coerce %1% to a string", v, fakeEnv(1), 0); } @@ -2030,7 +2024,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) { string path = coerceToString(pos, v, context, false, false); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, fakeEnv(1), 0); return path; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ae1e6ee60..91e43ddfe 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -208,7 +208,6 @@ public: string forceString(Value & v, const Pos & pos = noPos); string forceString(Value & v, PathSet & context, const Pos & pos = noPos); string forceStringNoCtx(Value & v, const Pos & pos = noPos); - // string forceStringNoCtx(std::optional b, Value & v, const Pos & pos = noPos); /* Return true iff the value `v' denotes a derivation (i.e. a set with attribute `type = "derivation"'). */ diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 65c7cac1d..9ccecca55 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -295,7 +295,6 @@ void ExprVar::bindVars(const std::shared_ptr &env) "undefined variable" error now. */ if (withLevel == -1) { - // std::cout << " throw UndefinedVarError({" << std::endl; throw UndefinedVarError({ .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), .errPos = pos -- cgit v1.2.3 From 69e26c5c4ba106bd16f60bfaac88ccf888b4383f Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 25 Nov 2021 08:23:07 -0700 Subject: more cleanup --- src/libcmd/command.cc | 4 ++-- src/libexpr/eval.cc | 23 +++++++++++------------ src/libexpr/nixexpr.cc | 1 - 3 files changed, 13 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 8a6dd71b2..2c62bfa7f 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -81,8 +81,8 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { - auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); - runRepl(evalState, *vm); + auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); + runRepl(evalState, *vm); } }; } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 8e263334a..11a61da26 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -620,7 +620,7 @@ std::optional EvalState::getDoc(Value & v) void printStaticEnvBindings(const StaticEnv &se, int lvl) { - for (auto i = se.vars.begin(); i != se.vars.end(); ++i) + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { std::cout << lvl << i->first << std::endl; } @@ -628,22 +628,21 @@ void printStaticEnvBindings(const StaticEnv &se, int lvl) if (se.up) { printStaticEnvBindings(*se.up, ++lvl); } - + } void printStaticEnvBindings(const Expr &expr) { - // just print the names for now - if (expr.staticenv) - { - printStaticEnvBindings(*expr.staticenv.get(), 0); - } - + // just print the names for now + if (expr.staticenv) + { + printStaticEnvBindings(*expr.staticenv.get(), 0); + } } void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) { - // add bindings for the next level up first, so that the bindings for this level + // add bindings for the next level up first, so that the bindings for this level // override the higher levels. if (env.up && se.up) { mapStaticEnvBindings( *se.up, *env.up,vm); @@ -651,13 +650,13 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // iterate through staticenv bindings and add them. auto map = valmap(); - for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) { - map[iter->first] = env.values[iter->second]; + map[iter->first] = env.values[iter->second]; } vm.merge(map); - + } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 9ccecca55..3e42789a2 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -3,7 +3,6 @@ #include "util.hh" #include -#include namespace nix { -- cgit v1.2.3 From e82aec4efcd06cbd60d57f401fb7e93ab595128c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 30 Nov 2021 14:15:02 -0700 Subject: fix merge issues --- src/libcmd/command.cc | 9 +-------- src/libcmd/repl.cc | 5 +++-- src/libexpr/eval.cc | 5 +++-- src/libexpr/nixexpr.cc | 14 +++++++------- src/libexpr/primops.cc | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 4c5d985aa..2e00b42ff 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -68,7 +68,7 @@ extern std::function EvalCommand::getEvalState() { if (!evalState) { - evalState = std::make_shared(searchPath, getStore()); + evalState = std::make_shared(searchPath, getEvalStore(), getStore()); if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); @@ -102,13 +102,6 @@ ref EvalCommand::getEvalStore() return ref(evalStore); } -ref EvalCommand::getEvalState() -{ - if (!evalState) - evalState = std::make_shared(searchPath, getEvalStore(), getStore()); - return ref(evalState); -} - BuiltPathsCommand::BuiltPathsCommand(bool recursive) : recursive(recursive) { diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 6faa9f9fa..910f0f694 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -205,6 +205,7 @@ void NixRepl::mainLoop(const std::vector & files) if (!files.empty()) { for (auto & i : files) loadedFiles.push_back(i); + } reloadFiles(); if (!loadedFiles.empty()) notice(""); @@ -639,7 +640,7 @@ void NixRepl::addAttrsToScope(Value & attrs) { state->forceAttrs(attrs); for (auto & i : *attrs.attrs) - addVarToScope(i.name, *i.value); + addVarToScope(i.name, i.value); notice("Added %1% variables.", attrs.attrs->size()); } @@ -650,7 +651,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v) throw Error("environment full; cannot add more variables"); staticEnv->vars.emplace_back(name, displ); staticEnv->sort(); - env->values[displ++] = &v; + env->values[displ++] = v; varNames.insert((string) name); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index a20123f34..8737930b5 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -591,7 +591,7 @@ Value * EvalState::addConstant(const string & name, Value & v) void EvalState::addConstant(const string & name, Value * v) { - staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl); + staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl); baseEnv.values[baseEnvDispl++] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v)); @@ -1459,7 +1459,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & user. */ for (auto & i : *args[0]->attrs) if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end()) - throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name); + throwTypeError(pos, "%1% called with unexpected argument '%2%'", + lambda, i.name, *fun.lambda.env, &lambda); abort(); // can't happen } } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 696b149e3..dd0031a7c 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -346,7 +346,7 @@ void ExprAttrs::bindVars(const std::shared_ptr &env) Displacement displ = 0; for (auto & i : attrs) - newEnv.vars.emplace_back(i.first, i.second.displ = displ++); + newEnv->vars.emplace_back(i.first, i.second.displ = displ++); // No need to sort newEnv since attrs is in sorted order. @@ -391,13 +391,13 @@ void ExprLambda::bindVars(const std::shared_ptr &env) Displacement displ = 0; - if (!arg.empty()) newEnv.vars.emplace_back(arg, displ++); + if (!arg.empty()) newEnv->vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) - newEnv.vars.emplace_back(i.name, displ++); + newEnv->vars.emplace_back(i.name, displ++); - newEnv.sort(); + newEnv->sort(); for (auto & i : formals->formals) if (i.def) i.def->bindVars(newEnv); @@ -406,7 +406,7 @@ void ExprLambda::bindVars(const std::shared_ptr &env) body->bindVars(newEnv); } -void ExprCall::bindVars(const StaticEnv & env) +void ExprCall::bindVars(const std::shared_ptr &env) { if (debuggerHook) staticenv = env; @@ -416,7 +416,7 @@ void ExprCall::bindVars(const StaticEnv & env) e->bindVars(env); } -void ExprLet::bindVars(const StaticEnv & env) +void ExprLet::bindVars(const std::shared_ptr &env) { if (debuggerHook) staticenv = env; @@ -425,7 +425,7 @@ void ExprLet::bindVars(const StaticEnv & env) Displacement displ = 0; for (auto & i : attrs->attrs) - newEnv.vars.emplace_back(i.first, i.second.displ = displ++); + newEnv->vars.emplace_back(i.first, i.second.displ = displ++); // No need to sort newEnv since attrs->attrs is in sorted order. diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index a9ee96bfa..2638b0076 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -188,7 +188,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS unsigned int displ = 0; for (auto & attr : *vScope->attrs) { - staticEnv.vars.emplace_back(attr.name, displ); + staticEnv->vars.emplace_back(attr.name, displ); env->values[displ++] = attr.value; } @@ -3750,7 +3750,7 @@ void EvalState::createBaseEnv() because attribute lookups expect it to be sorted. */ baseEnv.values[0]->attrs->sort(); - staticBaseEnv.sort(); + staticBaseEnv->sort(); /* Note: we have to initialize the 'derivation' constant *after* building baseEnv/staticBaseEnv because it uses 'builtins'. */ -- cgit v1.2.3 From c151a9b4262dfc5fc251ed0ebcf862731b0f795c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 30 Nov 2021 15:14:23 -0700 Subject: fix linking --- src/libcmd/local.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index 1ec258a54..4d42e4c8b 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -8,8 +8,8 @@ libcmd_SOURCES := $(wildcard $(d)/*.cc) libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix -# libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -libcmd_LDFLAGS += -llowdown -pthread +libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -pthread +# libcmd_LDFLAGS += -llowdown -pthread libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix -- cgit v1.2.3 From f317019edda7afac8590e68d4d979b03a2cdbf62 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 20 Dec 2021 12:32:21 -0700 Subject: :d error --- src/libcmd/command.cc | 2 +- src/libcmd/command.hh | 2 ++ src/libcmd/repl.cc | 93 ++++++++++++++++++++++++++++++++++++++++++--------- src/libexpr/eval.hh | 1 + src/libexpr/parser.y | 5 +++ 5 files changed, 86 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 2e00b42ff..b37959a2e 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -82,7 +82,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); - runRepl(evalState, *vm); + runRepl(evalState, ref(&error), *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 0d847d255..e27ee2e9e 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -314,6 +314,8 @@ void printClosureDiff( void runRepl( ref evalState, + std::optional> debugError, const std::map & extraEnv); + } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 910f0f694..0eea2389b 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -50,6 +50,8 @@ struct NixRepl ref state; Bindings * autoArgs; + std::optional> debugError; + Strings loadedFiles; const static int envSize = 32768; @@ -70,6 +72,7 @@ struct NixRepl void loadFile(const Path & path); void loadFlake(const std::string & flakeRef); void initEnv(); + void loadFiles(); void reloadFiles(); void addAttrsToScope(Value & attrs); void addVarToScope(const Symbol & name, Value * v); @@ -199,6 +202,9 @@ namespace { void NixRepl::mainLoop(const std::vector & files) { + std::cout << "iinitial mainLoop; " << std::endl; + // printStaticEnvBindings(*staticEnv, 0); + string error = ANSI_RED "error:" ANSI_NORMAL " "; notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n"); @@ -207,7 +213,7 @@ void NixRepl::mainLoop(const std::vector & files) loadedFiles.push_back(i); } - reloadFiles(); + loadFiles(); if (!loadedFiles.empty()) notice(""); // Allow nix-repl specific settings in .inputrc @@ -225,6 +231,9 @@ void NixRepl::mainLoop(const std::vector & files) std::string input; + std::cout << "pre MAINLOOP; " << std::endl; + // printStaticEnvBindings(*staticEnv, 0); + while (true) { // When continuing input from previous lines, don't print a prompt, just align to the same // number of chars as the prompt. @@ -415,21 +424,40 @@ bool NixRepl::processLine(string line) std::cout << "The following commands are available:\n" << "\n" - << " Evaluate and print expression\n" - << " = Bind expression to variable\n" - << " :a Add attributes from resulting set to scope\n" - << " :b Build derivation\n" - << " :e Open package or function in $EDITOR\n" - << " :i Build derivation, then install result into current profile\n" - << " :l Load Nix expression and add it to scope\n" - << " :lf Load Nix flake and add it to scope\n" - << " :p Evaluate and print expression recursively\n" - << " :q Exit nix-repl\n" - << " :r Reload all files\n" - << " :s Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n" - << " :u Build derivation, then start nix-shell\n" - << " :doc Show documentation of a builtin function\n"; + << " Evaluate and print expression\n" + << " = Bind expression to variable\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build derivation\n" + << " :e Open package or function in $EDITOR\n" + << " :i Build derivation, then install result into current profile\n" + << " :l Load Nix expression and add it to scope\n" + << " :lf Load Nix flake and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :q Exit nix-repl\n" + << " :r Reload all files\n" + << " :s Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n" + << " :u Build derivation, then start nix-shell\n" + << " :doc Show documentation of a builtin function\n" + << " :d Debug mode commands\n" + << " :d stack Show call stack\n" + << " :d stack Detail for step N\n" + << " :d error Show current error\n"; + } + + else if (command == ":d" || command == ":debug") { + std::cout << "debug: '" << arg << "'" << std::endl; + if (arg == "stack") { + } + else if (arg == "error") { + if (this->debugError.has_value()) { + showErrorInfo(std::cout, (*debugError)->info(), true); + } + else + { + notice("error information not available"); + } + } } else if (command == ":a" || command == ":add") { @@ -561,11 +589,13 @@ bool NixRepl::processLine(string line) line[p + 1] != '=' && isVarName(name = removeWhitespace(string(line, 0, p)))) { + std::cout << "isvarname" << std::endl; Expr * e = parseString(string(line, p + 1)); Value *v = new Value(*state->allocValue()); v->mkThunk(env, e); addVarToScope(state->symbols.create(name), v); } else { + std::cout << "evalstring" << std::endl; Value v; evalString(line, v); printValue(std::cout, v, 1) << std::endl; @@ -623,6 +653,12 @@ void NixRepl::reloadFiles() { initEnv(); + loadFiles(); +} + + +void NixRepl::loadFiles() +{ Strings old = loadedFiles; loadedFiles.clear(); @@ -649,12 +685,28 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v) { if (displ >= envSize) throw Error("environment full; cannot add more variables"); + if (auto oldVar = staticEnv->find(name); oldVar != staticEnv->vars.end()) + staticEnv->vars.erase(oldVar); staticEnv->vars.emplace_back(name, displ); staticEnv->sort(); env->values[displ++] = v; varNames.insert((string) name); + notice("Added variable to scope: %1%", name); + } +// version from master. +// void NixRepl::addVarToScope(const Symbol & name, Value & v) +// { +// if (displ >= envSize) +// throw Error("environment full; cannot add more variables"); +// if (auto oldVar = staticEnv.find(name); oldVar != staticEnv.vars.end()) +// staticEnv.vars.erase(oldVar); +// staticEnv.vars.emplace_back(name, displ); +// staticEnv.sort(); +// env->values[displ++] = &v; +// varNames.insert((string) name); +// } Expr * NixRepl::parseString(string s) { @@ -665,8 +717,11 @@ Expr * NixRepl::parseString(string s) void NixRepl::evalString(string s, Value & v) { + std::cout << "pre partstirns:l" << std::endl; Expr * e = parseString(s); + std::cout << "pre e->eval" << std::endl; e->eval(*state, *env, v); + std::cout << "prev fv" << std::endl; state->forceValue(v); } @@ -817,10 +872,13 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, + std::optional> debugError, const std::map & extraEnv) { auto repl = std::make_unique(evalState); + repl->debugError = debugError; + repl->initEnv(); std::set names; @@ -834,6 +892,9 @@ void runRepl( printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); // printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); + std::cout << " pre repl->mainLoop({});" << std::endl; + // printStaticEnvBindings(*repl->staticEnv, 0); + repl->mainLoop({}); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 485c2df83..4b3e7d69a 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -26,6 +26,7 @@ typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, extern std::function debuggerHook; void printStaticEnvBindings(const Expr &expr); +void printStaticEnvBindings(const StaticEnv &se, int lvl = 0); struct PrimOp { diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 58af0df7d..066dc4ecc 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -21,6 +21,7 @@ #include "nixexpr.hh" #include "eval.hh" #include "globals.hh" +#include namespace nix { @@ -615,6 +616,10 @@ Expr * EvalState::parse(const char * text, FileOrigin origin, if (res) throw ParseError(data.error.value()); + std::cout << " data.result->bindVars(staticEnv); " << std::endl; + + // printStaticEnvBindings(*staticEnv, 0); + data.result->bindVars(staticEnv); return data.result; -- cgit v1.2.3 From b4a59a5eec5bdb94ee2bbc8365f024d5787abd60 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 22 Dec 2021 15:38:49 -0700 Subject: DebugStackTracker class in one place --- src/libcmd/command.cc | 2 ++ src/libcmd/repl.cc | 1 + src/libexpr/eval.cc | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/libexpr/eval.hh | 2 ++ src/libexpr/nixexpr.hh | 25 +++++++++++++++++++ src/libutil/error.cc | 2 ++ src/libutil/logging.hh | 1 + 7 files changed, 96 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index b37959a2e..0ada5fa3c 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -75,6 +75,8 @@ ref EvalCommand::getEvalState() printStaticEnvBindings(expr); + std::cout << evalState->vCallFlake << std::endl; + std::cout << "expr: " << std::endl; expr.show(std::cout); std::cout << std::endl; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 0eea2389b..2a925df64 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -451,6 +451,7 @@ bool NixRepl::processLine(string line) } else if (arg == "error") { if (this->debugError.has_value()) { + // TODO user --show-trace setting? showErrorInfo(std::cout, (*debugError)->info(), true); } else diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 8737930b5..00d2c1643 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -854,13 +855,20 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { + std::cout << "throwUndefinedVarError" << std::endl; + + std::cout << "loggerSettings.showTrace: " << loggerSettings.showTrace << std::endl; + auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); - if (debuggerHook && expr) + if (debuggerHook && expr) { + + std::cout << "throwUndefinedVarError debuggerHook" << std::endl; debuggerHook(error, env, *expr); + } throw error; } @@ -888,6 +896,16 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con e.addTrace(pos, s, s2); } +// LocalNoInline(void makeErrorTrace(Error & e, const char * s, const string & s2)) +// { +// Trace { .pos = e, .hint = hint } +// } + +// LocalNoInline(void makeErrorTrace(Error & e, const Pos & pos, const char * s, const string & s2)) +// { +// return Trace { .pos = e, .hint = hintfmt(s, s2); }; +// } + void mkString(Value & v, const char * s) { v.mkString(dupString(s)); @@ -934,7 +952,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) { - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, 0); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, (Expr*)&var); } for (size_t l = env->prevWith; l; --l, env = env->up) ; } @@ -1092,6 +1110,39 @@ void EvalState::resetFileCache() fileParseCache.clear(); } +class DebugTraceStacker { + public: + DebugTraceStacker(EvalState &evalState, Trace t) + :evalState(evalState), trace(t) + { + evalState.debugTraces.push_front(t); + } + ~DebugTraceStacker() { + // assert(evalState.debugTraces.front() == trace); + evalState.debugTraces.pop_front(); + } + + EvalState &evalState; + Trace trace; + +}; + +// class DebugTraceStacker { +// DebugTraceStacker(std::ref evalState, std::ref t) +// :evalState(evalState), trace(t) +// { +// evalState->debugTraces.push_front(t); +// } +// ~DebugTraceStacker() { +// assert(evalState->debugTraces.pop_front() == trace); +// } + +// std::ref evalState; +// std::ref trace; + +// }; + + void EvalState::cacheFile( const Path & path, @@ -1103,6 +1154,15 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { + std::unique_ptr dts = debuggerHook ? + std::unique_ptr(new DebugTraceStacker(*this, + Trace { .pos = (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), + .hint = hintfmt("while evaluating the file '%1%':", resolvedPath) + } + )) : std::unique_ptr(); + + // Trace( .pos = (e->getPos() ? std::optional(ErrPos(*e->getPos())): + // std::nullopt), hintfmt("while evaluating the file '%1%':", resolvedPath)); // Enforce that 'flake.nix' is a direct attrset, not a // computation. if (mustBeTrivial && @@ -1472,6 +1532,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & try { lambda.body->eval(*this, env2, vCur); } catch (Error & e) { + std::cout << "eval showErrorInfo showTrace: " << loggerSettings.showTrace.get() << std::endl; if (loggerSettings.showTrace.get()) { addErrorTrace(e, lambda.pos, "while evaluating %s", (lambda.name.set() diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 4b3e7d69a..c3717b3c2 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -109,6 +109,8 @@ public: RootValue vCallFlake = nullptr; RootValue vImportedDrvToDerivation = nullptr; + std::list debugTraces; + private: SrcToStore srcToStore; diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 825933fa1..a9a5f5316 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -84,6 +84,7 @@ struct Expr virtual void setName(Symbol & name); std::shared_ptr staticenv; + virtual Pos* getPos() = 0; }; std::ostream & operator << (std::ostream & str, const Expr & e); @@ -100,6 +101,8 @@ struct ExprInt : Expr ExprInt(NixInt n) : n(n) { mkInt(v, n); }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); + + Pos* getPos() { return 0; } }; struct ExprFloat : Expr @@ -109,6 +112,8 @@ struct ExprFloat : Expr ExprFloat(NixFloat nf) : nf(nf) { mkFloat(v, nf); }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); + + Pos* getPos() { return 0; } }; struct ExprString : Expr @@ -118,6 +123,8 @@ struct ExprString : Expr ExprString(const Symbol & s) : s(s) { mkString(v, s); }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); + + Pos* getPos() { return 0; } }; /* Temporary class used during parsing of indented strings. */ @@ -125,6 +132,8 @@ struct ExprIndStr : Expr { string s; ExprIndStr(const string & s) : s(s) { }; + + Pos* getPos() { return 0; } }; struct ExprPath : Expr @@ -134,6 +143,7 @@ struct ExprPath : Expr ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); + Pos* getPos() { return 0; } }; typedef uint32_t Level; @@ -161,6 +171,7 @@ struct ExprVar : Expr ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); + Pos* getPos() { return &pos; } }; struct ExprSelect : Expr @@ -171,6 +182,7 @@ struct ExprSelect : Expr ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprOpHasAttr : Expr @@ -179,6 +191,7 @@ struct ExprOpHasAttr : Expr AttrPath attrPath; ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { }; COMMON_METHODS + Pos* getPos() { return e->getPos(); } }; struct ExprAttrs : Expr @@ -207,6 +220,7 @@ struct ExprAttrs : Expr ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { }; ExprAttrs() : recursive(false), pos(noPos) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprList : Expr @@ -214,6 +228,7 @@ struct ExprList : Expr std::vector elems; ExprList() { }; COMMON_METHODS + Pos* getPos() { return 0; } }; struct Formal @@ -252,6 +267,7 @@ struct ExprLambda : Expr string showNamePos() const; inline bool hasFormals() const { return formals != nullptr; } COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprCall : Expr @@ -263,6 +279,7 @@ struct ExprCall : Expr : fun(fun), args(args), pos(pos) { } COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprLet : Expr @@ -271,6 +288,7 @@ struct ExprLet : Expr Expr * body; ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { }; COMMON_METHODS + Pos* getPos() { return 0; } }; struct ExprWith : Expr @@ -280,6 +298,7 @@ struct ExprWith : Expr size_t prevWith; ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprIf : Expr @@ -288,6 +307,7 @@ struct ExprIf : Expr Expr * cond, * then, * else_; ExprIf(const Pos & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprAssert : Expr @@ -296,6 +316,7 @@ struct ExprAssert : Expr Expr * cond, * body; ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprOpNot : Expr @@ -303,6 +324,7 @@ struct ExprOpNot : Expr Expr * e; ExprOpNot(Expr * e) : e(e) { }; COMMON_METHODS + Pos* getPos() { return 0; } }; #define MakeBinOp(name, s) \ @@ -321,6 +343,7 @@ struct ExprOpNot : Expr e1->bindVars(env); e2->bindVars(env); \ } \ void eval(EvalState & state, Env & env, Value & v); \ + Pos* getPos() { return &pos; } \ }; MakeBinOp(ExprOpEq, "==") @@ -339,6 +362,7 @@ struct ExprConcatStrings : Expr ExprConcatStrings(const Pos & pos, bool forceString, vector * es) : pos(pos), forceString(forceString), es(es) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; struct ExprPos : Expr @@ -346,6 +370,7 @@ struct ExprPos : Expr Pos pos; ExprPos(const Pos & pos) : pos(pos) { }; COMMON_METHODS + Pos* getPos() { return &pos; } }; diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 203d79087..c2b9d2707 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -221,6 +221,8 @@ static std::string indent(std::string_view indentFirst, std::string_view indentR std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace) { + std::cout << "showErrorInfo showTrace: " << showTrace << std::endl; + std::string prefix; switch (einfo.level) { case Verbosity::lvlError: { diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 96ad69790..f10a9af38 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -38,6 +38,7 @@ typedef uint64_t ActivityId; struct LoggerSettings : Config { Setting showTrace{ + // this, false, "show-trace", this, false, "show-trace", R"( Where Nix should print out a stack trace in case of Nix -- cgit v1.2.3 From bc20e54e0044e08c68a7af1f1e12d001baba8a74 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 22 Dec 2021 19:40:08 -0700 Subject: stack traces basically working --- src/libcmd/repl.cc | 20 +++++++++++++++ src/libexpr/eval.cc | 72 +++++++++++++++++++++++++++++++++++++++------------- src/libutil/error.hh | 3 +++ 3 files changed, 78 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 2a925df64..3289aea3e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -448,6 +448,26 @@ bool NixRepl::processLine(string line) else if (command == ":d" || command == ":debug") { std::cout << "debug: '" << arg << "'" << std::endl; if (arg == "stack") { + std::cout << "eval stack:" << std::endl; + for (auto iter = this->state->debugTraces.begin(); + iter != this->state->debugTraces.end(); ++iter) { + std::cout << "\n" << "… " << iter->hint.str() << "\n"; + + if (iter->pos.has_value() && (*iter->pos)) { + auto pos = iter->pos.value(); + std::cout << "\n"; + printAtPos(pos, std::cout); + + auto loc = getCodeLines(pos); + if (loc.has_value()) { + std::cout << "\n"; + printCodeLines(std::cout, "", pos, *loc); + std::cout << "\n"; + } + } + } + + } else if (arg == "error") { if (this->debugError.has_value()) { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 00d2c1643..c46113560 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -38,6 +38,23 @@ namespace nix { std::function debuggerHook; +class DebugTraceStacker { + public: + DebugTraceStacker(EvalState &evalState, Trace t) + :evalState(evalState), trace(t) + { + evalState.debugTraces.push_front(t); + } + ~DebugTraceStacker() { + // assert(evalState.debugTraces.front() == trace); + evalState.debugTraces.pop_front(); + } + + EvalState &evalState; + Trace trace; + +}; + static char * dupString(const char * s) { char * t; @@ -1110,23 +1127,6 @@ void EvalState::resetFileCache() fileParseCache.clear(); } -class DebugTraceStacker { - public: - DebugTraceStacker(EvalState &evalState, Trace t) - :evalState(evalState), trace(t) - { - evalState.debugTraces.push_front(t); - } - ~DebugTraceStacker() { - // assert(evalState.debugTraces.front() == trace); - evalState.debugTraces.pop_front(); - } - - EvalState &evalState; - Trace trace; - -}; - // class DebugTraceStacker { // DebugTraceStacker(std::ref evalState, std::ref t) // :evalState(evalState), trace(t) @@ -1387,6 +1387,17 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { + std::unique_ptr dts = + debuggerHook ? + std::unique_ptr( + new DebugTraceStacker( + state, + Trace { .pos = *pos2, + .hint = hintfmt( + "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)) + })) + : std::unique_ptr(); for (auto & i : attrPath) { state.nrLookups++; @@ -1530,6 +1541,21 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { + std::unique_ptr dts = + debuggerHook ? + std::unique_ptr( + new DebugTraceStacker( + *this, + Trace { .pos = lambda.pos, + .hint = hintfmt( + "while evaluating %s", + (lambda.name.set() + ? "'" + (string) lambda.name + "'" + : "anonymous lambda")) + })) + : std::unique_ptr(); + + lambda.body->eval(*this, env2, vCur); } catch (Error & e) { std::cout << "eval showErrorInfo showTrace: " << loggerSettings.showTrace.get() << std::endl; @@ -1924,6 +1950,18 @@ void EvalState::forceValueDeep(Value & v) if (v.type() == nAttrs) { for (auto & i : *v.attrs) try { + std::unique_ptr dts = + debuggerHook ? + std::unique_ptr( + new DebugTraceStacker( + *this, + Trace { .pos = *i.pos, + .hint = hintfmt( + "while evaluating the attribute '%1%'", i.name) + })) + : std::unique_ptr(); + + recurse(*i.value); } catch (Error & e) { addErrorTrace(e, *i.pos, "while evaluating the attribute '%1%'", i.name); diff --git a/src/libutil/error.hh b/src/libutil/error.hh index b6670c8b2..06301f709 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -106,6 +106,9 @@ void printCodeLines(std::ostream & out, const ErrPos & errPos, const LinesOfCode & loc); +void printAtPos(const ErrPos & pos, std::ostream & out); + + struct Trace { std::optional pos; hintformat hint; -- cgit v1.2.3 From 1bda6a01e1cb4d2b22ff2256fcbde044e2f04d24 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 23 Dec 2021 08:14:17 -0700 Subject: indenting --- src/libexpr/eval.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c46113560..15eaef667 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1542,18 +1542,18 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { std::unique_ptr dts = - debuggerHook ? - std::unique_ptr( - new DebugTraceStacker( - *this, - Trace { .pos = lambda.pos, - .hint = hintfmt( - "while evaluating %s", - (lambda.name.set() - ? "'" + (string) lambda.name + "'" - : "anonymous lambda")) - })) - : std::unique_ptr(); + debuggerHook ? + std::unique_ptr( + new DebugTraceStacker( + *this, + Trace {.pos = lambda.pos, + .hint = hintfmt( + "while evaluating %s", + (lambda.name.set() + ? "'" + (string) lambda.name + "'" + : "anonymous lambda")) + })) + : std::unique_ptr(); lambda.body->eval(*this, env2, vCur); -- cgit v1.2.3 From deb1fd66e8c884937827813c079135532913ca86 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 23 Dec 2021 09:08:41 -0700 Subject: makeDebugTraceStacker --- src/libexpr/eval.cc | 93 ++++++++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 15eaef667..d7deb550e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -49,10 +49,8 @@ class DebugTraceStacker { // assert(evalState.debugTraces.front() == trace); evalState.debugTraces.pop_front(); } - EvalState &evalState; Trace trace; - }; static char * dupString(const char * s) @@ -882,8 +880,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); if (debuggerHook && expr) { - - std::cout << "throwUndefinedVarError debuggerHook" << std::endl; + std::cout << "throwUndefinedVarError debuggerHook" << std::endl; debuggerHook(error, env, *expr); } @@ -913,15 +910,17 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con e.addTrace(pos, s, s2); } -// LocalNoInline(void makeErrorTrace(Error & e, const char * s, const string & s2)) -// { -// Trace { .pos = e, .hint = hint } -// } +LocalNoInline(std::unique_ptr + makeDebugTraceStacker(EvalState &state, std::optional pos, const char * s, const string & s2)) +{ + return std::unique_ptr( + new DebugTraceStacker( + state, + Trace {.pos = pos, + .hint = hintfmt(s, s2) + })); +} -// LocalNoInline(void makeErrorTrace(Error & e, const Pos & pos, const char * s, const string & s2)) -// { -// return Trace { .pos = e, .hint = hintfmt(s, s2); }; -// } void mkString(Value & v, const char * s) { @@ -1127,20 +1126,6 @@ void EvalState::resetFileCache() fileParseCache.clear(); } -// class DebugTraceStacker { -// DebugTraceStacker(std::ref evalState, std::ref t) -// :evalState(evalState), trace(t) -// { -// evalState->debugTraces.push_front(t); -// } -// ~DebugTraceStacker() { -// assert(evalState->debugTraces.pop_front() == trace); -// } - -// std::ref evalState; -// std::ref trace; - -// }; @@ -1154,15 +1139,14 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { - std::unique_ptr dts = debuggerHook ? - std::unique_ptr(new DebugTraceStacker(*this, - Trace { .pos = (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), - .hint = hintfmt("while evaluating the file '%1%':", resolvedPath) - } - )) : std::unique_ptr(); + std::unique_ptr dts = + debuggerHook ? + makeDebugTraceStacker( + *this, + (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), + "while evaluating the file '%1%':", resolvedPath) + : std::unique_ptr(); - // Trace( .pos = (e->getPos() ? std::optional(ErrPos(*e->getPos())): - // std::nullopt), hintfmt("while evaluating the file '%1%':", resolvedPath)); // Enforce that 'flake.nix' is a direct attrset, not a // computation. if (mustBeTrivial && @@ -1387,16 +1371,13 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - std::unique_ptr dts = - debuggerHook ? - std::unique_ptr( - new DebugTraceStacker( - state, - Trace { .pos = *pos2, - .hint = hintfmt( - "while evaluating the attribute '%1%'", - showAttrPath(state, env, attrPath)) - })) + std::unique_ptr dts = + debuggerHook ? + makeDebugTraceStacker( + state, + *pos2, + "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)) : std::unique_ptr(); for (auto & i : attrPath) { @@ -1541,21 +1522,15 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { - std::unique_ptr dts = - debuggerHook ? - std::unique_ptr( - new DebugTraceStacker( - *this, - Trace {.pos = lambda.pos, - .hint = hintfmt( + std::unique_ptr dts = + debuggerHook ? + makeDebugTraceStacker(*this, lambda.pos, "while evaluating %s", (lambda.name.set() ? "'" + (string) lambda.name + "'" : "anonymous lambda")) - })) : std::unique_ptr(); - lambda.body->eval(*this, env2, vCur); } catch (Error & e) { std::cout << "eval showErrorInfo showTrace: " << loggerSettings.showTrace.get() << std::endl; @@ -1950,18 +1925,12 @@ void EvalState::forceValueDeep(Value & v) if (v.type() == nAttrs) { for (auto & i : *v.attrs) try { - std::unique_ptr dts = - debuggerHook ? - std::unique_ptr( - new DebugTraceStacker( - *this, - Trace { .pos = *i.pos, - .hint = hintfmt( + std::unique_ptr dts = + debuggerHook ? + makeDebugTraceStacker(*this, *i.pos, "while evaluating the attribute '%1%'", i.name) - })) : std::unique_ptr(); - recurse(*i.value); } catch (Error & e) { addErrorTrace(e, *i.pos, "while evaluating the attribute '%1%'", i.name); -- cgit v1.2.3 From e5eebda19475ab4f25346128e5428c27e526c7ce Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 23 Dec 2021 13:36:39 -0700 Subject: DebugTrace --- src/libcmd/command.cc | 2 +- src/libcmd/command.hh | 4 +--- src/libcmd/repl.cc | 11 +++++------ src/libexpr/eval.cc | 22 +++++++++++++++------- src/libexpr/eval.hh | 8 +++++++- 5 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 0ada5fa3c..6c0f84c4b 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -84,7 +84,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); - runRepl(evalState, ref(&error), *vm); + runRepl(evalState, &error, *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index e27ee2e9e..e2c72256e 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -314,8 +314,6 @@ void printClosureDiff( void runRepl( ref evalState, - std::optional> debugError, + const Error *debugError, const std::map & extraEnv); - - } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 3289aea3e..6859e5c07 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -50,7 +50,7 @@ struct NixRepl ref state; Bindings * autoArgs; - std::optional> debugError; + const Error *debugError; Strings loadedFiles; @@ -470,13 +470,12 @@ bool NixRepl::processLine(string line) } else if (arg == "error") { - if (this->debugError.has_value()) { - // TODO user --show-trace setting? - showErrorInfo(std::cout, (*debugError)->info(), true); + if (this->debugError) { + showErrorInfo(std::cout, debugError->info(), true); } else { - notice("error information not available"); + notice("error information not available"); } } } @@ -893,7 +892,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, - std::optional> debugError, + const Error *debugError, const std::map & extraEnv) { auto repl = std::make_unique(evalState); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d7deb550e..b8d060276 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -40,7 +40,7 @@ std::function deb class DebugTraceStacker { public: - DebugTraceStacker(EvalState &evalState, Trace t) + DebugTraceStacker(EvalState &evalState, DebugTrace t) :evalState(evalState), trace(t) { evalState.debugTraces.push_front(t); @@ -50,7 +50,7 @@ class DebugTraceStacker { evalState.debugTraces.pop_front(); } EvalState &evalState; - Trace trace; + DebugTrace trace; }; static char * dupString(const char * s) @@ -911,12 +911,14 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con } LocalNoInline(std::unique_ptr - makeDebugTraceStacker(EvalState &state, std::optional pos, const char * s, const string & s2)) + makeDebugTraceStacker(EvalState &state, Expr &expr, std::optional pos, const char * s, const string & s2)) { return std::unique_ptr( new DebugTraceStacker( state, - Trace {.pos = pos, + DebugTrace + {.pos = pos, + .expr = expr, .hint = hintfmt(s, s2) })); } @@ -1143,6 +1145,7 @@ void EvalState::cacheFile( debuggerHook ? makeDebugTraceStacker( *this, + *e, (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), "while evaluating the file '%1%':", resolvedPath) : std::unique_ptr(); @@ -1375,6 +1378,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) debuggerHook ? makeDebugTraceStacker( state, + *this, *pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)) @@ -1524,7 +1528,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & try { std::unique_ptr dts = debuggerHook ? - makeDebugTraceStacker(*this, lambda.pos, + makeDebugTraceStacker(*this, *lambda.body, lambda.pos, "while evaluating %s", (lambda.name.set() ? "'" + (string) lambda.name + "'" @@ -1925,10 +1929,14 @@ void EvalState::forceValueDeep(Value & v) if (v.type() == nAttrs) { for (auto & i : *v.attrs) try { + std::unique_ptr dts = debuggerHook ? - makeDebugTraceStacker(*this, *i.pos, - "while evaluating the attribute '%1%'", i.name) + // if the value is a thunk, we're evaling. otherwise no trace necessary. + (i.value->isThunk() ? + makeDebugTraceStacker(*this, *v.thunk.expr, *i.pos, + "while evaluating the attribute '%1%'", i.name) + : std::unique_ptr()) : std::unique_ptr(); recurse(*i.value); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index c3717b3c2..c7a19e100 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -74,6 +74,12 @@ struct RegexCache; std::shared_ptr makeRegexCache(); +struct DebugTrace { + std::optional pos; + Expr &expr; + hintformat hint; +}; + class EvalState { @@ -109,7 +115,7 @@ public: RootValue vCallFlake = nullptr; RootValue vImportedDrvToDerivation = nullptr; - std::list debugTraces; + std::list debugTraces; private: SrcToStore srcToStore; -- cgit v1.2.3 From d0d589044512a77b345b7e576e2c45910c74eb02 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 13:47:35 -0700 Subject: don't add underscore names to extras --- src/libexpr/eval.cc | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index b8d060276..377e1b2f8 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -716,18 +716,34 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // add bindings for the next level up first, so that the bindings for this level // override the higher levels. if (env.up && se.up) { - mapStaticEnvBindings( *se.up, *env.up,vm); - } + mapStaticEnvBindings( *se.up, *env.up,vm); + + // iterate through staticenv bindings and add them. + auto map = valmap(); + for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + { + map[iter->first] = env.values[iter->second]; + } - // iterate through staticenv bindings and add them. - auto map = valmap(); - for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + vm.merge(map); + } + else { - map[iter->first] = env.values[iter->second]; + std::cout << " -------------------- " << std::endl; + // iterate through staticenv bindings and add them, + // except for the __* ones. + auto map = valmap(); + for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + { + std::cout << iter->first << std::endl; + std::string s = iter->first; + if (s.substr(0,2) != "__") { + map[iter->first] = env.values[iter->second]; + } + } + + vm.merge(map); } - - vm.merge(map); - } -- cgit v1.2.3 From ff82ba98b41eb3e4b1ce96ed02504acea03eb29c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 14:06:04 -0700 Subject: don't add builtins to extras, initEnv() in regular repl --- src/libcmd/repl.cc | 3 ++- src/libexpr/eval.cc | 20 ++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 6859e5c07..b14f43ec4 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -901,8 +901,8 @@ void runRepl( repl->initEnv(); + // add 'extra' vars. std::set names; - for (auto & [name, value] : extraEnv) { // names.insert(ANSI_BOLD + name + ANSI_NORMAL); names.insert(name); @@ -951,6 +951,7 @@ struct CmdRepl : StoreCommand, MixEvalArgs auto repl = std::make_unique(evalState); repl->autoArgs = getAutoArgs(*repl->state); + repl->initEnv(); repl->mainLoop(files); } }; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 377e1b2f8..d99e73471 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -715,8 +715,9 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) { // add bindings for the next level up first, so that the bindings for this level // override the higher levels. + // The top level bindings (builtins) are skipped since they are added for us by initEnv() if (env.up && se.up) { - mapStaticEnvBindings( *se.up, *env.up,vm); + mapStaticEnvBindings(*se.up, *env.up,vm); // iterate through staticenv bindings and add them. auto map = valmap(); @@ -725,23 +726,6 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) map[iter->first] = env.values[iter->second]; } - vm.merge(map); - } - else - { - std::cout << " -------------------- " << std::endl; - // iterate through staticenv bindings and add them, - // except for the __* ones. - auto map = valmap(); - for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) - { - std::cout << iter->first << std::endl; - std::string s = iter->first; - if (s.substr(0,2) != "__") { - map[iter->first] = env.values[iter->second]; - } - } - vm.merge(map); } } -- cgit v1.2.3 From 2a66c120e66953bf8d6cf6866eb2783549527d40 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 14:48:34 -0700 Subject: by refernce for addVarToScope --- src/libcmd/repl.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index b14f43ec4..188bf75e4 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -75,7 +75,7 @@ struct NixRepl void loadFiles(); void reloadFiles(); void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value * v); + void addVarToScope(const Symbol & name, Value & v); Expr * parseString(string s); void evalString(string s, Value & v); @@ -613,7 +613,7 @@ bool NixRepl::processLine(string line) Expr * e = parseString(string(line, p + 1)); Value *v = new Value(*state->allocValue()); v->mkThunk(env, e); - addVarToScope(state->symbols.create(name), v); + addVarToScope(state->symbols.create(name), *v); } else { std::cout << "evalstring" << std::endl; Value v; @@ -696,12 +696,12 @@ void NixRepl::addAttrsToScope(Value & attrs) { state->forceAttrs(attrs); for (auto & i : *attrs.attrs) - addVarToScope(i.name, i.value); + addVarToScope(i.name, *i.value); notice("Added %1% variables.", attrs.attrs->size()); } -void NixRepl::addVarToScope(const Symbol & name, Value * v) +void NixRepl::addVarToScope(const Symbol & name, Value & v) { if (displ >= envSize) throw Error("environment full; cannot add more variables"); @@ -709,7 +709,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v) staticEnv->vars.erase(oldVar); staticEnv->vars.emplace_back(name, displ); staticEnv->sort(); - env->values[displ++] = v; + env->values[displ++] = &v; varNames.insert((string) name); notice("Added variable to scope: %1%", name); @@ -906,7 +906,7 @@ void runRepl( for (auto & [name, value] : extraEnv) { // names.insert(ANSI_BOLD + name + ANSI_NORMAL); names.insert(name); - repl->addVarToScope(repl->state->symbols.create(name), value); + repl->addVarToScope(repl->state->symbols.create(name), *value); } printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); -- cgit v1.2.3 From 6801a423fc9abdfd2cb7307f2970553bcfad089d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 16:28:45 -0700 Subject: :d env --- src/libcmd/repl.cc | 26 +++++++++++++++----------- src/libexpr/eval.cc | 7 +++++-- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 188bf75e4..3948ede02 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -402,7 +402,6 @@ StorePath NixRepl::getDerivationPath(Value & v) { return drvPath; } - bool NixRepl::processLine(string line) { if (line == "") return true; @@ -441,7 +440,8 @@ bool NixRepl::processLine(string line) << " :doc Show documentation of a builtin function\n" << " :d Debug mode commands\n" << " :d stack Show call stack\n" - << " :d stack Detail for step N\n" + // << " :d stack Detail for stack level N\n" + << " :d env Show env stack\n" << " :d error Show current error\n"; } @@ -466,17 +466,21 @@ bool NixRepl::processLine(string line) } } } - - + } else if (arg == "env") { + std::cout << "env stack:" << std::endl; + auto iter = this->state->debugTraces.begin(); + if (iter != this->state->debugTraces.end()) { + printStaticEnvBindings(iter->expr); + } } else if (arg == "error") { - if (this->debugError) { - showErrorInfo(std::cout, debugError->info(), true); - } - else - { - notice("error information not available"); - } + if (this->debugError) { + showErrorInfo(std::cout, debugError->info(), true); + } + else + { + notice("error information not available"); + } } } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d99e73471..f1e6cfdf2 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -691,10 +691,14 @@ std::optional EvalState::getDoc(Value & v) void printStaticEnvBindings(const StaticEnv &se, int lvl) { + std::cout << "Env level " << lvl << std::endl; + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { - std::cout << lvl << i->first << std::endl; + std::cout << i->first << " "; } + std::cout << std::endl; + std::cout << std::endl; if (se.up) { printStaticEnvBindings(*se.up, ++lvl); @@ -730,7 +734,6 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) } } - valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) { auto vm = new valmap(); -- cgit v1.2.3 From 9760fa8661f7562e0b8979338200904053cc4631 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 17:35:27 -0700 Subject: add DebugTrace for the current error --- src/libcmd/command.cc | 2 +- src/libcmd/command.hh | 2 ++ src/libcmd/repl.cc | 10 ++++++++++ src/libexpr/eval.cc | 17 +---------------- src/libexpr/eval.hh | 18 ++++++++++++++++-- 5 files changed, 30 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 6c0f84c4b..897d81981 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -84,7 +84,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); - runRepl(evalState, &error, *vm); + runRepl(evalState, &error, expr, *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index e2c72256e..8af9eae27 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -312,8 +312,10 @@ void printClosureDiff( const StorePath & afterPath, std::string_view indent); + void runRepl( ref evalState, const Error *debugError, + const Expr &expr, const std::map & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 3948ede02..4a61d2be4 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -897,6 +897,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, const Error *debugError, + const Expr &expr, const std::map & extraEnv) { auto repl = std::make_unique(evalState); @@ -905,6 +906,15 @@ void runRepl( repl->initEnv(); + // tack on a final DebugTrace for the error position. + DebugTraceStacker ldts( + *evalState, + DebugTrace + {.pos = debugError->info().errPos, + .expr = expr, + .hint = debugError->info().msg + }); + // add 'extra' vars. std::set names; for (auto & [name, value] : extraEnv) { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f1e6cfdf2..4bdcc052f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -38,21 +38,6 @@ namespace nix { std::function debuggerHook; -class DebugTraceStacker { - public: - DebugTraceStacker(EvalState &evalState, DebugTrace t) - :evalState(evalState), trace(t) - { - evalState.debugTraces.push_front(t); - } - ~DebugTraceStacker() { - // assert(evalState.debugTraces.front() == trace); - evalState.debugTraces.pop_front(); - } - EvalState &evalState; - DebugTrace trace; -}; - static char * dupString(const char * s) { char * t; @@ -701,7 +686,7 @@ void printStaticEnvBindings(const StaticEnv &se, int lvl) std::cout << std::endl; if (se.up) { - printStaticEnvBindings(*se.up, ++lvl); + printStaticEnvBindings(*se.up, ++lvl); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index c7a19e100..2f8cc82b0 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -76,11 +76,10 @@ std::shared_ptr makeRegexCache(); struct DebugTrace { std::optional pos; - Expr &expr; + const Expr &expr; hintformat hint; }; - class EvalState { public: @@ -406,6 +405,21 @@ private: friend void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v); }; +class DebugTraceStacker { + public: + DebugTraceStacker(EvalState &evalState, DebugTrace t) + :evalState(evalState), trace(t) + { + evalState.debugTraces.push_front(t); + } + ~DebugTraceStacker() + { + // assert(evalState.debugTraces.front() == trace); + evalState.debugTraces.pop_front(); + } + EvalState &evalState; + DebugTrace trace; +}; /* Return a string representing the type of the value `v'. */ string showType(ValueType type); -- cgit v1.2.3 From 4610e02d04c9f41ac355d2ca6a27d3a631ffefc6 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 18:12:46 -0700 Subject: remove debug code --- src/libcmd/command.cc | 10 +++++----- src/libcmd/repl.cc | 18 ------------------ src/libexpr/eval.cc | 6 ------ src/libexpr/parser.y | 4 ---- src/libutil/error.cc | 2 -- 5 files changed, 5 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 897d81981..b97458b2d 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -73,13 +73,13 @@ ref EvalCommand::getEvalState() debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); - printStaticEnvBindings(expr); + // printStaticEnvBindings(expr); - std::cout << evalState->vCallFlake << std::endl; + // std::cout << evalState->vCallFlake << std::endl; - std::cout << "expr: " << std::endl; - expr.show(std::cout); - std::cout << std::endl; + // std::cout << "expr: " << std::endl; + // expr.show(std::cout); + // std::cout << std::endl; if (expr.staticenv) { diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 4a61d2be4..64547344a 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -202,9 +202,6 @@ namespace { void NixRepl::mainLoop(const std::vector & files) { - std::cout << "iinitial mainLoop; " << std::endl; - // printStaticEnvBindings(*staticEnv, 0); - string error = ANSI_RED "error:" ANSI_NORMAL " "; notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n"); @@ -231,9 +228,6 @@ void NixRepl::mainLoop(const std::vector & files) std::string input; - std::cout << "pre MAINLOOP; " << std::endl; - // printStaticEnvBindings(*staticEnv, 0); - while (true) { // When continuing input from previous lines, don't print a prompt, just align to the same // number of chars as the prompt. @@ -446,7 +440,6 @@ bool NixRepl::processLine(string line) } else if (command == ":d" || command == ":debug") { - std::cout << "debug: '" << arg << "'" << std::endl; if (arg == "stack") { std::cout << "eval stack:" << std::endl; for (auto iter = this->state->debugTraces.begin(); @@ -613,13 +606,11 @@ bool NixRepl::processLine(string line) line[p + 1] != '=' && isVarName(name = removeWhitespace(string(line, 0, p)))) { - std::cout << "isvarname" << std::endl; Expr * e = parseString(string(line, p + 1)); Value *v = new Value(*state->allocValue()); v->mkThunk(env, e); addVarToScope(state->symbols.create(name), *v); } else { - std::cout << "evalstring" << std::endl; Value v; evalString(line, v); printValue(std::cout, v, 1) << std::endl; @@ -715,8 +706,6 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v) staticEnv->sort(); env->values[displ++] = &v; varNames.insert((string) name); - notice("Added variable to scope: %1%", name); - } // version from master. @@ -741,11 +730,8 @@ Expr * NixRepl::parseString(string s) void NixRepl::evalString(string s, Value & v) { - std::cout << "pre partstirns:l" << std::endl; Expr * e = parseString(s); - std::cout << "pre e->eval" << std::endl; e->eval(*state, *env, v); - std::cout << "prev fv" << std::endl; state->forceValue(v); } @@ -924,10 +910,6 @@ void runRepl( } printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); - // printError("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)); - - std::cout << " pre repl->mainLoop({});" << std::endl; - // printStaticEnvBindings(*repl->staticEnv, 0); repl->mainLoop({}); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 4bdcc052f..2596fbe3a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -858,17 +858,12 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { - std::cout << "throwUndefinedVarError" << std::endl; - - std::cout << "loggerSettings.showTrace: " << loggerSettings.showTrace << std::endl; - auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); if (debuggerHook && expr) { - std::cout << "throwUndefinedVarError debuggerHook" << std::endl; debuggerHook(error, env, *expr); } @@ -1525,7 +1520,6 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & lambda.body->eval(*this, env2, vCur); } catch (Error & e) { - std::cout << "eval showErrorInfo showTrace: " << loggerSettings.showTrace.get() << std::endl; if (loggerSettings.showTrace.get()) { addErrorTrace(e, lambda.pos, "while evaluating %s", (lambda.name.set() diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 066dc4ecc..c537aa0c2 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -616,10 +616,6 @@ Expr * EvalState::parse(const char * text, FileOrigin origin, if (res) throw ParseError(data.error.value()); - std::cout << " data.result->bindVars(staticEnv); " << std::endl; - - // printStaticEnvBindings(*staticEnv, 0); - data.result->bindVars(staticEnv); return data.result; diff --git a/src/libutil/error.cc b/src/libutil/error.cc index c2b9d2707..203d79087 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -221,8 +221,6 @@ static std::string indent(std::string_view indentFirst, std::string_view indentR std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace) { - std::cout << "showErrorInfo showTrace: " << showTrace << std::endl; - std::string prefix; switch (einfo.level) { case Verbosity::lvlError: { -- cgit v1.2.3 From 5954cbf3e9dca0e3b84e4bf2def74abb3d6f80cd Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 27 Dec 2021 18:29:55 -0700 Subject: more cleanup --- src/libcmd/command.cc | 8 -------- src/libcmd/repl.cc | 14 -------------- src/libexpr/eval.cc | 4 ---- src/libexpr/nixexpr.hh | 40 ++++++++++++++++++---------------------- src/libutil/logging.hh | 1 - 5 files changed, 18 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index b97458b2d..e44c737f5 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -73,14 +73,6 @@ ref EvalCommand::getEvalState() debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); - // printStaticEnvBindings(expr); - - // std::cout << evalState->vCallFlake << std::endl; - - // std::cout << "expr: " << std::endl; - // expr.show(std::cout); - // std::cout << std::endl; - if (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 64547344a..cf784db61 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -434,7 +434,6 @@ bool NixRepl::processLine(string line) << " :doc Show documentation of a builtin function\n" << " :d Debug mode commands\n" << " :d stack Show call stack\n" - // << " :d stack Detail for stack level N\n" << " :d env Show env stack\n" << " :d error Show current error\n"; } @@ -708,19 +707,6 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v) varNames.insert((string) name); } -// version from master. -// void NixRepl::addVarToScope(const Symbol & name, Value & v) -// { -// if (displ >= envSize) -// throw Error("environment full; cannot add more variables"); -// if (auto oldVar = staticEnv.find(name); oldVar != staticEnv.vars.end()) -// staticEnv.vars.erase(oldVar); -// staticEnv.vars.emplace_back(name, displ); -// staticEnv.sort(); -// env->values[displ++] = &v; -// varNames.insert((string) name); -// } - Expr * NixRepl::parseString(string s) { Expr * e = state->parseExprFromString(s, curDir, staticEnv); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 2596fbe3a..ac437e69d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -672,8 +672,6 @@ std::optional EvalState::getDoc(Value & v) return {}; } - - void printStaticEnvBindings(const StaticEnv &se, int lvl) { std::cout << "Env level " << lvl << std::endl; @@ -1112,8 +1110,6 @@ void EvalState::resetFileCache() } - - void EvalState::cacheFile( const Path & path, const Path & resolvedPath, diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index a9a5f5316..bfa215fda 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -99,10 +99,9 @@ struct ExprInt : Expr NixInt n; Value v; ExprInt(NixInt n) : n(n) { mkInt(v, n); }; - COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + COMMON_METHODS }; struct ExprFloat : Expr @@ -110,10 +109,9 @@ struct ExprFloat : Expr NixFloat nf; Value v; ExprFloat(NixFloat nf) : nf(nf) { mkFloat(v, nf); }; - COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + COMMON_METHODS }; struct ExprString : Expr @@ -121,10 +119,9 @@ struct ExprString : Expr Symbol s; Value v; ExprString(const Symbol & s) : s(s) { mkString(v, s); }; - COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + COMMON_METHODS }; /* Temporary class used during parsing of indented strings. */ @@ -132,7 +129,6 @@ struct ExprIndStr : Expr { string s; ExprIndStr(const string & s) : s(s) { }; - Pos* getPos() { return 0; } }; @@ -141,9 +137,9 @@ struct ExprPath : Expr string s; Value v; ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); }; - COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); Pos* getPos() { return 0; } + COMMON_METHODS }; typedef uint32_t Level; @@ -169,9 +165,9 @@ struct ExprVar : Expr ExprVar(const Symbol & name) : name(name) { }; ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; - COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprSelect : Expr @@ -181,8 +177,8 @@ struct ExprSelect : Expr AttrPath attrPath; ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprOpHasAttr : Expr @@ -190,8 +186,8 @@ struct ExprOpHasAttr : Expr Expr * e; AttrPath attrPath; ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { }; - COMMON_METHODS Pos* getPos() { return e->getPos(); } + COMMON_METHODS }; struct ExprAttrs : Expr @@ -219,16 +215,16 @@ struct ExprAttrs : Expr DynamicAttrDefs dynamicAttrs; ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { }; ExprAttrs() : recursive(false), pos(noPos) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprList : Expr { std::vector elems; ExprList() { }; - COMMON_METHODS Pos* getPos() { return 0; } + COMMON_METHODS }; struct Formal @@ -266,8 +262,8 @@ struct ExprLambda : Expr void setName(Symbol & name); string showNamePos() const; inline bool hasFormals() const { return formals != nullptr; } - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprCall : Expr @@ -278,8 +274,8 @@ struct ExprCall : Expr ExprCall(const Pos & pos, Expr * fun, std::vector && args) : fun(fun), args(args), pos(pos) { } - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprLet : Expr @@ -287,8 +283,8 @@ struct ExprLet : Expr ExprAttrs * attrs; Expr * body; ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { }; - COMMON_METHODS Pos* getPos() { return 0; } + COMMON_METHODS }; struct ExprWith : Expr @@ -297,8 +293,8 @@ struct ExprWith : Expr Expr * attrs, * body; size_t prevWith; ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprIf : Expr @@ -306,8 +302,8 @@ struct ExprIf : Expr Pos pos; Expr * cond, * then, * else_; ExprIf(const Pos & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprAssert : Expr @@ -315,16 +311,16 @@ struct ExprAssert : Expr Pos pos; Expr * cond, * body; ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprOpNot : Expr { Expr * e; ExprOpNot(Expr * e) : e(e) { }; - COMMON_METHODS Pos* getPos() { return 0; } + COMMON_METHODS }; #define MakeBinOp(name, s) \ @@ -361,16 +357,16 @@ struct ExprConcatStrings : Expr vector * es; ExprConcatStrings(const Pos & pos, bool forceString, vector * es) : pos(pos), forceString(forceString), es(es) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; struct ExprPos : Expr { Pos pos; ExprPos(const Pos & pos) : pos(pos) { }; - COMMON_METHODS Pos* getPos() { return &pos; } + COMMON_METHODS }; diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index f10a9af38..96ad69790 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -38,7 +38,6 @@ typedef uint64_t ActivityId; struct LoggerSettings : Config { Setting showTrace{ - // this, false, "show-trace", this, false, "show-trace", R"( Where Nix should print out a stack trace in case of Nix -- cgit v1.2.3 From c6691089814ac16eb02bab968a97ea2b0fe942f2 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 3 Jan 2022 18:13:16 -0700 Subject: merge cleanup --- src/libcmd/command.cc | 20 +++++++------------- src/libcmd/repl.cc | 8 ++++---- 2 files changed, 11 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index b254a90f0..252bc1fad 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -68,7 +68,13 @@ extern std::function EvalCommand::getEvalState() { if (!evalState) { - evalState = std::make_shared(searchPath, getEvalStore(), getStore()); + evalState = +#if HAVE_BOEHMGC + std::allocate_shared(traceable_allocator(), +#else + std::make_shared( +#endif + searchPath, getEvalStore(), getStore()); if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); @@ -96,18 +102,6 @@ ref EvalCommand::getEvalStore() return ref(evalStore); } -ref EvalCommand::getEvalState() -{ - if (!evalState) evalState = -#if HAVE_BOEHMGC - std::allocate_shared(traceable_allocator(), -#else - std::make_shared( -#endif - searchPath, getEvalStore(), getStore()); - return ref(evalState); -} - BuiltPathsCommand::BuiltPathsCommand(bool recursive) : recursive(recursive) { diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index e7628082a..4cf93c26e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -435,7 +435,7 @@ bool NixRepl::processLine(string line) << " :u Build derivation, then start nix-shell\n" << " :doc Show documentation of a builtin function\n" << " :log Show logs for a derivation\n" - << " :st [bool] Enable, disable or toggle showing traces for errors\n"; + << " :st [bool] Enable, disable or toggle showing traces for errors\n" << " :d Debug mode commands\n" << " :d stack Show call stack\n" << " :d env Show env stack\n" @@ -730,12 +730,12 @@ void NixRepl::addAttrsToScope(Value & attrs) throw Error("environment full; cannot add more variables"); for (auto & i : *attrs.attrs) { - staticEnv.vars.emplace_back(i.name, displ); + staticEnv->vars.emplace_back(i.name, displ); env->values[displ++] = i.value; varNames.insert((string) i.name); } - staticEnv.sort(); - staticEnv.deduplicate(); + staticEnv->sort(); + staticEnv->deduplicate(); notice("Added %1% variables.", attrs.attrs->size()); } -- cgit v1.2.3 From 1b6b33d43d5fa4675848b39121f681ae330b2b86 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 3 Jan 2022 18:29:43 -0700 Subject: filter out underscore names --- src/libexpr/eval.cc | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 851058b3e..86561c6b0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -680,16 +680,28 @@ void printStaticEnvBindings(const StaticEnv &se, int lvl) { std::cout << "Env level " << lvl << std::endl; - for (auto i = se.vars.begin(); i != se.vars.end(); ++i) - { - std::cout << i->first << " "; - } - std::cout << std::endl; - std::cout << std::endl; - if (se.up) { + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) + { + std::cout << i->first << " "; + } + std::cout << std::endl; + std::cout << std::endl; + printStaticEnvBindings(*se.up, ++lvl); } + else + { + // for the top level, don't print the double underscore ones; they are in builtins. + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) + { + if (((string)i->first).substr(0,2) != "__") + std::cout << i->first << " "; + } + std::cout << std::endl; + std::cout << std::endl; + + } } -- cgit v1.2.3 From a4d8a799b7dd6b5368b7892747d18911f8ff9ba2 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 5 Jan 2022 12:21:18 -0700 Subject: tidy up debugtraces --- src/libexpr/eval.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 86561c6b0..d9c26106e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1151,14 +1151,14 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { - std::unique_ptr dts = + auto dts = debuggerHook ? makeDebugTraceStacker( *this, *e, (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), "while evaluating the file '%1%':", resolvedPath) - : std::unique_ptr(); + : nullptr; // Enforce that 'flake.nix' is a direct attrset, not a // computation. @@ -1384,7 +1384,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - std::unique_ptr dts = + auto dts = debuggerHook ? makeDebugTraceStacker( state, @@ -1392,7 +1392,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) *pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)) - : std::unique_ptr(); + : nullptr; for (auto & i : attrPath) { state.nrLookups++; @@ -1536,14 +1536,14 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { - std::unique_ptr dts = + auto dts = debuggerHook ? makeDebugTraceStacker(*this, *lambda.body, lambda.pos, "while evaluating %s", (lambda.name.set() ? "'" + (string) lambda.name + "'" : "anonymous lambda")) - : std::unique_ptr(); + : nullptr; lambda.body->eval(*this, env2, vCur); } catch (Error & e) { @@ -1939,14 +1939,14 @@ void EvalState::forceValueDeep(Value & v) for (auto & i : *v.attrs) try { - std::unique_ptr dts = + auto dts = debuggerHook ? // if the value is a thunk, we're evaling. otherwise no trace necessary. (i.value->isThunk() ? makeDebugTraceStacker(*this, *v.thunk.expr, *i.pos, "while evaluating the attribute '%1%'", i.name) - : std::unique_ptr()) - : std::unique_ptr(); + : nullptr) + : nullptr; recurse(*i.value); } catch (Error & e) { -- cgit v1.2.3 From bf8a065be0d0cdccf5b6bc1034dc3e1709b21bd5 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 5 Jan 2022 12:28:31 -0700 Subject: add colors; remove headings --- src/libcmd/repl.cc | 2 -- src/libexpr/eval.cc | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 4cf93c26e..4ecbf51b5 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -444,7 +444,6 @@ bool NixRepl::processLine(string line) else if (command == ":d" || command == ":debug") { if (arg == "stack") { - std::cout << "eval stack:" << std::endl; for (auto iter = this->state->debugTraces.begin(); iter != this->state->debugTraces.end(); ++iter) { std::cout << "\n" << "… " << iter->hint.str() << "\n"; @@ -463,7 +462,6 @@ bool NixRepl::processLine(string line) } } } else if (arg == "env") { - std::cout << "env stack:" << std::endl; auto iter = this->state->debugTraces.begin(); if (iter != this->state->debugTraces.end()) { printStaticEnvBindings(iter->expr); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d9c26106e..585042b9d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -679,12 +679,15 @@ std::optional EvalState::getDoc(Value & v) void printStaticEnvBindings(const StaticEnv &se, int lvl) { std::cout << "Env level " << lvl << std::endl; - + if (se.up) { + std::cout << ANSI_MAGENTA; for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { std::cout << i->first << " "; } + std::cout << ANSI_NORMAL; + std::cout << std::endl; std::cout << std::endl; @@ -692,12 +695,14 @@ void printStaticEnvBindings(const StaticEnv &se, int lvl) } else { + std::cout << ANSI_MAGENTA; // for the top level, don't print the double underscore ones; they are in builtins. for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { if (((string)i->first).substr(0,2) != "__") std::cout << i->first << " "; } + std::cout << ANSI_NORMAL; std::cout << std::endl; std::cout << std::endl; -- cgit v1.2.3 From 84aeb74377ce41408680256813870271999e8208 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 5 Jan 2022 14:25:45 -0700 Subject: revert value-add --- src/libcmd/repl.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 4ecbf51b5..57463bd79 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -641,9 +641,9 @@ bool NixRepl::processLine(string line) isVarName(name = removeWhitespace(string(line, 0, p)))) { Expr * e = parseString(string(line, p + 1)); - Value *v = new Value(*state->allocValue()); - v->mkThunk(env, e); - addVarToScope(state->symbols.create(name), *v); + Value & v(*state->allocValue()); + v.mkThunk(env, e); + addVarToScope(state->symbols.create(name), v); } else { Value v; evalString(line, v); -- cgit v1.2.3 From c51b527c280ee08b3ce3ca6d229139c4292b3176 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 7 Jan 2022 16:37:44 -0700 Subject: add env to DebugTrace --- src/libcmd/repl.cc | 1 + src/libexpr/eval.cc | 9 ++++++--- src/libexpr/eval.hh | 6 +++++- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 57463bd79..fdd63621f 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -927,6 +927,7 @@ void runRepl( DebugTrace {.pos = debugError->info().errPos, .expr = expr, + .env = *repl->env, .hint = debugError->info().msg }); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 585042b9d..e01147169 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -913,7 +913,7 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con } LocalNoInline(std::unique_ptr - makeDebugTraceStacker(EvalState &state, Expr &expr, std::optional pos, const char * s, const string & s2)) + makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, std::optional pos, const char * s, const string & s2)) { return std::unique_ptr( new DebugTraceStacker( @@ -921,6 +921,7 @@ LocalNoInline(std::unique_ptr DebugTrace {.pos = pos, .expr = expr, + .env = env, .hint = hintfmt(s, s2) })); } @@ -1161,6 +1162,7 @@ void EvalState::cacheFile( makeDebugTraceStacker( *this, *e, + this->baseEnv, (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), "while evaluating the file '%1%':", resolvedPath) : nullptr; @@ -1394,6 +1396,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) makeDebugTraceStacker( state, *this, + env, *pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)) @@ -1543,7 +1546,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & try { auto dts = debuggerHook ? - makeDebugTraceStacker(*this, *lambda.body, lambda.pos, + makeDebugTraceStacker(*this, *lambda.body, env2, lambda.pos, "while evaluating %s", (lambda.name.set() ? "'" + (string) lambda.name + "'" @@ -1948,7 +1951,7 @@ void EvalState::forceValueDeep(Value & v) debuggerHook ? // if the value is a thunk, we're evaling. otherwise no trace necessary. (i.value->isThunk() ? - makeDebugTraceStacker(*this, *v.thunk.expr, *i.pos, + makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, *i.pos, "while evaluating the attribute '%1%'", i.name) : nullptr) : nullptr; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 5dbb9b5e5..3c74bb4a1 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -77,6 +77,7 @@ std::shared_ptr makeRegexCache(); struct DebugTrace { std::optional pos; const Expr &expr; + const Env &env; hintformat hint; }; @@ -203,7 +204,7 @@ public: trivial (i.e. doesn't require arbitrary computation). */ void evalFile(const Path & path, Value & v, bool mustBeTrivial = false); - /* Like `cacheFile`, but with an already parsed expression. */ + /* Like `evalFile`, but with an already parsed expression. */ void cacheFile( const Path & path, const Path & resolvedPath, @@ -416,6 +417,9 @@ class DebugTraceStacker { DebugTraceStacker(EvalState &evalState, DebugTrace t) :evalState(evalState), trace(t) { + + // evalState.debuggerHook(const Error & error, const Env & env, const Expr & expr); + evalState.debugTraces.push_front(t); } ~DebugTraceStacker() -- cgit v1.2.3 From a963674d88f2f1af6181f126ed4288ec65b61fc6 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sat, 8 Jan 2022 11:03:48 -0700 Subject: optinoal error; compiles --- src/libcmd/command.cc | 9 +++++---- src/libcmd/repl.cc | 24 ++++++++++++++---------- src/libexpr/eval.cc | 33 ++++++++++++++++++++------------- src/libexpr/eval.hh | 11 ++--------- src/libexpr/nixexpr.hh | 2 +- 5 files changed, 42 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 252bc1fad..ed8f6d295 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -63,7 +63,7 @@ EvalCommand::EvalCommand() }); } -extern std::function debuggerHook; +extern std::function debuggerHook; ref EvalCommand::getEvalState() { @@ -76,13 +76,14 @@ ref EvalCommand::getEvalState() #endif searchPath, getEvalStore(), getStore()); if (startReplOnEvalErrors) - debuggerHook = [evalState{ref(evalState)}](const Error & error, const Env & env, const Expr & expr) { - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error.what()); + debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { + 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 (expr.staticenv) { auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); - runRepl(evalState, &error, expr, *vm); + runRepl(evalState, error, expr, *vm); } }; } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index fdd63621f..e66cf4430 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -917,19 +917,23 @@ void runRepl( { auto repl = std::make_unique(evalState); - repl->debugError = debugError; + // repl->debugError = debugError; repl->initEnv(); - // tack on a final DebugTrace for the error position. - DebugTraceStacker ldts( - *evalState, - DebugTrace - {.pos = debugError->info().errPos, - .expr = expr, - .env = *repl->env, - .hint = debugError->info().msg - }); + // auto dts = debugError ? + // std::unique_ptr( + // // tack on a final DebugTrace for the error position. + // new DebugTraceStacker( + // *evalState, + // DebugTrace + // {.pos = debugError->info().errPos, + // .expr = expr, + // .env = *repl->env, + // .hint = debugError->info().msg + // }) + // ) + // : nullptr; // add 'extra' vars. std::set names; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e01147169..7b3745e52 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -36,7 +36,7 @@ namespace nix { -std::function debuggerHook; +std::function debuggerHook; static char * dupString(const char * s) { @@ -756,7 +756,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env auto error = EvalError(s, s2); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -768,7 +768,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -778,7 +778,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con auto error = EvalError(s, s2, s3); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -791,7 +791,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -805,7 +805,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -818,7 +818,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -831,7 +831,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -844,7 +844,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -857,7 +857,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -870,7 +870,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -883,7 +883,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * }); if (debuggerHook && expr) { - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); } throw error; @@ -897,7 +897,7 @@ LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char }); if (debuggerHook && expr) - debuggerHook(error, env, *expr); + debuggerHook(&error, env, *expr); throw error; } @@ -926,6 +926,13 @@ LocalNoInline(std::unique_ptr })); } +DebugTraceStacker::DebugTraceStacker(EvalState &evalState, DebugTrace t) +:evalState(evalState), trace(t) +{ + evalState.debugTraces.push_front(t); + if (debuggerHook) + debuggerHook(0, t.env, t.expr); +} void mkString(Value & v, const char * s) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3c74bb4a1..1a097ab8c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -24,7 +24,7 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); -extern std::function debuggerHook; +extern std::function debuggerHook; void printStaticEnvBindings(const Expr &expr); void printStaticEnvBindings(const StaticEnv &se, int lvl = 0); @@ -414,14 +414,7 @@ private: class DebugTraceStacker { public: - DebugTraceStacker(EvalState &evalState, DebugTrace t) - :evalState(evalState), trace(t) - { - - // evalState.debuggerHook(const Error & error, const Env & env, const Expr & expr); - - evalState.debugTraces.push_front(t); - } + DebugTraceStacker(EvalState &evalState, DebugTrace t); ~DebugTraceStacker() { // assert(evalState.debugTraces.front() == trace); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index c4c459f0b..8012c616e 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -18,7 +18,7 @@ MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); MakeError(RestrictedPathError, Error); -extern std::function debuggerHook; +extern std::function debuggerHook; /* Position objects. */ -- cgit v1.2.3 From 990bec78d30c5e23cd6aa83a6f98b1d4199bd8c3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sat, 8 Jan 2022 15:43:04 -0700 Subject: clear screen and show top debug trace --- src/libcmd/command.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index ed8f6d295..5848a15bf 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -77,8 +77,30 @@ ref EvalCommand::getEvalState() searchPath, getEvalStore(), getStore()); if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { + std::cout << "\033[2J\033[1;1H"; + 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()); + else + { + auto iter = evalState->debugTraces.begin(); + if (iter != evalState->debugTraces.end()) { + std::cout << "\n" << "… " << iter->hint.str() << "\n"; + + if (iter->pos.has_value() && (*iter->pos)) { + auto pos = iter->pos.value(); + std::cout << "\n"; + printAtPos(pos, std::cout); + + auto loc = getCodeLines(pos); + if (loc.has_value()) { + std::cout << "\n"; + printCodeLines(std::cout, "", pos, *loc); + std::cout << "\n"; + } + } + } + } if (expr.staticenv) { -- cgit v1.2.3 From 412d58f0bb65104b0065dbf721a92b9e5dcdcdbb Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 3 Feb 2022 13:15:21 -0700 Subject: break() primop; step and go debug commands --- src/libcmd/repl.cc | 16 +++++++++++++++- src/libexpr/eval.cc | 3 ++- src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 22 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index e66cf4430..5c14c7d3e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -439,7 +439,11 @@ bool NixRepl::processLine(string line) << " :d Debug mode commands\n" << " :d stack Show call stack\n" << " :d env Show env stack\n" - << " :d error Show current error\n"; + << " :d error Show current error\n" + << " :d go Go until end of program, exception, or builtins.break().\n" + << " :d step Go one step\n" + ; + } else if (command == ":d" || command == ":debug") { @@ -476,6 +480,16 @@ bool NixRepl::processLine(string line) notice("error information not available"); } } + else if (arg == "step") { + // set flag and exit repl. + state->debugStop = true; + return false; + } + else if (arg == "go") { + // set flag and exit repl. + state->debugStop = false; + return false; + } } else if (command == ":a" || command == ":add") { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7b3745e52..426cff2d3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -417,6 +417,7 @@ EvalState::EvalState( , repair(NoRepair) , store(store) , buildStore(buildStore ? buildStore : store) + , debugStop(true) , regexCache(makeRegexCache()) , baseEnv(allocEnv(128)) , staticBaseEnv(new StaticEnv(false, 0)) @@ -930,7 +931,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState &evalState, DebugTrace t) :evalState(evalState), trace(t) { evalState.debugTraces.push_front(t); - if (debuggerHook) + if (evalState.debugStop && debuggerHook) debuggerHook(0, t.env, t.expr); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1a097ab8c..649fda778 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -115,6 +115,7 @@ public: RootValue vCallFlake = nullptr; RootValue vImportedDrvToDerivation = nullptr; + bool debugStop; std::list debugTraces; private: diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 66265f917..3a54e1490 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -710,6 +710,28 @@ static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { .fun = prim_genericClosure, }); +static RegisterPrimOp primop_break({ + .name = "break", + .args = {}, + .doc = R"( + In debug mode, pause Nix expression evaluation and enter the repl. + )", + .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) + { + // PathSet context; + // string s = state.coerceToString(pos, *args[0], context); + if (debuggerHook && !state.debugTraces.empty()) + { + auto &dt = state.debugTraces.front(); + // std::optional pos; + // const Expr &expr; + // const Env &env; + // hintformat hint; + debuggerHook(nullptr, dt.env, dt.expr); + } + } +}); + static RegisterPrimOp primop_abort({ .name = "abort", .args = {"s"}, -- cgit v1.2.3 From 3ddf864e1b2c5c27b2e6f7203e262c85bf760f7c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 4 Feb 2022 14:50:25 -0700 Subject: print value in break --- src/libcmd/command.cc | 3 ++- src/libexpr/primops.cc | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 5848a15bf..701976265 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -77,7 +77,8 @@ ref EvalCommand::getEvalState() searchPath, getEvalStore(), getStore()); if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { - std::cout << "\033[2J\033[1;1H"; + // clear the screen. + // std::cout << "\033[2J\033[1;1H"; 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()); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3a54e1490..48a10cd27 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -712,12 +712,13 @@ static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { static RegisterPrimOp primop_break({ .name = "break", - .args = {}, + .args = {"v"}, .doc = R"( In debug mode, pause Nix expression evaluation and enter the repl. )", .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) { + std::cout << "primop_break, value: " << *args[0] << std::endl; // PathSet context; // string s = state.coerceToString(pos, *args[0], context); if (debuggerHook && !state.debugTraces.empty()) @@ -728,6 +729,9 @@ static RegisterPrimOp primop_break({ // const Env &env; // hintformat hint; debuggerHook(nullptr, dt.env, dt.expr); + + // returning the value we were passed. + v = *args[0]; } } }); -- cgit v1.2.3 From 195db83148d17484809ca8af0932b1be1803a29a Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 4 Feb 2022 17:35:56 -0700 Subject: a few merge fixes --- src/libexpr/eval.cc | 24 ++++++++++++------------ src/libexpr/eval.hh | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 790b00ace..6c89b87b7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -860,18 +860,18 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env, Expr *expr)) -{ - auto error = TypeError({ - .msg = hintfmt(s, s2), - .errPos = pos - }); +// LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env, Expr *expr)) +// { +// auto error = TypeError({ +// .msg = hintfmt(s, s2), +// .errPos = pos +// }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); +// if (debuggerHook && expr) +// debuggerHook(&error, env, *expr); - throw error; -} +// throw error; +// } LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr *expr)) { @@ -1243,7 +1243,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e) Value v; e->eval(*this, env, v); if (v.type() != nBool) - throwTypeError("value is %1% while a Boolean was expected", v); + throwTypeError(noPos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -1262,7 +1262,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); if (v.type() != nAttrs) - throwTypeError("value is %1% while a set was expected", v); + throwTypeError(noPos, "value is %1% while a set was expected", v); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 8c4430bc8..a7d1207f2 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -195,7 +195,7 @@ public: Expr * parseExprFromFile(const Path & path, std::shared_ptr & staticEnv); /* Parse a Nix expression from the specified string. */ - Expr * parseExprFromString(std::string s, const Path & basePath, , std::shared_ptr & staticEnv); + Expr * parseExprFromString(std::string s, const Path & basePath, std::shared_ptr & staticEnv); Expr * parseExprFromString(std::string s, const Path & basePath); Expr * parseStdin(); @@ -331,7 +331,7 @@ private: friend struct ExprLet; Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path, - const Path & basePath, std::shared_ptr & staticEnv); + const PathView basePath, std::shared_ptr & staticEnv); public: -- cgit v1.2.3 From 7954a18a48a1301a6d7f781e36ea20ee2a62d480 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 4 Feb 2022 17:40:06 -0700 Subject: link change --- src/libcmd/local.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index 713c1bf11..a12837ce5 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -9,8 +9,8 @@ libcmd_SOURCES := $(wildcard $(d)/*.cc) libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix # libcmd_LDFLAGS += -llowdown -pthread -# libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -pthread -libcmd_LDFLAGS += $(LOWDOWN_LIBS) -pthread +libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -pthread +# libcmd_LDFLAGS += $(LOWDOWN_LIBS) -pthread libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix -- cgit v1.2.3 From bc67cb5ad12b7d042067ba9727b0b8b37c5f3e53 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 10 Feb 2022 15:05:38 -0700 Subject: remove fakeEnv stuff and instead use last context from the stack --- src/libexpr/eval.cc | 112 ++++++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6c89b87b7..e584efbfb 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -775,31 +775,39 @@ valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) evaluator. So here are some helper functions for throwing exceptions. */ -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, EvalState &evalState)) { auto error = EvalError(s, s2); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } + throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, EvalState &evalState)) { auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } throw error; } -LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr *expr)) { - auto error = EvalError(s, s2, s3); + auto error = EvalError({ + .msg = hintfmt(s, s2), + .errPos = pos + }); if (debuggerHook && expr) debuggerHook(&error, env, *expr); @@ -807,15 +815,32 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3, EvalState &evalState)) { auto error = EvalError({ .msg = hintfmt(s, s2, s3), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } + + throw error; +} + +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, EvalState &evalState)) +{ + auto error = EvalError({ + .msg = hintfmt(s, s2, s3), + .errPos = noPos + }); + + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } throw error; } @@ -834,45 +859,37 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, EvalState &evalState)) { auto error = TypeError({ .msg = hintfmt(s), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr *expr)) + +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, EvalState &evalState)) { auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } throw error; } -// LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const string &s2, Env & env, Expr *expr)) -// { -// auto error = TypeError({ -// .msg = hintfmt(s, s2), -// .errPos = pos -// }); - -// if (debuggerHook && expr) -// debuggerHook(&error, env, *expr); - -// throw error; -// } - LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr *expr)) { auto error = TypeError({ @@ -886,13 +903,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -// LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, Env & env, Expr *expr)) -// { -// auto error = TypeError({ -// .msg = hintfmt(s, showType(v)) -// .errPos = e ; -// } - LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) { auto error = AssertionError({ @@ -2053,8 +2063,8 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nInt) - throwTypeError(pos, "value is %1% while an integer was expected", v, - fakeEnv(1), 0); + throwTypeError(pos, "value is %1% while an integer was expected", v, *this); + return v.integer; } @@ -2066,7 +2076,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) return v.integer; else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v, - fakeEnv(1), 0); + *this); return v.fpoint; } @@ -2076,7 +2086,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v, - fakeEnv(1), 0); + *this); return v.boolean; } @@ -2092,7 +2102,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v, - fakeEnv(1), 0); + *this); } @@ -2101,7 +2111,7 @@ std::string_view EvalState::forceString(Value & v, const Pos & pos) forceValue(v, pos); if (v.type() != nString) { throwTypeError(pos, "value is %1% while a string was expected", v, - fakeEnv(1), 0); + *this); } return v.string.s; } @@ -2152,10 +2162,10 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], fakeEnv(1), 0); + v.string.s, v.string.context[0], *this); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], fakeEnv(1), 0); + v.string.s, v.string.context[0], *this); } return s; } @@ -2210,8 +2220,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & return std::move(*maybeString); auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", - fakeEnv(1), 0); + throwTypeError(pos, "cannot coerce a set to a string", *this); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2240,8 +2249,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & } } - throwTypeError(pos, "cannot coerce %1% to a string", v, - fakeEnv(1), 0); + throwTypeError(pos, "cannot coerce %1% to a string", v, *this); } @@ -2250,7 +2258,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path) if (nix::isDerivation(path)) throwEvalError("file names are not allowed to end in '%1%'", drvExtension, - fakeEnv(1), 0); + *this); Path dstPath; auto i = srcToStore.find(path); @@ -2276,7 +2284,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) string path = coerceToString(pos, v, context, false, false).toOwned(); if (path == "" || path[0] != '/') throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, - fakeEnv(1), 0); + *this); return path; } @@ -2358,7 +2366,7 @@ bool EvalState::eqValues(Value & v1, Value & v2) throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2), - fakeEnv(1), 0); + *this); } } -- cgit v1.2.3 From 3ff5ac3586f0e15e231489e5e36ae783e51e9bab Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 10 Feb 2022 16:01:49 -0700 Subject: update the eval-inline throw fns --- src/libexpr/eval-inline.hh | 28 +++++++++++++++++++++------- src/libexpr/eval.cc | 41 ++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index aef1f6351..7ed05950a 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -7,20 +7,34 @@ namespace nix { -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, EvalState &evalState)) { - throw EvalError({ + auto error = EvalError({ .msg = hintfmt(s), .errPos = pos }); + + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } + + throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, EvalState &evalState)) { - throw TypeError({ + auto error = TypeError({ .msg = hintfmt(s, showType(v)), .errPos = pos }); + + if (debuggerHook && !evalState.debugTraces.empty()) { + DebugTrace &last = evalState.debugTraces.front(); + debuggerHook(&error, last.env, last.expr); + } + + throw error; } @@ -48,7 +62,7 @@ void EvalState::forceValue(Value & v, Callable getPos) else if (v.isApp()) callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.isBlackhole()) - throwEvalError(getPos(), "infinite recursion encountered"); + throwEvalError(getPos(), "infinite recursion encountered", *this); } @@ -63,7 +77,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos) { forceValue(v, getPos); if (v.type() != nAttrs) - throwTypeError(getPos(), "value is %1% while a set was expected", v); + throwTypeError(getPos(), "value is %1% while a set was expected", v, *this); } @@ -71,7 +85,7 @@ inline void EvalState::forceList(Value & v, const Pos & pos) { forceValue(v, pos); if (!v.isList()) - throwTypeError(pos, "value is %1% while a list was expected", v); + throwTypeError(pos, "value is %1% while a list was expected", v, *this); } /* Note: Various places expect the allocated memory to be zeroed. */ diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e584efbfb..79bdaff47 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -787,6 +787,19 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Eva throw error; } +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, Env & env, Expr *expr)) +{ + auto error = EvalError({ + .msg = hintfmt(s), + .errPos = pos + }); + + if (debuggerHook && expr) + debuggerHook(&error, env, *expr); + + throw error; +} + LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, EvalState &evalState)) { auto error = EvalError({ @@ -875,17 +888,15 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, EvalS } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, EvalState &evalState)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr *expr)) { auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos }); - if (debuggerHook && !evalState.debugTraces.empty()) { - DebugTrace &last = evalState.debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + if (debuggerHook && expr) + debuggerHook(&error, env, *expr); throw error; } @@ -1253,7 +1264,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e) Value v; e->eval(*this, env, v); if (v.type() != nBool) - throwTypeError(noPos, "value is %1% while a Boolean was expected", v); + throwTypeError(noPos, "value is %1% while a Boolean was expected", v, env, e); return v.boolean; } @@ -1263,7 +1274,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) Value v; e->eval(*this, env, v); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v); + throwTypeError(pos, "value is %1% while a Boolean was expected", v, env, e); return v.boolean; } @@ -1272,7 +1283,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); if (v.type() != nAttrs) - throwTypeError(noPos, "value is %1% while a set was expected", v); + throwTypeError(noPos, "value is %1% while a set was expected", v, env, e); } @@ -1377,8 +1388,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Symbol nameSym = state.symbols.create(nameVal.string.s); Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) - throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, - env, this); + throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, env, this); i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ @@ -1697,7 +1707,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } else - throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur); + throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur, *this); } vRes = vCur; @@ -2005,7 +2015,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) v.mkFloat(nf); else if (firstType == nPath) { if (!context.empty()) - throwEvalError(pos, "a string that refers to a store path cannot be appended to a path"); + throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, this); v.mkPath(canonPath(str())); } else v.mkStringMove(c_str(), context); @@ -2256,9 +2266,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) - throwEvalError("file names are not allowed to end in '%1%'", - drvExtension, - *this); + throwEvalError("file names are not allowed to end in '%1%'", drvExtension, *this); Path dstPath; auto i = srcToStore.find(path); @@ -2283,8 +2291,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) { string path = coerceToString(pos, v, context, false, false).toOwned(); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, - *this); + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, *this); return path; } -- cgit v1.2.3 From 4cffb130e385bc3f4c5ca0482ad8c4dd22229cfe Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 11 Feb 2022 14:14:25 -0700 Subject: for primops, enter the debugger at the last DebugTrace in the stack --- src/libexpr/eval.cc | 13 +++- src/libexpr/eval.hh | 2 + src/libexpr/nixexpr.cc | 2 +- src/libexpr/primops.cc | 167 +++++++++++++++++++++++++------------------------ 4 files changed, 99 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 79bdaff47..71a28bafa 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -437,7 +437,7 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) - , debugStop(true) + , debugStop(false) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) @@ -787,6 +787,17 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, Eva throw error; } +void EvalState::debug_throw(Error e) { + // 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()) { + DebugTrace &last = debugTraces.front(); + debuggerHook(&e, last.env, last.expr); + } + throw e; +} + LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, Env & env, Expr *expr)) { auto error = EvalError({ diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index a7d1207f2..1390c8885 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -118,6 +118,8 @@ public: bool debugStop; std::list debugTraces; + void debug_throw(Error e); + private: SrcToStore srcToStore; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 41ee92d27..e09bd9484 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -305,7 +305,7 @@ void ExprVar::bindVars(const std::shared_ptr &env) if (withLevel == -1) { throw UndefinedVarError({ - .msg = hintfmt("undefined variable (ExprVar bindvars) '%1%'", name), + .msg = hintfmt("undefined variable '%1%'", name), .errPos = pos }); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3b429f328..956c55e49 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -46,7 +46,7 @@ StringMap EvalState::realiseContext(const PathSet & context) auto [ctxS, outputName] = decodeContext(i); auto ctx = store->parseStorePath(ctxS); if (!store->isValidPath(ctx)) - throw InvalidPathError(store->printStorePath(ctx)); + debug_throw(InvalidPathError(store->printStorePath(ctx))); if (!outputName.empty() && ctx.isDerivation()) { drvs.push_back({ctx, {outputName}}); } else { @@ -57,9 +57,9 @@ StringMap EvalState::realiseContext(const PathSet & context) if (drvs.empty()) return {}; if (!evalSettings.enableImportFromDerivation) - throw Error( + debug_throw(Error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", - store->printStorePath(drvs.begin()->drvPath)); + store->printStorePath(drvs.begin()->drvPath))); /* Build/substitute the context. */ std::vector buildReqs; @@ -71,8 +71,8 @@ StringMap EvalState::realiseContext(const PathSet & context) auto outputPaths = store->queryDerivationOutputMap(drvPath); for (auto & outputName : outputs) { if (outputPaths.count(outputName) == 0) - throw Error("derivation '%s' does not have an output named '%s'", - store->printStorePath(drvPath), outputName); + debug_throw(Error("derivation '%s' does not have an output named '%s'", + store->printStorePath(drvPath), outputName)); res.insert_or_assign( downstreamPlaceholder(*store, drvPath, outputName), store->printStorePath(outputPaths.at(outputName)) @@ -318,17 +318,17 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); if (!handle) - throw EvalError("could not open '%1%': %2%", path, dlerror()); + state.debug_throw(EvalError("could not open '%1%': %2%", path, dlerror())); dlerror(); ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str()); if(!func) { char *message = dlerror(); if (message) - throw EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message); + state.debug_throw(EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message)); else - throw EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", - sym, path); + state.debug_throw(EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", + sym, path)); } (func)(state, v); @@ -344,10 +344,10 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) auto elems = args[0]->listElems(); auto count = args[0]->listSize(); if (count == 0) { - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("at least one argument to 'exec' required"), .errPos = pos - }); + })); } PathSet context; auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); @@ -358,11 +358,11 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) try { auto _ = state.realiseContext(context); // FIXME: Handle CA derivations } catch (InvalidPathError & e) { - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", program, e.path), .errPos = pos - }); + })); } auto output = runProgram(program, true, commandArgs); @@ -545,7 +545,7 @@ struct CompareValues if (v1->type() == nInt && v2->type() == nFloat) return v1->integer < v2->fpoint; if (v1->type() != v2->type()) - throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); + state.debug_throw(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); switch (v1->type()) { case nInt: return v1->integer < v2->integer; @@ -567,7 +567,8 @@ struct CompareValues } } default: - throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); + state.debug_throw(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); + return false; } } }; @@ -597,10 +598,10 @@ static Bindings::iterator getAttr( Pos aPos = *attrSet->pos; if (aPos == noPos) { - throw TypeError({ + state.debug_throw(TypeError({ .msg = errorMsg, .errPos = pos, - }); + })); } else { auto e = TypeError({ .msg = errorMsg, @@ -610,7 +611,7 @@ static Bindings::iterator getAttr( // Adding another trace for the function name to make it clear // which call received wrong arguments. e.addTrace(pos, hintfmt("while invoking '%s'", funcName)); - throw e; + state.debug_throw(e); } } @@ -664,10 +665,10 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar Bindings::iterator key = e->attrs->find(state.sKey); if (key == e->attrs->end()) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("attribute 'key' required"), .errPos = pos - }); + })); state.forceValue(*key->value, pos); if (!doneKeys.insert(key->value).second) continue; @@ -734,7 +735,7 @@ static RegisterPrimOp primop_abort({ { PathSet context; string s = state.coerceToString(pos, *args[0], context).toOwned(); - throw Abort("evaluation aborted with the following error message: '%1%'", s); + state.debug_throw(Abort("evaluation aborted with the following error message: '%1%'", s)); } }); @@ -752,7 +753,7 @@ static RegisterPrimOp primop_throw({ { PathSet context; string s = state.coerceToString(pos, *args[0], context).toOwned(); - throw ThrownError(s); + state.debug_throw(ThrownError(s)); } }); @@ -1006,37 +1007,37 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive; else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; else - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), .errPos = posDrvName - }); + })); }; auto handleOutputs = [&](const Strings & ss) { outputs.clear(); for (auto & j : ss) { if (outputs.find(j) != outputs.end()) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("duplicate derivation output '%1%'", j), .errPos = posDrvName - }); + })); /* !!! Check whether j is a valid attribute name. */ /* Derivations cannot be named ‘drv’, because then we'd have an attribute ‘drvPath’ in the resulting set. */ if (j == "drv") - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("invalid derivation output name 'drv'" ), .errPos = posDrvName - }); + })); outputs.insert(j); } if (outputs.empty()) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("derivation cannot have an empty set of outputs"), .errPos = posDrvName - }); + })); }; try { @@ -1155,23 +1156,23 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Do we have all required attributes? */ if (drv.builder == "") - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("required attribute 'builder' missing"), .errPos = posDrvName - }); + })); if (drv.platform == "") - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("required attribute 'system' missing"), .errPos = posDrvName - }); + })); /* Check whether the derivation name is valid. */ if (isDerivation(drvName)) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), .errPos = posDrvName - }); + })); if (outputHash) { /* Handle fixed-output derivations. @@ -1179,10 +1180,10 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * Ignore `__contentAddressed` because fixed output derivations are already content addressed. */ if (outputs.size() != 1 || *(outputs.begin()) != "out") - throw Error({ + state.debug_throw(Error({ .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), .errPos = posDrvName - }); + })); std::optional ht = parseHashTypeOpt(outputHashAlgo); Hash h = newHashAllowEmpty(*outputHash, ht); @@ -1350,10 +1351,10 @@ static RegisterPrimOp primop_toPath({ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, Value & v) { if (evalSettings.pureEval) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), .errPos = pos - }); + })); PathSet context; Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); @@ -1362,10 +1363,10 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V e.g. nix-push does the right thing. */ if (!state.store->isStorePath(path)) path = canonPath(path, true); if (!state.store->isInStore(path)) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = pos - }); + })); auto path2 = state.store->toStorePath(path).first; if (!settings.readOnlyMode) state.store->ensurePath(path2); @@ -1468,7 +1469,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va auto path = realisePath(state, pos, *args[0]); string s = readFile(path); if (s.find((char) 0) != string::npos) - throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path); + state.debug_throw(Error("the contents of the file '%1%' cannot be represented as a Nix string", path)); StorePathSet refs; if (state.store->isInStore(path)) { try { @@ -1520,10 +1521,10 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va auto rewrites = state.realiseContext(context); path = rewriteStrings(path, rewrites); } catch (InvalidPathError & e) { - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), .errPos = pos - }); + })); } @@ -1547,10 +1548,10 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - throw Error({ + state.debug_throw(Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = pos - }); + })); auto path = realisePath(state, pos, *args[1]); @@ -1787,13 +1788,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu for (auto path : context) { if (path.at(0) != '/') - throw EvalError( { + state.debug_throw(EvalError( { .msg = hintfmt( "in 'toFile': the file named '%1%' must not contain a reference " "to a derivation but contains (%2%)", name, path), .errPos = pos - }); + })); refs.insert(state.store->parseStorePath(path)); } @@ -1951,7 +1952,7 @@ static void addPath( ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs)); if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath)) - throw Error("store path mismatch in (possibly filtered) path added from '%s'", path); + state.debug_throw(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); } else dstPath = state.store->printStorePath(*expectedStorePath); @@ -1973,12 +1974,12 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) - throw TypeError({ + state.debug_throw(TypeError({ .msg = hintfmt( "first argument in call to 'filterSource' is not a function but %1%", showType(*args[0])), .errPos = pos - }); + })); addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); } @@ -2062,16 +2063,16 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value else if (n == "sha256") expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); else - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name), .errPos = *attr.pos - }); + })); } if (path.empty()) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("'path' required"), .errPos = pos - }); + })); if (name.empty()) name = baseNameOf(path); @@ -2442,10 +2443,10 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args return; } if (!args[0]->isLambda()) - throw TypeError({ + state.debug_throw(TypeError({ .msg = hintfmt("'functionArgs' requires a function"), .errPos = pos - }); + })); if (!args[0]->lambda.fun->hasFormals()) { v.mkAttrs(&state.emptyBindings); @@ -2620,10 +2621,10 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu { state.forceList(list, pos); if (n < 0 || (unsigned int) n >= list.listSize()) - throw Error({ - .msg = hintfmt("list index %1% is out of bounds", n), + state.debug_throw(Error({ + .msg = hintfmt("list index %1% is out of boundz", n), .errPos = pos - }); + })); state.forceValue(*list.listElems()[n], pos); v = *list.listElems()[n]; } @@ -2668,10 +2669,10 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value { state.forceList(*args[0], pos); if (args[0]->listSize() == 0) - throw Error({ + state.debug_throw(Error({ .msg = hintfmt("'tail' called on an empty list"), .errPos = pos - }); + })); state.mkList(v, args[0]->listSize() - 1); for (unsigned int n = 0; n < v.listSize(); ++n) @@ -2906,10 +2907,10 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val auto len = state.forceInt(*args[1], pos); if (len < 0) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("cannot create list of size %1%", len), .errPos = pos - }); + })); state.mkList(v, len); @@ -3213,10 +3214,10 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & NixFloat f2 = state.forceFloat(*args[1], pos); if (f2 == 0) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("division by zero"), .errPos = pos - }); + })); if (args[0]->type() == nFloat || args[1]->type() == nFloat) { v.mkFloat(state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); @@ -3225,10 +3226,10 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & NixInt i2 = state.forceInt(*args[1], pos); /* Avoid division overflow as it might raise SIGFPE. */ if (i1 == std::numeric_limits::min() && i2 == -1) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("overflow in integer division"), .errPos = pos - }); + })); v.mkInt(i1 / i2); } @@ -3356,10 +3357,10 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V auto s = state.coerceToString(pos, *args[2], context); if (start < 0) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("negative start position in 'substring'"), .errPos = pos - }); + })); v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context); } @@ -3407,10 +3408,10 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - throw Error({ + state.debug_throw(Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = pos - }); + })); PathSet context; // discarded auto s = state.forceString(*args[1], context, pos); @@ -3480,15 +3481,15 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = pos - }); + })); } else { - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = pos - }); + })); } } } @@ -3585,15 +3586,15 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = pos - }); + })); } else { - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = pos - }); + })); } } } @@ -3670,10 +3671,10 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar state.forceList(*args[0], pos); state.forceList(*args[1], pos); if (args[0]->listSize() != args[1]->listSize()) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), .errPos = pos - }); + })); vector from; from.reserve(args[0]->listSize()); -- cgit v1.2.3 From e761bf0601a56db26c31891a3433c1319814fffa Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 14 Feb 2022 14:04:34 -0700 Subject: make an 'info' level error on break --- src/libcmd/repl.cc | 16 +--------------- src/libexpr/primops.cc | 15 +++++++-------- 2 files changed, 8 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 51bbbbc57..db88aa9b6 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -931,24 +931,10 @@ void runRepl( { auto repl = std::make_unique(evalState); - // repl->debugError = debugError; + repl->debugError = debugError; repl->initEnv(); - // auto dts = debugError ? - // std::unique_ptr( - // // tack on a final DebugTrace for the error position. - // new DebugTraceStacker( - // *evalState, - // DebugTrace - // {.pos = debugError->info().errPos, - // .expr = expr, - // .env = *repl->env, - // .hint = debugError->info().msg - // }) - // ) - // : nullptr; - // add 'extra' vars. std::set names; for (auto & [name, value] : extraEnv) { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 956c55e49..25845bdc4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -699,6 +699,7 @@ static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { .fun = prim_genericClosure, }); + static RegisterPrimOp primop_break({ .name = "break", .args = {"v"}, @@ -707,17 +708,15 @@ static RegisterPrimOp primop_break({ )", .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) { - std::cout << "primop_break, value: " << *args[0] << std::endl; - // PathSet context; - // string s = state.coerceToString(pos, *args[0], context); + auto error = Error(ErrorInfo{ + .level = lvlInfo, + .msg = hintfmt("breakpoint reached; value was %1%", *args[0]), + .errPos = pos, + }); if (debuggerHook && !state.debugTraces.empty()) { auto &dt = state.debugTraces.front(); - // std::optional pos; - // const Expr &expr; - // const Env &env; - // hintformat hint; - debuggerHook(nullptr, dt.env, dt.expr); + debuggerHook(&error, dt.env, dt.expr); // returning the value we were passed. v = *args[0]; -- cgit v1.2.3 From c9bc3735f639a4d022ab071feb5dabd451a0d016 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 15 Feb 2022 09:49:25 -0700 Subject: quit repl from step mode --- src/libcmd/repl.cc | 22 +++++++++++++++------- src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 9 +++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index db88aa9b6..2b3dfcbd2 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -89,6 +89,7 @@ string removeWhitespace(string s) s = chomp(s); size_t n = s.find_first_not_of(" \n\r\t"); if (n != string::npos) s = string(s, n); + return s; } @@ -231,8 +232,12 @@ void NixRepl::mainLoop(const std::vector & files) // 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. + state->debugStop = false; + state->debugQuit = true; break; - + } try { if (!removeWhitespace(input).empty() && !processLine(input)) return; } catch (ParseError & e) { @@ -464,12 +469,12 @@ bool NixRepl::processLine(string line) std::cout << "\n"; } } - } + } } else if (arg == "env") { auto iter = this->state->debugTraces.begin(); if (iter != this->state->debugTraces.end()) { printStaticEnvBindings(iter->expr); - } + } } else if (arg == "error") { if (this->debugError) { @@ -481,12 +486,12 @@ bool NixRepl::processLine(string line) } } else if (arg == "step") { - // set flag and exit repl. + // set flag to stop at next DebugTrace; exit repl. state->debugStop = true; return false; } else if (arg == "go") { - // set flag and exit repl. + // set flag to run to next breakpoint or end of program; exit repl. state->debugStop = false; return false; } @@ -605,8 +610,11 @@ bool NixRepl::processLine(string line) printValue(std::cout, v, 1000000000) << std::endl; } - else if (command == ":q" || command == ":quit") + else if (command == ":q" || command == ":quit") { + state->debugStop = false; + state->debugQuit = true; return false; + } else if (command == ":doc") { Value v; @@ -944,7 +952,7 @@ void runRepl( } printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); - + repl->mainLoop({}); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 71a28bafa..3a835adb3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -438,6 +438,7 @@ EvalState::EvalState( , store(store) , buildStore(buildStore ? buildStore : store) , debugStop(false) + , debugQuit(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 1390c8885..e1d117c36 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -116,6 +116,7 @@ public: RootValue vImportedDrvToDerivation = nullptr; bool debugStop; + bool debugQuit; std::list debugTraces; void debug_throw(Error e); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 25845bdc4..80d78e150 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -718,6 +718,15 @@ static RegisterPrimOp primop_break({ auto &dt = state.debugTraces.front(); debuggerHook(&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 from debugger"), + .errPos = pos, + }); + } + // returning the value we were passed. v = *args[0]; } -- cgit v1.2.3 From 3d94d3ba91d8cde069ca635aae4c070c85a99759 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 15 Feb 2022 15:46:45 -0700 Subject: Expr refs instead of pointers --- src/libexpr/eval.cc | 76 ++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3a835adb3..f21919598 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -799,15 +799,15 @@ void EvalState::debug_throw(Error e) { throw e; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, Env & env, Expr &expr)) { auto error = EvalError({ .msg = hintfmt(s), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } @@ -827,15 +827,15 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, Env & env, Expr &expr)) { auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } @@ -870,7 +870,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con throw error; } -LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2, Env & env, Expr &expr)) { // p1 is where the error occurred; p2 is a position mentioned in the message. auto error = EvalError({ @@ -878,8 +878,8 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const .errPos = p1 }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } @@ -900,68 +900,67 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, EvalS } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v, Env & env, Expr &expr)) { auto error = TypeError({ .msg = hintfmt(s, v), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } -LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr &expr)) { auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(), s2), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } -LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1, Env & env, Expr &expr)) { auto error = AssertionError({ .msg = hintfmt(s, s1), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } -LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr &expr)) { auto error = UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = pos }); - if (debuggerHook && expr) { - debuggerHook(&error, env, *expr); - } + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } -LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env, Expr *expr)) +LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1, Env & env, Expr &expr)) { auto error = MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = pos }); - if (debuggerHook && expr) - debuggerHook(&error, env, *expr); + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } @@ -1055,7 +1054,8 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) { - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, (Expr*)&var); + // TODO deal with const_cast + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, *const_cast(&var)); } for (size_t l = env->prevWith; l; --l, env = env->up) ; } @@ -1276,7 +1276,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e) Value v; e->eval(*this, env, v); if (v.type() != nBool) - throwTypeError(noPos, "value is %1% while a Boolean was expected", v, env, e); + throwTypeError(noPos, "value is %1% while a Boolean was expected", v, env, *e); return v.boolean; } @@ -1286,7 +1286,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) Value v; e->eval(*this, env, v); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, env, e); + throwTypeError(pos, "value is %1% while a Boolean was expected", v, env, *e); return v.boolean; } @@ -1295,7 +1295,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); if (v.type() != nAttrs) - throwTypeError(noPos, "value is %1% while a set was expected", v, env, e); + throwTypeError(noPos, "value is %1% while a set was expected", v, env, *e); } @@ -1400,7 +1400,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Symbol nameSym = state.symbols.create(nameVal.string.s); Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) - throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, env, this); + throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos, env, *this); i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ @@ -1498,7 +1498,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } else { state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError(pos, "attribute '%1%' missing", name, env, this); + throwEvalError(pos, "attribute '%1%' missing", name, env, *this); } vAttrs = j->value; pos2 = j->pos; @@ -1599,7 +1599,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & auto j = args[0]->attrs->get(i.name); if (!j) { if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'", - lambda, i.name, *fun.lambda.env, &lambda); + lambda, i.name, *fun.lambda.env, lambda); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1615,7 +1615,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & for (auto & i : *args[0]->attrs) if (!lambda.formals->has(i.name)) throwTypeError(pos, "%1% called with unexpected argument '%2%'", - lambda, i.name, *fun.lambda.env, &lambda); + lambda, i.name, *fun.lambda.env, lambda); abort(); // can't happen } } @@ -1790,7 +1790,7 @@ this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See https://nixos.org/manual/nix/stable/#ss-functions.)", i.name, - *fun.lambda.env, fun.lambda.fun); + *fun.lambda.env, *fun.lambda.fun); } } } @@ -1822,7 +1822,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) if (!state.evalBool(env, cond, pos)) { std::ostringstream out; cond->show(out); - throwAssertionError(pos, "assertion '%1%' failed", out.str(), env, this); + throwAssertionError(pos, "assertion '%1%' failed", out.str(), env, *this); } body->eval(state, env, v); } @@ -1999,7 +1999,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) nf = n; nf += vTmp.fpoint; } else { - throwEvalError(i_pos, "cannot add %1% to an integer", showType(vTmp), env, this); + throwEvalError(i_pos, "cannot add %1% to an integer", showType(vTmp), env, *this); } } else if (firstType == nFloat) { if (vTmp.type() == nInt) { @@ -2007,7 +2007,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else - throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp), env, this); + throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp), env, *this); } else { if (s.empty()) s.reserve(es->size()); /* skip canonization of first path, which would only be not @@ -2027,7 +2027,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) v.mkFloat(nf); else if (firstType == nPath) { if (!context.empty()) - throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, this); + throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, *this); v.mkPath(canonPath(str())); } else v.mkStringMove(c_str(), context); -- cgit v1.2.3 From 417aaf4ff7ac1ca501c5a460775fa25d8e078c8a Mon Sep 17 00:00:00 2001 From: regnat Date: Wed, 22 Dec 2021 11:31:14 +0100 Subject: Correctly hijack the `file://` uri scheme with `_NIX_FORCE_HTTP` Setting the `_NIX_FORCE_HTTP` environment variable is supposed to force `file://` store urls to use the `HttpBinaryCacheStore` implementation rather than the `LocalBinaryCacheStore` one (very useful for testing). However because of a name mismatch, the `LocalBinaryCacheStore` was still registering the `file` scheme when this variable was set, meaning that the actual store implementation picked up on `file://` uris was dependent on the registration order of the stores (itself dependent on the link order of the object files). Fix this by making the `LocalBinaryCacheStore` gracefully not register the `file` uri scheme when the variable is set. --- src/libstore/local-binary-cache-store.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc index f754770f9..a3c3e4806 100644 --- a/src/libstore/local-binary-cache-store.cc +++ b/src/libstore/local-binary-cache-store.cc @@ -107,7 +107,7 @@ bool LocalBinaryCacheStore::fileExists(const std::string & path) std::set LocalBinaryCacheStore::uriSchemes() { - if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1") + if (getEnv("_NIX_FORCE_HTTP") == "1") return {}; else return {"file"}; -- cgit v1.2.3 From eaecaaa00ba79b05f49a908f2c96c6507d3a2d7b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 14 Mar 2022 11:39:53 -0600 Subject: more debug_throw coverage of EvalErrors --- src/libexpr/eval-cache.cc | 19 +++++++++++-------- src/libexpr/parser.y | 5 +++-- src/libexpr/primops.cc | 4 ++-- src/libexpr/primops/fetchTree.cc | 32 ++++++++++++++++---------------- src/libexpr/value-to-json.cc | 5 +++-- 5 files changed, 35 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index d6b9ea29b..b102684ec 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -506,14 +506,14 @@ std::string AttrCursor::getString() debug("using cached string attribute '%s'", getAttrPathStr()); return s->first; } else - throw TypeError("'%s' is not a string", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not a string", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nString && v.type() != nPath) - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); + root->state.debug_throw(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); return v.type() == nString ? v.string.s : v.path; } @@ -537,7 +537,7 @@ string_t AttrCursor::getStringWithContext() return *s; } } else - throw TypeError("'%s' is not a string", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not a string", getAttrPathStr())); } } @@ -548,7 +548,10 @@ string_t AttrCursor::getStringWithContext() else if (v.type() == nPath) return {v.path, {}}; else - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); + { + root->state.debug_throw(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); + return {v.path, {}}; // should never execute + } } bool AttrCursor::getBool() @@ -561,14 +564,14 @@ bool AttrCursor::getBool() debug("using cached Boolean attribute '%s'", getAttrPathStr()); return *b; } else - throw TypeError("'%s' is not a Boolean", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not a Boolean", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nBool) - throw TypeError("'%s' is not a Boolean", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not a Boolean", getAttrPathStr())); return v.boolean; } @@ -583,14 +586,14 @@ std::vector AttrCursor::getAttrs() debug("using cached attrset attribute '%s'", getAttrPathStr()); return *attrs; } else - throw TypeError("'%s' is not an attribute set", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not an attribute set", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nAttrs) - throw TypeError("'%s' is not an attribute set", getAttrPathStr()); + root->state.debug_throw(TypeError("'%s' is not an attribute set", getAttrPathStr())); std::vector attrs; for (auto & attr : *getValue().attrs) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d9291e7a2..184fba03e 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -783,13 +783,14 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c if (hasPrefix(path, "nix/")) return concatStrings(corepkgsPrefix, path.substr(4)); - throw ThrownError({ + debug_throw(ThrownError({ .msg = hintfmt(evalSettings.pureEval ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)" : "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)", path), .errPos = pos - }); + })); + return Path(); // should never execute due to debug_throw above. } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 80d78e150..4908482cf 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2542,7 +2542,7 @@ static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args attrsSeen[attr.name].first++; } catch (TypeError & e) { e.addTrace(pos, hintfmt("while invoking '%s'", "zipAttrsWith")); - throw; + state.debug_throw(e); } } @@ -3127,7 +3127,7 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos))); } catch (TypeError &e) { e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap")); - throw; + state.debug_throw(e); } len += lists[n].listSize(); } diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index d09e2d9e1..c9fcbb8f5 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -108,16 +108,16 @@ static void fetchTree( if (auto aType = args[0]->attrs->get(state.sType)) { if (type) - throw Error({ + state.debug_throw(EvalError({ .msg = hintfmt("unexpected attribute 'type'"), .errPos = pos - }); + })); type = state.forceStringNoCtx(*aType->value, *aType->pos); } else if (!type) - throw Error({ + state.debug_throw(EvalError({ .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), .errPos = pos - }); + })); attrs.emplace("type", type.value()); @@ -138,16 +138,16 @@ static void fetchTree( else if (attr.value->type() == nInt) attrs.emplace(attr.name, uint64_t(attr.value->integer)); else - throw TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", - attr.name, showType(*attr.value)); + state.debug_throw(TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", + attr.name, showType(*attr.value))); } if (!params.allowNameArgument) if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) - throw Error({ + state.debug_throw(EvalError({ .msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), .errPos = pos - }); + })); input = fetchers::Input::fromAttrs(std::move(attrs)); } else { @@ -167,7 +167,7 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (evalSettings.pureEval && !input.isImmutable()) - throw Error("in pure evaluation mode, 'fetchTree' requires an immutable input, at %s", pos); + state.debug_throw(EvalError("in pure evaluation mode, 'fetchTree' requires an immutable input, at %s", pos)); auto [tree, input2] = input.fetch(state.store); @@ -206,17 +206,17 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, else if (n == "name") name = state.forceStringNoCtx(*attr.value, *attr.pos); else - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), .errPos = *attr.pos - }); + })); } if (!url) - throw EvalError({ + state.debug_throw(EvalError({ .msg = hintfmt("'url' argument required"), .errPos = pos - }); + })); } else url = state.forceStringNoCtx(*args[0], pos); @@ -228,7 +228,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, name = baseNameOf(*url); if (evalSettings.pureEval && !expectedHash) - throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who); + state.debug_throw(EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who)); auto storePath = unpack @@ -240,8 +240,8 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, ? state.store->queryPathInfo(storePath)->narHash : hashFile(htSHA256, state.store->toRealPath(storePath)); if (hash != *expectedHash) - throw Error((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", - *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)); + state.debug_throw(EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", + *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true))); } state.allowPath(storePath); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 517da4c01..d8bf73cd5 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -84,7 +84,8 @@ void printValueAsJSON(EvalState & state, bool strict, .msg = hintfmt("cannot convert %1% to JSON", showType(v)), .errPos = v.determinePos(pos) }); - throw e.addTrace(pos, hintfmt("message for the trace")); + e.addTrace(pos, hintfmt("message for the trace")); + state.debug_throw(e); } } @@ -98,7 +99,7 @@ void printValueAsJSON(EvalState & state, bool strict, void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const { - throw TypeError("cannot convert %1% to JSON", showType()); + state.debug_throw(TypeError("cannot convert %1% to JSON", showType())); } -- cgit v1.2.3 From 3dfab6e534e0a1cf71c000a4d2a74e050ba576ce Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 14 Mar 2022 11:58:11 -0600 Subject: have only one debuggerHook declaration --- src/libcmd/command.cc | 4 ---- src/libexpr/eval.cc | 2 -- src/libexpr/eval.hh | 1 - src/libexpr/nixexpr.cc | 3 +++ 4 files changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 56288665a..18aa82577 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -93,10 +93,6 @@ EvalCommand::EvalCommand() }); } -extern std::function debuggerHook; - - - EvalCommand::~EvalCommand() { if (evalState) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f21919598..6758677ca 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -37,8 +37,6 @@ namespace nix { -std::function debuggerHook; - static char * allocString(size_t size) { char * t; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e1d117c36..5f4556053 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,7 +25,6 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); -extern std::function debuggerHook; void printStaticEnvBindings(const Expr &expr); void printStaticEnvBindings(const StaticEnv &se, int lvl = 0); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index e09bd9484..add65c1a2 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -6,6 +6,9 @@ namespace nix { +/* Launch the nix debugger */ + +std::function debuggerHook; /* Displaying abstract syntax trees. */ -- cgit v1.2.3 From 88a54108ebcdbeb1432d9afe5363557c25f94cfa Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 16 Mar 2022 12:09:47 -0600 Subject: formatting --- src/libcmd/command.cc | 2 +- src/libexpr/eval.hh | 2 +- src/libexpr/primops.cc | 28 ++++++++++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 18aa82577..209c455fc 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -128,7 +128,7 @@ ref EvalCommand::getEvalState() else { auto iter = evalState->debugTraces.begin(); - if (iter != evalState->debugTraces.end()) { + if (iter != evalState->debugTraces.end()) { std::cout << "\n" << "… " << iter->hint.str() << "\n"; if (iter->pos.has_value() && (*iter->pos)) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 5f4556053..64c3dfac0 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -114,10 +114,10 @@ public: RootValue vCallFlake = nullptr; RootValue vImportedDrvToDerivation = nullptr; + /* Debugger */ bool debugStop; bool debugQuit; std::list debugTraces; - void debug_throw(Error e); private: diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 4908482cf..9a26bae71 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -715,20 +715,20 @@ static RegisterPrimOp primop_break({ }); if (debuggerHook && !state.debugTraces.empty()) { - auto &dt = state.debugTraces.front(); - debuggerHook(&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 from debugger"), - .errPos = pos, - }); - } - - // returning the value we were passed. - v = *args[0]; + auto &dt = state.debugTraces.front(); + debuggerHook(&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 from debugger"), + .errPos = noPos, + }); + } + + // returning the value we were passed. + v = *args[0]; } } }); -- cgit v1.2.3 From 1bec3fb337b86f87e7600fc6b6072ded1a7d4927 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 25 Mar 2022 18:15:31 -0600 Subject: add DebugTrace for error --- src/libcmd/command.cc | 58 ++++++++++++++++++++++++++++++++------------------ src/libexpr/eval.cc | 3 ++- src/libexpr/eval.hh | 1 + src/libexpr/nixexpr.hh | 40 +++++++++++++++++----------------- 4 files changed, 60 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 209c455fc..34535802f 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -122,29 +122,45 @@ ref EvalCommand::getEvalState() debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { // clear the screen. // std::cout << "\033[2J\033[1;1H"; - + + auto dts = + error && expr.getPos() ? + std::unique_ptr( + new DebugTraceStacker( + *evalState, + DebugTrace + {.pos = *expr.getPos(), + .expr = expr, + .env = env, + .hint = error->info().msg, + .is_error = 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()); - else - { - auto iter = evalState->debugTraces.begin(); - if (iter != evalState->debugTraces.end()) { - std::cout << "\n" << "… " << iter->hint.str() << "\n"; - - if (iter->pos.has_value() && (*iter->pos)) { - auto pos = iter->pos.value(); - std::cout << "\n"; - printAtPos(pos, std::cout); - - auto loc = getCodeLines(pos); - if (loc.has_value()) { - std::cout << "\n"; - printCodeLines(std::cout, "", pos, *loc); - std::cout << "\n"; - } - } - } - } + + // else + // { + // auto iter = evalState->debugTraces.begin(); + // if (iter != evalState->debugTraces.end()) { + // std::cout << "\n" << "… " << iter->hint.str() << "\n"; + + // if (iter->pos.has_value() && (*iter->pos)) { + // auto pos = iter->pos.value(); + // std::cout << "\n"; + // printAtPos(pos, std::cout); + + // auto loc = getCodeLines(pos); + // if (loc.has_value()) { + // std::cout << "\n"; + // printCodeLines(std::cout, "", pos, *loc); + // std::cout << "\n"; + // } + // } + // } + // } if (expr.staticenv) { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6758677ca..f162f3e0b 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -983,7 +983,8 @@ LocalNoInline(std::unique_ptr {.pos = pos, .expr = expr, .env = env, - .hint = hintfmt(s, s2) + .hint = hintfmt(s, s2), + .is_error = false })); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 64c3dfac0..9de3475e8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -77,6 +77,7 @@ struct DebugTrace { const Expr &expr; const Env &env; hintformat hint; + bool is_error; }; class EvalState diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 64375b5ab..6419f882a 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -84,7 +84,7 @@ struct Expr virtual void setName(Symbol & name); std::shared_ptr staticenv; - virtual Pos* getPos() = 0; + virtual const Pos* getPos() const = 0; }; std::ostream & operator << (std::ostream & str, const Expr & e); @@ -100,7 +100,7 @@ struct ExprInt : Expr Value v; ExprInt(NixInt n) : n(n) { v.mkInt(n); }; Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -110,7 +110,7 @@ struct ExprFloat : Expr Value v; ExprFloat(NixFloat nf) : nf(nf) { v.mkFloat(nf); }; Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -120,7 +120,7 @@ struct ExprString : Expr Value v; ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); }; Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -130,7 +130,7 @@ struct ExprPath : Expr Value v; ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); }; Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -158,7 +158,7 @@ struct ExprVar : Expr ExprVar(const Symbol & name) : name(name) { }; ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; Value * maybeThunk(EvalState & state, Env & env); - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -169,7 +169,7 @@ struct ExprSelect : Expr AttrPath attrPath; ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -178,7 +178,7 @@ struct ExprOpHasAttr : Expr Expr * e; AttrPath attrPath; ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { }; - Pos* getPos() { return e->getPos(); } + const Pos* getPos() const { return e->getPos(); } COMMON_METHODS }; @@ -207,7 +207,7 @@ struct ExprAttrs : Expr DynamicAttrDefs dynamicAttrs; ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { }; ExprAttrs() : recursive(false), pos(noPos) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -215,7 +215,7 @@ struct ExprList : Expr { std::vector elems; ExprList() { }; - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -264,7 +264,7 @@ struct ExprLambda : Expr void setName(Symbol & name); string showNamePos() const; inline bool hasFormals() const { return formals != nullptr; } - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -276,7 +276,7 @@ struct ExprCall : Expr ExprCall(const Pos & pos, Expr * fun, std::vector && args) : fun(fun), args(args), pos(pos) { } - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -285,7 +285,7 @@ struct ExprLet : Expr ExprAttrs * attrs; Expr * body; ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { }; - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -295,7 +295,7 @@ struct ExprWith : Expr Expr * attrs, * body; size_t prevWith; ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -304,7 +304,7 @@ struct ExprIf : Expr Pos pos; Expr * cond, * then, * else_; ExprIf(const Pos & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -313,7 +313,7 @@ struct ExprAssert : Expr Pos pos; Expr * cond, * body; ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -321,7 +321,7 @@ struct ExprOpNot : Expr { Expr * e; ExprOpNot(Expr * e) : e(e) { }; - Pos* getPos() { return 0; } + const Pos* getPos() const { return 0; } COMMON_METHODS }; @@ -341,7 +341,7 @@ struct ExprOpNot : Expr e1->bindVars(env); e2->bindVars(env); \ } \ void eval(EvalState & state, Env & env, Value & v); \ - Pos* getPos() { return &pos; } \ + const Pos* getPos() const { return &pos; } \ }; MakeBinOp(ExprOpEq, "==") @@ -359,7 +359,7 @@ struct ExprConcatStrings : Expr vector > * es; ExprConcatStrings(const Pos & pos, bool forceString, vector > * es) : pos(pos), forceString(forceString), es(es) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; @@ -367,7 +367,7 @@ struct ExprPos : Expr { Pos pos; ExprPos(const Pos & pos) : pos(pos) { }; - Pos* getPos() { return &pos; } + const Pos* getPos() const { return &pos; } COMMON_METHODS }; -- cgit v1.2.3 From 14f515544bf7ea3c894fbc21d1393e69aa115784 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 28 Mar 2022 12:09:21 -0600 Subject: debugTraceIndex --- src/libcmd/repl.cc | 99 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 2b3dfcbd2..f0a8ef676 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -49,7 +49,8 @@ struct NixRepl ref state; Bindings * autoArgs; - const Error *debugError; + const Error *debugError; + int debugTraceIndex; Strings loadedFiles; @@ -96,6 +97,7 @@ string removeWhitespace(string s) NixRepl::NixRepl(ref state) : state(state) + , debugTraceIndex(0) , staticEnv(new StaticEnv(false, state->staticBaseEnv.get())) , historyFile(getDataDir() + "/nix/repl-history") { @@ -403,6 +405,28 @@ StorePath NixRepl::getDerivationPath(Value & v) { return drvPath; } +std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) +{ + if (dt.is_error) + out << ANSI_RED "error: " << ANSI_NORMAL; + out << dt.hint.str() << "\n"; + + if (dt.pos.has_value() && (*dt.pos)) { + auto pos = dt.pos.value(); + out << "\n"; + printAtPos(pos, out); + + auto loc = getCodeLines(pos); + if (loc.has_value()) { + out << "\n"; + printCodeLines(out, "", pos, *loc); + out << "\n"; + } + } + + return out; +} + bool NixRepl::processLine(string line) { if (line == "") return true; @@ -444,7 +468,7 @@ bool NixRepl::processLine(string line) << " :d Debug mode commands\n" << " :d stack Show call stack\n" << " :d env Show env stack\n" - << " :d error Show current error\n" + << " :d show Show current trace, or change to call stack index\n" << " :d go Go until end of program, exception, or builtins.break().\n" << " :d step Go one step\n" ; @@ -453,30 +477,63 @@ bool NixRepl::processLine(string line) else if (command == ":d" || command == ":debug") { if (arg == "stack") { + int idx = 0; for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); ++iter) { - std::cout << "\n" << "… " << iter->hint.str() << "\n"; - - if (iter->pos.has_value() && (*iter->pos)) { - auto pos = iter->pos.value(); - std::cout << "\n"; - printAtPos(pos, std::cout); - - auto loc = getCodeLines(pos); - if (loc.has_value()) { - std::cout << "\n"; - printCodeLines(std::cout, "", pos, *loc); - std::cout << "\n"; - } - } - } + iter != this->state->debugTraces.end(); + ++iter, ++idx) { + std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + showDebugTrace(std::cout, *iter); + } } else if (arg == "env") { - auto iter = this->state->debugTraces.begin(); - if (iter != this->state->debugTraces.end()) { - printStaticEnvBindings(iter->expr); + int idx = 0; + for (auto iter = this->state->debugTraces.begin(); + iter != this->state->debugTraces.end(); + ++iter, ++idx) { + if (idx == this->debugTraceIndex) + { + // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + printStaticEnvBindings(iter->expr); + break; + } + // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + // showDebugTrace(std::cout, *iter); + } + + // auto iter = this->state->debugTraces.begin(); + // if (iter != this->state->debugTraces.end()) { + // printStaticEnvBindings(iter->expr); + // } + } + else if (arg.compare(0,4,"show") == 0) { + try { + // change the DebugTrace index. + debugTraceIndex = stoi(arg.substr(4)); + + // std::cout << "idx: " << idx << std::endl; + // debugTraceIndex = idx; + + } + catch (...) + { + debugTraceIndex = 0; + } + + int idx = 0; + for (auto iter = this->state->debugTraces.begin(); + iter != this->state->debugTraces.end(); + ++iter, ++idx) { + if (idx == this->debugTraceIndex) + { + std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + showDebugTrace(std::cout, *iter); + break; + } + // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + // showDebugTrace(std::cout, *iter); } } else if (arg == "error") { + // TODO: remove, along with debugError. if (this->debugError) { showErrorInfo(std::cout, debugError->info(), true); } -- cgit v1.2.3 From 5ab7bdf0b14199da8423a8f2e433b2d6beef1e69 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 28 Mar 2022 15:28:59 -0600 Subject: load debug trace staticenv on 'show' --- src/libcmd/repl.cc | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index f0a8ef676..2e3a3b6df 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -78,6 +78,7 @@ struct NixRepl void addVarToScope(const Symbol & name, Value & v); Expr * parseString(string s); void evalString(string s, Value & v); + void loadDebugTraceEnv(DebugTrace &dt); typedef set ValuesSeen; std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); @@ -427,6 +428,25 @@ std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) return out; } +void NixRepl::loadDebugTraceEnv(DebugTrace &dt) +{ + if (dt.expr.staticenv) + { + initEnv(); + + auto vm = std::make_unique(*(mapStaticEnvBindings(*dt.expr.staticenv.get(), dt.env))); + + // add staticenv vars. + for (auto & [name, value] : *(vm.get())) { + this->addVarToScope(this->state->symbols.create(name), *value); + } + } + else + { + initEnv(); + } +} + bool NixRepl::processLine(string line) { if (line == "") return true; @@ -491,31 +511,18 @@ bool NixRepl::processLine(string line) ++iter, ++idx) { if (idx == this->debugTraceIndex) { - // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; printStaticEnvBindings(iter->expr); break; } - // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - // showDebugTrace(std::cout, *iter); } - - // auto iter = this->state->debugTraces.begin(); - // if (iter != this->state->debugTraces.end()) { - // printStaticEnvBindings(iter->expr); - // } } else if (arg.compare(0,4,"show") == 0) { try { // change the DebugTrace index. debugTraceIndex = stoi(arg.substr(4)); - - // std::cout << "idx: " << idx << std::endl; - // debugTraceIndex = idx; - } catch (...) { - debugTraceIndex = 0; } int idx = 0; @@ -526,6 +533,8 @@ bool NixRepl::processLine(string line) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, *iter); + printStaticEnvBindings(iter->expr); + loadDebugTraceEnv(*iter); break; } // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; -- cgit v1.2.3 From c0a567e1963faaf9b16f772d6b4e76496a88ed32 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Tue, 29 Mar 2022 16:44:47 -0600 Subject: remove const_cast --- src/libexpr/eval.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f162f3e0b..cc0380d4a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -937,7 +937,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, throw error; } -LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, Expr &expr)) +LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1, Env & env, const Expr &expr)) { auto error = UndefinedVarError({ .msg = hintfmt(s, s1), @@ -1053,8 +1053,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) { - // TODO deal with const_cast - throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, *const_cast(&var)); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name, *env, var); } for (size_t l = env->prevWith; l; --l, env = env->up) ; } -- cgit v1.2.3 From 1096d17b65834a7e1ff29d1afdf09536cc9d7a8d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 31 Mar 2022 09:37:36 -0600 Subject: show 'with' bindings as well as static --- src/libcmd/repl.cc | 10 ++++---- src/libexpr/eval.cc | 70 +++++++++++++++++++++++++++++++++++++++++------------ src/libexpr/eval.hh | 4 +-- 3 files changed, 62 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 2e3a3b6df..5de4cdf76 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -511,7 +511,7 @@ bool NixRepl::processLine(string line) ++iter, ++idx) { if (idx == this->debugTraceIndex) { - printStaticEnvBindings(iter->expr); + printEnvBindings(iter->expr, iter->env); break; } } @@ -533,7 +533,7 @@ bool NixRepl::processLine(string line) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, *iter); - printStaticEnvBindings(iter->expr); + printEnvBindings(iter->expr, iter->env); loadDebugTraceEnv(*iter); break; } @@ -1010,14 +1010,14 @@ void runRepl( repl->initEnv(); // add 'extra' vars. - std::set names; + // std::set names; for (auto & [name, value] : extraEnv) { // names.insert(ANSI_BOLD + name + ANSI_NORMAL); - names.insert(name); + // names.insert(name); repl->addVarToScope(repl->state->symbols.create(name), *value); } - printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); + // printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); repl->mainLoop({}); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index cc0380d4a..7c67f2ea8 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -699,22 +699,46 @@ std::optional EvalState::getDoc(Value & v) return {}; } -void printStaticEnvBindings(const StaticEnv &se, int lvl) + +// just for the current level of StaticEnv, not the whole chain. +void printStaticEnvBindings(const StaticEnv &se) { - std::cout << "Env level " << lvl << std::endl; + std::cout << ANSI_MAGENTA; + for (auto i = se.vars.begin(); i != se.vars.end(); ++i) + { + std::cout << i->first << " "; + } + std::cout << ANSI_NORMAL; + std::cout << std::endl; +} - if (se.up) { +// just for the current level of Env, not the whole chain. +void printWithBindings(const Env &env) +{ + if (env.type == Env::HasWithAttrs) + { + std::cout << "with: "; std::cout << ANSI_MAGENTA; - for (auto i = se.vars.begin(); i != se.vars.end(); ++i) - { - std::cout << i->first << " "; + Bindings::iterator j = env.values[0]->attrs->begin(); + while (j != env.values[0]->attrs->end()) { + std::cout << j->name << " "; + ++j; } std::cout << ANSI_NORMAL; - - std::cout << std::endl; std::cout << std::endl; + } +} + +void printEnvBindings(const StaticEnv &se, const Env &env, int lvl) +{ + std::cout << "Env level " << lvl << std::endl; - printStaticEnvBindings(*se.up, ++lvl); + if (se.up && env.up) { + std::cout << "static: "; + printStaticEnvBindings(se); + printWithBindings(env); + std::cout << std::endl; + printEnvBindings(*se.up, *env.up, ++lvl); } else { @@ -727,18 +751,19 @@ void printStaticEnvBindings(const StaticEnv &se, int lvl) } std::cout << ANSI_NORMAL; std::cout << std::endl; + printWithBindings(env); // probably nothing there for the top level. std::cout << std::endl; } - } -void printStaticEnvBindings(const Expr &expr) +// TODO: add accompanying env for With stuff. +void printEnvBindings(const Expr &expr, const Env &env) { // just print the names for now if (expr.staticenv) { - printStaticEnvBindings(*expr.staticenv.get(), 0); + printEnvBindings(*expr.staticenv.get(), env, 0); } } @@ -750,11 +775,26 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) if (env.up && se.up) { mapStaticEnvBindings(*se.up, *env.up,vm); - // iterate through staticenv bindings and add them. auto map = valmap(); - for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + if (env.type == Env::HasWithAttrs) + { + std::cout << "(env.type == Env::HasWithAttrs)" << std::endl; + Bindings::iterator j = env.values[0]->attrs->begin(); + while (j != env.values[0]->attrs->end()) { + // std::cout << "adding : " << j->name << std::endl; + map[j->name] = j->value; + // if (countCalls) attrSelects[*j->pos]++; + // return j->value; + ++j; + } + } + else { - map[iter->first] = env.values[iter->second]; + // iterate through staticenv bindings and add them. + for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) + { + map[iter->first] = env.values[iter->second]; + } } vm.merge(map); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9de3475e8..1c569fc36 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,8 +25,8 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); -void printStaticEnvBindings(const Expr &expr); -void printStaticEnvBindings(const StaticEnv &se, int lvl = 0); +void printEnvBindings(const Expr &expr, const Env &env); +void printEnvBindings(const StaticEnv &se, const Env &env, int lvl = 0); struct PrimOp { -- cgit v1.2.3 From f41c18b2210ac36743f03ea218860b7941f4264e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 31 Mar 2022 09:39:18 -0600 Subject: comments --- src/libexpr/eval.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7c67f2ea8..399cf126d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -781,10 +781,7 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) std::cout << "(env.type == Env::HasWithAttrs)" << std::endl; Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - // std::cout << "adding : " << j->name << std::endl; map[j->name] = j->value; - // if (countCalls) attrSelects[*j->pos]++; - // return j->value; ++j; } } -- cgit v1.2.3 From 5cfd038bd8bcd65c45f08f6c3665cd49e6643714 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 6 Apr 2022 19:08:29 -0600 Subject: show expr pos if DebugTrace one is noPos --- src/libcmd/command.cc | 2 +- src/libcmd/repl.cc | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 34535802f..cc353cbb4 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -129,7 +129,7 @@ ref EvalCommand::getEvalState() new DebugTraceStacker( *evalState, DebugTrace - {.pos = *expr.getPos(), + {.pos = (error->info().errPos ? *error->info().errPos : *expr.getPos()), .expr = expr, .env = env, .hint = error->info().msg, diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 5de4cdf76..416635f16 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -412,9 +412,11 @@ std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) out << ANSI_RED "error: " << ANSI_NORMAL; out << dt.hint.str() << "\n"; - if (dt.pos.has_value() && (*dt.pos)) { - auto pos = dt.pos.value(); - out << "\n"; + // prefer direct pos, but if noPos then try the expr. + auto pos = (*dt.pos ? *dt.pos : + (dt.expr.getPos() ? *dt.expr.getPos() : noPos)); + + if (pos) { printAtPos(pos, out); auto loc = getCodeLines(pos); -- cgit v1.2.3 From f37562187f2673535a8e636e7ea5b37662b5a65a Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 7 Apr 2022 11:17:31 -0600 Subject: free valmap on exit --- src/libcmd/command.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index cc353cbb4..e3c8fb29f 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -164,7 +164,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { - auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env); + std::unique_ptr vm(mapStaticEnvBindings(*expr.staticenv.get(), env)); runRepl(evalState, error, expr, *vm); } }; -- cgit v1.2.3 From d29af88d58283293d919066acd792fafd5e60689 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 7 Apr 2022 11:17:57 -0600 Subject: newline before env --- src/libcmd/repl.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 416635f16..376aa35cd 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -535,6 +535,7 @@ bool NixRepl::processLine(string line) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, *iter); + std::cout << std::endl; printEnvBindings(iter->expr, iter->env); loadDebugTraceEnv(*iter); break; -- cgit v1.2.3 From 50b52d51109c430fb2ac69ed5337a6a985e4a486 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 7 Apr 2022 12:03:18 -0600 Subject: remove debug code --- src/libexpr/eval.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 399cf126d..4211d72dd 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -778,7 +778,6 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) auto map = valmap(); if (env.type == Env::HasWithAttrs) { - std::cout << "(env.type == Env::HasWithAttrs)" << std::endl; Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { map[j->name] = j->value; -- cgit v1.2.3 From d2ec9b4e15718e42720787140d7825dcbfd73249 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 7 Apr 2022 12:09:47 -0600 Subject: in debugger mode, print the current error when another repl returns. --- src/libcmd/repl.cc | 56 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 376aa35cd..31d0019d4 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -203,6 +203,30 @@ namespace { } } +std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) +{ + if (dt.is_error) + out << ANSI_RED "error: " << ANSI_NORMAL; + out << dt.hint.str() << "\n"; + + // prefer direct pos, but if noPos then try the expr. + auto pos = (*dt.pos ? *dt.pos : + (dt.expr.getPos() ? *dt.expr.getPos() : noPos)); + + if (pos) { + printAtPos(pos, out); + + auto loc = getCodeLines(pos); + if (loc.has_value()) { + out << "\n"; + printCodeLines(out, "", pos, *loc); + out << "\n"; + } + } + + return out; +} + void NixRepl::mainLoop(const std::vector & files) { string error = ANSI_RED "error:" ANSI_NORMAL " "; @@ -251,6 +275,14 @@ void NixRepl::mainLoop(const std::vector & files) } else { printMsg(lvlError, e.msg()); } + } catch (EvalError & e) { + // 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 && !this->state->debugTraces.empty()) + showDebugTrace(std::cout, this->state->debugTraces.front()); + else + printMsg(lvlError, e.msg()); } catch (Error & e) { printMsg(lvlError, e.msg()); } catch (Interrupted & e) { @@ -406,30 +438,6 @@ StorePath NixRepl::getDerivationPath(Value & v) { return drvPath; } -std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) -{ - if (dt.is_error) - out << ANSI_RED "error: " << ANSI_NORMAL; - out << dt.hint.str() << "\n"; - - // prefer direct pos, but if noPos then try the expr. - auto pos = (*dt.pos ? *dt.pos : - (dt.expr.getPos() ? *dt.expr.getPos() : noPos)); - - if (pos) { - printAtPos(pos, out); - - auto loc = getCodeLines(pos); - if (loc.has_value()) { - out << "\n"; - printCodeLines(out, "", pos, *loc); - out << "\n"; - } - } - - return out; -} - void NixRepl::loadDebugTraceEnv(DebugTrace &dt) { if (dt.expr.staticenv) -- cgit v1.2.3 From b8b8ec710160cfd343a8fce33ec8734e23c98444 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 12:34:27 -0600 Subject: move throw to preverve Error type; turn off debugger for tryEval --- src/libcmd/repl.cc | 2 +- src/libexpr/eval-cache.cc | 46 +++++- src/libexpr/eval.cc | 26 +-- src/libexpr/eval.hh | 2 +- src/libexpr/parser.y | 7 +- src/libexpr/primops.cc | 337 +++++++++++++++++++++++++++++---------- src/libexpr/primops/fetchTree.cc | 74 ++++++--- src/libexpr/value-to-json.cc | 7 +- 8 files changed, 361 insertions(+), 140 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 3dd55e104..2e7974b5d 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -50,7 +50,7 @@ struct NixRepl ref state; Bindings * autoArgs; - const Error *debugError; + const Error *debugError; int debugTraceIndex; Strings loadedFiles; diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 9f6152561..0608d8378 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -528,14 +528,22 @@ std::string AttrCursor::getString() debug("using cached string attribute '%s'", getAttrPathStr()); return s->first; } else - root->state.debug_throw(TypeError("'%s' is not a string", getAttrPathStr())); + { + auto e = TypeError("'%s' is not a string", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } } } auto & v = forceValue(); if (v.type() != nString && v.type() != nPath) - root->state.debug_throw(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); + { + auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); + root->state.debugLastTrace(e); + throw e; + } return v.type() == nString ? v.string.s : v.path; } @@ -559,7 +567,11 @@ string_t AttrCursor::getStringWithContext() return *s; } } else - root->state.debug_throw(TypeError("'%s' is not a string", getAttrPathStr())); + { + auto e = TypeError("'%s' is not a string", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } } } @@ -571,7 +583,9 @@ string_t AttrCursor::getStringWithContext() return {v.path, {}}; else { - root->state.debug_throw(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); + auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); + root->state.debugLastTrace(e); + throw e; return {v.path, {}}; // should never execute } } @@ -586,14 +600,22 @@ bool AttrCursor::getBool() debug("using cached Boolean attribute '%s'", getAttrPathStr()); return *b; } else - root->state.debug_throw(TypeError("'%s' is not a Boolean", getAttrPathStr())); + { + auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } } } auto & v = forceValue(); if (v.type() != nBool) - root->state.debug_throw(TypeError("'%s' is not a Boolean", getAttrPathStr())); + { + auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } return v.boolean; } @@ -608,14 +630,22 @@ std::vector AttrCursor::getAttrs() debug("using cached attrset attribute '%s'", getAttrPathStr()); return *attrs; } else - root->state.debug_throw(TypeError("'%s' is not an attribute set", getAttrPathStr())); + { + auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } } } auto & v = forceValue(); if (v.type() != nAttrs) - root->state.debug_throw(TypeError("'%s' is not an attribute set", getAttrPathStr())); + { + auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); + root->state.debugLastTrace(e); + throw e; + } std::vector attrs; for (auto & attr : *getValue().attrs) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5ad7e546c..7d02222cf 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -833,15 +833,13 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2 throw error; } -void EvalState::debug_throw(Error e) { +void EvalState::debugLastTrace(Error & e) { // 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()) { DebugTrace &last = debugTraces.front(); debuggerHook(&e, last.env, last.expr); } - throw e; } LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr &expr)) @@ -865,10 +863,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook && !evalState.debugTraces.empty()) { - DebugTrace &last = evalState.debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + evalState.debugLastTrace(error); throw error; } @@ -906,10 +901,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const .errPos = pos }); - if (debuggerHook && !evalState.debugTraces.empty()) { - DebugTrace &last = evalState.debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + evalState.debugLastTrace(error); throw error; } @@ -921,10 +913,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2 .errPos = noPos }); - if (debuggerHook && !evalState.debugTraces.empty()) { - DebugTrace &last = evalState.debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + evalState.debugLastTrace(error); throw error; } @@ -950,10 +939,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, EvalS .errPos = pos }); - if (debuggerHook && !evalState.debugTraces.empty()) { - DebugTrace &last = evalState.debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + evalState.debugLastTrace(error); throw error; } @@ -972,8 +958,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const throw error; } -// LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v)); - LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2, Env & env, Expr &expr)) { auto error = TypeError({ diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 2ced5bea9..11f5707a4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -119,7 +119,7 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; - void debug_throw(Error e); + void debugLastTrace(Error & e); private: SrcToStore srcToStore; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 4182f36d5..ecfa5b7c2 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -783,14 +783,15 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c if (hasPrefix(path, "nix/")) return concatStrings(corepkgsPrefix, path.substr(4)); - debug_throw(ThrownError({ + auto e = ThrownError({ .msg = hintfmt(evalSettings.pureEval ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)" : "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)", path), .errPos = pos - })); - return Path(); // should never execute due to debug_throw above. + }); + debugLastTrace(e); + throw e; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index c40c54247..b1d2f5f40 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -46,7 +46,11 @@ StringMap EvalState::realiseContext(const PathSet & context) auto [ctx, outputName] = decodeContext(*store, i); auto ctxS = store->printStorePath(ctx); if (!store->isValidPath(ctx)) - debug_throw(InvalidPathError(store->printStorePath(ctx))); + { + auto e = InvalidPathError(store->printStorePath(ctx)); + debugLastTrace(e); + throw e; + } if (!outputName.empty() && ctx.isDerivation()) { drvs.push_back({ctx, {outputName}}); } else { @@ -57,9 +61,13 @@ StringMap EvalState::realiseContext(const PathSet & context) if (drvs.empty()) return {}; if (!evalSettings.enableImportFromDerivation) - debug_throw(Error( + { + auto e = Error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", - store->printStorePath(drvs.begin()->drvPath))); + store->printStorePath(drvs.begin()->drvPath)); + debugLastTrace(e); + throw e; + } /* Build/substitute the context. */ std::vector buildReqs; @@ -71,8 +79,12 @@ StringMap EvalState::realiseContext(const PathSet & context) auto outputPaths = store->queryDerivationOutputMap(drvPath); for (auto & outputName : outputs) { if (outputPaths.count(outputName) == 0) - debug_throw(Error("derivation '%s' does not have an output named '%s'", - store->printStorePath(drvPath), outputName)); + { + auto e = Error("derivation '%s' does not have an output named '%s'", + store->printStorePath(drvPath), outputName); + debugLastTrace(e); + throw e; + } res.insert_or_assign( downstreamPlaceholder(*store, drvPath, outputName), store->printStorePath(outputPaths.at(outputName)) @@ -318,17 +330,29 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); if (!handle) - state.debug_throw(EvalError("could not open '%1%': %2%", path, dlerror())); + { + auto e = EvalError("could not open '%1%': %2%", path, dlerror()); + state.debugLastTrace(e); + throw e; + } dlerror(); ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str()); if(!func) { char *message = dlerror(); if (message) - state.debug_throw(EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message)); + { + auto e = EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message); + state.debugLastTrace(e); + throw e; + } else - state.debug_throw(EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", - sym, path)); + { + auto e = EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", + sym, path); + state.debugLastTrace(e); + throw e; + } } (func)(state, v); @@ -344,10 +368,12 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) auto elems = args[0]->listElems(); auto count = args[0]->listSize(); if (count == 0) { - state.debug_throw(EvalError({ + auto e = EvalError({ .msg = hintfmt("at least one argument to 'exec' required"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; } PathSet context; auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); @@ -358,11 +384,13 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) try { auto _ = state.realiseContext(context); // FIXME: Handle CA derivations } catch (InvalidPathError & e) { - state.debug_throw(EvalError({ + auto ee = EvalError({ .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", program, e.path), .errPos = pos - })); + }); + state.debugLastTrace(ee); + throw ee; } auto output = runProgram(program, true, commandArgs); @@ -545,7 +573,11 @@ struct CompareValues if (v1->type() == nInt && v2->type() == nFloat) return v1->integer < v2->fpoint; if (v1->type() != v2->type()) - state.debug_throw(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); + { + auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); + state.debugLastTrace(e); + throw e; + } switch (v1->type()) { case nInt: return v1->integer < v2->integer; @@ -567,8 +599,11 @@ struct CompareValues } } default: - state.debug_throw(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); - return false; + { + auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); + state.debugLastTrace(e); + throw e; + } } } }; @@ -598,10 +633,12 @@ static Bindings::iterator getAttr( Pos aPos = *attrSet->pos; if (aPos == noPos) { - state.debug_throw(TypeError({ + auto e = TypeError({ .msg = errorMsg, .errPos = pos, - })); + }); + state.debugLastTrace(e); + throw e; } else { auto e = TypeError({ .msg = errorMsg, @@ -611,7 +648,8 @@ static Bindings::iterator getAttr( // Adding another trace for the function name to make it clear // which call received wrong arguments. e.addTrace(pos, hintfmt("while invoking '%s'", funcName)); - state.debug_throw(e); + state.debugLastTrace(e); + throw e; } } @@ -665,10 +703,14 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar Bindings::iterator key = e->attrs->find(state.sKey); if (key == e->attrs->end()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("attribute 'key' required"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } state.forceValue(*key->value, pos); if (!doneKeys.insert(key->value).second) continue; @@ -768,7 +810,11 @@ static RegisterPrimOp primop_abort({ { PathSet context; auto s = state.coerceToString(pos, *args[0], context).toOwned(); - state.debug_throw(Abort("evaluation aborted with the following error message: '%1%'", s)); + { + auto e = Abort("evaluation aborted with the following error message: '%1%'", s); + state.debugLastTrace(e); + throw e; + } } }); @@ -786,7 +832,9 @@ static RegisterPrimOp primop_throw({ { PathSet context; auto s = state.coerceToString(pos, *args[0], context).toOwned(); - state.debug_throw(ThrownError(s)); + auto e = ThrownError(s); + state.debugLastTrace(e); + throw e; } }); @@ -851,6 +899,8 @@ static RegisterPrimOp primop_floor({ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + auto saveDebuggerHook = debuggerHook; + debuggerHook = 0; try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -859,6 +909,7 @@ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Val attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } + debuggerHook = saveDebuggerHook; v.mkAttrs(attrs); } @@ -1041,37 +1092,53 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive; else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; else - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } }; auto handleOutputs = [&](const Strings & ss) { outputs.clear(); for (auto & j : ss) { if (outputs.find(j) != outputs.end()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("duplicate derivation output '%1%'", j), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } /* !!! Check whether j is a valid attribute name. */ /* Derivations cannot be named ‘drv’, because then we'd have an attribute ‘drvPath’ in the resulting set. */ if (j == "drv") - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("invalid derivation output name 'drv'" ), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } outputs.insert(j); } if (outputs.empty()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("derivation cannot have an empty set of outputs"), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } }; try { @@ -1196,23 +1263,35 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Do we have all required attributes? */ if (drv.builder == "") - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("required attribute 'builder' missing"), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } if (drv.platform == "") - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("required attribute 'system' missing"), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } /* Check whether the derivation name is valid. */ if (isDerivation(drvName)) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } if (outputHash) { /* Handle fixed-output derivations. @@ -1220,10 +1299,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * Ignore `__contentAddressed` because fixed output derivations are already content addressed. */ if (outputs.size() != 1 || *(outputs.begin()) != "out") - state.debug_throw(Error({ + { + auto e = Error({ .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), .errPos = posDrvName - })); + }); + state.debugLastTrace(e); + throw e; + } auto h = newHashAllowEmpty(*outputHash, parseHashTypeOpt(outputHashAlgo)); @@ -1386,10 +1469,14 @@ static RegisterPrimOp primop_toPath({ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, Value & v) { if (evalSettings.pureEval) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } PathSet context; Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); @@ -1398,10 +1485,14 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V e.g. nix-push does the right thing. */ if (!state.store->isStorePath(path)) path = canonPath(path, true); if (!state.store->isInStore(path)) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } auto path2 = state.store->toStorePath(path).first; if (!settings.readOnlyMode) state.store->ensurePath(path2); @@ -1504,7 +1595,11 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va auto path = realisePath(state, pos, *args[0]); auto s = readFile(path); if (s.find((char) 0) != std::string::npos) - state.debug_throw(Error("the contents of the file '%1%' cannot be represented as a Nix string", path)); + { + auto e = Error("the contents of the file '%1%' cannot be represented as a Nix string", path); + state.debugLastTrace(e); + throw e; + } StorePathSet refs; if (state.store->isInStore(path)) { try { @@ -1556,10 +1651,12 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va auto rewrites = state.realiseContext(context); path = rewriteStrings(path, rewrites); } catch (InvalidPathError & e) { - state.debug_throw(EvalError({ + auto ee = EvalError({ .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), .errPos = pos - })); + }); + state.debugLastTrace(ee); + throw ee; } @@ -1583,10 +1680,14 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - state.debug_throw(Error({ + { + auto e = Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } auto path = realisePath(state, pos, *args[1]); @@ -1823,13 +1924,17 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu for (auto path : context) { if (path.at(0) != '/') - state.debug_throw(EvalError( { + { + auto e = EvalError( { .msg = hintfmt( "in 'toFile': the file named '%1%' must not contain a reference " "to a derivation but contains (%2%)", name, path), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } refs.insert(state.store->parseStorePath(path)); } @@ -1986,7 +2091,11 @@ static void addPath( ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs); if (expectedHash && expectedStorePath != dstPath) - state.debug_throw(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); + { + auto e = Error("store path mismatch in (possibly filtered) path added from '%s'", path); + state.debugLastTrace(e); + throw e; + } state.allowAndSetStorePathString(dstPath, v); } else state.allowAndSetStorePathString(*expectedStorePath, v); @@ -2004,12 +2113,16 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) - state.debug_throw(TypeError({ + { + auto e = TypeError({ .msg = hintfmt( "first argument in call to 'filterSource' is not a function but %1%", showType(*args[0])), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); } @@ -2093,16 +2206,24 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value else if (n == "sha256") expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); else - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name), .errPos = *attr.pos - })); + }); + state.debugLastTrace(e); + throw e; + } } if (path.empty()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("'path' required"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } if (name.empty()) name = baseNameOf(path); @@ -2473,10 +2594,14 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args return; } if (!args[0]->isLambda()) - state.debug_throw(TypeError({ + { + auto e = TypeError({ .msg = hintfmt("'functionArgs' requires a function"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } if (!args[0]->lambda.fun->hasFormals()) { v.mkAttrs(&state.emptyBindings); @@ -2564,7 +2689,8 @@ static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args attrsSeen[attr.name].first++; } catch (TypeError & e) { e.addTrace(pos, hintfmt("while invoking '%s'", "zipAttrsWith")); - state.debug_throw(e); + state.debugLastTrace(e); + throw e; } } @@ -2651,10 +2777,14 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu { state.forceList(list, pos); if (n < 0 || (unsigned int) n >= list.listSize()) - state.debug_throw(Error({ + { + auto e = Error({ .msg = hintfmt("list index %1% is out of boundz", n), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } state.forceValue(*list.listElems()[n], pos); v = *list.listElems()[n]; } @@ -2699,10 +2829,14 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value { state.forceList(*args[0], pos); if (args[0]->listSize() == 0) - state.debug_throw(Error({ + { + auto e = Error({ .msg = hintfmt("'tail' called on an empty list"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } state.mkList(v, args[0]->listSize() - 1); for (unsigned int n = 0; n < v.listSize(); ++n) @@ -2937,10 +3071,14 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val auto len = state.forceInt(*args[1], pos); if (len < 0) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("cannot create list of size %1%", len), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } state.mkList(v, len); @@ -3149,7 +3287,8 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos))); } catch (TypeError &e) { e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap")); - state.debug_throw(e); + state.debugLastTrace(e); + throw e; } len += lists[n].listSize(); } @@ -3244,10 +3383,14 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & NixFloat f2 = state.forceFloat(*args[1], pos); if (f2 == 0) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("division by zero"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } if (args[0]->type() == nFloat || args[1]->type() == nFloat) { v.mkFloat(state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); @@ -3256,10 +3399,14 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & NixInt i2 = state.forceInt(*args[1], pos); /* Avoid division overflow as it might raise SIGFPE. */ if (i1 == std::numeric_limits::min() && i2 == -1) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("overflow in integer division"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } v.mkInt(i1 / i2); } @@ -3387,10 +3534,14 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V auto s = state.coerceToString(pos, *args[2], context); if (start < 0) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("negative start position in 'substring'"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context); } @@ -3438,10 +3589,14 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - state.debug_throw(Error({ + { + auto e = Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } PathSet context; // discarded auto s = state.forceString(*args[1], context, pos); @@ -3511,15 +3666,19 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - state.debug_throw(EvalError({ + auto e = EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; } else { - state.debug_throw(EvalError({ + auto e = EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; } } } @@ -3616,15 +3775,19 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - state.debug_throw(EvalError({ + auto e = EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; } else { - state.debug_throw(EvalError({ + auto e = EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; } } } @@ -3701,10 +3864,14 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar state.forceList(*args[0], pos); state.forceList(*args[1], pos); if (args[0]->listSize() != args[1]->listSize()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } std::vector from; from.reserve(args[0]->listSize()); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index bae0fb1e4..131cc87dc 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -108,16 +108,25 @@ static void fetchTree( if (auto aType = args[0]->attrs->get(state.sType)) { if (type) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("unexpected attribute 'type'"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + + } type = state.forceStringNoCtx(*aType->value, *aType->pos); } else if (!type) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } attrs.emplace("type", type.value()); @@ -138,16 +147,24 @@ static void fetchTree( else if (attr.value->type() == nInt) attrs.emplace(attr.name, uint64_t(attr.value->integer)); else - state.debug_throw(TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", - attr.name, showType(*attr.value))); + { + auto e = TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", + attr.name, showType(*attr.value)); + state.debugLastTrace(e); + throw e; + } } if (!params.allowNameArgument) if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } input = fetchers::Input::fromAttrs(std::move(attrs)); } else { @@ -167,7 +184,11 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (evalSettings.pureEval && !input.isLocked()) - state.debug_throw(EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", pos)); + { + auto e = EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", pos); + state.debugLastTrace(e); + throw e; + } auto [tree, input2] = input.fetch(state.store); @@ -205,18 +226,25 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); else if (n == "name") name = state.forceStringNoCtx(*attr.value, *attr.pos); - else - state.debug_throw(EvalError({ - .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), - .errPos = *attr.pos - })); + else { + auto e = EvalError({ + .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), + .errPos = *attr.pos + }); + state.debugLastTrace(e); + throw e; } + } if (!url) - state.debug_throw(EvalError({ + { + auto e = EvalError({ .msg = hintfmt("'url' argument required"), .errPos = pos - })); + }); + state.debugLastTrace(e); + throw e; + } } else url = state.forceStringNoCtx(*args[0], pos); @@ -228,7 +256,11 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, name = baseNameOf(*url); if (evalSettings.pureEval && !expectedHash) - state.debug_throw(EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who)); + { + auto e = EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who); + state.debugLastTrace(e); + throw e; + } // early exit if pinned and already in the store if (expectedHash && expectedHash->type == htSHA256) { @@ -255,8 +287,12 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, ? state.store->queryPathInfo(storePath)->narHash : hashFile(htSHA256, state.store->toRealPath(storePath)); if (hash != *expectedHash) - state.debug_throw(EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", - *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true))); + { + auto e = EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", + *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)); + state.debugLastTrace(e); + throw e; + } } state.allowAndSetStorePathString(storePath, v); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index d8bf73cd5..2f34feb1f 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -85,7 +85,8 @@ void printValueAsJSON(EvalState & state, bool strict, .errPos = v.determinePos(pos) }); e.addTrace(pos, hintfmt("message for the trace")); - state.debug_throw(e); + state.debugLastTrace(e); + throw e; } } @@ -99,7 +100,9 @@ void printValueAsJSON(EvalState & state, bool strict, void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const { - state.debug_throw(TypeError("cannot convert %1% to JSON", showType())); + auto e = TypeError("cannot convert %1% to JSON", showType()); + state.debugLastTrace(e); + throw e; } -- cgit v1.2.3 From a86c2a8481c5bedb992d7126bc342a34b9c4902e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 13:30:18 -0600 Subject: remove 'debugError', dead code --- src/libcmd/command.cc | 27 +-------------------------- src/libcmd/command.hh | 1 - src/libcmd/repl.cc | 19 ------------------- 3 files changed, 1 insertion(+), 46 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 5cb8728e9..5ef3b4bc6 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -120,9 +120,6 @@ ref EvalCommand::getEvalState() ; if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { - // clear the screen. - // std::cout << "\033[2J\033[1;1H"; - auto dts = error && expr.getPos() ? std::unique_ptr( @@ -137,35 +134,13 @@ ref EvalCommand::getEvalState() })) : 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()); - // else - // { - // auto iter = evalState->debugTraces.begin(); - // if (iter != evalState->debugTraces.end()) { - // std::cout << "\n" << "… " << iter->hint.str() << "\n"; - - // if (iter->pos.has_value() && (*iter->pos)) { - // auto pos = iter->pos.value(); - // std::cout << "\n"; - // printAtPos(pos, std::cout); - - // auto loc = getCodeLines(pos); - // if (loc.has_value()) { - // std::cout << "\n"; - // printCodeLines(std::cout, "", pos, *loc); - // std::cout << "\n"; - // } - // } - // } - // } - if (expr.staticenv) { std::unique_ptr vm(mapStaticEnvBindings(*expr.staticenv.get(), env)); - runRepl(evalState, error, expr, *vm); + runRepl(evalState, expr, *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 94ad80210..9247d401e 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,7 +274,6 @@ void printClosureDiff( void runRepl( ref evalState, - const Error *debugError, const Expr &expr, const std::map & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 2e7974b5d..22a6439b4 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -50,7 +50,6 @@ struct NixRepl ref state; Bindings * autoArgs; - const Error *debugError; int debugTraceIndex; Strings loadedFiles; @@ -552,16 +551,6 @@ bool NixRepl::processLine(std::string line) // showDebugTrace(std::cout, *iter); } } - else if (arg == "error") { - // TODO: remove, along with debugError. - if (this->debugError) { - showErrorInfo(std::cout, debugError->info(), true); - } - else - { - notice("error information not available"); - } - } else if (arg == "step") { // set flag to stop at next DebugTrace; exit repl. state->debugStop = true; @@ -1024,26 +1013,18 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, - const Error *debugError, const Expr &expr, const std::map & extraEnv) { auto repl = std::make_unique(evalState); - repl->debugError = debugError; - repl->initEnv(); // add 'extra' vars. - // std::set names; for (auto & [name, value] : extraEnv) { - // names.insert(ANSI_BOLD + name + ANSI_NORMAL); - // names.insert(name); repl->addVarToScope(repl->state->symbols.create(name), *value); } - // printError(hintfmt("The following extra variables are in scope: %s\n", concatStringsSep(", ", names)).str()); - repl->mainLoop({}); } -- cgit v1.2.3 From 27d45f9eb3c151afed8a20f1adc1d4dd1a200f09 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 15:46:12 -0600 Subject: minor cleanup --- src/libcmd/repl.cc | 2 -- src/libexpr/eval.cc | 45 +++++++++++++++++++--------------------- src/libexpr/parser.y | 1 - src/libexpr/primops/fetchTree.cc | 15 +++++++------- 4 files changed, 29 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 22a6439b4..edd74c993 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -547,8 +547,6 @@ bool NixRepl::processLine(std::string line) loadDebugTraceEnv(*iter); break; } - // std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - // showDebugTrace(std::cout, *iter); } } else if (arg == "step") { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7d02222cf..914739f70 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -789,6 +789,7 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) auto map = valmap(); if (env.type == Env::HasWithAttrs) { + // add 'with' bindings. Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { map[j->name] = j->value; @@ -1485,15 +1486,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) try { auto dts = - debuggerHook ? - makeDebugTraceStacker( - state, - *this, - env, - *pos2, - "while evaluating the attribute '%1%'", - showAttrPath(state, env, attrPath)) - : nullptr; + debuggerHook ? + makeDebugTraceStacker( + state, + *this, + env, + *pos2, + "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)) + : nullptr; for (auto & i : attrPath) { state.nrLookups++; @@ -2082,13 +2083,13 @@ void EvalState::forceValueDeep(Value & v) try { auto dts = - debuggerHook ? - // if the value is a thunk, we're evaling. otherwise no trace necessary. - (i.value->isThunk() ? - makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, *i.pos, - "while evaluating the attribute '%1%'", i.name) - : nullptr) - : nullptr; + debuggerHook ? + // if the value is a thunk, we're evaling. otherwise no trace necessary. + (i.value->isThunk() ? + makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, *i.pos, + "while evaluating the attribute '%1%'", i.name) + : nullptr) + : nullptr; recurse(*i.value); } catch (Error & e) { @@ -2123,8 +2124,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) if (v.type() == nInt) return v.integer; else if (v.type() != nFloat) - throwTypeError(pos, "value is %1% while a float was expected", v, - *this); + throwTypeError(pos, "value is %1% while a float was expected", v, *this); return v.fpoint; } @@ -2133,8 +2133,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, - *this); + throwTypeError(pos, "value is %1% while a Boolean was expected", v, *this); return v.boolean; } @@ -2149,8 +2148,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) - throwTypeError(pos, "value is %1% while a function was expected", v, - *this); + throwTypeError(pos, "value is %1% while a function was expected", v, *this); } @@ -2158,8 +2156,7 @@ std::string_view EvalState::forceString(Value & v, const Pos & pos) { forceValue(v, pos); if (v.type() != nString) { - throwTypeError(pos, "value is %1% while a string was expected", v, - *this); + throwTypeError(pos, "value is %1% while a string was expected", v, *this); } return v.string.s; } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index ecfa5b7c2..1a5832e6b 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -23,7 +23,6 @@ #include "nixexpr.hh" #include "eval.hh" #include "globals.hh" -#include namespace nix { diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 131cc87dc..c7b73b83d 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -226,13 +226,14 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); else if (n == "name") name = state.forceStringNoCtx(*attr.value, *attr.pos); - else { - auto e = EvalError({ - .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), - .errPos = *attr.pos - }); - state.debugLastTrace(e); - throw e; + else + { + auto e = EvalError({ + .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), + .errPos = *attr.pos + }); + state.debugLastTrace(e); + throw e; } } -- cgit v1.2.3 From 31bcd5562693aec52a09d7f0d7ecae0b1a7ae9e4 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 15:53:24 -0600 Subject: clean up makefiles --- src/libcmd/local.mk | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index a12837ce5..73a1a1086 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -8,9 +8,7 @@ libcmd_SOURCES := $(wildcard $(d)/*.cc) libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix -# libcmd_LDFLAGS += -llowdown -pthread libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -pthread -# libcmd_LDFLAGS += $(LOWDOWN_LIBS) -pthread libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix -- cgit v1.2.3 From 3aaf02839f1491e6d766661209904f74efde8970 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 16:22:27 -0600 Subject: trace stack, not call stack --- src/libcmd/repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index edd74c993..07e433293 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -495,7 +495,7 @@ bool NixRepl::processLine(std::string line) << " :log Show logs for a derivation\n" << " :st [bool] Enable, disable or toggle showing traces for errors\n" << " :d Debug mode commands\n" - << " :d stack Show call stack\n" + << " :d stack Show trace stack\n" << " :d env Show env stack\n" << " :d show Show current trace, or change to call stack index\n" << " :d go Go until end of program, exception, or builtins.break().\n" -- cgit v1.2.3 From f5757a0804e0278e1ad2ac7a46adeb3dc96ce034 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 8 Apr 2022 16:34:20 -0600 Subject: revise command help --- src/libcmd/repl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 07e433293..5c25183cc 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -497,7 +497,8 @@ bool NixRepl::processLine(std::string line) << " :d Debug mode commands\n" << " :d stack Show trace stack\n" << " :d env Show env stack\n" - << " :d show Show current trace, or change to call stack index\n" + << " :d show Show current trace\n" + << " :d show Change to another trace in the stack\n" << " :d go Go until end of program, exception, or builtins.break().\n" << " :d step Go one step\n" ; -- cgit v1.2.3 From a61841ac41646ad0345cef547facd2c20f1da957 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sat, 9 Apr 2022 07:45:23 -0600 Subject: don't use std::map merge --- src/libexpr/eval.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 914739f70..876bf8f37 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -784,15 +784,14 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // override the higher levels. // The top level bindings (builtins) are skipped since they are added for us by initEnv() if (env.up && se.up) { - mapStaticEnvBindings(*se.up, *env.up,vm); + mapStaticEnvBindings(*se.up, *env.up, vm); - auto map = valmap(); if (env.type == Env::HasWithAttrs) { // add 'with' bindings. Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - map[j->name] = j->value; + vm[j->name] = j->value; ++j; } } @@ -801,11 +800,9 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // iterate through staticenv bindings and add them. for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) { - map[iter->first] = env.values[iter->second]; + vm[iter->first] = env.values[iter->second]; } } - - vm.merge(map); } } -- cgit v1.2.3 From 8b197c492e4e2878eb58bb2994fb8d7f8044bf90 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sat, 9 Apr 2022 21:54:41 -0600 Subject: remove comma --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 876bf8f37..d0e147733 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -845,7 +845,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & s auto error = EvalError({ .msg = hintfmt(s, s2), .errPos = pos, - .suggestions = suggestions, + .suggestions = suggestions }); if (debuggerHook) -- cgit v1.2.3 From 2a5632c70dcb686a7764c23a5f330fcb9a33c8a1 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 29 Apr 2022 10:02:17 -0600 Subject: incorporate PosIdx changes, symbol changes. --- src/libcmd/command.cc | 4 +- src/libcmd/repl.cc | 16 ++-- src/libexpr/eval-inline.hh | 6 +- src/libexpr/eval.cc | 199 +++++++++++++++++++++++++++------------------ src/libexpr/eval.hh | 67 +++++++++++---- src/libexpr/nixexpr.cc | 6 +- src/libexpr/nixexpr.hh | 9 +- src/libexpr/primops.cc | 10 ++- 8 files changed, 198 insertions(+), 119 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 82b35d16f..3e789adba 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -126,7 +126,7 @@ ref EvalCommand::getEvalState() new DebugTraceStacker( *evalState, DebugTrace - {.pos = (error->info().errPos ? *error->info().errPos : *expr.getPos()), + {.pos = (error->info().errPos ? *error->info().errPos : evalState->positions[expr.getPos()]), .expr = expr, .env = env, .hint = error->info().msg, @@ -139,7 +139,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { - std::unique_ptr vm(mapStaticEnvBindings(*expr.staticenv.get(), env)); + std::unique_ptr vm(mapStaticEnvBindings(evalState->symbols, *expr.staticenv.get(), env)); runRepl(evalState, expr, *vm); } }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index d9ba7e7a4..40299e910 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -203,7 +203,7 @@ namespace { } } -std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) +std::ostream& showDebugTrace(std::ostream &out, const PosTable &positions, const DebugTrace &dt) { if (dt.is_error) out << ANSI_RED "error: " << ANSI_NORMAL; @@ -211,7 +211,7 @@ std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) // prefer direct pos, but if noPos then try the expr. auto pos = (*dt.pos ? *dt.pos : - (dt.expr.getPos() ? *dt.expr.getPos() : noPos)); + positions[(dt.expr.getPos() ? dt.expr.getPos() : noPos)]); if (pos) { printAtPos(pos, out); @@ -280,7 +280,7 @@ void NixRepl::mainLoop(const std::vector & files) // 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 && !this->state->debugTraces.empty()) - showDebugTrace(std::cout, this->state->debugTraces.front()); + showDebugTrace(std::cout, this->state->positions, this->state->debugTraces.front()); else printMsg(lvlError, e.msg()); } catch (Error & e) { @@ -443,7 +443,7 @@ void NixRepl::loadDebugTraceEnv(DebugTrace &dt) { initEnv(); - auto vm = std::make_unique(*(mapStaticEnvBindings(*dt.expr.staticenv.get(), dt.env))); + auto vm = std::make_unique(*(mapStaticEnvBindings(this->state->symbols, *dt.expr.staticenv.get(), dt.env))); // add staticenv vars. for (auto & [name, value] : *(vm.get())) { @@ -514,7 +514,7 @@ bool NixRepl::processLine(std::string line) iter != this->state->debugTraces.end(); ++iter, ++idx) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, *iter); + showDebugTrace(std::cout, this->state->positions, *iter); } } else if (arg == "env") { int idx = 0; @@ -523,7 +523,7 @@ bool NixRepl::processLine(std::string line) ++iter, ++idx) { if (idx == this->debugTraceIndex) { - printEnvBindings(iter->expr, iter->env); + printEnvBindings(state->symbols,iter->expr, iter->env); break; } } @@ -544,9 +544,9 @@ bool NixRepl::processLine(std::string line) if (idx == this->debugTraceIndex) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, *iter); + showDebugTrace(std::cout, this->state->positions, *iter); std::cout << std::endl; - printEnvBindings(iter->expr, iter->env); + printEnvBindings(state->symbols,iter->expr, iter->env); loadDebugTraceEnv(*iter); break; } diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 4e0826101..f2f4ba725 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -103,7 +103,7 @@ void EvalState::forceValue(Value & v, Callable getPos) else if (v.isApp()) callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.isBlackhole()) - throwEvalError(getPos(), "infinite recursion encountered", *this); + throwEvalError(getPos(), "infinite recursion encountered"); } @@ -120,7 +120,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos) { forceValue(v, getPos); if (v.type() != nAttrs) - throwTypeError(getPos(), "value is %1% while a set was expected", v, *this); + throwTypeError(getPos(), "value is %1% while a set was expected", v); } @@ -129,7 +129,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos) { forceValue(v, pos); if (!v.isList()) - throwTypeError(pos, "value is %1% while a list was expected", v, *this); + throwTypeError(pos, "value is %1% while a list was expected", v); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 896242e0c..7058d117f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -714,19 +714,19 @@ std::optional EvalState::getDoc(Value & v) // just for the current level of StaticEnv, not the whole chain. -void printStaticEnvBindings(const StaticEnv &se) +void printStaticEnvBindings(const SymbolTable &st, const StaticEnv &se) { std::cout << ANSI_MAGENTA; for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { - std::cout << i->first << " "; + std::cout << st[i->first] << " "; } std::cout << ANSI_NORMAL; std::cout << std::endl; } // just for the current level of Env, not the whole chain. -void printWithBindings(const Env &env) +void printWithBindings(const SymbolTable &st, const Env &env) { if (env.type == Env::HasWithAttrs) { @@ -734,7 +734,7 @@ void printWithBindings(const Env &env) std::cout << ANSI_MAGENTA; Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - std::cout << j->name << " "; + std::cout << st[j->name] << " "; ++j; } std::cout << ANSI_NORMAL; @@ -742,16 +742,16 @@ void printWithBindings(const Env &env) } } -void printEnvBindings(const StaticEnv &se, const Env &env, int lvl) +void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl) { std::cout << "Env level " << lvl << std::endl; if (se.up && env.up) { std::cout << "static: "; - printStaticEnvBindings(se); - printWithBindings(env); + printStaticEnvBindings(st, se); + printWithBindings(st, env); std::cout << std::endl; - printEnvBindings(*se.up, *env.up, ++lvl); + printEnvBindings(st, *se.up, *env.up, ++lvl); } else { @@ -759,41 +759,41 @@ void printEnvBindings(const StaticEnv &se, const Env &env, int lvl) // for the top level, don't print the double underscore ones; they are in builtins. for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { - if (((std::string)i->first).substr(0,2) != "__") - std::cout << i->first << " "; + if (((std::string)st[i->first]).substr(0,2) != "__") + std::cout << st[i->first] << " "; } std::cout << ANSI_NORMAL; std::cout << std::endl; - printWithBindings(env); // probably nothing there for the top level. + printWithBindings(st, env); // probably nothing there for the top level. std::cout << std::endl; } } // TODO: add accompanying env for With stuff. -void printEnvBindings(const Expr &expr, const Env &env) +void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env) { // just print the names for now if (expr.staticenv) { - printEnvBindings(*expr.staticenv.get(), env, 0); + printEnvBindings(st, *expr.staticenv.get(), env, 0); } } -void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) +void mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, valmap & vm) { // add bindings for the next level up first, so that the bindings for this level // override the higher levels. // The top level bindings (builtins) are skipped since they are added for us by initEnv() if (env.up && se.up) { - mapStaticEnvBindings(*se.up, *env.up, vm); + mapStaticEnvBindings(st, *se.up, *env.up, vm); if (env.type == Env::HasWithAttrs) { // add 'with' bindings. Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - vm[j->name] = j->value; + vm[st[j->name]] = j->value; ++j; } } @@ -802,51 +802,54 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // iterate through staticenv bindings and add them. for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) { - vm[iter->first] = env.values[iter->second]; + vm[st[iter->first]] = env.values[iter->second]; } } } } -valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) +valmap * mapStaticEnvBindings(const SymbolTable &st,const StaticEnv &se, const Env &env) { auto vm = new valmap(); - mapStaticEnvBindings(se, env, *vm); + mapStaticEnvBindings(st, se, env, *vm); return vm; } +void EvalState::debugLastTrace(Error & e) const { + // 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()) { + const DebugTrace &last = debugTraces.front(); + debuggerHook(&e, last.env, last.expr); + } +} + /* 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 exceptions. */ - -void EvalState::throwEvalError(const PosIdx pos, const char * s) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr &expr) const { auto error = EvalError({ .msg = hintfmt(s), .errPos = positions[pos] }); - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + if (debuggerHook) + debuggerHook(&error, env, expr); throw error; } -void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const +void EvalState::throwEvalError(const PosIdx pos, const char * s) const { - auto error = TypeError({ - .msg = hintfmt(s, showType(v)), + auto error = EvalError({ + .msg = hintfmt(s), .errPos = positions[pos] }); - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + debugLastTrace(error); throw error; } @@ -855,23 +858,11 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const { auto error = EvalError(s, s2); - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + debugLastTrace(error); throw error; } -void EvalState::debugLastTrace(Error & e) { - // 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()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&e, last.env, last.expr); - } -} - void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr &expr) const { @@ -899,16 +890,43 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri throw error; } -void EvalState::throwEvalError(const char * s, const std::string & s2, const std::string & s3, Env & env, Expr &expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr &expr) const { auto error = EvalError({ - .msg = hintfmt(s), - .errPos = pos + .msg = hintfmt(s, s2), + .errPos = positions[pos] }); if (debuggerHook) debuggerHook(&error, env, expr); + + throw error; +} + +void EvalState::throwEvalError(const char * s, const std::string & s2, + const std::string & s3) const +{ + auto error = EvalError({ + .msg = hintfmt(s, s2), + .errPos = positions[noPos] + }); + + debugLastTrace(error); + + throw error; +} + +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, + const std::string & s3) const +{ + auto error = EvalError({ + .msg = hintfmt(s, s2), + .errPos = positions[pos] + }); + + debugLastTrace(error); + throw error; } @@ -917,7 +935,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri { auto error = EvalError({ .msg = hintfmt(s, s2), - .errPos = pos + .errPos = positions[pos] }); if (debuggerHook) @@ -966,6 +984,31 @@ void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym throw error; } +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const +{ + auto error = TypeError({ + .msg = hintfmt(s, showType(v)), + .errPos = positions[pos] + }); + + debugLastTrace(error); + + throw error; +} + +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr &expr) const +{ + auto error = TypeError({ + .msg = hintfmt(s, showType(v)), + .errPos = positions[pos] + }); + + if (debuggerHook) + debuggerHook(&error, env, expr); + + throw error; +} + void EvalState::throwTypeError(const PosIdx pos, const char * s) const { auto error = TypeError({ @@ -973,7 +1016,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s) const .errPos = positions[pos] }); - evalState.debugLastTrace(error); + debugLastTrace(error); throw error; } @@ -1010,9 +1053,8 @@ void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) const { auto error = TypeError({ - .msg = hintfmt(s, fun.showNamePos(), s2), - .errPos = pos, - .suggestions = suggestions, + .msg = hintfmt(s, showType(v)), + .errPos = positions[expr.getPos()], }); if (debuggerHook) @@ -1070,8 +1112,8 @@ void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const e.addTrace(positions[pos], s, s2); } -LocalNoInline(std::unique_ptr - makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, std::optional pos, const char * s, const std::string & s2)) +std::unique_ptr makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, + std::optional pos, const char * s, const std::string & s2) { return std::unique_ptr( new DebugTraceStacker( @@ -1150,7 +1192,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name], *env, var); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name], *env, const_cast(var)); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1293,7 +1335,7 @@ void EvalState::cacheFile( *this, *e, this->baseEnv, - (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), + (e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt), "while evaluating the file '%1%':", resolvedPath) : nullptr; @@ -1528,7 +1570,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) state, *this, env, - *pos2, + state.positions[pos2], "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)) : nullptr; @@ -1694,10 +1736,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & try { auto dts = debuggerHook ? - makeDebugTraceStacker(*this, *lambda.body, env2, lambda.pos, + makeDebugTraceStacker(*this, *lambda.body, env2, positions[lambda.pos], "while evaluating %s", - (lambda.name.set() - ? "'" + (std::string) lambda.name + "'" + (lambda.name + ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda")) : nullptr; @@ -1786,7 +1828,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } else - throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur, *this); + throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur); } vRes = vCur; @@ -1855,7 +1897,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", symbols[i.name],, +https://nixos.org/manual/nix/stable/#ss-functions.)", symbols[i.name], *fun.lambda.env, *fun.lambda.fun); } } @@ -2092,7 +2134,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) v.mkFloat(nf); else if (firstType == nPath) { if (!context.empty()) - state.throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, *this);); + state.throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, *this); v.mkPath(canonPath(str())); } else v.mkStringMove(c_str(), context); @@ -2124,8 +2166,8 @@ void EvalState::forceValueDeep(Value & v) debuggerHook ? // if the value is a thunk, we're evaling. otherwise no trace necessary. (i.value->isThunk() ? - makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, *i.pos, - "while evaluating the attribute '%1%'", i.name) + makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, positions[i.pos], + "while evaluating the attribute '%1%'", symbols[i.name]) : nullptr) : nullptr; @@ -2150,7 +2192,7 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nInt) - throwTypeError(pos, "value is %1% while an integer was expected", v, *this); + throwTypeError(pos, "value is %1% while an integer was expected", v); return v.integer; } @@ -2162,7 +2204,7 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos) if (v.type() == nInt) return v.integer; else if (v.type() != nFloat) - throwTypeError(pos, "value is %1% while a float was expected", v, *this); + throwTypeError(pos, "value is %1% while a float was expected", v); return v.fpoint; } @@ -2171,7 +2213,7 @@ bool EvalState::forceBool(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, *this); + throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -2186,7 +2228,7 @@ void EvalState::forceFunction(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) - throwTypeError(pos, "value is %1% while a function was expected", v, *this); + throwTypeError(pos, "value is %1% while a function was expected", v); } @@ -2194,7 +2236,7 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nString) { - throwTypeError(pos, "value is %1% while a string was expected", v, *this); + throwTypeError(pos, "value is %1% while a string was expected", v); } return v.string.s; } @@ -2254,10 +2296,10 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], *this); + v.string.s, v.string.context[0]); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], *this); + v.string.s, v.string.context[0]); } return s; } @@ -2312,7 +2354,7 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet return std::move(*maybeString); auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", *this); + throwTypeError(pos, "cannot coerce a set to a string"); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2341,14 +2383,14 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet } } - throwTypeError(pos, "cannot coerce %1% to a string", v, *this); + throwTypeError(pos, "cannot coerce %1% to a string", v); } std::string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) - throwEvalError("file names are not allowed to end in '%1%'", drvExtension, *this); + throwEvalError("file names are not allowed to end in '%1%'", drvExtension); Path dstPath; auto i = srcToStore.find(path); @@ -2373,7 +2415,7 @@ Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context) { auto path = coerceToString(pos, v, context, false, false).toOwned(); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, *this); + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); return path; } @@ -2466,8 +2508,7 @@ bool EvalState::eqValues(Value & v1, Value & v2) default: throwEvalError("cannot compare %1% with %2%", showType(v1), - showType(v2), - *this); + showType(v2)); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 76bd63ca6..2e7df13fc 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,8 +25,8 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); -void printEnvBindings(const Expr &expr, const Env &env); -void printEnvBindings(const StaticEnv &se, const Env &env, int lvl = 0); +void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env); +void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl = 0); struct PrimOp { @@ -47,7 +47,7 @@ struct Env Value * values[0]; }; -valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env); +valmap * mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env); void copyContext(const Value & v, PathSet & context); @@ -123,7 +123,7 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; - void debugLastTrace(Error & e); + void debugLastTrace(Error & e) const; private: SrcToStore srcToStore; @@ -273,35 +273,66 @@ public: [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const Value & v) const; + void throwEvalError(const PosIdx pos, const char * s, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const char * s, const std::string & s2) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const std::string & s2) const; - [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; + void throwEvalError(const char * s, const std::string & s2, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const char * s, const std::string & s2, const std::string & s3, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2) const; + void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, + Env & env, Expr &expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, + Env & env, Expr & expr) const; + + [[gnu::noinline, gnu::noreturn]] + void throwTypeError(const PosIdx pos, const char * s, const Value & v) const; + [[gnu::noinline, gnu::noreturn]] + void throwTypeError(const PosIdx pos, const char * s, const Value & v, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2) const; + void throwTypeError(const PosIdx pos, const char * s, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol s2) const; + void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const char * s, const Value & v) const; + void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol s2, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwTypeError(const char * s, const Value & v, + Env & env, Expr & expr) const; + + [[gnu::noinline, gnu::noreturn]] + void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] - void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] - void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; [[gnu::noinline]] void addErrorTrace(Error & e, const char * s, const std::string & s2) const; @@ -480,7 +511,7 @@ private: class DebugTraceStacker { public: DebugTraceStacker(EvalState &evalState, DebugTrace t); - ~DebugTraceStacker() + ~DebugTraceStacker() { // assert(evalState.debugTraces.front() == trace); evalState.debugTraces.pop_front(); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index efaeba7c6..c6e545729 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -437,11 +437,11 @@ void ExprLambda::bindVars(const EvalState & es, const std::shared_ptrformals.size() : 0) + - (!arg ? 0 : 1)); + (!arg ? 0 : 1))); Displacement displ = 0; - if (arg) newEnv.vars.emplace_back(arg, displ++); + if (arg) newEnv->vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) @@ -506,7 +506,7 @@ void ExprWith::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); - StaticEnv newEnv(true, &env); + auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); body->bindVars(es, newEnv); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index d275a51e9..82fff6dcf 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -278,7 +278,12 @@ struct ExprList : Expr { std::vector elems; ExprList() { }; - const PosIdx getPos() const { return pos; } + const PosIdx getPos() const + { if (elems.empty()) + return noPos; + else + return elems.front()->getPos(); + } COMMON_METHODS }; @@ -389,7 +394,7 @@ struct ExprOpNot : Expr { Expr * e; ExprOpNot(Expr * e) : e(e) { }; - const Pos* getPos() const { return 0; } + const PosIdx getPos() const { return noPos; } COMMON_METHODS }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 212ce3de9..e2267d154 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -774,12 +774,14 @@ static RegisterPrimOp primop_break({ .doc = R"( In debug mode, pause Nix expression evaluation and enter the repl. )", - .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { + PathSet context; + auto s = state.coerceToString(pos, *args[0], context).toOwned(); auto error = Error(ErrorInfo{ .level = lvlInfo, - .msg = hintfmt("breakpoint reached; value was %1%", *args[0]), - .errPos = pos, + .msg = hintfmt("breakpoint reached; value was %1%", s), + .errPos = state.positions[pos], }); if (debuggerHook && !state.debugTraces.empty()) { @@ -791,7 +793,7 @@ static RegisterPrimOp primop_break({ throw Error(ErrorInfo{ .level = lvlInfo, .msg = hintfmt("quit from debugger"), - .errPos = noPos, + .errPos = state.positions[noPos], }); } -- cgit v1.2.3 From ca6cba8b81502450f8e377112ce11303ccedc760 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 29 Apr 2022 10:51:10 -0600 Subject: fix 'suggestions' error --- src/libexpr/eval.cc | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7058d117f..294168392 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -866,7 +866,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr &expr) const { - auto error = EvalError({ + auto error = EvalError(ErrorInfo{ .msg = hintfmt(s, s2), .errPos = positions[pos], .suggestions = suggestions, @@ -944,32 +944,6 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri throw error; } -/* -LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3, EvalState &evalState)) -{ - auto error = EvalError({ - .msg = hintfmt(s, s2, s3), - .errPos = positions[pos] - }); - - evalState.debugLastTrace(error); - - throw error; -} - -LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2, const std::string & s3, EvalState &evalState)) -{ - auto error = EvalError({ - .msg = hintfmt(s, s2, s3), - .errPos = noPos - }); - - evalState.debugLastTrace(error); - - throw error; -} -*/ - void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr &expr) const { // p1 is where the error occurred; p2 is a position mentioned in the message. -- cgit v1.2.3 From 172a83d22a3c984b6b569b5528d2338059bb748b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 29 Apr 2022 11:24:54 -0600 Subject: line endings --- src/libcmd/command.cc | 2 +- src/libcmd/repl.cc | 10 +++++----- src/libexpr/eval.cc | 12 ++++++------ src/libexpr/nixexpr.cc | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 3e789adba..56d529461 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -125,7 +125,7 @@ ref EvalCommand::getEvalState() std::unique_ptr( new DebugTraceStacker( *evalState, - DebugTrace + DebugTrace {.pos = (error->info().errPos ? *error->info().errPos : evalState->positions[expr.getPos()]), .expr = expr, .env = env, diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 40299e910..b94831064 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -276,10 +276,10 @@ void NixRepl::mainLoop(const std::vector & files) printMsg(lvlError, e.msg()); } } catch (EvalError & e) { - // 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; // show the error for this repl session instead. - if (debuggerHook && !this->state->debugTraces.empty()) + if (debuggerHook && !this->state->debugTraces.empty()) showDebugTrace(std::cout, this->state->positions, this->state->debugTraces.front()); else printMsg(lvlError, e.msg()); @@ -511,7 +511,7 @@ bool NixRepl::processLine(std::string line) if (arg == "stack") { int idx = 0; for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); + iter != this->state->debugTraces.end(); ++iter, ++idx) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, this->state->positions, *iter); @@ -519,7 +519,7 @@ bool NixRepl::processLine(std::string line) } else if (arg == "env") { int idx = 0; for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); + iter != this->state->debugTraces.end(); ++iter, ++idx) { if (idx == this->debugTraceIndex) { @@ -539,7 +539,7 @@ bool NixRepl::processLine(std::string line) int idx = 0; for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); + iter != this->state->debugTraces.end(); ++iter, ++idx) { if (idx == this->debugTraceIndex) { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 294168392..10dba69e7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -730,7 +730,7 @@ void printWithBindings(const SymbolTable &st, const Env &env) { if (env.type == Env::HasWithAttrs) { - std::cout << "with: "; + std::cout << "with: "; std::cout << ANSI_MAGENTA; Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { @@ -747,13 +747,13 @@ void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env std::cout << "Env level " << lvl << std::endl; if (se.up && env.up) { - std::cout << "static: "; + std::cout << "static: "; printStaticEnvBindings(st, se); printWithBindings(st, env); std::cout << std::endl; printEnvBindings(st, *se.up, *env.up, ++lvl); } - else + else { std::cout << ANSI_MAGENTA; // for the top level, don't print the double underscore ones; they are in builtins. @@ -784,7 +784,7 @@ void mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env { // add bindings for the next level up first, so that the bindings for this level // override the higher levels. - // The top level bindings (builtins) are skipped since they are added for us by initEnv() + // The top level bindings (builtins) are skipped since they are added for us by initEnv() if (env.up && se.up) { mapStaticEnvBindings(st, *se.up, *env.up, vm); @@ -1086,13 +1086,13 @@ void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const e.addTrace(positions[pos], s, s2); } -std::unique_ptr makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, +std::unique_ptr makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, std::optional pos, const char * s, const std::string & s2) { return std::unique_ptr( new DebugTraceStacker( state, - DebugTrace + DebugTrace {.pos = pos, .expr = expr, .env = env, diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index c6e545729..5624c4780 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -352,7 +352,7 @@ void ExprVar::bindVars(const EvalState & es, const std::shared_ptr(new StaticEnv(false, env.get(), recursive ? attrs.size() : 0)); + auto newEnv = std::shared_ptr(new StaticEnv(false, env.get(), recursive ? attrs.size() : 0)); Displacement displ = 0; for (auto & i : attrs) -- cgit v1.2.3 From c94180386182c8cd9e2a4a8053afb5938940c1d2 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 29 Apr 2022 11:27:38 -0600 Subject: spacing --- src/libutil/error.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 6eb80fb9e..a53e9802e 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -99,6 +99,7 @@ struct ErrPos { }; std::optional getCodeLines(const ErrPos & errPos); + void printCodeLines(std::ostream & out, const std::string & prefix, const ErrPos & errPos, @@ -106,7 +107,6 @@ void printCodeLines(std::ostream & out, void printAtPos(const ErrPos & pos, std::ostream & out); - struct Trace { std::optional pos; hintformat hint; -- cgit v1.2.3 From c81ffa692e56cd8a1069aea95159008a342e0f46 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 29 Apr 2022 11:35:50 -0600 Subject: remove 'libnix' --- src/libcmd/local.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index 73a1a1086..3a4de6bcb 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -10,6 +10,6 @@ libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain libcmd_LDFLAGS = $(EDITLINE_LIBS) -llowdown -pthread -libcmd_LIBS = libstore libutil libexpr libmain libfetchers libnix +libcmd_LIBS = libstore libutil libexpr libmain libfetchers $(eval $(call install-file-in, $(d)/nix-cmd.pc, $(libdir)/pkgconfig, 0644)) -- cgit v1.2.3 From dd8b91eebc0d31c9f8016609b36d89f58d8c4d19 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 5 May 2022 12:29:14 +0200 Subject: Style fixes In particular, use std::make_shared and enumerate(). Also renamed some fields to fit naming conventions. --- src/libcmd/command.cc | 28 +++---- src/libcmd/command.hh | 3 +- src/libcmd/repl.cc | 85 ++++++++----------- src/libexpr/eval.cc | 219 +++++++++++++++++++++++-------------------------- src/libexpr/eval.hh | 33 ++++---- src/libexpr/nixexpr.cc | 95 ++++++++++----------- src/libexpr/nixexpr.hh | 45 +++++----- src/libexpr/primops.cc | 40 ++++----- 8 files changed, 245 insertions(+), 303 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 56d529461..12cd5ed83 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -121,25 +121,23 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { auto dts = - error && expr.getPos() ? - std::unique_ptr( - new DebugTraceStacker( - *evalState, - DebugTrace - {.pos = (error->info().errPos ? *error->info().errPos : evalState->positions[expr.getPos()]), - .expr = expr, - .env = env, - .hint = error->info().msg, - .is_error = true - })) - : nullptr; + 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 (expr.staticenv) - { - std::unique_ptr vm(mapStaticEnvBindings(evalState->symbols, *expr.staticenv.get(), env)); + if (expr.staticEnv) { + auto vm = mapStaticEnvBindings(evalState->symbols, *expr.staticEnv.get(), env); runRepl(evalState, expr, *vm); } }; diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index db4d4c023..354877bc5 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -275,6 +275,7 @@ void printClosureDiff( void runRepl( ref evalState, - const Expr &expr, + const Expr & expr, const std::map & extraEnv); + } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index b94831064..c35f29a2f 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -51,7 +51,7 @@ struct NixRepl ref state; Bindings * autoArgs; - int debugTraceIndex; + size_t debugTraceIndex; Strings loadedFiles; @@ -79,7 +79,7 @@ struct NixRepl void addVarToScope(const Symbol name, Value & v); Expr * parseString(std::string s); void evalString(std::string s, Value & v); - void loadDebugTraceEnv(DebugTrace &dt); + void loadDebugTraceEnv(DebugTrace & dt); typedef std::set ValuesSeen; std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); @@ -203,15 +203,16 @@ namespace { } } -std::ostream& showDebugTrace(std::ostream &out, const PosTable &positions, const DebugTrace &dt) +static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positions, const DebugTrace & dt) { - if (dt.is_error) + if (dt.isError) out << ANSI_RED "error: " << ANSI_NORMAL; out << dt.hint.str() << "\n"; // prefer direct pos, but if noPos then try the expr. - auto pos = (*dt.pos ? *dt.pos : - positions[(dt.expr.getPos() ? dt.expr.getPos() : noPos)]); + auto pos = *dt.pos + ? *dt.pos + : positions[dt.expr.getPos() ? dt.expr.getPos() : noPos]; if (pos) { printAtPos(pos, out); @@ -258,8 +259,7 @@ void NixRepl::mainLoop(const std::vector & files) while (true) { // 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> " : " ")) - { + if (!getLine(input, input.empty() ? "nix-repl> " : " ")) { // ctrl-D should exit the debugger. state->debugStop = false; state->debugQuit = true; @@ -279,8 +279,8 @@ 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 && !this->state->debugTraces.empty()) - showDebugTrace(std::cout, this->state->positions, this->state->debugTraces.front()); + if (debuggerHook && !state->debugTraces.empty()) + showDebugTrace(std::cout, state->positions, state->debugTraces.front()); else printMsg(lvlError, e.msg()); } catch (Error & e) { @@ -437,22 +437,16 @@ StorePath NixRepl::getDerivationPath(Value & v) { return *drvPath; } -void NixRepl::loadDebugTraceEnv(DebugTrace &dt) +void NixRepl::loadDebugTraceEnv(DebugTrace & dt) { - if (dt.expr.staticenv) - { - initEnv(); + initEnv(); - auto vm = std::make_unique(*(mapStaticEnvBindings(this->state->symbols, *dt.expr.staticenv.get(), dt.env))); + if (dt.expr.staticEnv) { + auto vm = mapStaticEnvBindings(state->symbols, *dt.expr.staticEnv.get(), dt.env); // add staticenv vars. - for (auto & [name, value] : *(vm.get())) { - this->addVarToScope(this->state->symbols.create(name), *value); - } - } - else - { - initEnv(); + for (auto & [name, value] : *(vm.get())) + addVarToScope(state->symbols.create(name), *value); } } @@ -509,45 +503,31 @@ bool NixRepl::processLine(std::string line) else if (command == ":d" || command == ":debug") { if (arg == "stack") { - int idx = 0; - for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); - ++iter, ++idx) { - std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, this->state->positions, *iter); + for (const auto & [idx, i] : enumerate(state->debugTraces)) { + std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + showDebugTrace(std::cout, state->positions, i); } } else if (arg == "env") { - int idx = 0; - for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); - ++iter, ++idx) { - if (idx == this->debugTraceIndex) - { - printEnvBindings(state->symbols,iter->expr, iter->env); - break; - } + for (const auto & [idx, i] : enumerate(state->debugTraces)) { + if (idx == debugTraceIndex) { + printEnvBindings(state->symbols, i.expr, i.env); + break; + } } } - else if (arg.compare(0,4,"show") == 0) { + else if (arg.compare(0, 4, "show") == 0) { try { // change the DebugTrace index. debugTraceIndex = stoi(arg.substr(4)); - } - catch (...) - { - } + } catch (...) { } - int idx = 0; - for (auto iter = this->state->debugTraces.begin(); - iter != this->state->debugTraces.end(); - ++iter, ++idx) { - if (idx == this->debugTraceIndex) - { + for (const auto & [idx, i] : enumerate(state->debugTraces)) { + if (idx == debugTraceIndex) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, this->state->positions, *iter); + showDebugTrace(std::cout, state->positions, i); std::cout << std::endl; - printEnvBindings(state->symbols,iter->expr, iter->env); - loadDebugTraceEnv(*iter); + printEnvBindings(state->symbols, i.expr, i.env); + loadDebugTraceEnv(i); break; } } @@ -1032,9 +1012,8 @@ void runRepl( repl->initEnv(); // add 'extra' vars. - for (auto & [name, value] : extraEnv) { + for (auto & [name, value] : extraEnv) repl->addVarToScope(repl->state->symbols.create(name), *value); - } repl->mainLoop({}); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 10dba69e7..ca0eec6e3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -466,7 +466,7 @@ EvalState::EvalState( , env1AllocCache(std::make_shared(nullptr)) #endif , baseEnv(allocEnv(128)) - , staticBaseEnv(new StaticEnv(false, 0)) + , staticBaseEnv{std::make_shared(false, nullptr)} { countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0"; @@ -524,7 +524,7 @@ void EvalState::allowPath(const StorePath & storePath) allowedPaths->insert(store->toRealPath(storePath)); } -void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v) +void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v) { allowPath(storePath); @@ -714,22 +714,19 @@ std::optional EvalState::getDoc(Value & v) // just for the current level of StaticEnv, not the whole chain. -void printStaticEnvBindings(const SymbolTable &st, const StaticEnv &se) +void printStaticEnvBindings(const SymbolTable & st, const StaticEnv & se) { std::cout << ANSI_MAGENTA; - for (auto i = se.vars.begin(); i != se.vars.end(); ++i) - { - std::cout << st[i->first] << " "; - } + for (auto & i : se.vars) + std::cout << st[i.first] << " "; std::cout << ANSI_NORMAL; std::cout << std::endl; } // just for the current level of Env, not the whole chain. -void printWithBindings(const SymbolTable &st, const Env &env) +void printWithBindings(const SymbolTable & st, const Env & env) { - if (env.type == Env::HasWithAttrs) - { + if (env.type == Env::HasWithAttrs) { std::cout << "with: "; std::cout << ANSI_MAGENTA; Bindings::iterator j = env.values[0]->attrs->begin(); @@ -742,7 +739,7 @@ void printWithBindings(const SymbolTable &st, const Env &env) } } -void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl) +void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, int lvl) { std::cout << "Env level " << lvl << std::endl; @@ -752,16 +749,13 @@ void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env printWithBindings(st, env); std::cout << std::endl; printEnvBindings(st, *se.up, *env.up, ++lvl); - } - else - { + } else { std::cout << ANSI_MAGENTA; - // for the top level, don't print the double underscore ones; they are in builtins. - for (auto i = se.vars.begin(); i != se.vars.end(); ++i) - { - if (((std::string)st[i->first]).substr(0,2) != "__") - std::cout << st[i->first] << " "; - } + // for the top level, don't print the double underscore ones; + // they are in builtins. + for (auto & i : se.vars) + if (!hasPrefix(st[i.first], "__")) + std::cout << st[i.first] << " "; std::cout << ANSI_NORMAL; std::cout << std::endl; printWithBindings(st, env); // probably nothing there for the top level. @@ -771,56 +765,50 @@ void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env } // TODO: add accompanying env for With stuff. -void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env) +void printEnvBindings(const SymbolTable & st, const Expr & expr, const Env & env) { // just print the names for now - if (expr.staticenv) - { - printEnvBindings(st, *expr.staticenv.get(), env, 0); + if (expr.staticEnv) + printEnvBindings(st, *expr.staticEnv.get(), env, 0); +} + +void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, valmap & vm) +{ + // add bindings for the next level up first, so that the bindings for this level + // override the higher levels. + // The top level bindings (builtins) are skipped since they are added for us by initEnv() + if (env.up && se.up) { + mapStaticEnvBindings(st, *se.up, *env.up, vm); + + if (env.type == Env::HasWithAttrs) { + // add 'with' bindings. + Bindings::iterator j = env.values[0]->attrs->begin(); + while (j != env.values[0]->attrs->end()) { + vm[st[j->name]] = j->value; + ++j; + } + } else { + // iterate through staticenv bindings and add them. + for (auto & i : se.vars) + vm[st[i.first]] = env.values[i.second]; + } } } -void mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, valmap & vm) -{ - // add bindings for the next level up first, so that the bindings for this level - // override the higher levels. - // The top level bindings (builtins) are skipped since they are added for us by initEnv() - if (env.up && se.up) { - mapStaticEnvBindings(st, *se.up, *env.up, vm); - - if (env.type == Env::HasWithAttrs) - { - // add 'with' bindings. - Bindings::iterator j = env.values[0]->attrs->begin(); - while (j != env.values[0]->attrs->end()) { - vm[st[j->name]] = j->value; - ++j; - } - } - else - { - // iterate through staticenv bindings and add them. - for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) - { - vm[st[iter->first]] = env.values[iter->second]; - } - } - } -} - -valmap * mapStaticEnvBindings(const SymbolTable &st,const StaticEnv &se, const Env &env) -{ - auto vm = new valmap(); +std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env) +{ + auto vm = std::make_unique(); mapStaticEnvBindings(st, se, env, *vm); return vm; } - -void EvalState::debugLastTrace(Error & e) const { - // 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. +void EvalState::debugLastTrace(Error & e) const +{ + // 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()) { - const DebugTrace &last = debugTraces.front(); + const DebugTrace & last = debugTraces.front(); debuggerHook(&e, last.env, last.expr); } } @@ -829,7 +817,7 @@ void EvalState::debugLastTrace(Error & e) const { of stack space, which is a real killer in the recursive evaluator. So here are some helper functions for throwing exceptions. */ -void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr &expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr) const { auto error = EvalError({ .msg = hintfmt(s), @@ -864,7 +852,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const } void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const std::string & s2, Env & env, Expr &expr) const + const std::string & s2, Env & env, Expr & expr) const { auto error = EvalError(ErrorInfo{ .msg = hintfmt(s, s2), @@ -890,7 +878,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri throw error; } -void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr &expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) const { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -900,7 +888,6 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri if (debuggerHook) debuggerHook(&error, env, expr); - throw error; } @@ -931,7 +918,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - const std::string & s3, Env & env, Expr &expr) const + const std::string & s3, Env & env, Expr & expr) const { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -944,7 +931,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri throw error; } -void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr &expr) const +void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) const { // p1 is where the error occurred; p2 is a position mentioned in the message. auto error = EvalError({ @@ -970,7 +957,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v throw error; } -void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr &expr) const +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) const { auto error = TypeError({ .msg = hintfmt(s, showType(v)), @@ -1086,27 +1073,31 @@ void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const e.addTrace(positions[pos], s, s2); } -std::unique_ptr makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, - std::optional pos, const char * s, const std::string & s2) +static std::unique_ptr makeDebugTraceStacker( + EvalState & state, + Expr & expr, + Env & env, + std::optional pos, + const char * s, + const std::string & s2) { - return std::unique_ptr( - new DebugTraceStacker( - state, - DebugTrace - {.pos = pos, - .expr = expr, - .env = env, - .hint = hintfmt(s, s2), - .is_error = false - })); + return std::make_unique(state, + DebugTrace { + .pos = pos, + .expr = expr, + .env = env, + .hint = hintfmt(s, s2), + .isError = false + }); } -DebugTraceStacker::DebugTraceStacker(EvalState &evalState, DebugTrace t) -:evalState(evalState), trace(t) +DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) + : evalState(evalState) + , trace(std::move(t)) { - evalState.debugTraces.push_front(t); + evalState.debugTraces.push_front(trace); if (evalState.debugStop && debuggerHook) - debuggerHook(0, t.env, t.expr); + debuggerHook(nullptr, trace.env, trace.expr); } void Value::mkString(std::string_view s) @@ -1303,15 +1294,14 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { - auto dts = - debuggerHook ? - makeDebugTraceStacker( - *this, - *e, - this->baseEnv, - (e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt), - "while evaluating the file '%1%':", resolvedPath) - : nullptr; + auto dts = debuggerHook + ? makeDebugTraceStacker( + *this, + *e, + this->baseEnv, + e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt, + "while evaluating the file '%1%':", resolvedPath) + : nullptr; // Enforce that 'flake.nix' is a direct attrset, not a // computation. @@ -1538,15 +1528,14 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - auto dts = - debuggerHook ? - makeDebugTraceStacker( - state, - *this, - env, - state.positions[pos2], - "while evaluating the attribute '%1%'", - showAttrPath(state, env, attrPath)) + auto dts = debuggerHook + ? makeDebugTraceStacker( + state, + *this, + env, + state.positions[pos2], + "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)) : nullptr; for (auto & i : attrPath) { @@ -1708,14 +1697,14 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { - auto dts = - debuggerHook ? - makeDebugTraceStacker(*this, *lambda.body, env2, positions[lambda.pos], - "while evaluating %s", - (lambda.name - ? concatStrings("'", symbols[lambda.name], "'") - : "anonymous lambda")) - : nullptr; + auto dts = debuggerHook + ? makeDebugTraceStacker( + *this, *lambda.body, env2, positions[lambda.pos], + "while evaluating %s", + lambda.name + ? concatStrings("'", symbols[lambda.name], "'") + : "anonymous lambda") + : nullptr; lambda.body->eval(*this, env2, vCur); } catch (Error & e) { @@ -2135,14 +2124,10 @@ void EvalState::forceValueDeep(Value & v) if (v.type() == nAttrs) { for (auto & i : *v.attrs) try { - - auto dts = - debuggerHook ? - // if the value is a thunk, we're evaling. otherwise no trace necessary. - (i.value->isThunk() ? - makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, positions[i.pos], - "while evaluating the attribute '%1%'", symbols[i.name]) - : nullptr) + // If the value is a thunk, we're evaling. Otherwise no trace necessary. + auto dts = debuggerHook && i.value->isThunk() + ? makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, positions[i.pos], + "while evaluating the attribute '%1%'", symbols[i.name]) : nullptr; recurse(*i.value); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 2e7df13fc..f3852e248 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,8 +25,8 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); -void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env); -void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl = 0); +void printEnvBindings(const SymbolTable & st, const Expr & expr, const Env & env); +void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, int lvl = 0); struct PrimOp { @@ -47,7 +47,7 @@ struct Env Value * values[0]; }; -valmap * mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env); +std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env); void copyContext(const Value & v, PathSet & context); @@ -75,10 +75,10 @@ std::shared_ptr makeRegexCache(); struct DebugTrace { std::optional pos; - const Expr &expr; - const Env &env; + const Expr & expr; + const Env & env; hintformat hint; - bool is_error; + bool isError; }; class EvalState @@ -297,7 +297,7 @@ public: void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, - Env & env, Expr &expr) const; + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) const; @@ -508,16 +508,15 @@ private: friend struct Value; }; -class DebugTraceStacker { - public: - DebugTraceStacker(EvalState &evalState, DebugTrace t); - ~DebugTraceStacker() - { - // assert(evalState.debugTraces.front() == trace); - evalState.debugTraces.pop_front(); - } - EvalState &evalState; - DebugTrace trace; +struct DebugTraceStacker { + DebugTraceStacker(EvalState & evalState, DebugTrace t); + ~DebugTraceStacker() + { + // assert(evalState.debugTraces.front() == trace); + evalState.debugTraces.pop_front(); + } + EvalState & evalState; + DebugTrace trace; }; /* Return a string representing the type of the value `v'. */ diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 5624c4780..213cf93fa 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -296,39 +296,38 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath) /* Computing levels/displacements for variables. */ -void Expr::bindVars(const EvalState & es, const std::shared_ptr &env) +void Expr::bindVars(const EvalState & es, const std::shared_ptr & env) { abort(); } -void ExprInt::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprInt::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; -} + staticEnv = env;} -void ExprFloat::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprFloat::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; } -void ExprString::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprString::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; } -void ExprPath::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprPath::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; } -void ExprVar::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprVar::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; /* Check whether the variable appears in the environment. If so, set its level and displacement. */ @@ -353,20 +352,18 @@ void ExprVar::bindVars(const EvalState & es, const std::shared_ptrlevel = withLevel; } -void ExprSelect::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprSelect::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; e->bindVars(es, env); if (def) def->bindVars(es, env); @@ -375,10 +372,10 @@ void ExprSelect::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); } -void ExprOpHasAttr::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprOpHasAttr::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; e->bindVars(es, env); for (auto & i : attrPath) @@ -386,13 +383,13 @@ void ExprOpHasAttr::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); } -void ExprAttrs::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprAttrs::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; if (recursive) { - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get(), recursive ? attrs.size() : 0)); + auto newEnv = std::make_shared(false, env.get(), recursive ? attrs.size() : 0); Displacement displ = 0; for (auto & i : attrs) @@ -419,25 +416,24 @@ void ExprAttrs::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprList::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; for (auto & i : elems) i->bindVars(es, env); } -void ExprLambda::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprLambda::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; - auto newEnv = std::shared_ptr( - new StaticEnv( - false, env.get(), - (hasFormals() ? formals->formals.size() : 0) + - (!arg ? 0 : 1))); + auto newEnv = std::make_shared( + false, env.get(), + (hasFormals() ? formals->formals.size() : 0) + + (!arg ? 0 : 1)); Displacement displ = 0; @@ -456,22 +452,22 @@ void ExprLambda::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, newEnv); } -void ExprCall::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprCall::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; fun->bindVars(es, env); for (auto e : args) e->bindVars(es, env); } -void ExprLet::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprLet::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; - auto newEnv = std::shared_ptr(new StaticEnv(false, env.get(), attrs->attrs.size())); + auto newEnv = std::make_shared(false, env.get(), attrs->attrs.size()); Displacement displ = 0; for (auto & i : attrs->attrs) @@ -485,10 +481,10 @@ void ExprLet::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, newEnv); } -void ExprWith::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprWith::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous @@ -503,54 +499,53 @@ void ExprWith::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); - auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); + auto newEnv = std::make_shared(true, env.get()); body->bindVars(es, newEnv); } -void ExprIf::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprIf::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; cond->bindVars(es, env); then->bindVars(es, env); else_->bindVars(es, env); } -void ExprAssert::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprAssert::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; cond->bindVars(es, env); body->bindVars(es, env); } -void ExprOpNot::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprOpNot::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; e->bindVars(es, env); } -void ExprConcatStrings::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprConcatStrings::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; + staticEnv = env; for (auto & i : *this->es) i.second->bindVars(es, env); } -void ExprPos::bindVars(const EvalState & es, const std::shared_ptr &env) +void ExprPos::bindVars(const EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticenv = env; - + staticEnv = env; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 82fff6dcf..c4a509f31 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -148,8 +148,8 @@ struct Expr virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); - std::shared_ptr staticenv; - virtual const PosIdx getPos() const = 0; + std::shared_ptr staticEnv; + virtual PosIdx getPos() const { return noPos; } }; #define COMMON_METHODS \ @@ -163,7 +163,6 @@ struct ExprInt : Expr Value v; ExprInt(NixInt n) : n(n) { v.mkInt(n); }; Value * maybeThunk(EvalState & state, Env & env); - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -173,7 +172,6 @@ struct ExprFloat : Expr Value v; ExprFloat(NixFloat nf) : nf(nf) { v.mkFloat(nf); }; Value * maybeThunk(EvalState & state, Env & env); - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -183,7 +181,6 @@ struct ExprString : Expr Value v; ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); }; Value * maybeThunk(EvalState & state, Env & env); - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -193,7 +190,6 @@ struct ExprPath : Expr Value v; ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); }; Value * maybeThunk(EvalState & state, Env & env); - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -221,7 +217,7 @@ struct ExprVar : Expr ExprVar(Symbol name) : name(name) { }; ExprVar(const PosIdx & pos, Symbol name) : pos(pos), name(name) { }; Value * maybeThunk(EvalState & state, Env & env); - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -232,7 +228,7 @@ struct ExprSelect : Expr AttrPath attrPath; ExprSelect(const PosIdx & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; ExprSelect(const PosIdx & pos, Expr * e, Symbol name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -241,7 +237,7 @@ struct ExprOpHasAttr : Expr Expr * e; AttrPath attrPath; ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { }; - const PosIdx getPos() const { return e->getPos(); } + PosIdx getPos() const override { return e->getPos(); } COMMON_METHODS }; @@ -270,7 +266,7 @@ struct ExprAttrs : Expr DynamicAttrDefs dynamicAttrs; ExprAttrs(const PosIdx &pos) : recursive(false), pos(pos) { }; ExprAttrs() : recursive(false) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -278,13 +274,12 @@ struct ExprList : Expr { std::vector elems; ExprList() { }; - const PosIdx getPos() const - { if (elems.empty()) - return noPos; - else - return elems.front()->getPos(); - } COMMON_METHODS + + PosIdx getPos() const override + { + return elems.empty() ? noPos : elems.front()->getPos(); + } }; struct Formal @@ -337,7 +332,7 @@ struct ExprLambda : Expr void setName(Symbol name); std::string showNamePos(const EvalState & state) const; inline bool hasFormals() const { return formals != nullptr; } - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -349,7 +344,7 @@ struct ExprCall : Expr ExprCall(const PosIdx & pos, Expr * fun, std::vector && args) : fun(fun), args(args), pos(pos) { } - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -358,7 +353,6 @@ struct ExprLet : Expr ExprAttrs * attrs; Expr * body; ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { }; - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -368,7 +362,7 @@ struct ExprWith : Expr Expr * attrs, * body; size_t prevWith; ExprWith(const PosIdx & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -377,7 +371,7 @@ struct ExprIf : Expr PosIdx pos; Expr * cond, * then, * else_; ExprIf(const PosIdx & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -386,7 +380,7 @@ struct ExprAssert : Expr PosIdx pos; Expr * cond, * body; ExprAssert(const PosIdx & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -394,7 +388,6 @@ struct ExprOpNot : Expr { Expr * e; ExprOpNot(Expr * e) : e(e) { }; - const PosIdx getPos() const { return noPos; } COMMON_METHODS }; @@ -414,7 +407,7 @@ struct ExprOpNot : Expr e1->bindVars(es, env); e2->bindVars(es, env); \ } \ void eval(EvalState & state, Env & env, Value & v); \ - const PosIdx getPos() const { return pos; } \ + PosIdx getPos() const override { return pos; } \ }; MakeBinOp(ExprOpEq, "==") @@ -432,7 +425,7 @@ struct ExprConcatStrings : Expr std::vector > * es; ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector > * es) : pos(pos), forceString(forceString), es(es) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -440,7 +433,7 @@ struct ExprPos : Expr { PosIdx pos; ExprPos(const PosIdx & pos) : pos(pos) { }; - const PosIdx getPos() const { return pos; } + PosIdx getPos() const override { return pos; } COMMON_METHODS }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 41476abe3..27976dc74 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -227,7 +227,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v Env * env = &state.allocEnv(vScope->attrs->size()); env->up = &state.baseEnv; - auto staticEnv = std::shared_ptr(new StaticEnv(false, state.staticBaseEnv.get(), vScope->attrs->size())); + auto staticEnv = std::make_shared(false, state.staticBaseEnv.get(), vScope->attrs->size()); unsigned int displ = 0; for (auto & attr : *vScope->attrs) { @@ -329,8 +329,7 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu std::string sym(state.forceStringNoCtx(*args[1], pos)); void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); - if (!handle) - { + if (!handle) { auto e = EvalError("could not open '%1%': %2%", path, dlerror()); state.debugLastTrace(e); throw e; @@ -340,14 +339,11 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str()); if(!func) { char *message = dlerror(); - if (message) - { + if (message) { auto e = EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message); state.debugLastTrace(e); throw e; - } - else - { + } else { auto e = EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path); state.debugLastTrace(e); @@ -573,8 +569,7 @@ struct CompareValues return v1->fpoint < v2->integer; if (v1->type() == nInt && v2->type() == nFloat) return v1->integer < v2->fpoint; - if (v1->type() != v2->type()) - { + if (v1->type() != v2->type()) { auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); state.debugLastTrace(e); throw e; @@ -599,12 +594,11 @@ struct CompareValues return (*this)(v1->listElems()[i], v2->listElems()[i]); } } - default: - { - auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - state.debugLastTrace(e); - throw e; - } + default: { + auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); + state.debugLastTrace(e); + throw e; + } } } }; @@ -703,8 +697,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a Bindings::iterator key = e->attrs->find(state.sKey); - if (key == e->attrs->end()) - { + if (key == e->attrs->end()) { auto e = EvalError({ .msg = hintfmt("attribute 'key' required"), .errPos = state.positions[pos] @@ -772,7 +765,7 @@ static RegisterPrimOp primop_break({ .name = "break", .args = {"v"}, .doc = R"( - In debug mode, pause Nix expression evaluation and enter the repl. + In debug mode (enabled using `--debugger`), pause Nix expression evaluation and enter the REPL. )", .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { @@ -783,16 +776,15 @@ static RegisterPrimOp primop_break({ .msg = hintfmt("breakpoint reached; value was %1%", s), .errPos = state.positions[pos], }); - if (debuggerHook && !state.debugTraces.empty()) - { - auto &dt = state.debugTraces.front(); + if (debuggerHook && !state.debugTraces.empty()) { + auto & dt = state.debugTraces.front(); debuggerHook(&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 from debugger"), + .msg = hintfmt("quit the debugger"), .errPos = state.positions[noPos], }); } @@ -903,7 +895,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va { auto attrs = state.buildBindings(2); auto saveDebuggerHook = debuggerHook; - debuggerHook = 0; + debuggerHook = nullptr; try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); -- cgit v1.2.3 From 58645a78ab7c1654c513a1121511ee01551630bc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 5 May 2022 12:37:43 +0200 Subject: builtins.break: Return argument when debugging is not enabled --- src/libexpr/primops.cc | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 27976dc74..1871d4b9b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -766,32 +766,35 @@ static RegisterPrimOp primop_break({ .args = {"v"}, .doc = R"( In debug mode (enabled using `--debugger`), pause Nix expression evaluation and enter the REPL. + Otherwise, return the argument `v`. )", .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { - PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); - auto error = Error(ErrorInfo{ - .level = lvlInfo, - .msg = hintfmt("breakpoint reached; value was %1%", s), - .errPos = state.positions[pos], - }); if (debuggerHook && !state.debugTraces.empty()) { + PathSet context; + auto s = state.coerceToString(pos, *args[0], context).toOwned(); + + auto error = Error(ErrorInfo { + .level = lvlInfo, + .msg = hintfmt("breakpoint reached; value was %1%", s), + .errPos = state.positions[pos], + }); + auto & dt = state.debugTraces.front(); debuggerHook(&error, dt.env, dt.expr); if (state.debugQuit) { - // if the user elects to quit the repl, throw an exception. + // If the user elects to quit the repl, throw an exception. throw Error(ErrorInfo{ .level = lvlInfo, .msg = hintfmt("quit the debugger"), .errPos = state.positions[noPos], }); } - - // returning the value we were passed. - v = *args[0]; } + + // Return the value we were passed. + v = *args[0]; } }); -- cgit v1.2.3 From ce304d01544c799500bfffe48b7b0e85da888cd6 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 5 May 2022 15:24:57 -0600 Subject: rename debug commands to be more gdb-like; hide them except in debug mode --- src/libcmd/repl.cc | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index c35f29a2f..37e454b21 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -484,30 +484,38 @@ bool NixRepl::processLine(std::string line) << " :p Evaluate and print expression recursively\n" << " :q Exit nix-repl\n" << " :r Reload all files\n" - << " :s Build dependencies of derivation, then start nix-shell\n" + << " :sh Build dependencies of derivation, then start nix-shell\n" << " :t Describe result of evaluation\n" << " :u Build derivation, then start nix-shell\n" << " :doc Show documentation of a builtin function\n" << " :log Show logs for a derivation\n" - << " :st [bool] Enable, disable or toggle showing traces for errors\n" - << " :d Debug mode commands\n" - << " :d stack Show trace stack\n" - << " :d env Show env stack\n" - << " :d show Show current trace\n" - << " :d show Change to another trace in the stack\n" - << " :d go Go until end of program, exception, or builtins.break().\n" - << " :d step Go one step\n" + << " :te [bool] Enable, disable or toggle showing traces for errors\n" ; + if (debuggerHook) { + std::cout + << "\n" + << " Debug mode commands\n" + << " :env Show env stack\n" + << " :bt Show trace stack\n" + << " :st Show current trace\n" + << " :st Change to another trace in the stack\n" + << " :c Go until end of program, exception, or builtins.break().\n" + << " :s Go one step\n" + ; + } } - else if (command == ":d" || command == ":debug") { - if (arg == "stack") { + else if (debuggerHook) { + + if (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 (arg == "env") { + } + + else if (command == ":env") { for (const auto & [idx, i] : enumerate(state->debugTraces)) { if (idx == debugTraceIndex) { printEnvBindings(state->symbols, i.expr, i.env); @@ -515,10 +523,11 @@ bool NixRepl::processLine(std::string line) } } } - else if (arg.compare(0, 4, "show") == 0) { + + else if (command == ":st") { try { // change the DebugTrace index. - debugTraceIndex = stoi(arg.substr(4)); + debugTraceIndex = stoi(arg); } catch (...) { } for (const auto & [idx, i] : enumerate(state->debugTraces)) { @@ -532,12 +541,14 @@ bool NixRepl::processLine(std::string line) } } } - else if (arg == "step") { + + else if (command == ":s" || command == ":step") { // set flag to stop at next DebugTrace; exit repl. state->debugStop = true; return false; } - else if (arg == "go") { + + else if (command == ":c" || command == ":continue") { // set flag to run to next breakpoint or end of program; exit repl. state->debugStop = false; return false; @@ -613,7 +624,7 @@ bool NixRepl::processLine(std::string line) runNix("nix-shell", {state->store->printStorePath(drvPath)}); } - else if (command == ":b" || command == ":bl" || command == ":i" || command == ":s" || command == ":log") { + else if (command == ":b" || command == ":bl" || command == ":i" || command == ":sh" || command == ":log") { Value v; evalString(arg, v); StorePath drvPath = getDerivationPath(v); @@ -703,7 +714,7 @@ bool NixRepl::processLine(std::string line) throw Error("value does not have documentation"); } - else if (command == ":st" || command == ":show-trace") { + else if (command == ":te" || command == ":trace-enable") { if (arg == "false" || (arg == "" && loggerSettings.showTrace)) { std::cout << "not showing error traces\n"; loggerSettings.showTrace = false; -- cgit v1.2.3 From 09fcfee9252920b170e031b397709368a305bbc3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 5 May 2022 15:34:59 -0600 Subject: don't print the 'break' argument --- src/libexpr/primops.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 1871d4b9b..5ee917f19 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -771,12 +771,9 @@ static RegisterPrimOp primop_break({ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { if (debuggerHook && !state.debugTraces.empty()) { - PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); - auto error = Error(ErrorInfo { .level = lvlInfo, - .msg = hintfmt("breakpoint reached; value was %1%", s), + .msg = hintfmt("breakpoint reached"), .errPos = state.positions[pos], }); -- cgit v1.2.3 From f400c5466d45d342709483799d9b9c2ac24cf967 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 5 May 2022 15:43:23 -0600 Subject: rename valmap --- src/libexpr/eval.cc | 6 +++--- src/libexpr/eval.hh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index ca0eec6e3..659b97658 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -772,7 +772,7 @@ void printEnvBindings(const SymbolTable & st, const Expr & expr, const Env & env printEnvBindings(st, *expr.staticEnv.get(), env, 0); } -void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, valmap & vm) +void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, ValMap & vm) { // add bindings for the next level up first, so that the bindings for this level // override the higher levels. @@ -795,9 +795,9 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En } } -std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env) +std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env) { - auto vm = std::make_unique(); + auto vm = std::make_unique(); mapStaticEnvBindings(st, se, env, *vm); return vm; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index f3852e248..22f034e27 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -37,7 +37,7 @@ struct PrimOp const char * doc = nullptr; }; -typedef std::map valmap; +typedef std::map ValMap; struct Env { @@ -47,7 +47,7 @@ struct Env Value * values[0]; }; -std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env); +std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env); void copyContext(const Value & v, PathSet & context); -- cgit v1.2.3 From dea998b2f29eaad67b3003550fcfdf9d31045d4c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 5 May 2022 20:26:10 -0600 Subject: traceable_allocator --- src/libcmd/command.hh | 2 +- src/libcmd/repl.cc | 2 +- src/libexpr/eval.hh | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 354877bc5..454197b1c 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -276,6 +276,6 @@ void printClosureDiff( void runRepl( ref evalState, const Expr & expr, - const std::map & extraEnv); + const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 37e454b21..950195572 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -1016,7 +1016,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, const Expr &expr, - const std::map & extraEnv) + const ValMap & extraEnv) { auto repl = std::make_unique(evalState); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 22f034e27..65b1466ea 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -37,7 +37,11 @@ struct PrimOp const char * doc = nullptr; }; -typedef std::map ValMap; +#if HAVE_BOEHMGC + typedef std::map, traceable_allocator > > ValMap; +#else + typedef std::map ValMap; +#endif struct Env { -- cgit v1.2.3 From 99d69ac23faf06598ca0aabd61d22a575db848df Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 5 May 2022 21:23:03 -0600 Subject: fix repl bug --- src/libcmd/repl.cc | 75 ++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 950195572..8f0b1bfc0 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -506,53 +506,50 @@ bool NixRepl::processLine(std::string line) } - else if (debuggerHook) { - - if (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 == ":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 (command == ":env") { - for (const auto & [idx, i] : enumerate(state->debugTraces)) { - if (idx == debugTraceIndex) { - printEnvBindings(state->symbols, i.expr, i.env); - break; - } + else if (debuggerHook && (command == ":env")) { + for (const auto & [idx, i] : enumerate(state->debugTraces)) { + if (idx == debugTraceIndex) { + printEnvBindings(state->symbols, i.expr, i.env); + break; } } + } - else if (command == ":st") { - try { - // change the DebugTrace index. - debugTraceIndex = stoi(arg); - } catch (...) { } - - for (const auto & [idx, i] : enumerate(state->debugTraces)) { - if (idx == debugTraceIndex) { - std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, state->positions, i); - std::cout << std::endl; - printEnvBindings(state->symbols, i.expr, i.env); - loadDebugTraceEnv(i); - break; - } - } + else if (debuggerHook && (command == ":st")) { + try { + // change the DebugTrace index. + debugTraceIndex = stoi(arg); + } catch (...) { } + + for (const auto & [idx, i] : enumerate(state->debugTraces)) { + if (idx == debugTraceIndex) { + std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + showDebugTrace(std::cout, state->positions, i); + std::cout << std::endl; + printEnvBindings(state->symbols, i.expr, i.env); + loadDebugTraceEnv(i); + break; + } } + } - else if (command == ":s" || command == ":step") { - // set flag to stop at next DebugTrace; exit repl. - state->debugStop = true; - return false; - } + else if (debuggerHook && (command == ":s" || command == ":step")) { + // set flag to stop at next DebugTrace; exit repl. + state->debugStop = true; + return false; + } - else if (command == ":c" || command == ":continue") { - // set flag to run to next breakpoint or end of program; exit repl. - state->debugStop = false; - return false; - } + else if (debuggerHook && (command == ":c" || command == ":continue")) { + // set flag to run to next breakpoint or end of program; exit repl. + state->debugStop = false; + return false; } else if (command == ":a" || command == ":add") { -- cgit v1.2.3 From 2c9fafdc9e43f6da39c289888dedbbbf0ea0b208 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 6 May 2022 08:47:21 -0600 Subject: trying debugThrow --- src/libexpr/eval-cache.cc | 25 ++----- src/libexpr/eval.cc | 103 +++++++++----------------- src/libexpr/eval.hh | 6 +- src/libexpr/parser.y | 3 +- src/libexpr/primops.cc | 153 +++++++++++++++------------------------ src/libexpr/primops/fetchTree.cc | 27 +++---- src/libexpr/value-to-json.cc | 5 +- 7 files changed, 115 insertions(+), 207 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index e9d9d02a4..af213a484 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -556,8 +556,7 @@ std::string AttrCursor::getString() } else { auto e = TypeError("'%s' is not a string", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } } } @@ -567,8 +566,7 @@ std::string AttrCursor::getString() if (v.type() != nString && v.type() != nPath) { auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } return v.type() == nString ? v.string.s : v.path; @@ -595,8 +593,7 @@ string_t AttrCursor::getStringWithContext() } else { auto e = TypeError("'%s' is not a string", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } } } @@ -610,9 +607,7 @@ string_t AttrCursor::getStringWithContext() else { auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); - root->state.debugLastTrace(e); - throw e; - return {v.path, {}}; // should never execute + root->state.debugThrowLastTrace(e); } } @@ -628,8 +623,7 @@ bool AttrCursor::getBool() } else { auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } } } @@ -639,8 +633,7 @@ bool AttrCursor::getBool() if (v.type() != nBool) { auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } return v.boolean; @@ -691,8 +684,7 @@ std::vector AttrCursor::getAttrs() } else { auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } } } @@ -702,8 +694,7 @@ std::vector AttrCursor::getAttrs() if (v.type() != nAttrs) { auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); - root->state.debugLastTrace(e); - throw e; + root->state.debugThrowLastTrace(e); } std::vector attrs; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 659b97658..54872669a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -802,8 +802,9 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati return vm; } -void EvalState::debugLastTrace(Error & e) const +void EvalState::debugThrowLastTrace(Error & e) const { + std::cout << "debugThrowLastTrace(Error & e) const" << (debuggerHook == nullptr) << std::endl; // 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. @@ -811,6 +812,18 @@ void EvalState::debugLastTrace(Error & e) const const DebugTrace & last = debugTraces.front(); debuggerHook(&e, last.env, last.expr); } + + throw e; +} + + +void EvalState::debugThrow(const Error &error, const Env & env, const Expr & expr) const +{ + std::cout << "debugThrow" << (debuggerHook == nullptr) << std::endl; + if (debuggerHook) + debuggerHook(&error, env, expr); + + throw error; } /* Every "format" object (even temporary) takes up a few hundred bytes @@ -824,10 +837,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s) const @@ -837,18 +847,14 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s) const .errPos = positions[pos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwEvalError(const char * s, const std::string & s2) const { auto error = EvalError(s, s2); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, @@ -860,10 +866,7 @@ void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions .suggestions = suggestions, }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const @@ -873,9 +876,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) const @@ -885,10 +886,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwEvalError(const char * s, const std::string & s2, @@ -899,9 +897,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2, .errPos = positions[noPos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, @@ -912,9 +908,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, @@ -925,10 +919,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) const @@ -939,10 +930,7 @@ void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym .errPos = positions[p1] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const @@ -952,9 +940,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v .errPos = positions[pos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) const @@ -964,10 +950,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s) const @@ -977,9 +960,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s) const .errPos = positions[pos] }); - debugLastTrace(error); - - throw error; + debugThrowLastTrace(error); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, @@ -990,10 +971,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambd .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, @@ -1005,10 +983,7 @@ void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions .suggestions = suggestions, }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) const @@ -1018,10 +993,7 @@ void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr .errPos = positions[expr.getPos()], }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const @@ -1031,10 +1003,7 @@ void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std: .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const @@ -1044,10 +1013,7 @@ void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const s .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const @@ -1057,10 +1023,7 @@ void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, cons .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; + debugThrow(error, env, expr); } void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2) const diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 65b1466ea..add104a84 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -127,7 +127,11 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; - void debugLastTrace(Error & e) const; + + [[gnu::noinline, gnu::noreturn]] + void debugThrow(const Error &error, const Env & env, const Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void debugThrowLastTrace(Error & e) const; private: SrcToStore srcToStore; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 8edafdd57..b960cd8df 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -789,8 +789,7 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c path), .errPos = positions[pos] }); - debugLastTrace(e); - throw e; + debugThrowLastTrace(e); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 5ee917f19..34471dd8f 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -48,8 +48,7 @@ StringMap EvalState::realiseContext(const PathSet & context) if (!store->isValidPath(ctx)) { auto e = InvalidPathError(store->printStorePath(ctx)); - debugLastTrace(e); - throw e; + debugThrowLastTrace(e); } if (!outputName.empty() && ctx.isDerivation()) { drvs.push_back({ctx, {outputName}}); @@ -65,8 +64,7 @@ StringMap EvalState::realiseContext(const PathSet & context) auto e = Error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", store->printStorePath(drvs.begin()->drvPath)); - debugLastTrace(e); - throw e; + debugThrowLastTrace(e); } /* Build/substitute the context. */ @@ -82,8 +80,7 @@ StringMap EvalState::realiseContext(const PathSet & context) if (!outputPath) { auto e = Error("derivation '%s' does not have an output named '%s'", store->printStorePath(drvPath), outputName); - debugLastTrace(e); - throw e; + debugThrowLastTrace(e); } res.insert_or_assign( downstreamPlaceholder(*store, drvPath, outputName), @@ -331,8 +328,7 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); if (!handle) { auto e = EvalError("could not open '%1%': %2%", path, dlerror()); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } dlerror(); @@ -341,13 +337,11 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu char *message = dlerror(); if (message) { auto e = EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } else { auto e = EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } @@ -368,8 +362,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) .msg = hintfmt("at least one argument to 'exec' required"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } PathSet context; auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); @@ -385,8 +378,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) program, e.path), .errPos = state.positions[pos] }); - state.debugLastTrace(ee); - throw ee; + state.debugThrowLastTrace(ee); } auto output = runProgram(program, true, commandArgs); @@ -571,8 +563,7 @@ struct CompareValues return v1->integer < v2->fpoint; if (v1->type() != v2->type()) { auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } switch (v1->type()) { case nInt: @@ -596,8 +587,7 @@ struct CompareValues } default: { auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } } @@ -632,8 +622,7 @@ static Bindings::iterator getAttr( .msg = errorMsg, .errPos = state.positions[pos], }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } else { auto e = TypeError({ .msg = errorMsg, @@ -643,8 +632,7 @@ static Bindings::iterator getAttr( // Adding another trace for the function name to make it clear // which call received wrong arguments. e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", funcName)); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } @@ -702,8 +690,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a .msg = hintfmt("attribute 'key' required"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } state.forceValue(*key->value, pos); @@ -807,8 +794,7 @@ static RegisterPrimOp primop_abort({ auto s = state.coerceToString(pos, *args[0], context).toOwned(); { auto e = Abort("evaluation aborted with the following error message: '%1%'", s); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } }); @@ -828,8 +814,7 @@ static RegisterPrimOp primop_throw({ PathSet context; auto s = state.coerceToString(pos, *args[0], context).toOwned(); auto e = ThrownError(s); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } }); @@ -893,6 +878,7 @@ static RegisterPrimOp primop_floor({ * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { + std::cout << "priatraynasdf0" << std::endl; auto attrs = state.buildBindings(2); auto saveDebuggerHook = debuggerHook; debuggerHook = nullptr; @@ -900,7 +886,15 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); attrs.alloc("success").mkBool(true); + std::cout << "priatraynasdf0000" << std::endl; } catch (AssertionError & e) { + std::cout << "priatraynasdf" << std::endl; + + attrs.alloc(state.sValue).mkBool(false); + attrs.alloc("success").mkBool(false); + } catch (Error & e) { + std::cout << "priatraERASERynasdf" << std::endl; + attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } @@ -1092,8 +1086,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } }; @@ -1106,8 +1099,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("duplicate derivation output '%1%'", j), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } /* !!! Check whether j is a valid attribute name. */ @@ -1120,8 +1112,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("invalid derivation output name 'drv'" ), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } outputs.insert(j); } @@ -1131,8 +1122,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("derivation cannot have an empty set of outputs"), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } }; @@ -1263,8 +1253,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("required attribute 'builder' missing"), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } if (drv.platform == "") @@ -1273,8 +1262,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("required attribute 'system' missing"), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } /* Check whether the derivation name is valid. */ @@ -1284,8 +1272,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } if (outputHash) { @@ -1299,8 +1286,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), .errPos = state.positions[posDrvName] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } auto h = newHashAllowEmpty(*outputHash, parseHashTypeOpt(outputHashAlgo)); @@ -1474,8 +1460,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, .msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } PathSet context; @@ -1490,8 +1475,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, .msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } auto path2 = state.store->toStorePath(path).first; if (!settings.readOnlyMode) @@ -1597,8 +1581,7 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V if (s.find((char) 0) != std::string::npos) { auto e = Error("the contents of the file '%1%' cannot be represented as a Nix string", path); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } StorePathSet refs; if (state.store->isInStore(path)) { @@ -1655,8 +1638,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), .errPos = state.positions[pos] }); - state.debugLastTrace(ee); - throw ee; + state.debugThrowLastTrace(ee); } @@ -1685,8 +1667,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, V .msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } auto path = realisePath(state, pos, *args[1]); @@ -1932,8 +1913,7 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Val name, path), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } refs.insert(state.store->parseStorePath(path)); } @@ -2094,8 +2074,7 @@ static void addPath( if (expectedHash && expectedStorePath != dstPath) { auto e = Error("store path mismatch in (possibly filtered) path added from '%s'", path); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } state.allowAndSetStorePathString(dstPath, v); } else @@ -2121,8 +2100,7 @@ static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * arg showType(*args[0])), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); @@ -2212,8 +2190,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value .msg = hintfmt("unsupported argument '%1%' to 'addPath'", state.symbols[attr.name]), .errPos = state.positions[attr.pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } if (path.empty()) @@ -2222,8 +2199,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value .msg = hintfmt("'path' required"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } if (name.empty()) name = baseNameOf(path); @@ -2601,8 +2577,7 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg .msg = hintfmt("'functionArgs' requires a function"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } if (!args[0]->lambda.fun->hasFormals()) { @@ -2691,8 +2666,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg attrsSeen[attr.name].first++; } catch (TypeError & e) { e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", "zipAttrsWith")); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } @@ -2784,8 +2758,7 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val .msg = hintfmt("list index %1% is out of bounds", n), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } state.forceValue(*list.listElems()[n], pos); v = *list.listElems()[n]; @@ -2836,8 +2809,7 @@ static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value .msg = hintfmt("'tail' called on an empty list"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } state.mkList(v, args[0]->listSize() - 1); @@ -3078,8 +3050,7 @@ static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Va .msg = hintfmt("cannot create list of size %1%", len), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } state.mkList(v, len); @@ -3289,8 +3260,7 @@ static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args, state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos))); } catch (TypeError &e) { e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", "concatMap")); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } len += lists[n].listSize(); } @@ -3390,8 +3360,7 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value .msg = hintfmt("division by zero"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } if (args[0]->type() == nFloat || args[1]->type() == nFloat) { @@ -3406,8 +3375,7 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value .msg = hintfmt("overflow in integer division"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } v.mkInt(i1 / i2); @@ -3541,8 +3509,7 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, .msg = hintfmt("negative start position in 'substring'"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context); @@ -3596,8 +3563,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args, .msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } PathSet context; // discarded @@ -3672,15 +3638,13 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } else { auto e = EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } } @@ -3781,15 +3745,13 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } else { auto e = EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } } @@ -3871,8 +3833,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } std::vector from; diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 55fe7da24..e4fa3c5f9 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -113,8 +113,7 @@ static void fetchTree( .msg = hintfmt("unexpected attribute 'type'"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } type = state.forceStringNoCtx(*aType->value, aType->pos); } else if (!type) @@ -123,8 +122,7 @@ static void fetchTree( .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } attrs.emplace("type", type.value()); @@ -149,8 +147,7 @@ static void fetchTree( { auto e = TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", state.symbols[attr.name], showType(*attr.value)); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } @@ -161,8 +158,7 @@ static void fetchTree( .msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } input = fetchers::Input::fromAttrs(std::move(attrs)); @@ -185,8 +181,7 @@ static void fetchTree( if (evalSettings.pureEval && !input.isLocked()) { auto e = EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos]); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } auto [tree, input2] = input.fetch(state.store); @@ -231,8 +226,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v .msg = hintfmt("unsupported argument '%s' to '%s'", n, who), .errPos = state.positions[attr.pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } @@ -242,8 +236,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v .msg = hintfmt("'url' argument required"), .errPos = state.positions[pos] }); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } else url = state.forceStringNoCtx(*args[0], pos); @@ -258,8 +251,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v if (evalSettings.pureEval && !expectedHash) { auto e = EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } // early exit if pinned and already in the store @@ -290,8 +282,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v { auto e = EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } } diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 34f3a34c8..6a95e0414 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -85,7 +85,7 @@ void printValueAsJSON(EvalState & state, bool strict, .errPos = state.positions[v.determinePos(pos)] }); e.addTrace(state.positions[pos], hintfmt("message for the trace")); - state.debugLastTrace(e); + state.debugThrowLastTrace(e); throw e; } } @@ -101,8 +101,7 @@ void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const { auto e = TypeError("cannot convert %1% to JSON", showType()); - state.debugLastTrace(e); - throw e; + state.debugThrowLastTrace(e); } -- cgit v1.2.3 From fc66f48812383dad59ebdbabdd29bec34ed31921 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 6 May 2022 09:09:49 -0600 Subject: debugError() --- src/libexpr/eval.cc | 43 +++++++++++++++++++------------------------ src/libexpr/eval.hh | 2 ++ 2 files changed, 21 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 659b97658..c5e33a279 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -813,6 +813,13 @@ void EvalState::debugLastTrace(Error & e) const } } +void debugError(Error * e, Env & env, Expr & expr) +{ + if (debuggerHook) + debuggerHook(e, env, expr); +} + + /* 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 @@ -824,8 +831,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -860,8 +866,7 @@ void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions .suggestions = suggestions, }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -885,8 +890,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -925,8 +929,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -939,8 +942,7 @@ void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym .errPos = positions[p1] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -964,8 +966,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -990,8 +991,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambd .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -1005,8 +1005,7 @@ void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions .suggestions = suggestions, }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -1018,8 +1017,7 @@ void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr .errPos = positions[expr.getPos()], }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -1031,8 +1029,7 @@ void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std: .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -1044,8 +1041,7 @@ void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const s .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } @@ -1057,8 +1053,7 @@ void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, cons .errPos = positions[pos] }); - if (debuggerHook) - debuggerHook(&error, env, expr); + debugError(&error, env, expr); throw error; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 65b1466ea..db78e29b5 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -85,6 +85,8 @@ struct DebugTrace { bool isError; }; +void debugError(Error * e, Env & env, Expr & expr); + class EvalState { public: -- cgit v1.2.3 From 1ea13084c9aac84e7877f9051f656eb5ea519d8a Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 12 May 2022 13:59:58 -0600 Subject: template-ize debugThrow --- src/libexpr/eval.cc | 24 ------------------------ src/libexpr/eval.hh | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 54872669a..8ba3688d8 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -802,30 +802,6 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati return vm; } -void EvalState::debugThrowLastTrace(Error & e) const -{ - std::cout << "debugThrowLastTrace(Error & e) const" << (debuggerHook == nullptr) << std::endl; - // 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()) { - const DebugTrace & last = debugTraces.front(); - debuggerHook(&e, last.env, last.expr); - } - - throw e; -} - - -void EvalState::debugThrow(const Error &error, const Env & env, const Expr & expr) const -{ - std::cout << "debugThrow" << (debuggerHook == nullptr) << std::endl; - if (debuggerHook) - debuggerHook(&error, env, expr); - - throw error; -} - /* 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 diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index add104a84..1e728002a 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -128,10 +128,30 @@ public: bool debugQuit; std::list debugTraces; + template [[gnu::noinline, gnu::noreturn]] - void debugThrow(const Error &error, const Env & env, const Expr & expr) const; + void debugThrow(const E &error, const Env & env, const Expr & expr) const + { + if (debuggerHook) + debuggerHook(&error, env, expr); + + throw error; + } + + template [[gnu::noinline, gnu::noreturn]] - void debugThrowLastTrace(Error & e) const; + void debugThrowLastTrace(E & e) const + { + // 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()) { + const DebugTrace & last = debugTraces.front(); + debuggerHook(&e, last.env, last.expr); + } + + throw e; + } private: SrcToStore srcToStore; -- cgit v1.2.3 From 2d0d1ec99d032ce236ee0b8194ac2da762e7f462 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 12 May 2022 14:15:35 -0600 Subject: remove debug code --- src/libexpr/primops.cc | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index d2b94b95c..8ef8fe7f5 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -878,7 +878,6 @@ static RegisterPrimOp primop_floor({ * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { - std::cout << "priatraynasdf0" << std::endl; auto attrs = state.buildBindings(2); auto saveDebuggerHook = debuggerHook; debuggerHook = nullptr; @@ -886,15 +885,10 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); attrs.alloc("success").mkBool(true); - std::cout << "priatraynasdf0000" << std::endl; } catch (AssertionError & e) { - std::cout << "priatraynasdf" << std::endl; - attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } catch (Error & e) { - std::cout << "priatraERASERynasdf" << std::endl; - attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } -- cgit v1.2.3 From 2acdb90438f315e145f97218b1b34f75b40ebc70 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 12 May 2022 14:20:45 -0600 Subject: remove debug code --- src/libexpr/primops.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 8ef8fe7f5..ff5ae8809 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -888,9 +888,6 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va } catch (AssertionError & e) { attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); - } catch (Error & e) { - attrs.alloc(state.sValue).mkBool(false); - attrs.alloc("success").mkBool(false); } debuggerHook = saveDebuggerHook; v.mkAttrs(attrs); -- cgit v1.2.3 From 8150b93968c648c6d273aaffaffba94096ec3faf Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 13 May 2022 11:12:11 -0400 Subject: fix: alignment during flake show of legacyPackages Fixes: https://github.com/NixOS/nix/issues/6240 https://github.com/NixOS/nix/issues/6045 --- src/nix/flake.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 1938ce4e6..f55929751 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -1076,9 +1076,13 @@ struct CmdFlakeShow : FlakeCommand, MixJSON else if (attrPath.size() > 0 && attrPathS[0] == "legacyPackages") { if (attrPath.size() == 1) recurse(); - else if (!showLegacy) - logger->warn(fmt("%s: " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix)); - else { + else if (!showLegacy){ + if (!json) + logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix)); + else { + logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPathS))); + } + } else { if (visitor.isDerivation()) showDerivation(); else if (attrPath.size() <= 2) -- cgit v1.2.3 From 6faa56ea1f7f8b708e8c931f41b627541a023c79 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sun, 15 May 2022 12:05:34 -0600 Subject: remove extra argument --- src/libcmd/command.cc | 2 +- src/libcmd/command.hh | 1 - src/libcmd/repl.cc | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 12cd5ed83..bf97a3de8 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -138,7 +138,7 @@ ref EvalCommand::getEvalState() if (expr.staticEnv) { auto vm = mapStaticEnvBindings(evalState->symbols, *expr.staticEnv.get(), env); - runRepl(evalState, expr, *vm); + runRepl(evalState, *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 454197b1c..196bd3aaa 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -275,7 +275,6 @@ void printClosureDiff( void runRepl( ref evalState, - const Expr & expr, const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 8f0b1bfc0..deac3d408 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -1012,7 +1012,6 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m void runRepl( ref evalState, - const Expr &expr, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); -- cgit v1.2.3 From 86ba0a702c63b4a8ff79a07f9303318feb330642 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sun, 15 May 2022 12:05:51 -0600 Subject: fix thunk issue --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c36bb59fb..d9ea92cc0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -2073,7 +2073,7 @@ void EvalState::forceValueDeep(Value & v) try { // If the value is a thunk, we're evaling. Otherwise no trace necessary. auto dts = debuggerHook && i.value->isThunk() - ? makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, positions[i.pos], + ? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos], "while evaluating the attribute '%1%'", symbols[i.name]) : nullptr; -- cgit v1.2.3 From 667074b5867ffe40e3f1c59bd8e4ebf259f86aaa Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 16 May 2022 09:20:51 -0600 Subject: first whack at passing evalState as an arg to debuggerHook. --- src/libcmd/command.cc | 11 ++++++----- src/libcmd/command.hh | 2 +- src/libcmd/repl.cc | 2 +- src/libexpr/eval.cc | 2 +- src/libexpr/eval.hh | 4 ++-- src/libexpr/nixexpr.cc | 2 +- src/libexpr/nixexpr.hh | 2 +- src/libexpr/primops.cc | 2 +- src/libutil/ref.hh | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index bf97a3de8..ee5102a6a 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -119,13 +119,14 @@ ref EvalCommand::getEvalState() #endif ; if (startReplOnEvalErrors) - debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { + // debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { + debuggerHook = [](const EvalState & evalState, const Error * error, const Env & env, const Expr & expr) { auto dts = error && expr.getPos() ? std::make_unique( - *evalState, + evalState, DebugTrace { - .pos = error->info().errPos ? *error->info().errPos : evalState->positions[expr.getPos()], + .pos = error->info().errPos ? *error->info().errPos : evalState.positions[expr.getPos()], .expr = expr, .env = env, .hint = error->info().msg, @@ -137,8 +138,8 @@ ref EvalCommand::getEvalState() 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 (expr.staticEnv) { - auto vm = mapStaticEnvBindings(evalState->symbols, *expr.staticEnv.get(), env); - runRepl(evalState, *vm); + auto vm = mapStaticEnvBindings(evalState.symbols, *expr.staticEnv.get(), env); + runRepl(*const_cast(&evalState), *vm); } }; } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 196bd3aaa..8b37be901 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,7 +274,7 @@ void printClosureDiff( void runRepl( - ref evalState, + EvalState & evalState, const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index deac3d408..cb5d5bb34 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -1011,7 +1011,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } void runRepl( - ref evalState, + EvalState& evalState, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d9ea92cc0..3c998f7b6 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1044,7 +1044,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) { evalState.debugTraces.push_front(trace); if (evalState.debugStop && debuggerHook) - debuggerHook(nullptr, trace.env, trace.expr); + debuggerHook(evalState, nullptr, trace.env, trace.expr); } void Value::mkString(std::string_view s) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index f274278be..26717a6f8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -136,7 +136,7 @@ public: void debugThrow(const E &error, const Env & env, const Expr & expr) const { if (debuggerHook) - debuggerHook(&error, env, expr); + debuggerHook(*this, &error, env, expr); throw error; } @@ -150,7 +150,7 @@ public: // DebugTrace stack. if (debuggerHook && !debugTraces.empty()) { const DebugTrace & last = debugTraces.front(); - debuggerHook(&e, last.env, last.expr); + debuggerHook(*this, &e, last.env, last.expr); } throw e; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 213cf93fa..a7b7b8aad 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. */ diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index c4a509f31..856676033 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 ff5ae8809..e56e6314b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -765,7 +765,7 @@ static RegisterPrimOp primop_break({ }); auto & dt = state.debugTraces.front(); - debuggerHook(&error, dt.env, dt.expr); + debuggerHook(state, &error, dt.env, dt.expr); if (state.debugQuit) { // If the user elects to quit the repl, throw an exception. diff --git a/src/libutil/ref.hh b/src/libutil/ref.hh index f9578afc7..bf26321db 100644 --- a/src/libutil/ref.hh +++ b/src/libutil/ref.hh @@ -7,7 +7,7 @@ namespace nix { /* A simple non-nullable reference-counted pointer. Actually a wrapper - around std::shared_ptr that prevents non-null constructions. */ + around std::shared_ptr that prevents null constructions. */ template class ref { -- cgit v1.2.3 From 5b8c1deb18e0e6fc7a83fb8101cf5fc8dba38843 Mon Sep 17 00:00:00 2001 From: Tony Olagbaiye Date: Fri, 16 Oct 2020 00:35:24 +0100 Subject: fetchTree: Allow fetching plain files Add a new `file` fetcher type, which will fetch a plain file over http(s), or from the local file. Because plain `http(s)://` or `file://` urls can already correspond to `tarball` inputs (if the path ends-up with a know archive extension), the URL parsing logic is a bit convuluted in that: - {http,https,file}:// urls will be interpreted as either a tarball or a file input, depending on the extensions of the path part (so `https://foo.com/bar` will be a `file` input and `https://foo.com/bar.tar.gz` as a `tarball` input) - `file+{something}://` urls will be interpreted as `file` urls (with the `file+` part removed) - `tarball+{something}://` urls will be interpreted as `tarball` urls (with the `tarball+` part removed) Fix #3785 Co-Authored-By: Tony Olagbaiye --- src/libfetchers/tarball.cc | 90 ++++++++++++++++++++++++++++++++++------------ src/libutil/url.cc | 18 ++++++++++ src/libutil/url.hh | 15 ++++++++ src/nix/flake.md | 14 ++++++-- 4 files changed, 112 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index dde0ad761..09acb74d3 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -6,6 +6,7 @@ #include "archive.hh" #include "tarfile.hh" #include "types.hh" +#include "split.hh" namespace nix::fetchers { @@ -168,24 +169,34 @@ std::pair downloadTarball( }; } -struct TarballInputScheme : InputScheme +// An input scheme corresponding to a curable ressource +struct CurlInputScheme : InputScheme { - std::optional inputFromURL(const ParsedURL & url) override + virtual const std::string inputType() const = 0; + const std::set transportUrlSchemes = {"file", "http", "https"}; + + const bool hasTarballExtension(std::string_view path) const { - if (url.scheme != "file" && url.scheme != "http" && url.scheme != "https") return {}; + return hasSuffix(path, ".zip") || hasSuffix(path, ".tar") + || hasSuffix(path, ".tgz") || hasSuffix(path, ".tar.gz") + || hasSuffix(path, ".tar.xz") || hasSuffix(path, ".tar.bz2") + || hasSuffix(path, ".tar.zst"); + } - if (!hasSuffix(url.path, ".zip") - && !hasSuffix(url.path, ".tar") - && !hasSuffix(url.path, ".tgz") - && !hasSuffix(url.path, ".tar.gz") - && !hasSuffix(url.path, ".tar.xz") - && !hasSuffix(url.path, ".tar.bz2") - && !hasSuffix(url.path, ".tar.zst")) - return {}; + virtual bool isValidURL(const ParsedURL & url) const = 0; + + std::optional inputFromURL(const ParsedURL & url) override + { + if (!isValidURL(url)) + return std::nullopt; Input input; - input.attrs.insert_or_assign("type", "tarball"); - input.attrs.insert_or_assign("url", url.to_string()); + + auto urlWithoutApplicationScheme = url; + urlWithoutApplicationScheme.scheme = parseUrlScheme(url.scheme).transport; + + input.attrs.insert_or_assign("type", inputType()); + input.attrs.insert_or_assign("url", urlWithoutApplicationScheme.to_string()); auto narHash = url.query.find("narHash"); if (narHash != url.query.end()) input.attrs.insert_or_assign("narHash", narHash->second); @@ -194,14 +205,17 @@ struct TarballInputScheme : InputScheme std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != "tarball") return {}; + auto type = maybeGetStrAttr(attrs, "type"); + if (type != inputType()) return {}; + std::set allowedNames = {"type", "url", "narHash", "name", "unpack"}; for (auto & [name, value] : attrs) - if (name != "type" && name != "url" && /* name != "hash" && */ name != "narHash" && name != "name") - throw Error("unsupported tarball input attribute '%s'", name); + if (!allowedNames.count(name)) + throw Error("unsupported %s input attribute '%s'", *type, name); Input input; input.attrs = attrs; + //input.locked = (bool) maybeGetStrAttr(input.attrs, "hash"); return input; } @@ -209,14 +223,9 @@ struct TarballInputScheme : InputScheme ParsedURL toURL(const Input & input) override { auto url = parseURL(getStrAttr(input.attrs, "url")); - // NAR hashes are preferred over file hashes since tar/zip files - // don't have a canonical representation. + // NAR hashes are preferred over file hashes since tar/zip files // don't have a canonical representation. if (auto narHash = input.getNarHash()) url.query.insert_or_assign("narHash", narHash->to_string(SRI, true)); - /* - else if (auto hash = maybeGetStrAttr(input.attrs, "hash")) - url.query.insert_or_assign("hash", Hash(*hash).to_string(SRI, true)); - */ return url; } @@ -225,6 +234,42 @@ struct TarballInputScheme : InputScheme return true; } +}; + +struct FileInputScheme : CurlInputScheme +{ + const std::string inputType() const override { return "file"; } + + bool isValidURL(const ParsedURL & url) const override + { + auto parsedUrlScheme = parseUrlScheme(url.scheme); + return transportUrlSchemes.count(std::string(parsedUrlScheme.transport)) + && (parsedUrlScheme.application + ? parsedUrlScheme.application.value() == inputType() + : !hasTarballExtension(url.path)); + } + + std::pair fetch(ref store, const Input & input) override + { + auto file = downloadFile(store, getStrAttr(input.attrs, "url"), input.getName(), false); + return {std::move(file.storePath), input}; + } +}; + +struct TarballInputScheme : CurlInputScheme +{ + const std::string inputType() const override { return "tarball"; } + + bool isValidURL(const ParsedURL & url) const override + { + auto parsedUrlScheme = parseUrlScheme(url.scheme); + + return transportUrlSchemes.count(std::string(parsedUrlScheme.transport)) + && (parsedUrlScheme.application + ? parsedUrlScheme.application.value() == inputType() + : hasTarballExtension(url.path)); + } + std::pair fetch(ref store, const Input & input) override { auto tree = downloadTarball(store, getStrAttr(input.attrs, "url"), input.getName(), false).first; @@ -233,5 +278,6 @@ struct TarballInputScheme : InputScheme }; static auto rTarballInputScheme = OnStartup([] { registerInputScheme(std::make_unique()); }); +static auto rFileInputScheme = OnStartup([] { registerInputScheme(std::make_unique()); }); } diff --git a/src/libutil/url.cc b/src/libutil/url.cc index f6232d255..5b7abeb49 100644 --- a/src/libutil/url.cc +++ b/src/libutil/url.cc @@ -1,6 +1,7 @@ #include "url.hh" #include "url-parts.hh" #include "util.hh" +#include "split.hh" namespace nix { @@ -136,4 +137,21 @@ bool ParsedURL::operator ==(const ParsedURL & other) const && fragment == other.fragment; } +/** + * Parse a URL scheme of the form '(applicationScheme\+)?transportScheme' + * into a tuple '(applicationScheme, transportScheme)' + * + * > parseUrlScheme("http") == ParsedUrlScheme{ {}, "http"} + * > parseUrlScheme("tarball+http") == ParsedUrlScheme{ {"tarball"}, "http"} + */ +ParsedUrlScheme parseUrlScheme(std::string_view scheme) +{ + auto application = splitPrefixTo(scheme, '+'); + auto transport = scheme; + return ParsedUrlScheme { + .application = application, + .transport = transport, + }; +} + } diff --git a/src/libutil/url.hh b/src/libutil/url.hh index 6e77142e3..2a9fb34c1 100644 --- a/src/libutil/url.hh +++ b/src/libutil/url.hh @@ -27,4 +27,19 @@ std::map decodeQuery(const std::string & query); ParsedURL parseURL(const std::string & url); +/* + * Although that’s not really standardized anywhere, an number of tools + * use a scheme of the form 'x+y' in urls, where y is the “transport layer” + * scheme, and x is the “application layer” scheme. + * + * For example git uses `git+https` to designate remotes using a Git + * protocol over http. + */ +struct ParsedUrlScheme { + std::optional application; + std::string_view transport; +}; + +ParsedUrlScheme parseUrlScheme(std::string_view scheme); + } diff --git a/src/nix/flake.md b/src/nix/flake.md index aa3f9f303..a1ab43281 100644 --- a/src/nix/flake.md +++ b/src/nix/flake.md @@ -181,9 +181,17 @@ Currently the `type` attribute can be one of the following: * `tarball`: Tarballs. The location of the tarball is specified by the attribute `url`. - In URL form, the schema must be `http://`, `https://` or `file://` - URLs and the extension must be `.zip`, `.tar`, `.tgz`, `.tar.gz`, - `.tar.xz`, `.tar.bz2` or `.tar.zst`. + In URL form, the schema must be `tarball+http://`, `tarball+https://` or `tarball+file://`. + If the extension corresponds to a known archive format (`.zip`, `.tar`, + `.tgz`, `.tar.gz`, `.tar.xz`, `.tar.bz2` or `.tar.zst`), then the `tarball+` + can be dropped. + +* `file`: Plain files or directory tarballs, either over http(s) or from the local + disk. + + In URL form, the schema must be `file+http://`, `file+https://` or `file+file://`. + If the extension doesn’t correspond to a known archive format (as defined by the + `tarball` fetcher), then the `file+` prefix can be dropped. * `github`: A more efficient way to fetch repositories from GitHub. The following attributes are required: -- cgit v1.2.3 From 357fb84dbaad0b056704915c6a43764cda63ee7f Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 19 May 2022 10:48:10 -0600 Subject: use an expr->StaticEnv table in evalState --- src/libcmd/command.cc | 5 ++-- src/libcmd/repl.cc | 9 +++--- src/libexpr/eval.cc | 8 +++--- src/libexpr/eval.hh | 12 +++++++- src/libexpr/nixexpr.cc | 77 +++++++++++++++++++++++++------------------------- src/libexpr/nixexpr.hh | 7 ++--- 6 files changed, 65 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index bf97a3de8..b8c3b0846 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -136,8 +136,9 @@ ref EvalCommand::getEvalState() 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 (expr.staticEnv) { - auto vm = mapStaticEnvBindings(evalState->symbols, *expr.staticEnv.get(), env); + auto se = evalState->getStaticEnv(expr); + if (se) { + auto vm = mapStaticEnvBindings(evalState->symbols, *se.get(), env); runRepl(evalState, *vm); } }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index deac3d408..43c2ce65e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -441,8 +441,9 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt) { initEnv(); - if (dt.expr.staticEnv) { - auto vm = mapStaticEnvBindings(state->symbols, *dt.expr.staticEnv.get(), dt.env); + auto se = state->getStaticEnv(dt.expr); + if (se) { + auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env); // add staticenv vars. for (auto & [name, value] : *(vm.get())) @@ -516,7 +517,7 @@ bool NixRepl::processLine(std::string line) else if (debuggerHook && (command == ":env")) { for (const auto & [idx, i] : enumerate(state->debugTraces)) { if (idx == debugTraceIndex) { - printEnvBindings(state->symbols, i.expr, i.env); + printEnvBindings(*state, i.expr, i.env); break; } } @@ -533,7 +534,7 @@ bool NixRepl::processLine(std::string line) std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; showDebugTrace(std::cout, state->positions, i); std::cout << std::endl; - printEnvBindings(state->symbols, i.expr, i.env); + printEnvBindings(*state, i.expr, i.env); loadDebugTraceEnv(i); break; } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d9ea92cc0..c9e4a05b7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -772,12 +772,12 @@ void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & } } -// TODO: add accompanying env for With stuff. -void printEnvBindings(const SymbolTable & st, const Expr & expr, const Env & env) +void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env) { // just print the names for now - if (expr.staticEnv) - printEnvBindings(st, *expr.staticEnv.get(), env, 0); + auto se = es.getStaticEnv(expr); + if (se) + printEnvBindings(es.symbols, *se, env, 0); } void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, ValMap & vm) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index f274278be..0543cb35c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,7 +25,7 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); -void printEnvBindings(const SymbolTable & st, const Expr & expr, const Env & env); +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 @@ -130,6 +130,16 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; + std::map > exprEnvs; + const std::shared_ptr getStaticEnv(const Expr &expr) const + { + auto i = exprEnvs.find(&expr); + if (i != exprEnvs.end()) + return i->second; + else + return std::shared_ptr();; + } + template [[gnu::noinline, gnu::noreturn]] diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 213cf93fa..4fb43707e 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -296,38 +296,39 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath) /* Computing levels/displacements for variables. */ -void Expr::bindVars(const EvalState & es, const std::shared_ptr & env) +void Expr::bindVars(EvalState & es, const std::shared_ptr & env) { abort(); } -void ExprInt::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprInt::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env;} + es.exprEnvs.insert(std::make_pair(this, env)); +} -void ExprFloat::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprFloat::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprString::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprString::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprPath::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprPath::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); } -void ExprVar::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprVar::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); /* Check whether the variable appears in the environment. If so, set its level and displacement. */ @@ -360,10 +361,10 @@ void ExprVar::bindVars(const EvalState & es, const std::shared_ptrlevel = withLevel; } -void ExprSelect::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprSelect::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); if (def) def->bindVars(es, env); @@ -372,10 +373,10 @@ void ExprSelect::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); } -void ExprOpHasAttr::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); for (auto & i : attrPath) @@ -383,10 +384,10 @@ void ExprOpHasAttr::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); } -void ExprAttrs::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); if (recursive) { auto newEnv = std::make_shared(false, env.get(), recursive ? attrs.size() : 0); @@ -416,19 +417,19 @@ void ExprAttrs::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprList::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : elems) i->bindVars(es, env); } -void ExprLambda::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprLambda::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared( false, env.get(), @@ -452,20 +453,20 @@ void ExprLambda::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, newEnv); } -void ExprCall::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprCall::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); fun->bindVars(es, env); for (auto e : args) e->bindVars(es, env); } -void ExprLet::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprLet::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared(false, env.get(), attrs->attrs.size()); @@ -481,10 +482,10 @@ void ExprLet::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, newEnv); } -void ExprWith::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprWith::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); /* Does this `with' have an enclosing `with'? If so, record its level so that `lookupVar' can look up variables in the previous @@ -499,53 +500,53 @@ void ExprWith::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); auto newEnv = std::make_shared(true, env.get()); body->bindVars(es, newEnv); } -void ExprIf::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprIf::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); then->bindVars(es, env); else_->bindVars(es, env); } -void ExprAssert::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprAssert::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); body->bindVars(es, env); } -void ExprOpNot::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); } -void ExprConcatStrings::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : *this->es) i.second->bindVars(es, env); } -void ExprPos::bindVars(const EvalState & es, const std::shared_ptr & env) +void ExprPos::bindVars(EvalState & es, const std::shared_ptr & env) { if (debuggerHook) - staticEnv = env; + es.exprEnvs.insert(std::make_pair(this, env)); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index c4a509f31..e923f36a4 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -144,18 +144,17 @@ struct Expr { virtual ~Expr() { }; virtual void show(const SymbolTable & symbols, std::ostream & str) const; - virtual void bindVars(const EvalState & es, const std::shared_ptr & env); + virtual void bindVars(EvalState & es, const std::shared_ptr & env); virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); - std::shared_ptr staticEnv; virtual PosIdx getPos() const { return noPos; } }; #define COMMON_METHODS \ void show(const SymbolTable & symbols, std::ostream & str) const; \ void eval(EvalState & state, Env & env, Value & v); \ - void bindVars(const EvalState & es, const std::shared_ptr & env); + void bindVars(EvalState & es, const std::shared_ptr & env); struct ExprInt : Expr { @@ -402,7 +401,7 @@ struct ExprOpNot : Expr { \ str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \ } \ - void bindVars(const EvalState & es, const std::shared_ptr & env) \ + void bindVars(EvalState & es, const std::shared_ptr & env) \ { \ e1->bindVars(es, env); e2->bindVars(es, env); \ } \ -- cgit v1.2.3 From 7ddef73d026d79adc0c4f3fd1518d88d1331c38c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 19 May 2022 12:44:40 -0600 Subject: de-const evalState exceptions --- src/libcmd/command.cc | 7 ++++--- src/libcmd/command.hh | 3 ++- src/libcmd/repl.cc | 4 +++- src/libexpr/eval.cc | 38 +++++++++++++++++++------------------- src/libexpr/eval.hh | 48 ++++++++++++++++++++++++------------------------ src/libexpr/nixexpr.cc | 2 +- src/libexpr/nixexpr.hh | 2 +- 7 files changed, 54 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 9cf2ff5e3..a7d7bfb17 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -118,9 +118,10 @@ ref EvalCommand::getEvalState() searchPath, getEvalStore(), getStore()) #endif ; + // 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 = [](const 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( @@ -137,9 +138,9 @@ ref EvalCommand::getEvalState() 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); + auto se = evalState.getStaticEnv(expr); if (se) { - auto vm = mapStaticEnvBindings(evalState->symbols, *se.get(), env); + auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env); runRepl(evalState, *vm); } }; diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 8b37be901..04bffa8df 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,7 +274,8 @@ void printClosureDiff( void runRepl( - EvalState & evalState, + ref evalState, + // EvalState & evalState, const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 5b17f2fb2..5aecf3ac3 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -96,6 +96,7 @@ std::string removeWhitespace(std::string s) } +// NixRepl::NixRepl(ref state) NixRepl::NixRepl(ref state) : state(state) , debugTraceIndex(0) @@ -1012,7 +1013,8 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } void runRepl( - EvalState& evalState, + ref evalState, + // EvalState& evalState, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bd1cbaab5..f95ff4931 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -814,7 +814,7 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati of stack space, which is a real killer in the recursive evaluator. So here are some helper functions for throwing exceptions. */ -void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr) { auto error = EvalError({ .msg = hintfmt(s), @@ -824,7 +824,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr debugThrow(error, env, expr); } -void EvalState::throwEvalError(const PosIdx pos, const char * s) const +void EvalState::throwEvalError(const PosIdx pos, const char * s) { auto error = EvalError({ .msg = hintfmt(s), @@ -834,7 +834,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s) const debugThrowLastTrace(error); } -void EvalState::throwEvalError(const char * s, const std::string & s2) const +void EvalState::throwEvalError(const char * s, const std::string & s2) { auto error = EvalError(s, s2); @@ -842,7 +842,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const } void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const std::string & s2, Env & env, Expr & expr) const + const std::string & s2, Env & env, Expr & expr) { auto error = EvalError(ErrorInfo{ .msg = hintfmt(s, s2), @@ -853,7 +853,7 @@ void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions debugThrow(error, env, expr); } -void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -863,7 +863,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri debugThrowLastTrace(error); } -void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -874,7 +874,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri } void EvalState::throwEvalError(const char * s, const std::string & s2, - const std::string & s3) const + const std::string & s3) { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -885,7 +885,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2, } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - const std::string & s3) const + const std::string & s3) { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -896,7 +896,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - const std::string & s3, Env & env, Expr & expr) const + const std::string & s3, Env & env, Expr & expr) { auto error = EvalError({ .msg = hintfmt(s, s2), @@ -906,7 +906,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri debugThrow(error, env, expr); } -void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) const +void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) { // p1 is where the error occurred; p2 is a position mentioned in the message. auto error = EvalError({ @@ -917,7 +917,7 @@ void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym debugThrow(error, env, expr); } -void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) { auto error = TypeError({ .msg = hintfmt(s, showType(v)), @@ -927,7 +927,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v debugThrowLastTrace(error); } -void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) const +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) { auto error = TypeError({ .msg = hintfmt(s, showType(v)), @@ -937,7 +937,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v debugThrow(error, env, expr); } -void EvalState::throwTypeError(const PosIdx pos, const char * s) const +void EvalState::throwTypeError(const PosIdx pos, const char * s) { auto error = TypeError({ .msg = hintfmt(s), @@ -948,7 +948,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s) const } void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, - const Symbol s2, Env & env, Expr &expr) const + const Symbol s2, Env & env, Expr &expr) { auto error = TypeError({ .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), @@ -959,7 +959,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambd } void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol s2, Env & env, Expr &expr) const + const ExprLambda & fun, const Symbol s2, Env & env, Expr &expr) { auto error = TypeError(ErrorInfo { .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), @@ -970,7 +970,7 @@ void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions debugThrow(error, env, expr); } -void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) const +void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) { auto error = TypeError({ .msg = hintfmt(s, showType(v)), @@ -980,7 +980,7 @@ void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr debugThrow(error, env, expr); } -void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const +void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { auto error = AssertionError({ .msg = hintfmt(s, s1), @@ -990,7 +990,7 @@ void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std: debugThrow(error, env, expr); } -void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const +void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { auto error = UndefinedVarError({ .msg = hintfmt(s, s1), @@ -1000,7 +1000,7 @@ void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const s debugThrow(error, env, expr); } -void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) const +void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { auto error = MissingArgumentError({ .msg = hintfmt(s, s1), diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 5227c7ce1..763150dae 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -143,7 +143,7 @@ public: template [[gnu::noinline, gnu::noreturn]] - void debugThrow(const E &error, const Env & env, const Expr & expr) const + void debugThrow(const E &error, const Env & env, const Expr & expr) { if (debuggerHook) debuggerHook(*this, &error, env, expr); @@ -153,7 +153,7 @@ public: template [[gnu::noinline, gnu::noreturn]] - void debugThrowLastTrace(E & e) const + void debugThrowLastTrace(E & e) { // Call this in the situation where Expr and Env are inaccessible. // The debugger will start in the last context that's in the @@ -312,68 +312,68 @@ public: std::string_view forceStringNoCtx(Value & v, const PosIdx pos = noPos); [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s) const; + void throwEvalError(const PosIdx pos, const char * s); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2) const; + void throwEvalError(const char * s, const std::string & s2); [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const; + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const char * s, const std::string & s2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const char * s, const std::string & s2, const std::string & s3, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) const; + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3); [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; + void throwEvalError(const char * s, const std::string & s2, const std::string & s3); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const Value & v) const; + void throwTypeError(const PosIdx pos, const char * s, const Value & v); [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s, const Value & v, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s) const; + void throwTypeError(const PosIdx pos, const char * s); [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol s2, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwTypeError(const char * s, const Value & v, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline, gnu::noreturn]] void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr) const; + Env & env, Expr & expr); [[gnu::noinline]] void addErrorTrace(Error & e, const char * s, const std::string & s2) const; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index cb5e1c3f2..21b71d7c9 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. */ diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 80b6afa3e..fdafb1711 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. */ -- cgit v1.2.3 From 0600df86b8bc59633457f7ceb79e84c8ea3fed17 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 19 May 2022 17:01:23 -0600 Subject: 'debugMode' --- src/libcmd/command.cc | 53 ++++++++++++++++++++++++++------------------------ 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, 105 insertions(+), 71 deletions(-) (limited to 'src') 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 (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)}](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()); + + // 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); } -- cgit v1.2.3 From 884d59178735bcb5d5db7db97a05ad62a175493b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 20 May 2022 10:33:50 -0600 Subject: debugRepl ftn pointer --- src/libcmd/command.cc | 27 +++++++++++++++++++++++++++ src/libexpr/eval.cc | 12 ++++++++---- src/libexpr/eval.hh | 10 +++++----- src/libexpr/primops.cc | 2 +- 4 files changed, 41 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index a4ea5bc33..b61b9b61d 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -120,7 +120,34 @@ ref EvalCommand::getEvalState() ; evalState->debugMode = startReplOnEvalErrors; + // TODO move this somewhere else. Its only here to get the evalState ptr! + if (startReplOnEvalErrors) { + evalState->debugRepl = &runRepl; + }; + // // 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()); + + // auto se = evalState.getStaticEnv(expr); + // if (se) { + // auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env); + // runRepl(evalState, *vm); + // } // if (startReplOnEvalErrors) // // debuggerHook = [evalState{ref(evalState)}](const Error * error, const Env & env, const Expr & expr) { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 1cde4a9ab..5faecdbe3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -463,7 +463,7 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) - , debugMode(false) + , debugRepl(0) , debugStop(false) , debugQuit(false) , regexCache(makeRegexCache()) @@ -811,8 +811,12 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati return vm; } -void EvalState::debugRepl(const Error * error, const Env & env, const Expr & expr) +void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & expr) { + // double check we've got the debugRepl ftn pointer. + if (!debugRepl) + return; + auto dts = error && expr.getPos() ? std::make_unique( @@ -832,7 +836,7 @@ void EvalState::debugRepl(const Error * error, const Env & env, const Expr & exp auto se = getStaticEnv(expr); if (se) { auto vm = mapStaticEnvBindings(symbols, *se.get(), env); - runRepl(*this, *vm); + (debugRepl)(*this, *vm); } } @@ -1070,7 +1074,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) { evalState.debugTraces.push_front(trace); if (evalState.debugStop && evalState.debugMode) - evalState.debugRepl(nullptr, trace.env, trace.expr); + evalState.runDebugRepl(nullptr, trace.env, trace.expr); } void Value::mkString(std::string_view s) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 711a4d6be..90bd5497b 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -48,8 +48,6 @@ 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); @@ -129,6 +127,8 @@ public: RootValue vImportedDrvToDerivation = nullptr; /* Debugger */ + void (* debugRepl)(EvalState & es, const ValMap & extraEnv); + bool debugMode; bool debugStop; bool debugQuit; @@ -143,14 +143,14 @@ public: return std::shared_ptr();; } - void debugRepl(const Error * error, const Env & env, const Expr & expr); + void runDebugRepl(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 (debugMode) - debugRepl(&error, env, expr); + runDebugRepl(&error, env, expr); throw error; } @@ -164,7 +164,7 @@ public: // DebugTrace stack. if (debugMode && !debugTraces.empty()) { const DebugTrace & last = debugTraces.front(); - debugRepl(&e, last.env, last.expr); + runDebugRepl(&e, last.env, last.expr); } throw e; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index f7429197a..3ca377b7c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -765,7 +765,7 @@ static RegisterPrimOp primop_break({ }); auto & dt = state.debugTraces.front(); - state.debugRepl(&error, dt.env, dt.expr); + state.runDebugRepl(&error, dt.env, dt.expr); if (state.debugQuit) { // If the user elects to quit the repl, throw an exception. -- cgit v1.2.3 From 982c8a959b0a686c1c532429b206507c7641e083 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 20 May 2022 12:45:36 -0600 Subject: remove special tryEval behavior --- src/libexpr/primops.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ff5ae8809..1727a276c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -879,8 +879,6 @@ 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; try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -889,7 +887,6 @@ 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; v.mkAttrs(attrs); } -- cgit v1.2.3 From 81a9bf0ad2ff3244096ed14299c65c0b32c0aca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Na=C3=AFm=20Camille=20Favier?= Date: Sat, 21 May 2022 14:41:24 +0200 Subject: =?UTF-8?q?typo:=20defaultApps=20=E2=86=92=20defaultApp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nix/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 1938ce4e6..500116eaf 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -509,7 +509,7 @@ struct CmdFlakeCheck : FlakeCommand std::string_view replacement = name == "defaultPackage" ? "packages..default" : - name == "defaultApps" ? "apps..default" : + name == "defaultApp" ? "apps..default" : name == "defaultTemplate" ? "templates.default" : name == "defaultBundler" ? "bundlers..default" : name == "overlay" ? "overlays.default" : -- cgit v1.2.3 From 34ffaa9f5786fafa68c55bae99c5512506f7f0db Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sun, 22 May 2022 18:57:45 -0600 Subject: changning repl to use EvalState& instead of ref --- src/libcmd/command.hh | 3 +- src/libcmd/repl.cc | 145 +++++++++++++++++++++++++------------------------- 2 files changed, 74 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 196bd3aaa..b064f490a 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,7 +274,6 @@ void printClosureDiff( void runRepl( - ref evalState, + EvalState &evalState, const ValMap & extraEnv); - } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 43c2ce65e..7b9ad9d71 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -48,7 +48,8 @@ struct NixRepl #endif { std::string curDir; - ref state; + EvalState &state; + // ref state; Bindings * autoArgs; size_t debugTraceIndex; @@ -63,7 +64,7 @@ struct NixRepl const Path historyFile; - NixRepl(ref state); + NixRepl(EvalState &state); ~NixRepl(); void mainLoop(const std::vector & files); StringSet completePrefix(const std::string & prefix); @@ -96,10 +97,10 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(ref state) +NixRepl::NixRepl(EvalState &state) : state(state) , debugTraceIndex(0) - , staticEnv(new StaticEnv(false, state->staticBaseEnv.get())) + , staticEnv(new StaticEnv(false, state.staticBaseEnv.get())) , historyFile(getDataDir() + "/nix/repl-history") { curDir = absPath("."); @@ -261,8 +262,8 @@ void NixRepl::mainLoop(const std::vector & files) // number of chars as the prompt. if (!getLine(input, input.empty() ? "nix-repl> " : " ")) { // ctrl-D should exit the debugger. - state->debugStop = false; - state->debugQuit = true; + state.debugStop = false; + state.debugQuit = true; break; } try { @@ -279,8 +280,8 @@ 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()) - showDebugTrace(std::cout, state->positions, state->debugTraces.front()); + if (debuggerHook && !state.debugTraces.empty()) + showDebugTrace(std::cout, state.positions, state.debugTraces.front()); else printMsg(lvlError, e.msg()); } catch (Error & e) { @@ -386,11 +387,11 @@ StringSet NixRepl::completePrefix(const std::string & prefix) Expr * e = parseString(expr); Value v; - e->eval(*state, *env, v); - state->forceAttrs(v, noPos); + e->eval(state, *env, v); + state.forceAttrs(v, noPos); 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; completions.insert(concatStrings(prev, expr, ".", name)); } @@ -426,14 +427,14 @@ static bool isVarName(std::string_view s) StorePath NixRepl::getDerivationPath(Value & v) { - auto drvInfo = getDerivation(*state, v, false); + auto drvInfo = getDerivation(state, v, false); if (!drvInfo) throw Error("expression does not evaluate to a derivation, so I can't build it"); auto drvPath = drvInfo->queryDrvPath(); if (!drvPath) throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)"); - if (!state->store->isValidPath(*drvPath)) - throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath)); + if (!state.store->isValidPath(*drvPath)) + throw Error("expression evaluated to invalid derivation '%s'", state.store->printStorePath(*drvPath)); return *drvPath; } @@ -441,13 +442,13 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt) { initEnv(); - auto se = state->getStaticEnv(dt.expr); + auto se = state.getStaticEnv(dt.expr); if (se) { - auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env); + auto vm = mapStaticEnvBindings(state.symbols, *se.get(), dt.env); // add staticenv vars. for (auto & [name, value] : *(vm.get())) - addVarToScope(state->symbols.create(name), *value); + addVarToScope(state.symbols.create(name), *value); } } @@ -508,16 +509,16 @@ bool NixRepl::processLine(std::string line) } else if (debuggerHook && (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 << ": "; - showDebugTrace(std::cout, state->positions, i); + showDebugTrace(std::cout, state.positions, i); } } else if (debuggerHook && (command == ":env")) { - for (const auto & [idx, i] : enumerate(state->debugTraces)) { + for (const auto & [idx, i] : enumerate(state.debugTraces)) { if (idx == debugTraceIndex) { - printEnvBindings(*state, i.expr, i.env); + printEnvBindings(state, i.expr, i.env); break; } } @@ -529,12 +530,12 @@ bool NixRepl::processLine(std::string line) debugTraceIndex = stoi(arg); } catch (...) { } - for (const auto & [idx, i] : enumerate(state->debugTraces)) { + for (const auto & [idx, i] : enumerate(state.debugTraces)) { if (idx == debugTraceIndex) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, state->positions, i); + showDebugTrace(std::cout, state.positions, i); std::cout << std::endl; - printEnvBindings(*state, i.expr, i.env); + printEnvBindings(state, i.expr, i.env); loadDebugTraceEnv(i); break; } @@ -543,13 +544,13 @@ bool NixRepl::processLine(std::string line) else if (debuggerHook && (command == ":s" || command == ":step")) { // set flag to stop at next DebugTrace; exit repl. - state->debugStop = true; + state.debugStop = true; return false; } else if (debuggerHook && (command == ":c" || command == ":continue")) { // set flag to run to next breakpoint or end of program; exit repl. - state->debugStop = false; + state.debugStop = false; return false; } @@ -560,7 +561,7 @@ bool NixRepl::processLine(std::string line) } else if (command == ":l" || command == ":load") { - state->resetFileCache(); + state.resetFileCache(); loadFile(arg); } @@ -569,7 +570,7 @@ bool NixRepl::processLine(std::string line) } else if (command == ":r" || command == ":reload") { - state->resetFileCache(); + state.resetFileCache(); reloadFiles(); } @@ -580,15 +581,15 @@ bool NixRepl::processLine(std::string line) const auto [file, line] = [&] () -> std::pair { if (v.type() == nPath || v.type() == nString) { PathSet context; - auto filename = state->coerceToString(noPos, v, context).toOwned(); - state->symbols.create(filename); + auto filename = state.coerceToString(noPos, v, context).toOwned(); + state.symbols.create(filename); return {filename, 0}; } 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}; } else { // assume it's a derivation - return findPackageFilename(*state, v, arg); + return findPackageFilename(state, v, arg); } }(); @@ -602,7 +603,7 @@ bool NixRepl::processLine(std::string line) runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }); // Reload right after exiting the editor - state->resetFileCache(); + state.resetFileCache(); reloadFiles(); } @@ -616,30 +617,30 @@ bool NixRepl::processLine(std::string line) Value v, f, result; evalString(arg, v); evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); - state->callFunction(f, v, result, PosIdx()); + state.callFunction(f, v, result, PosIdx()); 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") { Value v; evalString(arg, v); StorePath drvPath = getDerivationPath(v); - Path drvPathRaw = state->store->printStorePath(drvPath); + Path drvPathRaw = state.store->printStorePath(drvPath); if (command == ":b" || command == ":bl") { - state->store->buildPaths({DerivedPath::Built{drvPath}}); - auto drv = state->store->readDerivation(drvPath); + state.store->buildPaths({DerivedPath::Built{drvPath}}); + auto drv = state.store->readDerivation(drvPath); logger->cout("\nThis derivation produced the following outputs:"); - for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) { - auto localStore = state->store.dynamic_pointer_cast(); + for (auto & [outputName, outputPath] : state.store->queryDerivationOutputMap(drvPath)) { + auto localStore = state.store.dynamic_pointer_cast(); if (localStore && command == ":bl") { std::string symlink = "repl-result-" + outputName; localStore->addPermRoot(outputPath, absPath(symlink)); - logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath)); + logger->cout(" ./%s -> %s", symlink, state.store->printStorePath(outputPath)); } else { - logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath)); + logger->cout(" %s -> %s", outputName, state.store->printStorePath(outputPath)); } } } else if (command == ":i") { @@ -651,7 +652,7 @@ bool NixRepl::processLine(std::string line) }); auto subs = getDefaultSubstituters(); - subs.push_front(state->store); + subs.push_front(state.store); bool foundLog = false; RunPager pager; @@ -684,15 +685,15 @@ bool NixRepl::processLine(std::string line) } else if (command == ":q" || command == ":quit") { - state->debugStop = false; - state->debugQuit = true; + state.debugStop = false; + state.debugQuit = true; return false; } else if (command == ":doc") { Value v; evalString(arg, v); - if (auto doc = state->getDoc(v)) { + if (auto doc = state.getDoc(v)) { std::string markdown; if (!doc->args.empty() && doc->name) { @@ -736,9 +737,9 @@ bool NixRepl::processLine(std::string line) isVarName(name = removeWhitespace(line.substr(0, p)))) { Expr * e = parseString(line.substr(p + 1)); - Value & v(*state->allocValue()); + Value & v(*state.allocValue()); v.mkThunk(env, e); - addVarToScope(state->symbols.create(name), v); + addVarToScope(state.symbols.create(name), v); } else { Value v; evalString(line, v); @@ -755,8 +756,8 @@ void NixRepl::loadFile(const Path & path) loadedFiles.remove(path); loadedFiles.push_back(path); Value v, v2; - state->evalFile(lookupFileArg(*state, path), v); - state->autoCallFunction(*autoArgs, v, v2); + state.evalFile(lookupFileArg(state, path), v); + state.autoCallFunction(*autoArgs, v, v2); addAttrsToScope(v2); } @@ -771,8 +772,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS) Value v; - flake::callFlake(*state, - flake::lockFlake(*state, flakeRef, + flake::callFlake(state, + flake::lockFlake(state, flakeRef, flake::LockFlags { .updateLockFile = false, .useRegistries = !evalSettings.pureEval, @@ -785,14 +786,14 @@ void NixRepl::loadFlake(const std::string & flakeRefS) void NixRepl::initEnv() { - env = &state->allocEnv(envSize); - env->up = &state->baseEnv; + env = &state.allocEnv(envSize); + env->up = &state.baseEnv; displ = 0; staticEnv->vars.clear(); varNames.clear(); - for (auto & i : state->staticBaseEnv->vars) - varNames.emplace(state->symbols[i.first]); + for (auto & i : state.staticBaseEnv->vars) + varNames.emplace(state.symbols[i.first]); } @@ -821,14 +822,14 @@ void NixRepl::loadFiles() 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) throw Error("environment full; cannot add more variables"); for (auto & i : *attrs.attrs) { staticEnv->vars.emplace_back(i.name, displ); env->values[displ++] = i.value; - varNames.emplace(state->symbols[i.name]); + varNames.emplace(state.symbols[i.name]); } staticEnv->sort(); staticEnv->deduplicate(); @@ -845,13 +846,13 @@ void NixRepl::addVarToScope(const Symbol name, Value & v) staticEnv->vars.emplace_back(name, displ); staticEnv->sort(); env->values[displ++] = &v; - varNames.emplace(state->symbols[name]); + varNames.emplace(state.symbols[name]); } 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; } @@ -859,8 +860,8 @@ Expr * NixRepl::parseString(std::string s) void NixRepl::evalString(std::string s, Value & v) { Expr * e = parseString(s); - e->eval(*state, *env, v); - state->forceValue(v, [&]() { return v.determinePos(noPos); }); + e->eval(state, *env, v); + state.forceValue(v, [&]() { return v.determinePos(noPos); }); } @@ -890,7 +891,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m str.flush(); checkInterrupt(); - state->forceValue(v, [&]() { return v.determinePos(noPos); }); + state.forceValue(v, [&]() { return v.determinePos(noPos); }); switch (v.type()) { @@ -919,14 +920,14 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m case nAttrs: { seen.insert(&v); - bool isDrv = state->isDerivation(v); + bool isDrv = state.isDerivation(v); if (isDrv) { str << "«derivation "; - Bindings::iterator i = v.attrs->find(state->sDrvPath); + Bindings::iterator i = v.attrs->find(state.sDrvPath); PathSet context; 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 str << "???"; str << "»"; @@ -938,7 +939,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m typedef std::map Sorted; Sorted sorted; 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) { if (isVarName(i.first)) @@ -988,7 +989,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m case nFunction: if (v.isLambda()) { 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; } else if (v.isPrimOp()) { str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; @@ -1012,7 +1013,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } void runRepl( - ref evalState, + EvalState &evalState, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); @@ -1021,7 +1022,7 @@ void runRepl( // add 'extra' vars. for (auto & [name, value] : extraEnv) - repl->addVarToScope(repl->state->symbols.create(name), *value); + repl->addVarToScope(repl->state.symbols.create(name), *value); repl->mainLoop({}); } @@ -1057,8 +1058,8 @@ struct CmdRepl : StoreCommand, MixEvalArgs auto evalState = make_ref(searchPath, store); - auto repl = std::make_unique(evalState); - repl->autoArgs = getAutoArgs(*repl->state); + auto repl = std::make_unique(*evalState); + repl->autoArgs = getAutoArgs(repl->state); repl->initEnv(); repl->mainLoop(files); } -- cgit v1.2.3 From 7ccb2700c0401c553631e07aeb49e08f976274a3 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sun, 22 May 2022 19:15:58 -0600 Subject: comments --- src/libcmd/command.cc | 50 -------------------------------------------------- src/libexpr/nixexpr.cc | 4 ---- src/libexpr/nixexpr.hh | 2 -- 3 files changed, 56 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index b61b9b61d..c1d9eefc6 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -121,59 +121,9 @@ ref EvalCommand::getEvalState() evalState->debugMode = startReplOnEvalErrors; - // TODO move this somewhere else. Its only here to get the evalState ptr! if (startReplOnEvalErrors) { evalState->debugRepl = &runRepl; }; - // // 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()); - - // auto se = evalState.getStaticEnv(expr); - // if (se) { - // auto vm = mapStaticEnvBindings(evalState.symbols, *se.get(), env); - // runRepl(evalState, *vm); - // } - // 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()); - - // 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/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index b40791694..52d48122c 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -8,10 +8,6 @@ namespace nix { -/* Launch the nix debugger */ - -// std::function debuggerHook; - /* Displaying abstract syntax trees. */ static void showString(std::ostream & str, std::string_view s) diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 6a5d02ed1..9b3a9f5d0 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -22,8 +22,6 @@ MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); MakeError(RestrictedPathError, Error); -// extern std::function debuggerHook; - /* Position objects. */ struct Pos -- cgit v1.2.3 From 13d02af0799f5d2f7a53825936d587e22edcacb6 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Sun, 22 May 2022 21:45:24 -0600 Subject: remove redundant 'debugMode' flag --- src/libcmd/command.cc | 2 -- src/libcmd/repl.cc | 14 +++++++------- src/libexpr/eval.cc | 12 ++++++------ src/libexpr/eval.hh | 6 ++---- src/libexpr/nixexpr.cc | 38 +++++++++++++++++++------------------- src/libexpr/primops.cc | 2 +- 6 files changed, 35 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index c1d9eefc6..7f8072d75 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -119,8 +119,6 @@ ref EvalCommand::getEvalState() #endif ; - evalState->debugMode = startReplOnEvalErrors; - if (startReplOnEvalErrors) { evalState->debugRepl = &runRepl; }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index d335a56cd..940a287c7 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 (state.debugMode && !state.debugTraces.empty()) + if (state.debugRepl && !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 (state.debugMode) { + if (state.debugRepl) { std::cout << "\n" << " Debug mode commands\n" @@ -508,14 +508,14 @@ bool NixRepl::processLine(std::string line) } - else if (state.debugMode && (command == ":bt" || command == ":backtrace")) { + else if (state.debugRepl && (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 (state.debugMode && (command == ":env")) { + else if (state.debugRepl && (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 (state.debugMode && (command == ":st")) { + else if (state.debugRepl && (command == ":st")) { try { // change the DebugTrace index. debugTraceIndex = stoi(arg); @@ -542,13 +542,13 @@ bool NixRepl::processLine(std::string line) } } - else if (state.debugMode && (command == ":s" || command == ":step")) { + else if (state.debugRepl && (command == ":s" || command == ":step")) { // set flag to stop at next DebugTrace; exit repl. state.debugStop = true; return false; } - else if (state.debugMode && (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. state.debugStop = false; return false; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5faecdbe3..c457df380 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -813,7 +813,7 @@ std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const Stati void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & expr) { - // double check we've got the debugRepl ftn pointer. + // double check we've got the debugRepl function pointer. if (!debugRepl) return; @@ -1073,7 +1073,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) , trace(std::move(t)) { evalState.debugTraces.push_front(trace); - if (evalState.debugStop && evalState.debugMode) + if (evalState.debugStop && evalState.debugRepl) evalState.runDebugRepl(nullptr, trace.env, trace.expr); } @@ -1271,7 +1271,7 @@ void EvalState::cacheFile( fileParseCache[resolvedPath] = e; try { - auto dts = debugMode + auto dts = debugRepl ? makeDebugTraceStacker( *this, *e, @@ -1505,7 +1505,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - auto dts = state.debugMode + auto dts = state.debugRepl ? makeDebugTraceStacker( state, *this, @@ -1674,7 +1674,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & /* Evaluate the body. */ try { - auto dts = debugMode + auto dts = debugRepl ? makeDebugTraceStacker( *this, *lambda.body, env2, positions[lambda.pos], "while evaluating %s", @@ -2102,7 +2102,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 = debugMode && i.value->isThunk() + auto dts = debugRepl && 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 90bd5497b..c86075ae3 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -128,8 +128,6 @@ public: /* Debugger */ void (* debugRepl)(EvalState & es, const ValMap & extraEnv); - - bool debugMode; bool debugStop; bool debugQuit; std::list debugTraces; @@ -149,7 +147,7 @@ public: [[gnu::noinline, gnu::noreturn]] void debugThrow(const E &error, const Env & env, const Expr & expr) { - if (debugMode) + if (debugRepl) runDebugRepl(&error, env, expr); throw error; @@ -162,7 +160,7 @@ 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 (debugMode && !debugTraces.empty()) { + if (debugRepl && !debugTraces.empty()) { const DebugTrace & last = debugTraces.front(); runDebugRepl(&e, last.env, last.expr); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 52d48122c..7c623a07d 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -299,31 +299,31 @@ void Expr::bindVars(EvalState & es, const std::shared_ptr & env void ExprInt::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprFloat::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprString::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprPath::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); } void ExprVar::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); /* Check whether the variable appears in the environment. If so, @@ -359,7 +359,7 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr & void ExprSelect::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -371,7 +371,7 @@ void ExprSelect::bindVars(EvalState & es, const std::shared_ptr void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -382,7 +382,7 @@ void ExprOpHasAttr::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); if (recursive) { @@ -415,7 +415,7 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr void ExprList::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : elems) @@ -424,7 +424,7 @@ void ExprList::bindVars(EvalState & es, const std::shared_ptr & void ExprLambda::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared( @@ -451,7 +451,7 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr void ExprCall::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); fun->bindVars(es, env); @@ -461,7 +461,7 @@ void ExprCall::bindVars(EvalState & es, const std::shared_ptr & void ExprLet::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); auto newEnv = std::make_shared(false, env.get(), attrs->attrs.size()); @@ -480,7 +480,7 @@ void ExprLet::bindVars(EvalState & es, const std::shared_ptr & void ExprWith::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); /* Does this `with' have an enclosing `with'? If so, record its @@ -495,7 +495,7 @@ void ExprWith::bindVars(EvalState & es, const std::shared_ptr & break; } - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); attrs->bindVars(es, env); @@ -505,7 +505,7 @@ void ExprWith::bindVars(EvalState & es, const std::shared_ptr & void ExprIf::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); @@ -515,7 +515,7 @@ void ExprIf::bindVars(EvalState & es, const std::shared_ptr & e void ExprAssert::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); cond->bindVars(es, env); @@ -524,7 +524,7 @@ void ExprAssert::bindVars(EvalState & es, const std::shared_ptr void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); @@ -532,7 +532,7 @@ void ExprOpNot::bindVars(EvalState & es, const std::shared_ptr void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); for (auto & i : *this->es) @@ -541,7 +541,7 @@ void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr & env) { - if (es.debugMode) + if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 60a70f336..b24d4c68a 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 (state.debugMode && !state.debugTraces.empty()) { + if (state.debugRepl && !state.debugTraces.empty()) { auto error = Error(ErrorInfo { .level = lvlInfo, .msg = hintfmt("breakpoint reached"), -- cgit v1.2.3 From ba035f7dd03232d093a1265778b9587bab92cf1d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 23 May 2022 10:13:47 -0600 Subject: comment --- src/libcmd/repl.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 940a287c7..d7201b321 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -49,7 +49,6 @@ struct NixRepl { std::string curDir; EvalState &state; - // ref state; Bindings * autoArgs; size_t debugTraceIndex; -- cgit v1.2.3 From b916c08feba5173c3455890cff615fd46464409a Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 24 May 2022 14:20:48 +0200 Subject: libfetchers: drop `getGitDir` and hardcode `.git` As discussed[1] this is most likely not desirable. [1] https://github.com/NixOS/nix/pull/6440#issuecomment-1120876248 --- src/libfetchers/git.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index d23a820a4..a71bff76f 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -26,11 +26,6 @@ namespace { // old version of git, which will ignore unrecognized `-c` options. const std::string gitInitialBranch = "__nix_dummy_branch"; -std::string getGitDir() -{ - return getEnv("GIT_DIR").value_or(".git"); -} - bool isCacheFileWithinTtl(const time_t now, const struct stat & st) { return st.st_mtime + settings.tarballTtl > now; @@ -152,7 +147,7 @@ struct WorkdirInfo WorkdirInfo getWorkdirInfo(const Input & input, const Path & workdir) { const bool submodules = maybeGetBoolAttr(input.attrs, "submodules").value_or(false); - auto gitDir = getGitDir(); + std::string gitDir(".git"); auto env = getEnv(); // Set LC_ALL to C: because we rely on the error messages from git rev-parse to determine what went wrong @@ -370,7 +365,7 @@ struct GitInputScheme : InputScheme { auto sourcePath = getSourcePath(input); assert(sourcePath); - auto gitDir = getGitDir(); + auto gitDir = ".git"; runProgram("git", true, { "-C", *sourcePath, "--git-dir", gitDir, "add", "--force", "--intent-to-add", "--", std::string(file) }); @@ -396,7 +391,7 @@ struct GitInputScheme : InputScheme std::pair fetch(ref store, const Input & _input) override { Input input(_input); - auto gitDir = getGitDir(); + auto gitDir = ".git"; std::string name = input.getName(); -- cgit v1.2.3 From 91b7d5373acdc5d9b3f2c13d16b9850ab5fc9e9d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 May 2022 12:32:22 +0200 Subject: Style tweaks --- src/libcmd/command.hh | 2 +- src/libcmd/repl.cc | 8 +- src/libexpr/eval-cache.cc | 40 ++---- src/libexpr/eval.cc | 114 +++++---------- src/libexpr/eval.hh | 10 +- src/libexpr/parser.y | 5 +- src/libexpr/primops.cc | 294 ++++++++++++--------------------------- src/libexpr/primops/fetchTree.cc | 59 +++----- src/libexpr/value-to-json.cc | 3 +- 9 files changed, 165 insertions(+), 370 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index b064f490a..916695102 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,6 +274,6 @@ void printClosureDiff( void runRepl( - EvalState &evalState, + EvalState & evalState, const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index d7201b321..7d8bbdb7e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -48,7 +48,7 @@ struct NixRepl #endif { std::string curDir; - EvalState &state; + EvalState & state; Bindings * autoArgs; size_t debugTraceIndex; @@ -63,11 +63,11 @@ struct NixRepl const Path historyFile; - NixRepl(EvalState &state); + NixRepl(EvalState & state); ~NixRepl(); void mainLoop(const std::vector & files); StringSet completePrefix(const std::string & prefix); - bool getLine(std::string & input, const std::string &prompt); + bool getLine(std::string & input, const std::string & prompt); StorePath getDerivationPath(Value & v); bool processLine(std::string line); void loadFile(const Path & path); @@ -96,7 +96,7 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(EvalState &state) +NixRepl::NixRepl(EvalState & state) : state(state) , debugTraceIndex(0) , staticEnv(new StaticEnv(false, state.staticBaseEnv.get())) diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index af213a484..1be98fc95 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -554,20 +554,14 @@ std::string AttrCursor::getString() debug("using cached string attribute '%s'", getAttrPathStr()); return s->first; } else - { - auto e = TypeError("'%s' is not a string", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a string", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nString && v.type() != nPath) - { - auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); return v.type() == nString ? v.string.s : v.path; } @@ -591,10 +585,7 @@ string_t AttrCursor::getStringWithContext() return *s; } } else - { - auto e = TypeError("'%s' is not a string", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a string", getAttrPathStr())); } } @@ -605,10 +596,7 @@ string_t AttrCursor::getStringWithContext() else if (v.type() == nPath) return {v.path, {}}; else - { - auto e = TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()))); } bool AttrCursor::getBool() @@ -621,20 +609,14 @@ bool AttrCursor::getBool() debug("using cached Boolean attribute '%s'", getAttrPathStr()); return *b; } else - { - auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a Boolean", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nBool) - { - auto e = TypeError("'%s' is not a Boolean", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not a Boolean", getAttrPathStr())); return v.boolean; } @@ -682,20 +664,14 @@ std::vector AttrCursor::getAttrs() debug("using cached attrset attribute '%s'", getAttrPathStr()); return *attrs; } else - { - auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not an attribute set", getAttrPathStr())); } } auto & v = forceValue(); if (v.type() != nAttrs) - { - auto e = TypeError("'%s' is not an attribute set", getAttrPathStr()); - root->state.debugThrowLastTrace(e); - } + root->state.debugThrowLastTrace(TypeError("'%s' is not an attribute set", getAttrPathStr())); std::vector attrs; for (auto & attr : *getValue().attrs) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c457df380..6dc7918b1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -816,7 +816,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & // double check we've got the debugRepl function pointer. if (!debugRepl) return; - + auto dts = error && expr.getPos() ? std::make_unique( @@ -846,198 +846,160 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & exceptions. */ void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr) { - auto error = EvalError({ + debugThrow(EvalError({ .msg = hintfmt(s), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s) { - auto error = EvalError({ + debugThrowLastTrace(EvalError({ .msg = hintfmt(s), .errPos = positions[pos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwEvalError(const char * s, const std::string & s2) { - auto error = EvalError(s, s2); - - debugThrowLastTrace(error); + debugThrowLastTrace(EvalError(s, s2)); } void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr & expr) { - auto error = EvalError(ErrorInfo{ + debugThrow(EvalError(ErrorInfo{ .msg = hintfmt(s, s2), .errPos = positions[pos], .suggestions = suggestions, - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) { - auto error = EvalError({ + debugThrowLastTrace(EvalError({ .msg = hintfmt(s, s2), .errPos = positions[pos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) { - auto error = EvalError({ + debugThrow(EvalError({ .msg = hintfmt(s, s2), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwEvalError(const char * s, const std::string & s2, const std::string & s3) { - auto error = EvalError({ + debugThrowLastTrace(EvalError({ .msg = hintfmt(s, s2), .errPos = positions[noPos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) { - auto error = EvalError({ + debugThrowLastTrace(EvalError({ .msg = hintfmt(s, s2), .errPos = positions[pos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, Env & env, Expr & expr) { - auto error = EvalError({ + debugThrow(EvalError({ .msg = hintfmt(s, s2), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) { // p1 is where the error occurred; p2 is a position mentioned in the message. - auto error = EvalError({ + debugThrow(EvalError({ .msg = hintfmt(s, symbols[sym], positions[p2]), .errPos = positions[p1] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) { - auto error = TypeError({ + debugThrowLastTrace(TypeError({ .msg = hintfmt(s, showType(v)), .errPos = positions[pos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) { - auto error = TypeError({ + debugThrow(TypeError({ .msg = hintfmt(s, showType(v)), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s) { - auto error = TypeError({ + debugThrowLastTrace(TypeError({ .msg = hintfmt(s), .errPos = positions[pos] - }); - - debugThrowLastTrace(error); + })); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, Env & env, Expr &expr) { - auto error = TypeError({ + debugThrow(TypeError({ .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol s2, Env & env, Expr &expr) { - auto error = TypeError(ErrorInfo { + debugThrow(TypeError(ErrorInfo { .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), .errPos = positions[pos], .suggestions = suggestions, - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) { - auto error = TypeError({ + debugThrow(TypeError({ .msg = hintfmt(s, showType(v)), .errPos = positions[expr.getPos()], - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { - auto error = AssertionError({ + debugThrow(AssertionError({ .msg = hintfmt(s, s1), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { - auto error = UndefinedVarError({ + debugThrow(UndefinedVarError({ .msg = hintfmt(s, s1), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) { - auto error = MissingArgumentError({ + debugThrow(MissingArgumentError({ .msg = hintfmt(s, s1), .errPos = positions[pos] - }); - - debugThrow(error, env, expr); + }), env, expr); } void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2) const diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index c86075ae3..3444815fd 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -131,11 +131,11 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; - std::map > exprEnvs; - const std::shared_ptr getStaticEnv(const Expr &expr) const + std::map> exprEnvs; + const std::shared_ptr getStaticEnv(const Expr & expr) const { auto i = exprEnvs.find(&expr); - if (i != exprEnvs.end()) + if (i != exprEnvs.end()) return i->second; else return std::shared_ptr();; @@ -145,7 +145,7 @@ public: template [[gnu::noinline, gnu::noreturn]] - void debugThrow(const E &error, const Env & env, const Expr & expr) + void debugThrow(E && error, const Env & env, const Expr & expr) { if (debugRepl) runDebugRepl(&error, env, expr); @@ -155,7 +155,7 @@ public: template [[gnu::noinline, gnu::noreturn]] - void debugThrowLastTrace(E & e) + void debugThrowLastTrace(E && e) { // Call this in the situation where Expr and Env are inaccessible. // The debugger will start in the last context that's in the diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index b960cd8df..e3e0ac168 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -782,14 +782,13 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c if (hasPrefix(path, "nix/")) return concatStrings(corepkgsPrefix, path.substr(4)); - auto e = ThrownError({ + debugThrowLastTrace(ThrownError({ .msg = hintfmt(evalSettings.pureEval ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)" : "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)", path), .errPos = positions[pos] - }); - debugThrowLastTrace(e); + })); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index b24d4c68a..96cd84b82 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -46,10 +46,7 @@ StringMap EvalState::realiseContext(const PathSet & context) auto [ctx, outputName] = decodeContext(*store, i); auto ctxS = store->printStorePath(ctx); if (!store->isValidPath(ctx)) - { - auto e = InvalidPathError(store->printStorePath(ctx)); - debugThrowLastTrace(e); - } + debugThrowLastTrace(InvalidPathError(store->printStorePath(ctx))); if (!outputName.empty() && ctx.isDerivation()) { drvs.push_back({ctx, {outputName}}); } else { @@ -60,12 +57,9 @@ StringMap EvalState::realiseContext(const PathSet & context) if (drvs.empty()) return {}; if (!evalSettings.enableImportFromDerivation) - { - auto e = Error( + debugThrowLastTrace(Error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", - store->printStorePath(drvs.begin()->drvPath)); - debugThrowLastTrace(e); - } + store->printStorePath(drvs.begin()->drvPath))); /* Build/substitute the context. */ std::vector buildReqs; @@ -77,11 +71,9 @@ StringMap EvalState::realiseContext(const PathSet & context) const auto outputPaths = store->queryDerivationOutputMap(drvPath); for (auto & outputName : outputs) { auto outputPath = get(outputPaths, outputName); - if (!outputPath) { - auto e = Error("derivation '%s' does not have an output named '%s'", - store->printStorePath(drvPath), outputName); - debugThrowLastTrace(e); - } + if (!outputPath) + debugThrowLastTrace(Error("derivation '%s' does not have an output named '%s'", + store->printStorePath(drvPath), outputName)); res.insert_or_assign( downstreamPlaceholder(*store, drvPath, outputName), store->printStorePath(*outputPath) @@ -326,23 +318,17 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu std::string sym(state.forceStringNoCtx(*args[1], pos)); void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); - if (!handle) { - auto e = EvalError("could not open '%1%': %2%", path, dlerror()); - state.debugThrowLastTrace(e); - } + if (!handle) + state.debugThrowLastTrace(EvalError("could not open '%1%': %2%", path, dlerror())); dlerror(); ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str()); if(!func) { char *message = dlerror(); - if (message) { - auto e = EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message); - state.debugThrowLastTrace(e); - } else { - auto e = EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", - sym, path); - state.debugThrowLastTrace(e); - } + if (message) + state.debugThrowLastTrace(EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message)); + else + state.debugThrowLastTrace(EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path)); } (func)(state, v); @@ -357,13 +343,11 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) state.forceList(*args[0], pos); auto elems = args[0]->listElems(); auto count = args[0]->listSize(); - if (count == 0) { - auto e = EvalError({ + if (count == 0) + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("at least one argument to 'exec' required"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); PathSet context; auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); Strings commandArgs; @@ -373,12 +357,11 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) try { auto _ = state.realiseContext(context); // FIXME: Handle CA derivations } catch (InvalidPathError & e) { - auto ee = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", program, e.path), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(ee); + })); } auto output = runProgram(program, true, commandArgs); @@ -561,10 +544,8 @@ struct CompareValues return v1->fpoint < v2->integer; if (v1->type() == nInt && v2->type() == nFloat) return v1->integer < v2->fpoint; - if (v1->type() != v2->type()) { - auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - state.debugThrowLastTrace(e); - } + if (v1->type() != v2->type()) + state.debugThrowLastTrace(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); switch (v1->type()) { case nInt: return v1->integer < v2->integer; @@ -585,10 +566,8 @@ struct CompareValues return (*this)(v1->listElems()[i], v2->listElems()[i]); } } - default: { - auto e = EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - state.debugThrowLastTrace(e); - } + default: + state.debugThrowLastTrace(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); } } }; @@ -618,11 +597,10 @@ static Bindings::iterator getAttr( auto aPos = attrSet->pos; if (!aPos) { - auto e = TypeError({ + state.debugThrowLastTrace(TypeError({ .msg = errorMsg, .errPos = state.positions[pos], - }); - state.debugThrowLastTrace(e); + })); } else { auto e = TypeError({ .msg = errorMsg, @@ -685,13 +663,11 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a Bindings::iterator key = e->attrs->find(state.sKey); - if (key == e->attrs->end()) { - auto e = EvalError({ + if (key == e->attrs->end()) + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("attribute 'key' required"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); state.forceValue(*key->value, pos); if (!doneKeys.insert(key->value).second) continue; @@ -792,10 +768,7 @@ static RegisterPrimOp primop_abort({ { PathSet context; auto s = state.coerceToString(pos, *args[0], context).toOwned(); - { - auto e = Abort("evaluation aborted with the following error message: '%1%'", s); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s)); } }); @@ -813,8 +786,7 @@ static RegisterPrimOp primop_throw({ { PathSet context; auto s = state.coerceToString(pos, *args[0], context).toOwned(); - auto e = ThrownError(s); - state.debugThrowLastTrace(e); + state.debugThrowLastTrace(ThrownError(s)); } }); @@ -1069,49 +1041,37 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive; else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; else - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); }; auto handleOutputs = [&](const Strings & ss) { outputs.clear(); for (auto & j : ss) { if (outputs.find(j) != outputs.end()) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("duplicate derivation output '%1%'", j), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); /* !!! Check whether j is a valid attribute name. */ /* Derivations cannot be named ‘drv’, because then we'd have an attribute ‘drvPath’ in the resulting set. */ if (j == "drv") - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("invalid derivation output name 'drv'" ), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); outputs.insert(j); } if (outputs.empty()) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("derivation cannot have an empty set of outputs"), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); }; try { @@ -1236,32 +1196,23 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * /* Do we have all required attributes? */ if (drv.builder == "") - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("required attribute 'builder' missing"), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); if (drv.platform == "") - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("required attribute 'system' missing"), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); /* Check whether the derivation name is valid. */ if (isDerivation(drvName)) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); if (outputHash) { /* Handle fixed-output derivations. @@ -1269,13 +1220,10 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * Ignore `__contentAddressed` because fixed output derivations are already content addressed. */ if (outputs.size() != 1 || *(outputs.begin()) != "out") - { - auto e = Error({ + state.debugThrowLastTrace(Error({ .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), .errPos = state.positions[posDrvName] - }); - state.debugThrowLastTrace(e); - } + })); auto h = newHashAllowEmpty(*outputHash, parseHashTypeOpt(outputHashAlgo)); @@ -1443,13 +1391,10 @@ static RegisterPrimOp primop_toPath({ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v) { if (evalSettings.pureEval) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); PathSet context; Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); @@ -1458,13 +1403,10 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, e.g. nix-push does the right thing. */ if (!state.store->isStorePath(path)) path = canonPath(path, true); if (!state.store->isInStore(path)) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); auto path2 = state.store->toStorePath(path).first; if (!settings.readOnlyMode) state.store->ensurePath(path2); @@ -1567,10 +1509,7 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V auto path = realisePath(state, pos, *args[0]); auto s = readFile(path); if (s.find((char) 0) != std::string::npos) - { - auto e = Error("the contents of the file '%1%' cannot be represented as a Nix string", path); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(Error("the contents of the file '%1%' cannot be represented as a Nix string", path)); StorePathSet refs; if (state.store->isInStore(path)) { try { @@ -1622,14 +1561,12 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V auto rewrites = state.realiseContext(context); path = rewriteStrings(path, rewrites); } catch (InvalidPathError & e) { - auto ee = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(ee); + })); } - searchPath.emplace_back(prefix, path); } @@ -1650,13 +1587,10 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, V auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - { - auto e = Error({ + state.debugThrowLastTrace(Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); auto path = realisePath(state, pos, *args[1]); @@ -1893,16 +1827,13 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Val for (auto path : context) { if (path.at(0) != '/') - { - auto e = EvalError( { + state.debugThrowLastTrace(EvalError({ .msg = hintfmt( "in 'toFile': the file named '%1%' must not contain a reference " "to a derivation but contains (%2%)", name, path), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); refs.insert(state.store->parseStorePath(path)); } @@ -2060,10 +1991,7 @@ static void addPath( ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs); if (expectedHash && expectedStorePath != dstPath) - { - auto e = Error("store path mismatch in (possibly filtered) path added from '%s'", path); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); state.allowAndSetStorePathString(dstPath, v); } else state.allowAndSetStorePathString(*expectedStorePath, v); @@ -2081,15 +2009,12 @@ static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * arg state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) - { - auto e = TypeError({ + state.debugThrowLastTrace(TypeError({ .msg = hintfmt( "first argument in call to 'filterSource' is not a function but %1%", showType(*args[0])), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); } @@ -2173,22 +2098,16 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value else if (n == "sha256") expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos), htSHA256); else - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("unsupported argument '%1%' to 'addPath'", state.symbols[attr.name]), .errPos = state.positions[attr.pos] - }); - state.debugThrowLastTrace(e); - } + })); } if (path.empty()) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("'path' required"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); if (name.empty()) name = baseNameOf(path); @@ -2560,13 +2479,10 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg return; } if (!args[0]->isLambda()) - { - auto e = TypeError({ + state.debugThrowLastTrace(TypeError({ .msg = hintfmt("'functionArgs' requires a function"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); if (!args[0]->lambda.fun->hasFormals()) { v.mkAttrs(&state.emptyBindings); @@ -2741,13 +2657,10 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val { state.forceList(list, pos); if (n < 0 || (unsigned int) n >= list.listSize()) - { - auto e = Error({ + state.debugThrowLastTrace(Error({ .msg = hintfmt("list index %1% is out of bounds", n), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); state.forceValue(*list.listElems()[n], pos); v = *list.listElems()[n]; } @@ -2792,13 +2705,10 @@ static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value { state.forceList(*args[0], pos); if (args[0]->listSize() == 0) - { - auto e = Error({ + state.debugThrowLastTrace(Error({ .msg = hintfmt("'tail' called on an empty list"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); state.mkList(v, args[0]->listSize() - 1); for (unsigned int n = 0; n < v.listSize(); ++n) @@ -3033,13 +2943,10 @@ static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Va auto len = state.forceInt(*args[1], pos); if (len < 0) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("cannot create list of size %1%", len), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); state.mkList(v, len); @@ -3343,13 +3250,10 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value NixFloat f2 = state.forceFloat(*args[1], pos); if (f2 == 0) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("division by zero"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); if (args[0]->type() == nFloat || args[1]->type() == nFloat) { v.mkFloat(state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); @@ -3358,13 +3262,10 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value NixInt i2 = state.forceInt(*args[1], pos); /* Avoid division overflow as it might raise SIGFPE. */ if (i1 == std::numeric_limits::min() && i2 == -1) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("overflow in integer division"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); v.mkInt(i1 / i2); } @@ -3492,13 +3393,10 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, auto s = state.coerceToString(pos, *args[2], context); if (start < 0) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("negative start position in 'substring'"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context); } @@ -3546,13 +3444,10 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args, auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - { - auto e = Error({ + state.debugThrowLastTrace(Error({ .msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); PathSet context; // discarded auto s = state.forceString(*args[1], context, pos); @@ -3622,18 +3517,15 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } else { - auto e = EvalError({ + })); + } else + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); } } @@ -3729,18 +3621,15 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) } catch (std::regex_error &e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } else { - auto e = EvalError({ + })); + } else + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); } } @@ -3816,13 +3705,10 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a state.forceList(*args[0], pos); state.forceList(*args[1], pos); if (args[0]->listSize() != args[1]->listSize()) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); std::vector from; from.reserve(args[0]->listSize()); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index e4fa3c5f9..e5eeea520 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -108,22 +108,16 @@ static void fetchTree( if (auto aType = args[0]->attrs->get(state.sType)) { if (type) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("unexpected attribute 'type'"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); type = state.forceStringNoCtx(*aType->value, aType->pos); } else if (!type) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); attrs.emplace("type", type.value()); @@ -144,22 +138,16 @@ static void fetchTree( else if (attr.value->type() == nInt) attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer)); else - { - auto e = TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", - state.symbols[attr.name], showType(*attr.value)); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", + state.symbols[attr.name], showType(*attr.value))); } if (!params.allowNameArgument) if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); input = fetchers::Input::fromAttrs(std::move(attrs)); } else { @@ -179,10 +167,7 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (evalSettings.pureEval && !input.isLocked()) - { - auto e = EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos]); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos])); auto [tree, input2] = input.fetch(state.store); @@ -221,23 +206,17 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v else if (n == "name") name = state.forceStringNoCtx(*attr.value, attr.pos); else - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("unsupported argument '%s' to '%s'", n, who), .errPos = state.positions[attr.pos] - }); - state.debugThrowLastTrace(e); - } + })); } if (!url) - { - auto e = EvalError({ + state.debugThrowLastTrace(EvalError({ .msg = hintfmt("'url' argument required"), .errPos = state.positions[pos] - }); - state.debugThrowLastTrace(e); - } + })); } else url = state.forceStringNoCtx(*args[0], pos); @@ -249,10 +228,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v name = baseNameOf(*url); if (evalSettings.pureEval && !expectedHash) - { - auto e = EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(EvalError("in pure evaluation mode, '%s' requires a 'sha256' argument", who)); // early exit if pinned and already in the store if (expectedHash && expectedHash->type == htSHA256) { @@ -279,11 +255,8 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v ? state.store->queryPathInfo(storePath)->narHash : hashFile(htSHA256, state.store->toRealPath(storePath)); if (hash != *expectedHash) - { - auto e = EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", - *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)); - state.debugThrowLastTrace(e); - } + state.debugThrowLastTrace(EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", + *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true))); } state.allowAndSetStorePathString(storePath, v); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 6a95e0414..03504db61 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -100,8 +100,7 @@ void printValueAsJSON(EvalState & state, bool strict, void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const { - auto e = TypeError("cannot convert %1% to JSON", showType()); - state.debugThrowLastTrace(e); + state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType())); } -- cgit v1.2.3 From 2f8a34cddcdd738afebde38e83b2315d3e305152 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 May 2022 15:05:39 +0200 Subject: Fix warning --- src/nix/profile.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 1aae347df..3814e7d5a 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -263,7 +263,8 @@ builtPathsPerInstallable( struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { - std::optional priority; + std::optional priority; + CmdProfileInstall() { addFlag({ .longName = "priority", -- cgit v1.2.3 From d8398d33c9a09e1f5599127ae6d477e7e0868b55 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 May 2022 15:29:27 +0200 Subject: Typo --- src/libfetchers/tarball.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index 09acb74d3..6c551bd93 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -169,7 +169,7 @@ std::pair downloadTarball( }; } -// An input scheme corresponding to a curable ressource +// An input scheme corresponding to a curl-downloadable resource. struct CurlInputScheme : InputScheme { virtual const std::string inputType() const = 0; -- cgit v1.2.3 From 27ebb97d0a51a3198f2c95cbdccd6f56274c19ee Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 May 2022 15:45:10 +0200 Subject: Handle EOFs in string literals correctly We can't return a STR token without setting a valid StringToken, otherwise the parser will crash. Fixes #6562. --- src/libexpr/lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l index 4c28b976e..462b3b602 100644 --- a/src/libexpr/lexer.l +++ b/src/libexpr/lexer.l @@ -198,7 +198,7 @@ or { return OR_KW; } (...|\$[^\{\"\\]|\\.|\$\\.)+ would have triggered. This is technically invalid, but we leave the problem to the parser who fails with exact location. */ - return STR; + return EOF; } \'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; } -- cgit v1.2.3 From b4c24a29c62259a068c8270be62cf5a412e1e35c Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 25 May 2022 10:21:20 -0600 Subject: back to ref in NixRepl --- src/libcmd/command.hh | 2 +- src/libcmd/repl.cc | 156 +++++++++++++++++++++++++------------------------- src/libexpr/eval.cc | 2 +- src/libexpr/eval.hh | 5 +- 4 files changed, 82 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 916695102..8982f21d0 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -274,6 +274,6 @@ void printClosureDiff( void runRepl( - EvalState & evalState, + ref evalState, const ValMap & extraEnv); } diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 7d8bbdb7e..993dcd634 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -48,7 +48,7 @@ struct NixRepl #endif { std::string curDir; - EvalState & state; + ref state; Bindings * autoArgs; size_t debugTraceIndex; @@ -63,7 +63,7 @@ struct NixRepl const Path historyFile; - NixRepl(EvalState & state); + NixRepl(ref state); ~NixRepl(); void mainLoop(const std::vector & files); StringSet completePrefix(const std::string & prefix); @@ -96,10 +96,10 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(EvalState & state) +NixRepl::NixRepl(ref state) : state(state) , debugTraceIndex(0) - , staticEnv(new StaticEnv(false, state.staticBaseEnv.get())) + , staticEnv(new StaticEnv(false, state->staticBaseEnv.get())) , historyFile(getDataDir() + "/nix/repl-history") { curDir = absPath("."); @@ -261,8 +261,8 @@ void NixRepl::mainLoop(const std::vector & files) // number of chars as the prompt. if (!getLine(input, input.empty() ? "nix-repl> " : " ")) { // ctrl-D should exit the debugger. - state.debugStop = false; - state.debugQuit = true; + state->debugStop = false; + state->debugQuit = true; break; } try { @@ -279,8 +279,8 @@ 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 (state.debugRepl && !state.debugTraces.empty()) - showDebugTrace(std::cout, state.positions, state.debugTraces.front()); + if (state->debugRepl && !state->debugTraces.empty()) + showDebugTrace(std::cout, state->positions, state->debugTraces.front()); else printMsg(lvlError, e.msg()); } catch (Error & e) { @@ -386,11 +386,11 @@ StringSet NixRepl::completePrefix(const std::string & prefix) Expr * e = parseString(expr); Value v; - e->eval(state, *env, v); - state.forceAttrs(v, noPos); + e->eval(*state, *env, v); + state->forceAttrs(v, noPos); 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; completions.insert(concatStrings(prev, expr, ".", name)); } @@ -426,14 +426,14 @@ static bool isVarName(std::string_view s) StorePath NixRepl::getDerivationPath(Value & v) { - auto drvInfo = getDerivation(state, v, false); + auto drvInfo = getDerivation(*state, v, false); if (!drvInfo) throw Error("expression does not evaluate to a derivation, so I can't build it"); auto drvPath = drvInfo->queryDrvPath(); if (!drvPath) throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)"); - if (!state.store->isValidPath(*drvPath)) - throw Error("expression evaluated to invalid derivation '%s'", state.store->printStorePath(*drvPath)); + if (!state->store->isValidPath(*drvPath)) + throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath)); return *drvPath; } @@ -441,13 +441,13 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt) { initEnv(); - auto se = state.getStaticEnv(dt.expr); + auto se = state->getStaticEnv(dt.expr); if (se) { - auto vm = mapStaticEnvBindings(state.symbols, *se.get(), dt.env); + auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env); // add staticenv vars. 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 Show logs for a derivation\n" << " :te [bool] Enable, disable or toggle showing traces for errors\n" ; - if (state.debugRepl) { + if (state->debugRepl) { std::cout << "\n" << " Debug mode commands\n" @@ -507,49 +507,49 @@ bool NixRepl::processLine(std::string line) } - else if (state.debugRepl && (command == ":bt" || command == ":backtrace")) { - for (const auto & [idx, i] : enumerate(state.debugTraces)) { + else if (state->debugRepl && (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); + showDebugTrace(std::cout, state->positions, i); } } - else if (state.debugRepl && (command == ":env")) { - for (const auto & [idx, i] : enumerate(state.debugTraces)) { + else if (state->debugRepl && (command == ":env")) { + for (const auto & [idx, i] : enumerate(state->debugTraces)) { if (idx == debugTraceIndex) { - printEnvBindings(state, i.expr, i.env); + printEnvBindings(*state, i.expr, i.env); break; } } } - else if (state.debugRepl && (command == ":st")) { + else if (state->debugRepl && (command == ":st")) { try { // change the DebugTrace index. debugTraceIndex = stoi(arg); } catch (...) { } - for (const auto & [idx, i] : enumerate(state.debugTraces)) { + for (const auto & [idx, i] : enumerate(state->debugTraces)) { if (idx == debugTraceIndex) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, state.positions, i); + showDebugTrace(std::cout, state->positions, i); std::cout << std::endl; - printEnvBindings(state, i.expr, i.env); + printEnvBindings(*state, i.expr, i.env); loadDebugTraceEnv(i); 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. - state.debugStop = true; + state->debugStop = true; 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. - state.debugStop = false; + state->debugStop = false; return false; } @@ -560,7 +560,7 @@ bool NixRepl::processLine(std::string line) } else if (command == ":l" || command == ":load") { - state.resetFileCache(); + state->resetFileCache(); loadFile(arg); } @@ -569,7 +569,7 @@ bool NixRepl::processLine(std::string line) } else if (command == ":r" || command == ":reload") { - state.resetFileCache(); + state->resetFileCache(); reloadFiles(); } @@ -580,15 +580,15 @@ bool NixRepl::processLine(std::string line) const auto [file, line] = [&] () -> std::pair { if (v.type() == nPath || v.type() == nString) { PathSet context; - auto filename = state.coerceToString(noPos, v, context).toOwned(); - state.symbols.create(filename); + auto filename = state->coerceToString(noPos, v, context).toOwned(); + state->symbols.create(filename); return {filename, 0}; } 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}; } else { // 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 }); // Reload right after exiting the editor - state.resetFileCache(); + state->resetFileCache(); reloadFiles(); } @@ -616,30 +616,30 @@ bool NixRepl::processLine(std::string line) Value v, f, result; evalString(arg, v); evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); - state.callFunction(f, v, result, PosIdx()); + state->callFunction(f, v, result, PosIdx()); 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") { Value v; evalString(arg, v); StorePath drvPath = getDerivationPath(v); - Path drvPathRaw = state.store->printStorePath(drvPath); + Path drvPathRaw = state->store->printStorePath(drvPath); if (command == ":b" || command == ":bl") { - state.store->buildPaths({DerivedPath::Built{drvPath}}); - auto drv = state.store->readDerivation(drvPath); + state->store->buildPaths({DerivedPath::Built{drvPath}}); + auto drv = state->store->readDerivation(drvPath); logger->cout("\nThis derivation produced the following outputs:"); - for (auto & [outputName, outputPath] : state.store->queryDerivationOutputMap(drvPath)) { - auto localStore = state.store.dynamic_pointer_cast(); + for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) { + auto localStore = state->store.dynamic_pointer_cast(); if (localStore && command == ":bl") { std::string symlink = "repl-result-" + outputName; localStore->addPermRoot(outputPath, absPath(symlink)); - logger->cout(" ./%s -> %s", symlink, state.store->printStorePath(outputPath)); + logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath)); } else { - logger->cout(" %s -> %s", outputName, state.store->printStorePath(outputPath)); + logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath)); } } } else if (command == ":i") { @@ -651,7 +651,7 @@ bool NixRepl::processLine(std::string line) }); auto subs = getDefaultSubstituters(); - subs.push_front(state.store); + subs.push_front(state->store); bool foundLog = false; RunPager pager; @@ -684,15 +684,15 @@ bool NixRepl::processLine(std::string line) } else if (command == ":q" || command == ":quit") { - state.debugStop = false; - state.debugQuit = true; + state->debugStop = false; + state->debugQuit = true; return false; } else if (command == ":doc") { Value v; evalString(arg, v); - if (auto doc = state.getDoc(v)) { + if (auto doc = state->getDoc(v)) { std::string markdown; if (!doc->args.empty() && doc->name) { @@ -736,9 +736,9 @@ bool NixRepl::processLine(std::string line) isVarName(name = removeWhitespace(line.substr(0, p)))) { Expr * e = parseString(line.substr(p + 1)); - Value & v(*state.allocValue()); + Value & v(*state->allocValue()); v.mkThunk(env, e); - addVarToScope(state.symbols.create(name), v); + addVarToScope(state->symbols.create(name), v); } else { Value v; evalString(line, v); @@ -755,8 +755,8 @@ void NixRepl::loadFile(const Path & path) loadedFiles.remove(path); loadedFiles.push_back(path); Value v, v2; - state.evalFile(lookupFileArg(state, path), v); - state.autoCallFunction(*autoArgs, v, v2); + state->evalFile(lookupFileArg(*state, path), v); + state->autoCallFunction(*autoArgs, v, v2); addAttrsToScope(v2); } @@ -771,8 +771,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS) Value v; - flake::callFlake(state, - flake::lockFlake(state, flakeRef, + flake::callFlake(*state, + flake::lockFlake(*state, flakeRef, flake::LockFlags { .updateLockFile = false, .useRegistries = !evalSettings.pureEval, @@ -785,14 +785,14 @@ void NixRepl::loadFlake(const std::string & flakeRefS) void NixRepl::initEnv() { - env = &state.allocEnv(envSize); - env->up = &state.baseEnv; + env = &state->allocEnv(envSize); + env->up = &state->baseEnv; displ = 0; staticEnv->vars.clear(); varNames.clear(); - for (auto & i : state.staticBaseEnv->vars) - varNames.emplace(state.symbols[i.first]); + for (auto & i : state->staticBaseEnv->vars) + varNames.emplace(state->symbols[i.first]); } @@ -821,14 +821,14 @@ void NixRepl::loadFiles() 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) throw Error("environment full; cannot add more variables"); for (auto & i : *attrs.attrs) { staticEnv->vars.emplace_back(i.name, displ); env->values[displ++] = i.value; - varNames.emplace(state.symbols[i.name]); + varNames.emplace(state->symbols[i.name]); } staticEnv->sort(); staticEnv->deduplicate(); @@ -845,13 +845,13 @@ void NixRepl::addVarToScope(const Symbol name, Value & v) staticEnv->vars.emplace_back(name, displ); staticEnv->sort(); env->values[displ++] = &v; - varNames.emplace(state.symbols[name]); + varNames.emplace(state->symbols[name]); } 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; } @@ -859,8 +859,8 @@ Expr * NixRepl::parseString(std::string s) void NixRepl::evalString(std::string s, Value & v) { Expr * e = parseString(s); - e->eval(state, *env, v); - state.forceValue(v, [&]() { return v.determinePos(noPos); }); + e->eval(*state, *env, v); + 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(); checkInterrupt(); - state.forceValue(v, [&]() { return v.determinePos(noPos); }); + state->forceValue(v, [&]() { return v.determinePos(noPos); }); switch (v.type()) { @@ -919,14 +919,14 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m case nAttrs: { seen.insert(&v); - bool isDrv = state.isDerivation(v); + bool isDrv = state->isDerivation(v); if (isDrv) { str << "«derivation "; - Bindings::iterator i = v.attrs->find(state.sDrvPath); + Bindings::iterator i = v.attrs->find(state->sDrvPath); PathSet context; 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 str << "???"; str << "»"; @@ -938,7 +938,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m typedef std::map Sorted; Sorted sorted; 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) { if (isVarName(i.first)) @@ -988,7 +988,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m case nFunction: if (v.isLambda()) { 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; } else if (v.isPrimOp()) { str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; @@ -1012,7 +1012,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } void runRepl( - EvalState &evalState, + refevalState, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); @@ -1021,7 +1021,7 @@ void runRepl( // add 'extra' vars. for (auto & [name, value] : extraEnv) - repl->addVarToScope(repl->state.symbols.create(name), *value); + repl->addVarToScope(repl->state->symbols.create(name), *value); repl->mainLoop({}); } @@ -1057,8 +1057,8 @@ struct CmdRepl : StoreCommand, MixEvalArgs auto evalState = make_ref(searchPath, store); - auto repl = std::make_unique(*evalState); - repl->autoArgs = getAutoArgs(repl->state); + auto repl = std::make_unique(evalState); + repl->autoArgs = getAutoArgs(*repl->state); repl->initEnv(); repl->mainLoop(files); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6dc7918b1..18baf1cb7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -836,7 +836,7 @@ 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)(*this, *vm); + (debugRepl)(ref(shared_from_this()), *vm); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3444815fd..d793e2a31 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -13,7 +13,6 @@ #include #include - namespace nix { @@ -88,7 +87,7 @@ struct DebugTrace { void debugError(Error * e, Env & env, Expr & expr); -class EvalState +class EvalState : public std::enable_shared_from_this { public: SymbolTable symbols; @@ -127,7 +126,7 @@ public: RootValue vImportedDrvToDerivation = nullptr; /* Debugger */ - void (* debugRepl)(EvalState & es, const ValMap & extraEnv); + void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; std::list debugTraces; -- cgit v1.2.3 From 9068d32e12750542b59418501ce1bd3835e92400 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 25 May 2022 12:55:58 -0600 Subject: remove parens from repl help --- src/libcmd/repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 993dcd634..458e824c5 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -500,7 +500,7 @@ bool NixRepl::processLine(std::string line) << " :bt Show trace stack\n" << " :st Show current trace\n" << " :st Change to another trace in the stack\n" - << " :c Go until end of program, exception, or builtins.break().\n" + << " :c Go until end of program, exception, or builtins.break\n" << " :s Go one step\n" ; } -- cgit v1.2.3 From c156155239dafd68104a843916d8d737e6e61bed Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Thu, 26 May 2022 10:53:06 +0200 Subject: createUnixDomainSocket: listen(unix, 5 -> 100) This solves the error error: cannot connect to socket at '/nix/var/nix/daemon-socket/socket': Connection refused on build farm systems that are loaded but operating normally. I've seen this happen on an M1 mac running a loaded hercules-ci-agent. Hercules CI uses multiple worker processes, which may connect to the Nix daemon around the same time. It's not unthinkable that the Nix daemon listening process isn't scheduled until after 6 workers try to connect, especially on a system under load with many workers. Is the increase safe? The number is the number of connections that the kernel will buffer while the listening process hasn't `accept`-ed them yet. It did not - and will not - restrict the total number of daemon forks that a client can create. History The number 5 has remained unchanged since the introduction in nix-worker with 0130ef88ea in 2006. --- src/libutil/util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libutil/util.cc b/src/libutil/util.cc index d4d78329d..1c19938a8 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1818,7 +1818,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) if (chmod(path.c_str(), mode) == -1) throw SysError("changing permissions on '%1%'", path); - if (listen(fdSocket.get(), 5) == -1) + if (listen(fdSocket.get(), 100) == -1) throw SysError("cannot listen on socket '%1%'", path); return fdSocket; -- cgit v1.2.3 From 9acc770ce4bf0e748b41d2f9515c436ae6960c6d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 May 2022 15:49:41 +0200 Subject: Remove pre-C++11 hackiness --- src/libexpr/eval.hh | 4 ++-- src/libexpr/get-drvs.hh | 2 +- src/libexpr/nixexpr.hh | 4 ++-- src/libexpr/parser.y | 16 ++++++++-------- src/libexpr/primops.cc | 2 +- src/libexpr/value.hh | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index d793e2a31..0a32d5885 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -173,7 +173,7 @@ private: /* A cache from path names to parse trees. */ #if HAVE_BOEHMGC - typedef std::map, traceable_allocator > > FileParseCache; + typedef std::map, traceable_allocator>> FileParseCache; #else typedef std::map FileParseCache; #endif @@ -181,7 +181,7 @@ private: /* A cache from path names to values. */ #if HAVE_BOEHMGC - typedef std::map, traceable_allocator > > FileEvalCache; + typedef std::map, traceable_allocator>> FileEvalCache; #else typedef std::map FileEvalCache; #endif diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 7cc1abef2..bbd2d3c47 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -73,7 +73,7 @@ public: #if HAVE_BOEHMGC -typedef std::list > DrvInfos; +typedef std::list> DrvInfos; #else typedef std::list DrvInfos; #endif diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 9b3a9f5d0..8813c61a9 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -419,8 +419,8 @@ struct ExprConcatStrings : Expr { PosIdx pos; bool forceString; - std::vector > * es; - ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector > * es) + std::vector> * es; + ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector> * es) : pos(pos), forceString(forceString), es(es) { }; PosIdx getPos() const override { return pos; } COMMON_METHODS diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index e3e0ac168..8cbc2da4d 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -193,7 +193,7 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals, static Expr * stripIndentation(const PosIdx pos, SymbolTable & symbols, - std::vector > > & es) + std::vector>> & es) { if (es.empty()) return new ExprString(""); @@ -233,7 +233,7 @@ static Expr * stripIndentation(const PosIdx pos, SymbolTable & symbols, } /* Strip spaces from each line. */ - auto * es2 = new std::vector >; + auto * es2 = new std::vector>; atStartOfLine = true; size_t curDropped = 0; size_t n = es.size(); @@ -320,8 +320,8 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err StringToken uri; StringToken str; std::vector * attrNames; - std::vector > * string_parts; - std::vector > > * ind_string_parts; + std::vector> * string_parts; + std::vector>> * ind_string_parts; } %type start expr expr_function expr_if expr_op @@ -415,7 +415,7 @@ expr_op | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); } | expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); } | expr_op '+' expr_op - { $$ = new ExprConcatStrings(CUR_POS, false, new std::vector >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); } + { $$ = new ExprConcatStrings(CUR_POS, false, new std::vector>({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); } | expr_op '-' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {$1, $3}); } | expr_op '*' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__mul")), {$1, $3}); } | expr_op '/' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__div")), {$1, $3}); } @@ -503,9 +503,9 @@ string_parts_interpolated : string_parts_interpolated STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(std::string($2))); } | string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); } - | DOLLAR_CURLY expr '}' { $$ = new std::vector >; $$->emplace_back(makeCurPos(@1, data), $2); } + | DOLLAR_CURLY expr '}' { $$ = new std::vector>; $$->emplace_back(makeCurPos(@1, data), $2); } | STR DOLLAR_CURLY expr '}' { - $$ = new std::vector >; + $$ = new std::vector>; $$->emplace_back(makeCurPos(@1, data), new ExprString(std::string($1))); $$->emplace_back(makeCurPos(@2, data), $3); } @@ -528,7 +528,7 @@ path_start ind_string_parts : ind_string_parts IND_STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $2); } | ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); } - | { $$ = new std::vector > >; } + | { $$ = new std::vector>>; } ; binds diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 11542b06b..aab6919d4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -574,7 +574,7 @@ struct CompareValues #if HAVE_BOEHMGC -typedef std::list > ValueList; +typedef std::list> ValueList; #else typedef std::list ValueList; #endif diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 58a8a56a0..2008df74d 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -404,9 +404,9 @@ public: #if HAVE_BOEHMGC -typedef std::vector > ValueVector; -typedef std::map, traceable_allocator > > ValueMap; -typedef std::map, traceable_allocator > > ValueVectorMap; +typedef std::vector> ValueVector; +typedef std::map, traceable_allocator>> ValueMap; +typedef std::map, traceable_allocator>> ValueVectorMap; #else typedef std::vector ValueVector; typedef std::map ValueMap; -- cgit v1.2.3 From b36d5172cb2cd99f8ae5262b3e3536cceac76b50 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Thu, 26 May 2022 18:36:10 +0100 Subject: src/libutil/json.cc: add missing include for gcc-13 Without the change llvm build fails on this week's gcc-13 snapshot as: src/libutil/json.cc: In function 'void nix::toJSON(std::ostream&, const char*, const char*)': src/libutil/json.cc:33:22: error: 'uint16_t' was not declared in this scope 33 | put(hex[(uint16_t(*i) >> 12) & 0xf]); | ^~~~~~~~ src/libutil/json.cc:5:1: note: 'uint16_t' is defined in header ''; did you forget to '#include '? 4 | #include +++ |+#include 5 | --- src/libutil/json.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libutil/json.cc b/src/libutil/json.cc index 3a981376f..b0a5d7e75 100644 --- a/src/libutil/json.cc +++ b/src/libutil/json.cc @@ -1,6 +1,7 @@ #include "json.hh" #include +#include #include namespace nix { -- cgit v1.2.3 From ec07a70979a86cc436de7e46e03789b4606d25ab Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 27 May 2022 11:25:05 +0200 Subject: Style fix --- src/libexpr/primops.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index aab6919d4..eea274301 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -3514,7 +3514,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) (v.listElems()[i] = state.allocValue())->mkString(match[i + 1].str()); } - } catch (std::regex_error &e) { + } catch (std::regex_error & e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ state.debugThrowLastTrace(EvalError({ @@ -3618,7 +3618,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) assert(idx == 2 * len + 1); - } catch (std::regex_error &e) { + } catch (std::regex_error & e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ state.debugThrowLastTrace(EvalError({ -- cgit v1.2.3 From 027fd45230b74c67e65d06e7073c04b62c60eb4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Fri, 27 May 2022 16:15:28 +0200 Subject: Fix a segfault in the git fetcher The git fetcher code used to dereference the (potentially empty) `ref` input attribute. This was magically working, probably because the compiler somehow outsmarted us, but is now blowing up with newer nixpkgs versions. Fix that by not trying to access this field while we don't know for sure that it has been defined. Fix #6554 --- src/libfetchers/git.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index a71bff76f..9cbd39247 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -449,11 +449,10 @@ struct GitInputScheme : InputScheme } } - const Attrs unlockedAttrs({ + Attrs unlockedAttrs({ {"type", cacheType}, {"name", name}, {"url", actualUrl}, - {"ref", *input.getRef()}, }); Path repoDir; @@ -466,6 +465,7 @@ struct GitInputScheme : InputScheme head = "master"; } input.attrs.insert_or_assign("ref", *head); + unlockedAttrs.insert_or_assign("ref", *head); } if (!input.getRev()) @@ -482,6 +482,7 @@ struct GitInputScheme : InputScheme head = "master"; } input.attrs.insert_or_assign("ref", *head); + unlockedAttrs.insert_or_assign("ref", *head); } if (auto res = getCache()->lookup(store, unlockedAttrs)) { -- cgit v1.2.3 From 8e8e9d8705a68e1be63d6d8059c6c07127826525 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 30 May 2022 11:32:37 +0200 Subject: Respect the outputSpecified attribute E.g. 'nix build nixpkgs#libxml2.dev' will build the 'dev' output. --- src/libcmd/installables.cc | 9 ++++++++- src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 3 ++- src/libexpr/get-drvs.cc | 37 +++++++++++++++++++++++++------------ 4 files changed, 36 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 635ce19b6..21db2b08b 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -623,7 +623,14 @@ std::tuple InstallableF std::set outputsToInstall; std::optional priority; - if (auto aMeta = attr->maybeGetAttr(state->sMeta)) { + if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) { + if (aOutputSpecified->getBool()) { + if (auto aOutputName = attr->maybeGetAttr("outputName")) + outputsToInstall = { aOutputName->getString() }; + } + } + + else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) { if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall")) for (auto & s : aOutputsToInstall->getListOfStrings()) outputsToInstall.insert(s); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 18baf1cb7..40462afdf 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -459,6 +459,7 @@ EvalState::EvalState( , sKey(symbols.create("key")) , sPath(symbols.create("path")) , sPrefix(symbols.create("prefix")) + , sOutputSpecified(symbols.create("outputSpecified")) , repair(NoRepair) , emptyBindings(0) , store(store) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0a32d5885..7b8732169 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -103,7 +103,8 @@ public: sOutputHash, sOutputHashAlgo, sOutputHashMode, sRecurseForDerivations, sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, - sPrefix; + sPrefix, + sOutputSpecified; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index d616b3921..346741dd5 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -132,23 +132,36 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall } else outputs.emplace("out", withPaths ? std::optional{queryOutPath()} : std::nullopt); } + if (!onlyOutputsToInstall || !attrs) return outputs; - /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */ - const Value * outTI = queryMeta("outputsToInstall"); - if (!outTI) return outputs; - const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'"); - /* ^ this shows during `nix-env -i` right under the bad derivation */ - if (!outTI->isList()) throw errMsg; - Outputs result; - for (auto elem : outTI->listItems()) { - if (elem->type() != nString) throw errMsg; - auto out = outputs.find(elem->string.s); - if (out == outputs.end()) throw errMsg; + Bindings::iterator i; + if (attrs && (i = attrs->find(state->sOutputSpecified)) != attrs->end() && state->forceBool(*i->value, i->pos)) { + Outputs result; + auto out = outputs.find(queryOutputName()); + if (out == outputs.end()) + throw Error("derivation does not have output '%s'", queryOutputName()); result.insert(*out); + return result; + } + + else { + /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */ + const Value * outTI = queryMeta("outputsToInstall"); + if (!outTI) return outputs; + const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'"); + /* ^ this shows during `nix-env -i` right under the bad derivation */ + if (!outTI->isList()) throw errMsg; + Outputs result; + for (auto elem : outTI->listItems()) { + if (elem->type() != nString) throw errMsg; + auto out = outputs.find(elem->string.s); + if (out == outputs.end()) throw errMsg; + result.insert(*out); + } + return result; } - return result; } -- cgit v1.2.3 From b8faa837429cbcb4f950248571c761c98895e7cd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 30 May 2022 13:24:04 +0200 Subject: HttpBinaryCacheStore::getFile(): Don't throw an exception This violates the noexcept specification. Fixes #6445. --- src/libstore/http-binary-cache-store.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc index 3cb5efdbf..73bcd6e81 100644 --- a/src/libstore/http-binary-cache-store.cc +++ b/src/libstore/http-binary-cache-store.cc @@ -161,7 +161,12 @@ protected: void getFile(const std::string & path, Callback> callback) noexcept override { - checkEnabled(); + try { + checkEnabled(); + } catch (...) { + callback.rethrow(); + return; + } auto request(makeRequest(path)); -- cgit v1.2.3 From 6378f0bb328437de759f7ed8405fcafbb3bcac54 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 30 May 2022 13:27:13 +0200 Subject: RemoteStore::queryRealisationUncached(): Fix potential noexcept violation --- src/libstore/remote-store.cc | 50 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 14aeba75c..bc36aef5d 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -718,36 +718,34 @@ void RemoteStore::registerDrvOutput(const Realisation & info) void RemoteStore::queryRealisationUncached(const DrvOutput & id, Callback> callback) noexcept { - auto conn(getConnection()); + try { + auto conn(getConnection()); - if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 27) { - warn("the daemon is too old to support content-addressed derivations, please upgrade it to 2.4"); - try { - callback(nullptr); - } catch (...) { return callback.rethrow(); } - } + if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 27) { + warn("the daemon is too old to support content-addressed derivations, please upgrade it to 2.4"); + return callback(nullptr); + } - conn->to << wopQueryRealisation; - conn->to << id.to_string(); - conn.processStderr(); + conn->to << wopQueryRealisation; + conn->to << id.to_string(); + conn.processStderr(); - auto real = [&]() -> std::shared_ptr { - if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) { - auto outPaths = worker_proto::read( - *this, conn->from, Phantom> {}); - if (outPaths.empty()) - return nullptr; - return std::make_shared(Realisation { .id = id, .outPath = *outPaths.begin() }); - } else { - auto realisations = worker_proto::read( - *this, conn->from, Phantom> {}); - if (realisations.empty()) - return nullptr; - return std::make_shared(*realisations.begin()); - } - }(); + auto real = [&]() -> std::shared_ptr { + if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) { + auto outPaths = worker_proto::read( + *this, conn->from, Phantom> {}); + if (outPaths.empty()) + return nullptr; + return std::make_shared(Realisation { .id = id, .outPath = *outPaths.begin() }); + } else { + auto realisations = worker_proto::read( + *this, conn->from, Phantom> {}); + if (realisations.empty()) + return nullptr; + return std::make_shared(*realisations.begin()); + } + }(); - try { callback(std::shared_ptr(real)); } catch (...) { return callback.rethrow(); } } -- cgit v1.2.3