mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-24 23:06:16 +02:00
Fix relative path handling in the parser
This commit is contained in:
parent
cd893a22f5
commit
1ee5dd6d96
18 changed files with 72 additions and 46 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue