diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index e6a8d41e2..e52c53dac 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -3,6 +3,7 @@ #include #include "error.hh" +#include "eval-error.hh" #include "repl-interacter.hh" #include "repl.hh" @@ -344,6 +345,58 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt) } } +static Value * lazyProbe(Expr * e, EvalState &state, Env &env) +{ + if (auto select = dynamic_cast(e)) { + if (select->attrPath.size() != 1) { + throw Unsupported(":probe: Nested attribute selection not supported yet. Workaround: use parentheses?"); + } + + if (select->def) { + // This seems like nonsensical input, and we only really support simple attribute paths + throw Unsupported(":probe: %1% keyword is not supported.", "or"); + } + + auto attr = select->attrPath[0]; + + if (!attr.symbol) { + throw Unsupported(":probe: Computed attribute selection not supported yet."); + } + + auto name = state.symbols[attr.symbol]; + auto v = lazyProbe(select->e, state, env); + + if (v->type() != nAttrs) { + state.error("can't look up '%1%', expecting the left hand side to be an attribute set, but it is %2%", name, v->type()).atPos(select->e->getPos()).debugThrow(); + } + + auto it = v->attrs()->find(attr.symbol); + if (it == v->attrs()->end()) { + state.error("attribute '%1%' missing", state.symbols[attr.symbol]).atPos(select->e->getPos()).debugThrow(); + } + return it->value; + } + if (auto ref = dynamic_cast(e)) { + auto name = state.symbols[ref->name]; + // TODO: subtly different intent, so factor out common logic from maybeThunk instead + Value * v = ref->maybeThunk(state, env); + if (!v) { + state.error("Variable '%1%' not found in scope", name).atPos(ref->getPos()).debugThrow(); + } + return v; + } + state.error("'%s' is not an expression I can probe. Use variables and attribute selection").atPos(e->getPos()).debugThrow(); +} + +static void printLazyProbe(Expr * e, EvalState &state, Env &env) +{ + Value * v = lazyProbe(e, state, env); + auto suspension = logger->suspend(); + std::cout << (v->type() == nThunk ? ANSI_GREEN : ANSI_BLUE); + std::cout << v->type() << std::endl; + std::cout << ANSI_NORMAL; +} + ProcessLineResult NixRepl::processLine(std::string line) { line = trim(line); @@ -380,6 +433,7 @@ ProcessLineResult NixRepl::processLine(std::string line) << " :lf, :load-flake Load Nix flake and add it to scope\n" << " :p, :print Evaluate and print expression recursively\n" << " Strings are printed directly, without escaping.\n" + << " :probe