Fix relative path handling in the parser

This commit is contained in:
Eelco Dolstra 2022-05-12 18:25:36 +02:00
parent cd893a22f5
commit 1ee5dd6d96
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
18 changed files with 72 additions and 46 deletions

View file

@ -81,7 +81,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
for (auto & i : autoArgs) { for (auto & i : autoArgs) {
auto v = state.allocValue(); auto v = state.allocValue();
if (i.second[0] == 'E') if (i.second[0] == 'E')
state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), absPath("."))); state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), state.rootPath(absPath("."))));
else else
v->mkString(((std::string_view) i.second).substr(1)); v->mkString(((std::string_view) i.second).substr(1));
res.insert(state.symbols.create(i.first), v); res.insert(state.symbols.create(i.first), v);

View file

@ -766,7 +766,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
else if (file) else if (file)
state->evalFile(lookupFileArg(*state, *file), *vFile); state->evalFile(lookupFileArg(*state, *file), *vFile);
else { else {
auto e = state->parseExprFromString(*expr, absPath(".")); auto e = state->parseExprFromString(*expr, state->rootPath(absPath(".")));
state->eval(e, *vFile); state->eval(e, *vFile);
} }

View file

@ -190,8 +190,8 @@ public:
Expr * parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv); Expr * parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv);
/* Parse a Nix expression from the specified string. */ /* Parse a Nix expression from the specified string. */
Expr * parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv); Expr * parseExprFromString(std::string s, const SourcePath & basePath, StaticEnv & staticEnv);
Expr * parseExprFromString(std::string s, const Path & basePath); Expr * parseExprFromString(std::string s, const SourcePath & basePath);
Expr * parseStdin(); Expr * parseStdin();
@ -356,8 +356,13 @@ private:
friend struct ExprAttrs; friend struct ExprAttrs;
friend struct ExprLet; friend struct ExprLet;
Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path, Expr * parse(
const PathView basePath, StaticEnv & staticEnv); char * text,
size_t length,
FileOrigin origin,
const PathView path,
const SourcePath & basePath,
StaticEnv & staticEnv);
public: public:

View file

@ -723,7 +723,7 @@ void callFlake(EvalState & state,
state.vCallFlake = allocRootValue(state.allocValue()); state.vCallFlake = allocRootValue(state.allocValue());
state.eval(state.parseExprFromString( state.eval(state.parseExprFromString(
#include "call-flake.nix.gen.hh" #include "call-flake.nix.gen.hh"
, "/"), **state.vCallFlake); , state.rootPath("/")), **state.vCallFlake);
} }
state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos); state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos);

View file

@ -185,10 +185,10 @@ struct ExprPath : Expr
{ {
std::string s; // FIXME: remove std::string s; // FIXME: remove
Value v; Value v;
ExprPath(InputAccessor & accessor, std::string s) ExprPath(SourcePath && path)
: s(std::move(s)) : s(path.path)
{ {
v.mkPath({accessor, this->s}); v.mkPath(std::move(path));
} }
COMMON_METHODS COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env); Value * maybeThunk(EvalState & state, Env & env);

View file

@ -31,14 +31,9 @@ namespace nix {
EvalState & state; EvalState & state;
SymbolTable & symbols; SymbolTable & symbols;
Expr * result; Expr * result;
Path basePath; SourcePath basePath;
PosTable::Origin origin; PosTable::Origin origin;
std::optional<ErrorInfo> error; std::optional<ErrorInfo> error;
ParseData(EvalState & state, PosTable::Origin origin)
: state(state)
, symbols(state.symbols)
, origin(std::move(origin))
{ };
}; };
struct ParserFormals { struct ParserFormals {
@ -513,15 +508,15 @@ string_parts_interpolated
path_start path_start
: PATH { : PATH {
Path path(absPath({$1.p, $1.l}, data->basePath)); SourcePath path { data->basePath.accessor, absPath({$1.p, $1.l}, data->basePath.path) };
/* add back in the trailing '/' to the first segment */ /* add back in the trailing '/' to the first segment */
if ($1.p[$1.l-1] == '/' && $1.l > 1) if ($1.p[$1.l-1] == '/' && $1.l > 1)
path += "/"; path.path += "/";
$$ = new ExprPath(*data->state.rootFS, path); $$ = new ExprPath(std::move(path));
} }
| HPATH { | HPATH {
Path path(getHome() + std::string($1.p + 1, $1.l - 1)); Path path(getHome() + std::string($1.p + 1, $1.l - 1));
$$ = new ExprPath(*data->state.rootFS, path); $$ = new ExprPath(data->state.rootPath(path));
} }
; ;
@ -643,12 +638,13 @@ namespace nix {
Expr * EvalState::parse(char * text, size_t length, FileOrigin origin, Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
const PathView path, const PathView basePath, StaticEnv & staticEnv) const PathView path, const SourcePath & basePath, StaticEnv & staticEnv)
{ {
yyscan_t scanner; yyscan_t scanner;
std::string file; std::string file;
switch (origin) { switch (origin) {
case foFile: case foFile:
// FIXME: change this to a SourcePath.
file = path; file = path;
break; break;
case foStdin: case foStdin:
@ -658,8 +654,12 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
default: default:
assert(false); assert(false);
} }
ParseData data(*this, {file, origin}); ParseData data {
data.basePath = basePath; .state = *this,
.symbols = symbols,
.basePath = basePath,
.origin = {file, origin},
};
yylex_init(&scanner); yylex_init(&scanner);
yy_scan_buffer(text, length, scanner); yy_scan_buffer(text, length, scanner);
@ -716,18 +716,18 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticE
// readFile hopefully have left some extra space for terminators // readFile hopefully have left some extra space for terminators
buffer.append("\0\0", 2); buffer.append("\0\0", 2);
// FIXME: pass SourcePaths // FIXME: pass SourcePaths
return parse(buffer.data(), buffer.size(), foFile, path.path, dirOf(path.path), staticEnv); return parse(buffer.data(), buffer.size(), foFile, path.path, path.parent(), staticEnv);
} }
Expr * EvalState::parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv) Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath, StaticEnv & staticEnv)
{ {
s.append("\0\0", 2); s.append("\0\0", 2);
return parse(s.data(), s.size(), foString, "", basePath, staticEnv); return parse(s.data(), s.size(), foString, "", basePath, staticEnv);
} }
Expr * EvalState::parseExprFromString(std::string s, const Path & basePath) Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
{ {
return parseExprFromString(std::move(s), basePath, staticBaseEnv); return parseExprFromString(std::move(s), basePath, staticBaseEnv);
} }
@ -739,7 +739,7 @@ Expr * EvalState::parseStdin()
auto buffer = drainFD(0); auto buffer = drainFD(0);
// drainFD should have left some extra space for terminators // drainFD should have left some extra space for terminators
buffer.append("\0\0", 2); buffer.append("\0\0", 2);
return parse(buffer.data(), buffer.size(), foStdin, "", absPath("."), staticBaseEnv); return parse(buffer.data(), buffer.size(), foStdin, "", rootPath(absPath(".")), staticBaseEnv);
} }

View file

