1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 11:36:03 +01:00

libexpr: parser.y: api.value.type variant

This commit is contained in:
Taeer Bar-Yam 2025-10-20 21:47:25 +02:00
parent 7e8db2eb59
commit 32b286e5d6
6 changed files with 99 additions and 125 deletions

View file

@ -2050,10 +2050,10 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
}; };
// List of returned strings. References to these Values must NOT be persisted. // List of returned strings. References to these Values must NOT be persisted.
SmallTemporaryValueVector<conservativeStackReservation> values(es->size()); SmallTemporaryValueVector<conservativeStackReservation> values(es.size());
Value * vTmpP = values.data(); Value * vTmpP = values.data();
for (auto & [i_pos, i] : *es) { for (auto & [i_pos, i] : es) {
Value & vTmp = *vTmpP++; Value & vTmp = *vTmpP++;
i->eval(state, env, vTmp); i->eval(state, env, vTmp);
@ -2097,7 +2097,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
.debugThrow(); .debugThrow();
} else { } else {
if (s.empty()) if (s.empty())
s.reserve(es->size()); s.reserve(es.size());
/* skip canonization of first path, which would only be not /* skip canonization of first path, which would only be not
canonized in the first place if it's coming from a ./${foo} type canonized in the first place if it's coming from a ./${foo} type
path */ path */

View file

@ -695,11 +695,11 @@ struct ExprConcatStrings : Expr
{ {
PosIdx pos; PosIdx pos;
bool forceString; bool forceString;
std::vector<std::pair<PosIdx, Expr *>> * es; std::vector<std::pair<PosIdx, Expr *>> es;
ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector<std::pair<PosIdx, Expr *>> * es) ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector<std::pair<PosIdx, Expr *>> && es)
: pos(pos) : pos(pos)
, forceString(forceString) , forceString(forceString)
, es(es) {}; , es(std::move(es)) {};
PosIdx getPos() const override PosIdx getPos() const override
{ {

View file

@ -282,7 +282,7 @@ ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, st
} }
/* Strip spaces from each line. */ /* Strip spaces from each line. */
auto * es2 = new std::vector<std::pair<PosIdx, Expr *>>; std::vector<std::pair<PosIdx, Expr *>> es2{};
atStartOfLine = true; atStartOfLine = true;
size_t curDropped = 0; size_t curDropped = 0;
size_t n = es.size(); size_t n = es.size();
@ -290,7 +290,7 @@ ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, st
const auto trimExpr = [&](Expr * e) { const auto trimExpr = [&](Expr * e) {
atStartOfLine = false; atStartOfLine = false;
curDropped = 0; curDropped = 0;
es2->emplace_back(i->first, e); es2.emplace_back(i->first, e);
}; };
const auto trimString = [&](const StringToken & t) { const auto trimString = [&](const StringToken & t) {
std::string s2; std::string s2;
@ -324,7 +324,7 @@ ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, st
// Ignore empty strings for a minor optimisation and AST simplification // Ignore empty strings for a minor optimisation and AST simplification
if (s2 != "") { if (s2 != "") {
es2->emplace_back(i->first, new ExprString(alloc, s2)); es2.emplace_back(i->first, new ExprString(alloc, s2));
} }
}; };
for (; i != es.end(); ++i, --n) { for (; i != es.end(); ++i, --n) {
@ -333,19 +333,17 @@ ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, st
// If there is nothing at all, return the empty string directly. // If there is nothing at all, return the empty string directly.
// This also ensures that equivalent empty strings result in the same ast, which is helpful when testing formatters. // This also ensures that equivalent empty strings result in the same ast, which is helpful when testing formatters.
if (es2->size() == 0) { if (es2.size() == 0) {
auto * const result = new ExprString(""); auto * const result = new ExprString("");
delete es2;
return result; return result;
} }
/* If this is a single string, then don't do a concatenation. */ /* If this is a single string, then don't do a concatenation. */
if (es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second)) { if (es2.size() == 1 && dynamic_cast<ExprString *>((es2)[0].second)) {
auto * const result = (*es2)[0].second; auto * const result = (es2)[0].second;
delete es2;
return result; return result;
} }
return new ExprConcatStrings(pos, true, es2); return new ExprConcatStrings(pos, true, std::move(es2));
} }
inline PosIdx LexerState::at(const ParserLocation & loc) inline PosIdx LexerState::at(const ParserLocation & loc)

View file

@ -142,11 +142,11 @@ or { return OR_KW; }
return PIPE_INTO; return PIPE_INTO;
} }
{ID} { yylval->id = {yytext, (size_t) yyleng}; return ID; } {ID} { yylval->emplace<StringToken>(yytext, (size_t) yyleng); return ID; }
{INT} { errno = 0; {INT} { errno = 0;
std::optional<int64_t> numMay = string2Int<int64_t>(yytext); std::optional<int64_t> numMay = string2Int<int64_t>(yytext);
if (numMay.has_value()) { if (numMay.has_value()) {
yylval->n = NixInt{*numMay}; yylval->emplace<NixInt>(*numMay);
} else { } else {
throw ParseError(ErrorInfo{ throw ParseError(ErrorInfo{
.msg = HintFmt("invalid integer '%1%'", yytext), .msg = HintFmt("invalid integer '%1%'", yytext),
@ -156,7 +156,7 @@ or { return OR_KW; }
return INT_LIT; return INT_LIT;
} }
{FLOAT} { errno = 0; {FLOAT} { errno = 0;
yylval->nf = strtod(yytext, 0); yylval->emplace<NixFloat>(strtod(yytext, 0));
if (errno != 0) if (errno != 0)
throw ParseError(ErrorInfo{ throw ParseError(ErrorInfo{
.msg = HintFmt("invalid float '%1%'", yytext), .msg = HintFmt("invalid float '%1%'", yytext),
@ -183,7 +183,7 @@ or { return OR_KW; }
/* It is impossible to match strings ending with '$' with one /* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */ of a rule. (A sane but undocumented limitation.) */
yylval->str = unescapeStr(yytext, yyleng, [&]() { return state->positions[CUR_POS]; }); yylval->emplace<StringToken>(unescapeStr(yytext, yyleng, [&]() { return state->positions[CUR_POS]; }));
return STR; return STR;
} }
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; } <STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
@ -198,27 +198,27 @@ or { return OR_KW; }
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; } \'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ { <IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->str = {yytext, (size_t) yyleng, true}; yylval->emplace<StringToken>(yytext, (size_t) yyleng, true);
forceNoNullByte(yylval->str, [&]() { return state->positions[CUR_POS]; }); forceNoNullByte(yylval->as<StringToken>(), [&]() { return state->positions[CUR_POS]; });
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\$ | <IND_STRING>\'\'\$ |
<IND_STRING>\$ { <IND_STRING>\$ {
yylval->str = {"$", 1}; yylval->emplace<StringToken>("$", 1);
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\' { <IND_STRING>\'\'\' {
yylval->str = {"''", 2}; yylval->emplace<StringToken>("''", 2);
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\\{ANY} { <IND_STRING>\'\'\\{ANY} {
yylval->str = unescapeStr(yytext + 2, yyleng - 2, [&]() { return state->positions[CUR_POS]; }); yylval->emplace<StringToken>(unescapeStr(yytext + 2, yyleng - 2, [&]() { return state->positions[CUR_POS]; }));
return IND_STR; return IND_STR;
} }
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; } <IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
<IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; } <IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; }
<IND_STRING>\' { <IND_STRING>\' {
yylval->str = {"'", 1}; yylval->emplace<StringToken>("'", 1);
return IND_STR; return IND_STR;
} }
@ -232,14 +232,14 @@ or { return OR_KW; }
<PATH_START>{PATH_SEG} { <PATH_START>{PATH_SEG} {
POP_STATE(); POP_STATE();
PUSH_STATE(INPATH_SLASH); PUSH_STATE(INPATH_SLASH);
yylval->path = {yytext, (size_t) yyleng}; yylval->emplace<StringToken>(yytext, (size_t) yyleng);
return PATH; return PATH;
} }
<PATH_START>{HPATH_START} { <PATH_START>{HPATH_START} {
POP_STATE(); POP_STATE();
PUSH_STATE(INPATH_SLASH); PUSH_STATE(INPATH_SLASH);
yylval->path = {yytext, (size_t) yyleng}; yylval->emplace<StringToken>(yytext, (size_t) yyleng);
return HPATH; return HPATH;
} }
@ -248,7 +248,7 @@ or { return OR_KW; }
PUSH_STATE(INPATH_SLASH); PUSH_STATE(INPATH_SLASH);
else else
PUSH_STATE(INPATH); PUSH_STATE(INPATH);
yylval->path = {yytext, (size_t) yyleng}; yylval->emplace<StringToken>(yytext, (size_t) yyleng);
return PATH; return PATH;
} }
{HPATH} { {HPATH} {
@ -256,7 +256,7 @@ or { return OR_KW; }
PUSH_STATE(INPATH_SLASH); PUSH_STATE(INPATH_SLASH);
else else
PUSH_STATE(INPATH); PUSH_STATE(INPATH);
yylval->path = {yytext, (size_t) yyleng}; yylval->emplace<StringToken>(yytext, (size_t) yyleng);
return HPATH; return HPATH;
} }
@ -272,7 +272,7 @@ or { return OR_KW; }
PUSH_STATE(INPATH_SLASH); PUSH_STATE(INPATH_SLASH);
else else
PUSH_STATE(INPATH); PUSH_STATE(INPATH);
yylval->str = {yytext, (size_t) yyleng}; yylval->emplace<StringToken>(yytext, (size_t) yyleng);
return STR; return STR;
} }
<INPATH>{ANY} | <INPATH>{ANY} |
@ -294,8 +294,8 @@ or { return OR_KW; }
}); });
} }
{SPATH} { yylval->path = {yytext, (size_t) yyleng}; return SPATH; } {SPATH} { yylval->emplace<StringToken>(yytext, (size_t) yyleng); return SPATH; }
{URI} { yylval->uri = {yytext, (size_t) yyleng}; return URI; } {URI} { yylval->emplace<StringToken>(yytext, (size_t) yyleng); return URI; }
%{ %{
// Doc comment rule // Doc comment rule

View file

@ -246,7 +246,7 @@ void ExprConcatStrings::show(const SymbolTable & symbols, std::ostream & str) co
{ {
bool first = true; bool first = true;
str << "("; str << "(";
for (auto & i : *es) { for (auto & i : es) {
if (first) if (first)
first = false; first = false;
else else
@ -564,7 +564,7 @@ void ExprConcatStrings::bindVars(EvalState & es, const std::shared_ptr<const Sta
if (es.debugRepl) if (es.debugRepl)
es.exprEnvs.insert(std::make_pair(this, env)); es.exprEnvs.insert(std::make_pair(this, env));
for (auto & i : *this->es) for (auto & i : this->es)
i.second->bindVars(es, env); i.second->bindVars(es, env);
} }

View file

@ -14,6 +14,10 @@
%code requires { %code requires {
// bison adds a bunch of switch statements with default:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
#ifndef BISON_HEADER #ifndef BISON_HEADER
#define BISON_HEADER #define BISON_HEADER
@ -120,46 +124,28 @@ static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
%} %}
%union { %define api.value.type variant
// !!! We're probably leaking stuff here.
nix::Expr * e;
nix::ExprList * list;
nix::ExprAttrs * attrs;
nix::Formals * formals;
nix::Formal * formal;
nix::NixInt n;
nix::NixFloat nf;
nix::StringToken id; // !!! -> Symbol
nix::StringToken path;
nix::StringToken uri;
nix::StringToken str;
std::vector<nix::AttrName> * attrNames;
std::vector<std::pair<nix::AttrName, nix::PosIdx>> * inheritAttrs;
std::vector<std::pair<nix::PosIdx, nix::Expr *>> * string_parts;
std::variant<nix::Expr *, std::string_view> * to_be_string;
std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, nix::StringToken>>> * ind_string_parts;
}
%type <e> start expr expr_function expr_if expr_op %type <nix::Expr *> start expr expr_function expr_if expr_op
%type <e> expr_select expr_simple expr_app %type <nix::Expr *> expr_select expr_simple expr_app
%type <e> expr_pipe_from expr_pipe_into %type <nix::Expr *> expr_pipe_from expr_pipe_into
%type <list> expr_list %type <nix::ExprList *> expr_list
%type <attrs> binds binds1 %type <nix::ExprAttrs *> binds binds1
%type <formals> formals formal_set %type <nix::Formals *> formals formal_set
%type <formal> formal %type <nix::Formal> formal
%type <attrNames> attrpath %type <std::vector<nix::AttrName>> attrpath
%type <inheritAttrs> attrs %type <std::vector<std::pair<nix::AttrName, nix::PosIdx>>> attrs
%type <string_parts> string_parts_interpolated %type <std::vector<std::pair<nix::PosIdx, nix::Expr *>>> string_parts_interpolated
%type <ind_string_parts> ind_string_parts %type <std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, nix::StringToken>>>> ind_string_parts
%type <e> path_start %type <nix::Expr *> path_start
%type <to_be_string> string_parts string_attr %type <std::variant<nix::Expr *, std::string_view>> string_parts string_attr
%type <id> attr %type <nix::StringToken> attr
%token <id> ID %token <nix::StringToken> ID
%token <str> STR IND_STR %token <nix::StringToken> STR IND_STR
%token <n> INT_LIT %token <nix::NixInt> INT_LIT
%token <nf> FLOAT_LIT %token <nix::NixFloat> FLOAT_LIT
%token <path> PATH HPATH SPATH PATH_END %token <nix::StringToken> PATH HPATH SPATH PATH_END
%token <uri> URI %token <nix::StringToken> URI
%token IF THEN ELSE ASSERT WITH LET IN_KW REC INHERIT EQ NEQ AND OR IMPL OR_KW %token IF THEN ELSE ASSERT WITH LET IN_KW REC INHERIT EQ NEQ AND OR IMPL OR_KW
%token PIPE_FROM PIPE_INTO /* <| and |> */ %token PIPE_FROM PIPE_INTO /* <| and |> */
%token DOLLAR_CURLY /* == ${ */ %token DOLLAR_CURLY /* == ${ */
@ -261,9 +247,9 @@ expr_op
| expr_op OR expr_op { $$ = new ExprOpOr(state->at(@2), $1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr(state->at(@2), $1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl(state->at(@2), $1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl(state->at(@2), $1, $3); }
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate(state->at(@2), $1, $3); } | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(state->at(@2), $1, $3); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr(state->alloc, $1, std::move(*$3)); delete $3; } | expr_op '?' attrpath { $$ = new ExprOpHasAttr(state->alloc, $1, std::move($3)); }
| expr_op '+' expr_op | expr_op '+' expr_op
{ $$ = new ExprConcatStrings(state->at(@2), false, new std::vector<std::pair<PosIdx, Expr *> >({{state->at(@1), $1}, {state->at(@3), $3}})); } { $$ = new ExprConcatStrings(state->at(@2), false, {{state->at(@1), $1}, {state->at(@3), $3}}); }
| expr_op '-' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.sub), {$1, $3}); } | expr_op '-' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.sub), {$1, $3}); }
| expr_op '*' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.mul), {$1, $3}); } | expr_op '*' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.mul), {$1, $3}); }
| expr_op '/' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.div), {$1, $3}); } | expr_op '/' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.div), {$1, $3}); }
@ -282,9 +268,9 @@ expr_app
expr_select expr_select
: expr_simple '.' attrpath : expr_simple '.' attrpath
{ $$ = new ExprSelect(state->alloc, CUR_POS, $1, std::move(*$3), nullptr); delete $3; } { $$ = new ExprSelect(state->alloc, CUR_POS, $1, std::move($3), nullptr); }
| expr_simple '.' attrpath OR_KW expr_select | expr_simple '.' attrpath OR_KW expr_select
{ $$ = new ExprSelect(state->alloc, CUR_POS, $1, std::move(*$3), $5); delete $3; $5->warnIfCursedOr(state->symbols, state->positions); } { $$ = new ExprSelect(state->alloc, CUR_POS, $1, std::move($3), $5); $5->warnIfCursedOr(state->symbols, state->positions); }
| /* Backwards compatibility: because Nixpkgs has a function named or, | /* Backwards compatibility: because Nixpkgs has a function named or,
allow stuff like map or [...]. This production is problematic (see allow stuff like map or [...]. This production is problematic (see
https://github.com/NixOS/nix/issues/11118) and will be refactored in the https://github.com/NixOS/nix/issues/11118) and will be refactored in the
@ -311,17 +297,15 @@ expr_simple
std::visit(overloaded{ std::visit(overloaded{
[&](std::string_view str) { $$ = new ExprString(state->alloc, str); }, [&](std::string_view str) { $$ = new ExprString(state->alloc, str); },
[&](Expr * expr) { $$ = expr; }}, [&](Expr * expr) { $$ = expr; }},
*$2); $2);
delete $2;
} }
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = state->stripIndentation(CUR_POS, std::move(*$2)); $$ = state->stripIndentation(CUR_POS, std::move($2));
delete $2;
} }
| path_start PATH_END | path_start PATH_END
| path_start string_parts_interpolated PATH_END { | path_start string_parts_interpolated PATH_END {
$2->insert($2->begin(), {state->at(@1), $1}); $2.insert($2.begin(), {state->at(@1), $1});
$$ = new ExprConcatStrings(CUR_POS, false, $2); $$ = new ExprConcatStrings(CUR_POS, false, std::move($2));
} }
| SPATH { | SPATH {
std::string_view path($1.p + 1, $1.l - 2); std::string_view path($1.p + 1, $1.l - 2);
@ -354,20 +338,19 @@ expr_simple
; ;
string_parts string_parts
: STR { $$ = new std::variant<Expr *, std::string_view>($1); } : STR { $$ = $1; }
| string_parts_interpolated { $$ = new std::variant<Expr *, std::string_view>(new ExprConcatStrings(CUR_POS, true, $1)); } | string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, std::move($1)); }
| { $$ = new std::variant<Expr *, std::string_view>(std::string_view()); } | { $$ = std::string_view(); }
; ;
string_parts_interpolated string_parts_interpolated
: string_parts_interpolated STR : string_parts_interpolated STR
{ $$ = $1; $1->emplace_back(state->at(@2), new ExprString(state->alloc, $2)); } { $$ = $1; $$.emplace_back(state->at(@2), new ExprString(state->alloc, $2)); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(state->at(@2), $3); } | string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $$.emplace_back(state->at(@2), $3); }
| DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<PosIdx, Expr *>>; $$->emplace_back(state->at(@1), $2); } | DOLLAR_CURLY expr '}' { $$.emplace_back(state->at(@1), $2); }
| STR DOLLAR_CURLY expr '}' { | STR DOLLAR_CURLY expr '}' {
$$ = new std::vector<std::pair<PosIdx, Expr *>>; $$.emplace_back(state->at(@1), new ExprString(state->alloc, $1));
$$->emplace_back(state->at(@1), new ExprString(state->alloc, $1)); $$.emplace_back(state->at(@2), $3);
$$->emplace_back(state->at(@2), $3);
} }
; ;
@ -408,9 +391,9 @@ path_start
; ;
ind_string_parts ind_string_parts
: ind_string_parts IND_STR { $$ = $1; $1->emplace_back(state->at(@2), $2); } : ind_string_parts IND_STR { $$ = $1; $$.emplace_back(state->at(@2), $2); }
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(state->at(@2), $3); } | ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $$.emplace_back(state->at(@2), $3); }
| { $$ = new std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>>; } | { }
; ;
binds binds
@ -421,19 +404,17 @@ binds
binds1 binds1
: binds1[accum] attrpath '=' expr ';' : binds1[accum] attrpath '=' expr ';'
{ $$ = $accum; { $$ = $accum;
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr); state->addAttr($$, std::move($attrpath), @attrpath, $expr, @expr);
delete $attrpath;
} }
| binds[accum] INHERIT attrs ';' | binds[accum] INHERIT attrs ';'
{ $$ = $accum; { $$ = $accum;
for (auto & [i, iPos] : *$attrs) { for (auto & [i, iPos] : $attrs) {
if ($accum->attrs.find(i.symbol) != $accum->attrs.end()) if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos); state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
$accum->attrs.emplace( $accum->attrs.emplace(
i.symbol, i.symbol,
ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited)); ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
} }
delete $attrs;
} }
| binds[accum] INHERIT '(' expr ')' attrs ';' | binds[accum] INHERIT '(' expr ')' attrs ';'
{ $$ = $accum; { $$ = $accum;
@ -441,7 +422,7 @@ binds1
$accum->inheritFromExprs = std::make_unique<std::vector<Expr *>>(); $accum->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
$accum->inheritFromExprs->push_back($expr); $accum->inheritFromExprs->push_back($expr);
auto from = new nix::ExprInheritFrom(state->at(@expr), $accum->inheritFromExprs->size() - 1); auto from = new nix::ExprInheritFrom(state->at(@expr), $accum->inheritFromExprs->size() - 1);
for (auto & [i, iPos] : *$attrs) { for (auto & [i, iPos] : $attrs) {
if ($accum->attrs.find(i.symbol) != $accum->attrs.end()) if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos); state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
$accum->attrs.emplace( $accum->attrs.emplace(
@ -451,51 +432,45 @@ binds1
iPos, iPos,
ExprAttrs::AttrDef::Kind::InheritedFrom)); ExprAttrs::AttrDef::Kind::InheritedFrom));
} }
delete $attrs;
} }
| attrpath '=' expr ';' | attrpath '=' expr ';'
{ $$ = new ExprAttrs; { $$ = new ExprAttrs;
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr); state->addAttr($$, std::move($attrpath), @attrpath, $expr, @expr);
delete $attrpath;
} }
; ;
attrs attrs
: attrs attr { $$ = $1; $1->emplace_back(AttrName(state->symbols.create($2)), state->at(@2)); } : attrs attr { $$ = $1; $$.emplace_back(AttrName(state->symbols.create($2)), state->at(@2)); }
| attrs string_attr | attrs string_attr
{ $$ = $1; { $$ = $1;
std::visit(overloaded { std::visit(overloaded {
[&](std::string_view str) { $$->emplace_back(AttrName(state->symbols.create(str)), state->at(@2)); }, [&](std::string_view str) { $$.emplace_back(AttrName(state->symbols.create(str)), state->at(@2)); },
[&](Expr * expr) { [&](Expr * expr) {
throw ParseError({ throw ParseError({
.msg = HintFmt("dynamic attributes not allowed in inherit"), .msg = HintFmt("dynamic attributes not allowed in inherit"),
.pos = state->positions[state->at(@2)] .pos = state->positions[state->at(@2)]
}); });
} }
}, *$2); }, $2);
delete $2;
} }
| { $$ = new std::vector<std::pair<AttrName, PosIdx>>; } | { }
; ;
attrpath attrpath
: attrpath '.' attr { $$ = $1; $1->push_back(AttrName(state->symbols.create($3))); } : attrpath '.' attr { $$ = $1; $$.push_back(AttrName(state->symbols.create($3))); }
| attrpath '.' string_attr | attrpath '.' string_attr
{ $$ = $1; { $$ = $1;
std::visit(overloaded { std::visit(overloaded {
[&](std::string_view str) { $$->push_back(AttrName(state->symbols.create(str))); }, [&](std::string_view str) { $$.push_back(AttrName(state->symbols.create(str))); },
[&](Expr * expr) { $$->push_back(AttrName(expr)); } [&](Expr * expr) { $$.push_back(AttrName(expr)); }
}, *$3); }, $3);
delete $3;
} }
| attr { $$ = new std::vector<AttrName>; $$->push_back(AttrName(state->symbols.create($1))); } | attr { $$.push_back(AttrName(state->symbols.create($1))); }
| string_attr | string_attr
{ $$ = new std::vector<AttrName>; { std::visit(overloaded {
std::visit(overloaded { [&](std::string_view str) { $$.push_back(AttrName(state->symbols.create(str))); },
[&](std::string_view str) { $$->push_back(AttrName(state->symbols.create(str))); }, [&](Expr * expr) { $$.push_back(AttrName(expr)); }
[&](Expr * expr) { $$->push_back(AttrName(expr)); } }, $1);
}, *$1);
delete $1;
} }
; ;
@ -506,7 +481,7 @@ attr
string_attr string_attr
: '"' string_parts '"' { $$ = $2; } : '"' string_parts '"' { $$ = $2; }
| DOLLAR_CURLY expr '}' { $$ = new std::variant<Expr *, std::string_view>($2); } | DOLLAR_CURLY expr '}' { $$ = $2; }
; ;
expr_list expr_list
@ -524,14 +499,14 @@ formal_set
formals formals
: formals[accum] ',' formal : formals[accum] ',' formal
{ $$ = $accum; $$->formals.emplace_back(*$formal); delete $formal; } { $$ = $accum; $$->formals.emplace_back(std::move($formal)); }
| formal | formal
{ $$ = new Formals; $$->formals.emplace_back(*$formal); delete $formal; } { $$ = new Formals; $$->formals.emplace_back(std::move($formal)); }
; ;
formal formal
: ID { $$ = new Formal{CUR_POS, state->symbols.create($1), 0}; } : ID { $$ = Formal{CUR_POS, state->symbols.create($1), 0}; }
| ID '?' expr { $$ = new Formal{CUR_POS, state->symbols.create($1), $3}; } | ID '?' expr { $$ = Formal{CUR_POS, state->symbols.create($1), $3}; }
; ;
%% %%
@ -582,3 +557,4 @@ Expr * parseExprFromBuf(
} }
#pragma GCC diagnostic pop // end ignored "-Wswitch-enum"