Skip to content

Commit bb68aa5

Browse files
authored
Fix case statement parsing and add real-world test cases (#283)
* fix: prevent separator_op from consuming first `;` of `;;` in case items The `separator_op` grammar rule matched a bare `;` which greedily consumed the first character of the `;;` (DSEMI) token inside case items when the command and `;;` were on the same line (e.g., `echo "hi" ;;`). Added a negative lookahead (`";" ~ !";"`) so `;` only matches when not followed by another `;`. Also adds real-world test cases from popular install scripts (pixi, rustup, nvm, docker, homebrew) to prevent regressions.
1 parent 665441b commit bb68aa5

10 files changed

Lines changed: 713 additions & 18 deletions

File tree

‎crates/deno_task_shell/src/grammar.pest‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,16 @@ VARIABLE_MODIFIER = _{
132132
VAR_CHECK_SET
133133
}
134134

135-
VAR_DEFAULT_VALUE = !{ ":-" ~ PARAMETER_PENDING_WORD? }
136-
VAR_ASSIGN_DEFAULT = !{ ":=" ~ PARAMETER_PENDING_WORD }
137-
VAR_ALTERNATE_VALUE = !{ ":+" ~ PARAMETER_PENDING_WORD }
135+
VAR_DEFAULT_VALUE = !{ ":-" ~ PATTERN_PENDING_WORD? }
136+
VAR_ASSIGN_DEFAULT = !{ ":=" ~ PATTERN_PENDING_WORD }
137+
VAR_ALTERNATE_VALUE = !{ ":+" ~ PATTERN_PENDING_WORD }
138138
VAR_SUBSTRING = !{ ":" ~ PARAMETER_PENDING_WORD ~ (":" ~ PARAMETER_PENDING_WORD)? }
139139
VAR_LONGEST_SUFFIX_REMOVE = !{ "%%" ~ PATTERN_PENDING_WORD }
140140
VAR_SHORTEST_SUFFIX_REMOVE = !{ "%" ~ PATTERN_PENDING_WORD }
141141
VAR_LONGEST_PREFIX_REMOVE = !{ "##" ~ PATTERN_PENDING_WORD }
142142
VAR_SHORTEST_PREFIX_REMOVE = !{ "#" ~ PATTERN_PENDING_WORD }
143-
VAR_CHECK_UNSET = !{ "-" ~ PARAMETER_PENDING_WORD? }
144-
VAR_CHECK_SET = !{ "+" ~ PARAMETER_PENDING_WORD? }
143+
VAR_CHECK_UNSET = !{ "-" ~ PATTERN_PENDING_WORD? }
144+
VAR_CHECK_SET = !{ "+" ~ PATTERN_PENDING_WORD? }
145145

146146
// Like PARAMETER_PENDING_WORD but allows ":" in patterns
147147
PATTERN_PENDING_WORD = ${
@@ -395,13 +395,13 @@ else_part = !{
395395
// a compound list (e.g., `if [ ... ] && [ ... ]; then` or `if command; then`).
396396
if_condition = !{ compound_list }
397397

398-
condition_inner = !{ unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD }
398+
condition_inner = !{ condition_negation? ~ (unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD) }
399399
condition_chain_op = { "||" | "&&" }
400400

401401
conditional_expression = !{
402402
("[[" ~ condition_inner ~ (condition_chain_op ~ condition_inner)* ~ "]]" ~ ";"?) |
403-
("[" ~ (unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD) ~ "]" ~ ";"?) |
404-
("test" ~ (unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD) ~ ";"?)
403+
("[" ~ condition_negation? ~ (unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD) ~ "]" ~ ";"?) |
404+
("test" ~ condition_negation? ~ (unary_conditional_expression | binary_conditional_expression | UNQUOTED_PENDING_WORD) ~ ";"?)
405405
}
406406

407407
unary_conditional_expression = !{
@@ -481,7 +481,7 @@ here_end = @{ ("\"" ~ UNQUOTED_PENDING_WORD ~ "\"") | UNQUOTED_PENDING_WORD }
481481

482482
newline_list = _{ NEWLINE+ }
483483
linebreak = _{ NEWLINE* }
484-
separator_op = { "&" | ";" }
484+
separator_op = { "&" | ";" ~ !";" }
485485
separator = _{ separator_op ~ linebreak | newline_list }
486486

487487
wordlist = !{ UNQUOTED_PENDING_WORD+ }

0 commit comments

Comments
 (0)