diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 9a9531a3f..b8eef9286 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -121,7 +121,7 @@ Pos findDerivationFilename(EvalState & state, Value & v, std::string what) Symbol file = state.symbols.create(filename); - return { file, lineno, 0 }; + return { foFile, file, lineno, 0 }; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1485dc7fe..8471c2f8b 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -249,7 +249,7 @@ private: friend struct ExprAttrs; friend struct ExprLet; - Expr * parse(const char * text, const Path & path, + Expr * parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, StaticEnv & staticEnv); public: diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 47d0e85ec..5a98b9149 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -24,11 +24,12 @@ MakeError(RestrictedPathError, Error); struct Pos { + FileOrigin origin; Symbol file; unsigned int line, column; - Pos() : line(0), column(0) { }; - Pos(const Symbol & file, unsigned int line, unsigned int column) - : file(file), line(line), column(column) { }; + Pos() : origin(foString), line(0), column(0) { }; + Pos(FileOrigin origin, const Symbol & file, unsigned int line, unsigned int column) + : origin(origin), file(file), line(line), column(column) { }; operator bool() const { return line != 0; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 0417a3c21..1a4f3d56b 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -30,7 +30,8 @@ namespace nix { SymbolTable & symbols; Expr * result; Path basePath; - Symbol path; + Symbol file; + FileOrigin origin; ErrorInfo error; Symbol sLetBody; ParseData(EvalState & state) @@ -250,7 +251,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vectorpath, loc.first_line, loc.first_column); + return Pos(data->origin, data->file, loc.first_line, loc.first_column); } #define CUR_POS makeCurPos(*yylocp, data) @@ -576,13 +577,24 @@ formal namespace nix { -Expr * EvalState::parse(const char * text, +Expr * EvalState::parse(const char * text, FileOrigin origin, const Path & path, const Path & basePath, StaticEnv & staticEnv) { yyscan_t scanner; ParseData data(*this); + data.origin = origin; + switch (origin) { + case foFile: + data.file = data.symbols.create(path); + break; + case foStdin: + case foString: + data.file = data.symbols.create(text); + break; + default: + throw Error("invalid FileOrigin in parse"); + } data.basePath = basePath; - data.path = data.symbols.create(path); yylex_init(&scanner); yy_scan_string(text, scanner); @@ -632,13 +644,13 @@ Expr * EvalState::parseExprFromFile(const Path & path) Expr * EvalState::parseExprFromFile(const Path & path, StaticEnv & staticEnv) { - return parse(readFile(path).c_str(), path, dirOf(path), staticEnv); + return parse(readFile(path).c_str(), foFile, path, dirOf(path), staticEnv); } Expr * EvalState::parseExprFromString(std::string_view s, const Path & basePath, StaticEnv & staticEnv) { - return parse(s.data(), "(string)", basePath, staticEnv); + return parse(s.data(), foString, "", basePath, staticEnv); } @@ -651,7 +663,8 @@ Expr * EvalState::parseExprFromString(std::string_view s, const Path & basePath) Expr * EvalState::parseStdin() { //Activity act(*logger, lvlTalkative, format("parsing standard input")); - return parseExprFromString(drainFD(0), absPath(".")); + // return parseExprFromString(foStdin, drainFD(0), absPath(".")); + return parse(drainFD(0).data(), foStdin, "", absPath("."), staticBaseEnv); } diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 7aff9381b..ee415e18c 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -59,22 +59,51 @@ void getCodeLines(NixCode &nixCode) return; // check this magic value! - if (nixCode.errPos.file == "(string)") - return; - - try { - AutoCloseFD fd = open(nixCode.errPos.file.c_str(), O_RDONLY | O_CLOEXEC); - if (!fd) - throw SysError("opening file '%1%'", nixCode.errPos.file); + if (nixCode.errPos.origin == foFile) { + try { + AutoCloseFD fd = open(nixCode.errPos.file.c_str(), O_RDONLY | O_CLOEXEC); + if (!fd) + throw SysError("opening file '%1%'", nixCode.errPos.file); + // count the newlines. + int count = 0; + string line; + int pl = nixCode.errPos.line - 1; + do + { + line = readLine(fd.get()); + ++count; + if (count < pl) + { + ; + } + else if (count == pl) { + nixCode.prevLineOfCode = line; + } else if (count == pl + 1) { + nixCode.errLineOfCode = line; + } else if (count == pl + 2) { + nixCode.nextLineOfCode = line; + break; + } + } while (true); + } + catch (EndOfFile &eof) { + ; + } + catch (std::exception &e) { + printError("error reading nix file: %s\n%s", nixCode.errPos.file, e.what()); + } + } else { + std::istringstream iss(nixCode.errPos.file); // count the newlines. - int count = 0; string line; int pl = nixCode.errPos.line - 1; + do { - line = readLine(fd.get()); + std::getline(iss, line); + // std::cout << "getline result: " << std::getline(iss, line) << std::endl; ++count; if (count < pl) { @@ -88,14 +117,11 @@ void getCodeLines(NixCode &nixCode) nixCode.nextLineOfCode = line; break; } + + if (!iss.good()) + break; } while (true); } - catch (EndOfFile &eof) { - ; - } - catch (std::exception &e) { - printError("error reading nix file: %s\n%s", nixCode.errPos.file, e.what()); - } } @@ -225,15 +251,27 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) // filename, line, column. if (einfo.nixCode.has_value()) { - if (einfo.nixCode->errPos.file != "") { - out << fmt("%1%in file: " ANSI_BLUE "%2% %3%" ANSI_NORMAL, - prefix, - einfo.nixCode->errPos.file, - showErrPos(einfo.nixCode->errPos)) << std::endl; - out << prefix << std::endl; - } else { - out << fmt("%1%from command line argument", prefix) << std::endl; - out << prefix << std::endl; + switch (einfo.nixCode->errPos.origin) { + case foFile: { + out << fmt("%1%in file: " ANSI_BLUE "%2% %3%" ANSI_NORMAL, + prefix, + einfo.nixCode->errPos.file, + showErrPos(einfo.nixCode->errPos)) << std::endl; + out << prefix << std::endl; + break; + } + case foString: { + out << fmt("%1%from command line argument", prefix) << std::endl; + out << prefix << std::endl; + break; + } + case foStdin: { + out << fmt("%1%from stdin", prefix) << std::endl; + out << prefix << std::endl; + break; + } + default: + throw Error("invalid FileOrigin in errPos"); } } diff --git a/src/libutil/error.hh b/src/libutil/error.hh index b374c2780..d60c0fefe 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -32,10 +32,18 @@ typedef enum { lvlVomit } Verbosity; +typedef enum { + foFile, + foStdin, + foString +} FileOrigin; + + struct ErrPos { int line = 0; int column = 0; string file; + FileOrigin origin; operator bool() const { @@ -45,6 +53,7 @@ struct ErrPos { template ErrPos& operator=(const P &pos) { + origin = pos.origin; line = pos.line; column = pos.column; file = pos.file;