@ -375,7 +375,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
Expr * parsed; Expr * parsed;
try { try {
auto base = state.positions[pos]; auto base = state.positions[pos];
parsed = state.parseExprFromString(std::move(output), base.file); parsed = state.parseExprFromString(std::move(output), state.rootPath(base.file));
} catch (Error & e) { } catch (Error & e) {
e.addTrace(state.positions[pos], "While parsing the output from '%1%'", program); e.addTrace(state.positions[pos], "While parsing the output from '%1%'", program);
throw; throw;
@ -1464,7 +1464,7 @@ static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Valu
state.forceValue(*args[0], pos); state.forceValue(*args[0], pos);
if (args[0]->type() == nPath) { if (args[0]->type() == nPath) {
auto path = args[0]->path(); auto path = args[0]->path();
v.mkPath({path.accessor, dirOf(path.path)}); v.mkPath(path.parent());
} else { } else {
auto path = state.coerceToString(pos, *args[0], context, false, false); auto path = state.coerceToString(pos, *args[0], context, false, false);
auto dir = dirOf(*path); auto dir = dirOf(*path);
@ -3967,7 +3967,7 @@ void EvalState::createBaseEnv()
// the parser needs two NUL bytes as terminators; one of them // the parser needs two NUL bytes as terminators; one of them
// is implied by being a C string. // is implied by being a C string.
"\0"; "\0";
eval(parse(code, sizeof(code), foFile, derivationNixPath, "/", staticBaseEnv), *vDerivation); eval(parse(code, sizeof(code), foFile, derivationNixPath, rootPath("/"), staticBaseEnv), *vDerivation);
} }

View file

@ -87,6 +87,11 @@ void InputAccessor::dumpPath(
dump(path); dump(path);
} }
std::string InputAccessor::showPath(PathView path)
{
return "/virtual/" + std::to_string(number) + path;
}
struct FSInputAccessorImpl : FSInputAccessor struct FSInputAccessorImpl : FSInputAccessor
{ {
Path root; Path root;
@ -210,6 +215,11 @@ struct FSInputAccessorImpl : FSInputAccessor
{ {
return (bool) allowedPaths; return (bool) allowedPaths;
} }
std::string showPath(PathView path) override
{
return root + path;
}
}; };
ref<FSInputAccessor> makeFSInputAccessor( ref<FSInputAccessor> makeFSInputAccessor(
@ -219,11 +229,6 @@ ref<FSInputAccessor> makeFSInputAccessor(
return make_ref<FSInputAccessorImpl>(root, std::move(allowedPaths)); return make_ref<FSInputAccessorImpl>(root, std::move(allowedPaths));
} }
std::string SourcePath::to_string() const
{
return path; // FIXME
}
std::ostream & operator << (std::ostream & str, const SourcePath & path) std::ostream & operator << (std::ostream & str, const SourcePath & path)
{ {
str << path.to_string(); str << path.to_string();
@ -286,4 +291,10 @@ std::string_view SourcePath::baseName() const
return path == "" || path == "/" ? "source" : baseNameOf(path); return path == "" || path == "/" ? "source" : baseNameOf(path);
} }
SourcePath SourcePath::parent() const
{
// FIXME:
return {accessor, dirOf(path)};
}
} }

View file

@ -52,6 +52,8 @@ struct InputAccessor
{ {
return number < x.number; return number < x.number;
} }
virtual std::string showPath(PathView path);
}; };
struct FSInputAccessor : InputAccessor struct FSInputAccessor : InputAccessor
@ -87,6 +89,8 @@ struct SourcePath
std::string_view baseName() const; std::string_view baseName() const;
SourcePath parent() const;
std::string readFile() const std::string readFile() const
{ return accessor.readFile(path); } { return accessor.readFile(path); }
@ -104,7 +108,8 @@ struct SourcePath
PathFilter & filter = defaultPathFilter) const PathFilter & filter = defaultPathFilter) const
{ return accessor.dumpPath(path, sink, filter); } { return accessor.dumpPath(path, sink, filter); }
std::string to_string() const; std::string to_string() const
{ return accessor.showPath(path); }
SourcePath append(std::string_view s) const; SourcePath append(std::string_view s) const;

View file

@ -292,7 +292,7 @@ static void main_nix_build(int argc, char * * argv)
else else
for (auto i : left) { for (auto i : left) {
if (fromArgs) if (fromArgs)
exprs.push_back(state->parseExprFromString(std::move(i), absPath("."))); exprs.push_back(state->parseExprFromString(std::move(i), state->rootPath(absPath("."))));
else { else {
auto absolute = i; auto absolute = i;
try { try {
@ -362,7 +362,9 @@ static void main_nix_build(int argc, char * * argv)
if (!shell) { if (!shell) {
try { try {
auto expr = state->parseExprFromString("(import <nixpkgs> {}).bashInteractive", absPath(".")); auto expr = state->parseExprFromString(
"(import <nixpkgs> {}).bashInteractive",
state->rootPath(absPath(".")));
Value v; Value v;
state->eval(expr, v); state->eval(expr, v);

View file

@ -410,7 +410,7 @@ static void queryInstSources(EvalState & state,
loadSourceExpr(state, instSource.nixExprPath, vArg); loadSourceExpr(state, instSource.nixExprPath, vArg);
for (auto & i : args) { for (auto & i : args) {
Expr * eFun = state.parseExprFromString(i, absPath(".")); Expr * eFun = state.parseExprFromString(i, state.rootPath(absPath(".")));
Value vFun, vTmp; Value vFun, vTmp;
state.eval(eFun, vFun); state.eval(eFun, vFun);
vTmp.mkApp(&vFun, &vArg); vTmp.mkApp(&vFun, &vArg);

View file

@ -114,7 +114,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
Value envBuilder; Value envBuilder;
state.eval(state.parseExprFromString( state.eval(state.parseExprFromString(
#include "buildenv.nix.gen.hh" #include "buildenv.nix.gen.hh"
, "/"), envBuilder); , state.rootPath("/")), envBuilder);
/* Construct a Nix expression that calls the user environment /* Construct a Nix expression that calls the user environment
builder with the manifest as argument. */ builder with the manifest as argument. */

View file

@ -182,7 +182,7 @@ static int main_nix_instantiate(int argc, char * * argv)
for (auto & i : files) { for (auto & i : files) {
Expr * e = fromArgs Expr * e = fromArgs
? state->parseExprFromString(i, absPath(".")) ? state->parseExprFromString(i, state->rootPath(absPath(".")))
: state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, i))); : state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, i)));
processExpr(*state, attrPaths, parseOnly, strict, autoArgs, processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, outputKind, xmlOutputSourceLocation, e); evalOnly, outputKind, xmlOutputSourceLocation, e);

View file

@ -65,7 +65,7 @@ struct CmdEval : MixJSON, InstallableCommand
if (apply) { if (apply) {
auto vApply = state->allocValue(); auto vApply = state->allocValue();
state->eval(state->parseExprFromString(*apply, absPath(".")), *vApply); state->eval(state->parseExprFromString(*apply, state->rootPath(absPath("."))), *vApply);
auto vRes = state->allocValue(); auto vRes = state->allocValue();
state->callFunction(*vApply, *v, *vRes, noPos); state->callFunction(*vApply, *v, *vRes, noPos);
v = vRes; v = vRes;

View file

@ -176,7 +176,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
auto vGenerateManpage = state.allocValue(); auto vGenerateManpage = state.allocValue();
state.eval(state.parseExprFromString( state.eval(state.parseExprFromString(
#include "generate-manpage.nix.gen.hh" #include "generate-manpage.nix.gen.hh"
, "/"), *vGenerateManpage); , state.rootPath("/")), *vGenerateManpage);
state.corepkgsFS->addFile( state.corepkgsFS->addFile(
"/utils.nix", "/utils.nix",

View file

@ -27,7 +27,10 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url)
Value vMirrors; Value vMirrors;
// FIXME: use nixpkgs flake // FIXME: use nixpkgs flake
state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors); state.eval(state.parseExprFromString(
"import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>",
state.rootPath(absPath("/"))),
vMirrors);
state.forceAttrs(vMirrors, noPos); state.forceAttrs(vMirrors, noPos);
auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName)); auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));

View file

@ -726,7 +726,7 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
Expr * NixRepl::parseString(std::string s) Expr * NixRepl::parseString(std::string s)
{ {
Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv); Expr * e = state->parseExprFromString(std::move(s), state->rootPath(curDir), staticEnv);
return e; return e;
} }

View file

@ -140,7 +140,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
auto state = std::make_unique<EvalState>(Strings(), store); auto state = std::make_unique<EvalState>(Strings(), store);
auto v = state->allocValue(); auto v = state->allocValue();
state->eval(state->parseExprFromString(res.data, "/no-such-path"), *v); state->eval(state->parseExprFromString(res.data, state->rootPath("/no-such-path")), *v);
Bindings & bindings(*state->allocBindings(0)); Bindings & bindings(*state->allocBindings(0));
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first; auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first;