mirror of
https://github.com/NixOS/nix
synced 2025-07-04 19:41:48 +02:00
libexpr: deprecate the bogus "or"-as-variable
As a prelude to making "or" work like a normal variable, emit a warning any time the "fn or" production is used in a context that will change how it is parsed when that production is refactored. In detail: in the future, OR_KW will be moved to expr_simple, and the cursed ExprCall production that is currently part of the expr_select nonterminal will be generated "normally" in expr_app instead. Any productions that accept an expr_select will be affected, except for the expr_app nonterminal itself (because, while expr_app has a production accepting a bare expr_select, its other production will continue to accept "fn or" expressions). So all we need to do is emit an appropriate warning when an expr_simple representing a cursed ExprCall is accepted in one of those productions without first going through expr_app. As the warning message describes, users can suppress the warning by wrapping their problematic "fn or" expressions in parentheses. For example, "f g or" can be made future-proof by rewriting it as "f (g or)"; similarly "[ x y or ]" can be rewritten as "[ x (y or) ]", etc. The parentheses preserve the current grouping behavior, as in the future "f g or" will be parsed as "(f g) or", just like "f g anything-else" is grouped. (Mechanically, this suppresses the warning because the problem ExprCalls go through the "expr_app : expr_select" production, which resets the cursed status on the ExprCall.)
This commit is contained in:
parent
68ba6ff470
commit
da332d678e
6 changed files with 79 additions and 8 deletions
|
@ -264,19 +264,28 @@ expr_op
|
|||
;
|
||||
|
||||
expr_app
|
||||
: expr_app expr_select { $$ = makeCall(CUR_POS, $1, $2); }
|
||||
| expr_select
|
||||
: expr_app expr_select { $$ = makeCall(CUR_POS, $1, $2); $2->warnIfCursedOr(state->symbols, state->positions); }
|
||||
| /* Once a ‘cursed or’ reaches this nonterminal, it is no longer cursed,
|
||||
because the uncursed parse would also produce an expr_app. But we need
|
||||
to remove the cursed status in order to prevent valid things like
|
||||
`f (g or)` from triggering the warning. */
|
||||
expr_select { $$ = $1; $$->resetCursedOr(); }
|
||||
;
|
||||
|
||||
expr_select
|
||||
: expr_simple '.' attrpath
|
||||
{ $$ = new ExprSelect(CUR_POS, $1, std::move(*$3), nullptr); delete $3; }
|
||||
| expr_simple '.' attrpath OR_KW expr_select
|
||||
{ $$ = new ExprSelect(CUR_POS, $1, std::move(*$3), $5); delete $3; }
|
||||
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
||||
function named ‘or’, allow stuff like ‘map or [...]’. */
|
||||
{ $$ = new ExprSelect(CUR_POS, $1, std::move(*$3), $5); delete $3; $5->warnIfCursedOr(state->symbols, state->positions); }
|
||||
| /* Backwards compatibility: because Nixpkgs has a function named ‘or’,
|
||||
allow stuff like ‘map or [...]’. This production is problematic (see
|
||||
https://github.com/NixOS/nix/issues/11118) and will be refactored in the
|
||||
future by treating `or` as a regular identifier. The refactor will (in
|
||||
very rare cases, we think) change the meaning of expressions, so we mark
|
||||
the ExprCall with data (establishing that it is a ‘cursed or’) that can
|
||||
be used to emit a warning when an affected expression is parsed. */
|
||||
expr_simple OR_KW
|
||||
{ $$ = new ExprCall(CUR_POS, $1, {new ExprVar(CUR_POS, state->s.or_)}); }
|
||||
{ $$ = new ExprCall(CUR_POS, $1, {new ExprVar(CUR_POS, state->s.or_)}, state->positions.add(state->origin, @$.endOffset)); }
|
||||
| expr_simple
|
||||
;
|
||||
|
||||
|
@ -472,7 +481,7 @@ string_attr
|
|||
;
|
||||
|
||||
expr_list
|
||||
: expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ }
|
||||
: expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */; $2->warnIfCursedOr(state->symbols, state->positions); }
|
||||
| { $$ = new ExprList; }
|
||||
;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue