diff options
-rw-r--r-- | third_party/nix/src/libexpr/parser.cc | 140 | ||||
-rw-r--r-- | third_party/nix/src/libexpr/parser.hh | 1 | ||||
-rw-r--r-- | third_party/nix/src/libexpr/parser.y | 165 |
3 files changed, 156 insertions, 150 deletions
diff --git a/third_party/nix/src/libexpr/parser.cc b/third_party/nix/src/libexpr/parser.cc index 50b7cc3ff8e3..a96d345cc126 100644 --- a/third_party/nix/src/libexpr/parser.cc +++ b/third_party/nix/src/libexpr/parser.cc @@ -1,5 +1,14 @@ #include "libexpr/parser.hh" +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "libexpr/eval.hh" +#include "libstore/download.hh" +#include "libstore/store-api.hh" + namespace nix { void addAttr(ExprAttrs* attrs, AttrPath& attrPath, Expr* e, const Pos& pos) { @@ -182,5 +191,136 @@ Expr* stripIndentation(const Pos& pos, SymbolTable& symbols, : new ExprConcatStrings(pos, true, es2); } +Path resolveExprPath(Path path) { + assert(path[0] == '/'); + + /* If `path' is a symlink, follow it. This is so that relative + path references work. */ + struct stat st; + while (true) { + if (lstat(path.c_str(), &st)) + throw SysError(format("getting status of '%1%'") % path); + if (!S_ISLNK(st.st_mode)) { + break; + } + path = absPath(readLink(path), dirOf(path)); + } + + /* If `path' refers to a directory, append `/default.nix'. */ + if (S_ISDIR(st.st_mode)) path = canonPath(path + "/default.nix"); + + return path; +} + +// These methods are actually declared in eval.hh, and were - for some +// reason - previously implemented in parser.y. + +Expr* EvalState::parseExprFromFile(const Path& path) { + return parseExprFromFile(path, staticBaseEnv); +} + +Expr* EvalState::parseExprFromFile(const Path& path, StaticEnv& staticEnv) { + return parse(readFile(path).c_str(), path, dirOf(path), staticEnv); +} + +Expr* EvalState::parseExprFromString(const std::string& s, const Path& basePath, + StaticEnv& staticEnv) { + return parse(s.c_str(), "(std::string)", basePath, staticEnv); +} + +Expr* EvalState::parseExprFromString(const std::string& s, + const Path& basePath) { + return parseExprFromString(s, basePath, staticBaseEnv); +} + +Expr* EvalState::parseStdin() { + // Activity act(*logger, lvlTalkative, format("parsing standard input")); + return parseExprFromString(drainFD(0), absPath(".")); +} + +void EvalState::addToSearchPath(const std::string& s) { + size_t pos = s.find('='); + std::string prefix; + Path path; + if (pos == std::string::npos) { + path = s; + } else { + prefix = std::string(s, 0, pos); + path = std::string(s, pos + 1); + } + + searchPath.emplace_back(prefix, path); +} + +Path EvalState::findFile(const std::string& path) { + return findFile(searchPath, path); +} + +Path EvalState::findFile(SearchPath& searchPath, const std::string& path, + const Pos& pos) { + for (auto& i : searchPath) { + std::string suffix; + if (i.first.empty()) + suffix = "/" + path; + else { + auto s = i.first.size(); + if (path.compare(0, s, i.first) != 0 || + (path.size() > s && path[s] != '/')) + continue; + suffix = path.size() == s ? "" : "/" + std::string(path, s); + } + auto r = resolveSearchPathElem(i); + if (!r.first) { + continue; + } + Path res = r.second + suffix; + if (pathExists(res)) { + return canonPath(res); + } + } + format f = format( + "file '%1%' was not found in the Nix search path (add it using $NIX_PATH " + "or -I)" + + std::string(pos ? ", at %2%" : "")); + f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); + throw ThrownError(f % path % pos); +} + +std::pair<bool, std::string> EvalState::resolveSearchPathElem( + const SearchPathElem& elem) { + auto i = searchPathResolved.find(elem.second); + if (i != searchPathResolved.end()) { + return i->second; + } + + std::pair<bool, std::string> res; + + if (isUri(elem.second)) { + try { + CachedDownloadRequest request(elem.second); + request.unpack = true; + res = {true, getDownloader()->downloadCached(store, request).path}; + } catch (DownloadError& e) { + LOG(WARNING) << "Nix search path entry '" << elem.second + << "' cannot be downloaded, ignoring"; + res = {false, ""}; + } + } else { + auto path = absPath(elem.second); + if (pathExists(path)) { + res = {true, path}; + } else { + LOG(WARNING) << "Nix search path entry '" << elem.second + << "' does not exist, ignoring"; + res = {false, ""}; + } + } + + DLOG(INFO) << "resolved search path element '" << elem.second << "' to '" + << res.second << "'"; + + searchPathResolved[elem.second] = res; + return res; +} } // namespace nix diff --git a/third_party/nix/src/libexpr/parser.hh b/third_party/nix/src/libexpr/parser.hh index 3de8280bf5f0..7f4c360b1bfd 100644 --- a/third_party/nix/src/libexpr/parser.hh +++ b/third_party/nix/src/libexpr/parser.hh @@ -53,5 +53,6 @@ void addFormal(const Pos& pos, Formals* formals, const Formal& formal); Expr* stripIndentation(const Pos& pos, SymbolTable& symbols, std::vector<Expr*>& es); +Path resolveExprPath(Path path); } // namespace nix diff --git a/third_party/nix/src/libexpr/parser.y b/third_party/nix/src/libexpr/parser.y index 2ec1cf6c558c..b272e4b03457 100644 --- a/third_party/nix/src/libexpr/parser.y +++ b/third_party/nix/src/libexpr/parser.y @@ -325,165 +325,30 @@ formal #include <unistd.h> #include "libexpr/eval.hh" -#include "libstore/download.hh" #include "libstore/store-api.hh" namespace nix { +Expr* EvalState::parse(const char* text, const Path& path, const Path& basePath, + StaticEnv& staticEnv) { + yyscan_t scanner; + ParseData data(*this); + data.basePath = basePath; + data.path = data.symbols.Create(path); -Expr * EvalState::parse(const char * text, - const Path & path, const Path & basePath, StaticEnv & staticEnv) -{ - yyscan_t scanner; - ParseData data(*this); - data.basePath = basePath; - data.path = data.symbols.Create(path); + yylex_init(&scanner); + yy_scan_string(text, scanner); + int res = yyparse(scanner, &data); + yylex_destroy(scanner); - yylex_init(&scanner); - yy_scan_string(text, scanner); - int res = yyparse(scanner, &data); - yylex_destroy(scanner); - - if (res) { throw ParseError(data.error); } - - data.result->bindVars(staticEnv); - - return data.result; -} - - -Path resolveExprPath(Path path) -{ - assert(path[0] == '/'); - - /* If `path' is a symlink, follow it. This is so that relative - path references work. */ - struct stat st; - while (true) { - if (lstat(path.c_str(), &st)) - throw SysError(format("getting status of '%1%'") % path); - if (!S_ISLNK(st.st_mode)) { break; } - path = absPath(readLink(path), dirOf(path)); - } - - /* If `path' refers to a directory, append `/default.nix'. */ - if (S_ISDIR(st.st_mode)) - path = canonPath(path + "/default.nix"); - - return path; -} - - -Expr * EvalState::parseExprFromFile(const Path & path) -{ - return parseExprFromFile(path, staticBaseEnv); -} - - -Expr * EvalState::parseExprFromFile(const Path & path, StaticEnv & staticEnv) -{ - return parse(readFile(path).c_str(), path, dirOf(path), staticEnv); -} - - -Expr * EvalState::parseExprFromString(const std::string & s, const Path & basePath, StaticEnv & staticEnv) -{ - return parse(s.c_str(), "(std::string)", basePath, staticEnv); -} - - -Expr * EvalState::parseExprFromString(const std::string & s, const Path & basePath) -{ - return parseExprFromString(s, basePath, staticBaseEnv); -} - - -Expr * EvalState::parseStdin() -{ - //Activity act(*logger, lvlTalkative, format("parsing standard input")); - return parseExprFromString(drainFD(0), absPath(".")); -} - - -void EvalState::addToSearchPath(const std::string & s) -{ - size_t pos = s.find('='); - std::string prefix; - Path path; - if (pos == std::string::npos) { - path = s; - } else { - prefix = std::string(s, 0, pos); - path = std::string(s, pos + 1); - } - - searchPath.emplace_back(prefix, path); -} - - -Path EvalState::findFile(const std::string & path) -{ - return findFile(searchPath, path); -} - - -Path EvalState::findFile(SearchPath & searchPath, const std::string & path, const Pos & pos) -{ - for (auto & i : searchPath) { - std::string suffix; - if (i.first.empty()) - suffix = "/" + path; - else { - auto s = i.first.size(); - if (path.compare(0, s, i.first) != 0 || - (path.size() > s && path[s] != '/')) - continue; - suffix = path.size() == s ? "" : "/" + std::string(path, s); - } - auto r = resolveSearchPathElem(i); - if (!r.first) { continue; } - Path res = r.second + suffix; - if (pathExists(res)) { return canonPath(res); } - } - format f = format( - "file '%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)" - + std::string(pos ? ", at %2%" : "")); - f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); - throw ThrownError(f % path % pos); -} - - -std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathElem & elem) -{ - auto i = searchPathResolved.find(elem.second); - if (i != searchPathResolved.end()) { return i->second; } - - std::pair<bool, std::string> res; - - if (isUri(elem.second)) { - try { - CachedDownloadRequest request(elem.second); - request.unpack = true; - res = { true, getDownloader()->downloadCached(store, request).path }; - } catch (DownloadError & e) { - LOG(WARNING) << "Nix search path entry '" << elem.second << "' cannot be downloaded, ignoring"; - res = { false, "" }; - } - } else { - auto path = absPath(elem.second); - if (pathExists(path)) { - res = { true, path }; - } else { - LOG(WARNING) << "Nix search path entry '" << elem.second << "' does not exist, ignoring"; - res = { false, "" }; - } - } + if (res) { + throw ParseError(data.error); + } - DLOG(INFO) << "resolved search path element '" << elem.second << "' to '" << res.second << "'"; + data.result->bindVars(staticEnv); - searchPathResolved[elem.second] = res; - return res; + return data.result; } } // namespace nix |