diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index c719f660c..a869cfb97 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -215,9 +215,8 @@ static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positi : (std::shared_ptr) positions[dt.expr.getPos() ? dt.expr.getPos() : noPos]; if (pos) { - pos->print(out); - - if (auto loc = pos->getCodeLines()) {; + out << pos; + if (auto loc = pos->getCodeLines()) { out << "\n"; printCodeLines(out, "", *pos, *loc); out << "\n"; @@ -584,7 +583,9 @@ bool NixRepl::processLine(std::string line) return {filename, 0}; } else if (v.isLambda()) { auto pos = state->positions[v.lambda.fun->pos]; - return {pos.file, pos.line}; + // FIXME + abort(); + //return {pos.file, pos.line}; } else { // assume it's a derivation return findPackageFilename(*state, v, arg); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 20afd20fe..89887823e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1081,9 +1081,9 @@ void EvalState::mkThunk_(Value & v, Expr * expr) void EvalState::mkPos(Value & v, PosIdx p) { auto pos = positions[p]; - if (!pos.file.empty()) { + if (auto path = std::get_if(&pos.origin)) { auto attrs = buildBindings(3); - attrs.alloc(sFile).mkString(pos.file); + attrs.alloc(sFile).mkString(path->path.abs()); attrs.alloc(sLine).mkInt(pos.line); attrs.alloc(sColumn).mkInt(pos.column); v.mkAttrs(attrs); @@ -1450,7 +1450,8 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } catch (Error & e) { auto pos2r = state.positions[pos2]; - if (pos2 && pos2r.file != state.derivationNixPath) + // FIXME: use MemoryAccessor + if (pos2 /* && pos2r.origin != Pos(state.derivationNixPath) */) state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)); throw; @@ -2465,7 +2466,8 @@ void EvalState::printStats() else obj.attr("name", nullptr); if (auto pos = positions[i.first->pos]) { - obj.attr("file", (const std::string &) pos.file); + // FIXME + //obj.attr("file", (const std::string &) pos.file); obj.attr("line", pos.line); obj.attr("column", pos.column); } @@ -2477,7 +2479,8 @@ void EvalState::printStats() for (auto & i : attrSelects) { auto obj = list.object(); if (auto pos = positions[i.first]) { - obj.attr("file", (const std::string &) pos.file); + // FIXME + //obj.attr("file", (const std::string &) pos.file); obj.attr("line", pos.line); obj.attr("column", pos.column); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 11038317f..56519573b 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -453,8 +453,7 @@ private: Expr * parse( char * text, size_t length, - FileOrigin origin, - const PathView path, + Pos::Origin origin, const SourcePath & basePath, std::shared_ptr & staticEnv); diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index f24347665..933dad35a 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -154,7 +154,7 @@ static Flake readFlake( Value vInfo; state.evalFile(flakePath, vInfo, true); - expectType(state, nAttrs, vInfo, state.positions.add({flakePath.to_string(), foFile}, 0, 0)); + expectType(state, nAttrs, vInfo, state.positions.add(Pos::Origin(rootDir), 1, 1)); Flake flake { .originalRef = originalRef, diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 8f19b24d0..08478455b 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -10,16 +10,27 @@ namespace nix { struct SourcePathAdapter : AbstractPos { - std::string file; + SourcePath path; + ref hack; // FIXME: remove + + SourcePathAdapter(SourcePath path) + : path(std::move(path)) + , hack(path.accessor.shared_from_this()) + { + } std::optional getSource() const override { - return std::nullopt; + try { + return path.readFile(); + } catch (Error &) { + return std::nullopt; + } } void print(std::ostream & out) const override { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "%s:%s" ANSI_NORMAL ":", file, showErrPos()); + out << path; } }; @@ -27,7 +38,7 @@ struct StringPosAdapter : AbstractPos { void print(std::ostream & out) const override { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "«string»:%s" ANSI_NORMAL ":", showErrPos()); + out << "«string»"; } }; @@ -35,35 +46,27 @@ struct StdinPosAdapter : AbstractPos { void print(std::ostream & out) const override { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "«stdin»:%s" ANSI_NORMAL ":", showErrPos()); + out << "«stdin»"; } }; Pos::operator std::shared_ptr() const { - if (!line) return nullptr; + std::shared_ptr pos; - switch (origin) { - case foFile: { - auto pos = std::make_shared(); + if (auto path = std::get_if(&origin)) + pos = std::make_shared(*path); + else if (std::get_if(&origin)) + pos = std::make_shared(); + else if (std::get_if(&origin)) + pos = std::make_shared(); + + if (pos) { pos->line = line; pos->column = column; - pos->file = file; - return pos; } - case foStdin: { - auto pos = std::make_shared(); - pos->line = line; - pos->column = column; - return pos; - } - case foString: - auto pos = std::make_shared(); - pos->line = line; - pos->column = column; - return pos; - } - assert(false); + + return pos; } /* Displaying abstract syntax trees. */ @@ -306,24 +309,10 @@ void ExprPos::show(const SymbolTable & symbols, std::ostream & str) const std::ostream & operator << (std::ostream & str, const Pos & pos) { - if (!pos) + if (auto pos2 = (std::shared_ptr) pos) { + str << *pos2; + } else str << "undefined position"; - else - { - auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%"); - switch (pos.origin) { - case foFile: - f % (const std::string &) pos.file; - break; - case foStdin: - case foString: - f % "(string)"; - break; - default: - throw Error("unhandled Pos origin!"); - } - str << (f % pos.line % pos.column).str(); - } return str; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 3fe75e09b..7b732995e 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -21,21 +21,20 @@ MakeError(TypeError, EvalError); MakeError(UndefinedVarError, Error); MakeError(MissingArgumentError, EvalError); -// FIXME: change this into a variant? -typedef enum { - foFile, - foStdin, - foString -} FileOrigin; - /* Position objects. */ struct Pos { - std::string file; - FileOrigin origin; uint32_t line; uint32_t column; + struct no_pos_tag {}; + struct stdin_tag {}; + struct string_tag {}; + + typedef std::variant Origin; + + Origin origin; + explicit operator bool() const { return line > 0; } operator std::shared_ptr() const; @@ -68,13 +67,12 @@ public: // current origins.back() can be reused or not. mutable uint32_t idx = std::numeric_limits::max(); - explicit Origin(uint32_t idx): idx(idx), file{}, origin{} {} + explicit Origin(uint32_t idx): idx(idx), origin{Pos::no_pos_tag()} {} public: - const std::string file; - const FileOrigin origin; + const Pos::Origin origin; - Origin(std::string file, FileOrigin origin): file(std::move(file)), origin(origin) {} + Origin(Pos::Origin origin): origin(origin) {} }; struct Offset { @@ -114,7 +112,7 @@ public: [] (const auto & a, const auto & b) { return a.idx < b.idx; }); const auto origin = *std::prev(pastOrigin); const auto offset = offsets[idx]; - return {origin.file, origin.origin, offset.line, offset.column}; + return {offset.line, offset.column, origin.origin}; } }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 1f1d7e7f9..14b712f6f 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -648,30 +648,16 @@ namespace nix { Expr * EvalState::parse( char * text, size_t length, - FileOrigin origin, - const PathView path, + Pos::Origin origin, const SourcePath & basePath, std::shared_ptr & staticEnv) { yyscan_t scanner; - std::string file; - switch (origin) { - case foFile: - // FIXME: change this to a SourcePath. - file = path; - break; - case foStdin: - case foString: - file = text; - break; - default: - assert(false); - } ParseData data { .state = *this, .symbols = symbols, .basePath = basePath, - .origin = {file, origin}, + .origin = {origin}, }; yylex_init(&scanner); @@ -713,14 +699,14 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr & staticEnv) { s.append("\0\0", 2); - return parse(s.data(), s.size(), foString, "", basePath, staticEnv); + return parse(s.data(), s.size(), Pos::string_tag(), basePath, staticEnv); } @@ -736,7 +722,7 @@ Expr * EvalState::parseStdin() auto buffer = drainFD(0); // drainFD should have left some extra space for terminators buffer.append("\0\0", 2); - return parse(buffer.data(), buffer.size(), foStdin, "", rootPath(absPath(".")), staticBaseEnv); + return parse(buffer.data(), buffer.size(), Pos::stdin_tag(), rootPath(absPath(".")), staticBaseEnv); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eca9c5903..8f8711e8c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -368,8 +368,8 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) auto output = runProgram(program, true, commandArgs); Expr * parsed; try { - auto base = state.positions[pos]; - parsed = state.parseExprFromString(std::move(output), state.rootPath(base.file)); + //auto base = state.positions[pos]; + parsed = state.parseExprFromString(std::move(output), state.rootPath("/")); } catch (Error & e) { e.addTrace(state.positions[pos], "While parsing the output from '%1%'", program); throw; @@ -3979,6 +3979,7 @@ void EvalState::createBaseEnv() /* Add a wrapper around the derivation primop that computes the `drvPath' and `outPath' attributes lazily. */ + // FIXME: use corepkgsFS. sDerivationNix = symbols.create(derivationNixPath); auto vDerivation = allocValue(); addConstant("derivation", vDerivation); @@ -3996,7 +3997,7 @@ void EvalState::createBaseEnv() // the parser needs two NUL bytes as terminators; one of them // is implied by being a C string. "\0"; - eval(parse(code, sizeof(code), foFile, derivationNixPath, rootPath("/"), staticBaseEnv), *vDerivation); + eval(parse(code, sizeof(code), Pos::string_tag(), rootPath("/"), staticBaseEnv), *vDerivation); } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index b6824832d..6f6f4d70e 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -24,7 +24,8 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos) { - xmlAttrs["path"] = pos.file; + // FIXME + //xmlAttrs["path"] = pos.file; xmlAttrs["line"] = (format("%1%") % pos.line).str(); xmlAttrs["column"] = (format("%1%") % pos.column).str(); } diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 52be6473d..fa825b2f6 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -35,13 +35,13 @@ std::ostream & operator<<(std::ostream & os, const hintformat & hf) return os << hf.str(); } -std::string AbstractPos::showErrPos() const +std::ostream & operator << (std::ostream & str, const AbstractPos & pos) { - if (column > 0) { - return fmt("%d:%d", line, column); - } else { - return fmt("%d", line); - } + pos.print(str); + str << ":" << pos.line; + if (pos.column > 0) + str << ":" << pos.column; + return str; } std::optional AbstractPos::getCodeLines() const @@ -202,8 +202,7 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s auto noSource = ANSI_ITALIC " (source not available)" ANSI_NORMAL "\n"; if (einfo.errPos) { - oss << "\n"; - einfo.errPos->print(oss); + oss << "\n" << ANSI_BLUE << "at " ANSI_WARNING << *einfo.errPos << ANSI_NORMAL << ":"; if (auto loc = einfo.errPos->getCodeLines()) { oss << "\n"; @@ -226,8 +225,7 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s oss << "\n" << "… " << iter->hint.str() << "\n"; if (iter->pos) { - oss << "\n"; - iter->pos->print(oss); + oss << "\n" << ANSI_BLUE << "at " ANSI_WARNING << *iter->pos << ANSI_NORMAL << ":"; if (auto loc = iter->pos->getCodeLines()) { oss << "\n"; diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 487c0c2ec..92d6d3e6e 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -73,11 +73,11 @@ struct AbstractPos virtual void print(std::ostream & out) const = 0; - std::string showErrPos() const; - std::optional getCodeLines() const; }; +std::ostream & operator << (std::ostream & str, const AbstractPos & pos); + void printCodeLines(std::ostream & out, const std::string & prefix, const AbstractPos & errPos, diff --git a/tests/function-trace.sh b/tests/function-trace.sh index 0b7f49d82..b0d6c9d59 100755 --- a/tests/function-trace.sh +++ b/tests/function-trace.sh @@ -11,7 +11,7 @@ expect_trace() { --expr "$expr" 2>&1 \ | grep "function-trace" \ | sed -e 's/ [0-9]*$//' - ); + ) echo -n "Tracing expression '$expr'" set +e @@ -32,40 +32,40 @@ expect_trace() { # failure inside a tryEval expect_trace 'builtins.tryEval (throw "example")' " -function-trace entered (string):1:1 at -function-trace entered (string):1:19 at -function-trace exited (string):1:19 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace entered «string»:1:19 at +function-trace exited «string»:1:19 at +function-trace exited «string»:1:1 at " # Missing argument to a formal function expect_trace '({ x }: x) { }' " -function-trace entered (string):1:1 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace exited «string»:1:1 at " # Too many arguments to a formal function expect_trace '({ x }: x) { x = "x"; y = "y"; }' " -function-trace entered (string):1:1 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace exited «string»:1:1 at " # Not enough arguments to a lambda expect_trace '(x: y: x + y) 1' " -function-trace entered (string):1:1 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace exited «string»:1:1 at " # Too many arguments to a lambda expect_trace '(x: x) 1 2' " -function-trace entered (string):1:1 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace exited «string»:1:1 at " # Not a function expect_trace '1 2' " -function-trace entered (string):1:1 at -function-trace exited (string):1:1 at +function-trace entered «string»:1:1 at +function-trace exited «string»:1:1 at " set -e diff --git a/tests/misc.sh b/tests/misc.sh index 2830856ae..7082f2198 100644 --- a/tests/misc.sh +++ b/tests/misc.sh @@ -17,10 +17,10 @@ nix-env -q --foo 2>&1 | grep "unknown flag" # Eval Errors. eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true) -echo $eval_arg_res | grep "at «string»:1:15:" +echo $eval_arg_res | grep "at «string»:1:15" echo $eval_arg_res | grep "infinite recursion encountered" eval_stdin_res=$(echo 'let a = {} // a; in a.foo' | nix-instantiate --eval -E - 2>&1 || true) -echo $eval_stdin_res | grep "at «stdin»:1:15:" +echo $eval_stdin_res | grep "at «stdin»:1:15" echo $eval_stdin_res | grep "infinite recursion encountered"