Skip to content

Fix case statement parsing and add real-world test cases#283

Merged
wolfv merged 7 commits intomainfrom
claude/fix-install-script-syntax-vVHwU
Mar 22, 2026
Merged

Fix case statement parsing and add real-world test cases#283
wolfv merged 7 commits intomainfrom
claude/fix-install-script-syntax-vVHwU

Conversation

@wolfv
Copy link
Member

@wolfv wolfv commented Mar 22, 2026

Summary

This PR fixes a grammar issue in case statement parsing and adds comprehensive test coverage for real-world case statement patterns.

Key Changes

  • Grammar fix: Updated separator_op rule in grammar.pest to prevent ;; (double semicolon) from being incorrectly parsed as two separate semicolon separators by adding a negative lookahead (!";")
  • Test coverage: Added extensive test cases for case statements:
    • case.sh: Added basic pattern matching tests (simple strings, wildcards, tilde expansion)
    • case_real_world.sh: Added 13 real-world case statement examples covering:
      • Platform detection (Darwin, Linux, FreeBSD, Android)
      • Architecture mapping (arm64, aarch64, x86_64, etc.)
      • WSL detection via kernel version matching
      • Channel validation
      • Mirror/download URL selection
      • Distribution version mapping
      • Shell configuration file detection
      • Terminal type detection

Implementation Details

The grammar fix ensures that the ;; case statement terminator is properly recognized as a single token rather than being split into two separate semicolons, which was likely causing parsing errors in complex case statements.

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm

claude and others added 7 commits March 22, 2026 06:37
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.

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
The grammar allows $(cmd) command substitution and $? exit status inside
parameter expansions like ${VAR:-$(fallback)}, but the parser's match
statement for PARAMETER_PENDING_WORD did not handle Rule::SUB_COMMAND or
Rule::EXIT_STATUS, causing "Unexpected rule" errors on real-world install
scripts.

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
Two additional issues found when running the pixi install script:

1. PARAMETER_PENDING_WORD stops at `:`, so `${VAR:-https://example.com}`
   only parsed `https` as the default value. Changed VAR_DEFAULT_VALUE,
   VAR_ASSIGN_DEFAULT, VAR_ALTERNATE_VALUE, VAR_CHECK_UNSET, and
   VAR_CHECK_SET to use PATTERN_PENDING_WORD (which allows `:`) instead
   of PARAMETER_PENDING_WORD. VAR_SUBSTRING still uses
   PARAMETER_PENDING_WORD since it needs `:` as a separator.

2. `set -eu` failed because `-u` (nounset) wasn't recognized. Added
   ShellOptions::NoUnset variant and set command handling.

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
…ORD in conditions

Three features that unblock real-world install scripts:

1. Heredoc support (<<DELIM ... DELIM):
   - Pre-processes input to extract heredoc bodies before PEG parsing
   - Supports unquoted (with $VAR expansion) and quoted (<<'DELIM') heredocs
   - Supports <<- for tab stripping
   - Added IoFile::HereDoc variant and pipe-based execution

2. Condition negation ([ ! expr ] and [[ ! expr ]]):
   - Added condition_negation to grammar for [ ], [[ ]], and test
   - Added ConditionInner::Negation variant
   - Handles evaluation by inverting the inner condition result

3. UNQUOTED_PENDING_WORD in conditions:
   - Grammar allows bare words in conditions but parser rejected them
   - Now treats bare words as non-empty string checks (-n equivalent)

With these fixes:
- pixi install script: runs cleanly (stops at curl/wget check)
- nvm install script: parses and runs
- rustup install script: progresses further (blocked by assignment-only commands)

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
…on, case

Heredoc tests added:
- Empty heredoc, custom delimiter, special characters (< > | & ; ())
- Command substitution expansion in body
- Multiple heredocs in sequence
- Tab stripping with <<-
- Multiple variable expansions per line
- Double-quoted delimiter (no expansion)

Condition tests added:
- Negation with -n and -z: [ ! -n "" ], [ ! -z "hello" ]
- Negation with numeric ops: [ ! 5 -eq 3 ], [ ! 5 -gt 10 ]
- Negation in compound conditions: [ ! expr ] && [ expr ]
- test builtin with negation
- Bare word in [[ ]] (implicit -n check): [[ "notempty" ]], [[ "" ]]

Variable expansion tests added:
- Nested defaults: ${A:-${B:-deep_default}}
- Colons in alternate value and assign default
- Command substitution with pipes in default: ${VAR:-$(echo x | tr ...)}

Case statement tests added:
- Empty case body (just ;;)
- Case with only default pattern
- No-match case (no default)
- Inline with multiple commands: a) cmd1; cmd2 ;;
- Command substitution in case word
- Nested case statements

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
Replace filesystem-based negation tests that used /tmp (which doesn't
exist on Windows) with string and numeric comparison tests that work
on all platforms.

https://claude.ai/code/session_01KeAvJYzHSHut73dHikHiwm
@wolfv wolfv merged commit bb68aa5 into main Mar 22, 2026
8 checks passed
@wolfv wolfv deleted the claude/fix-install-script-syntax-vVHwU branch March 22, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants