Found during the GH #95 lexer-overhaul census (PR #172); pre-existing and unchanged by the rewrite — reproduces identically on the old and new pipeline.
Repro
Y=fallback; echo ${X:-${Y}}
parse error:
1:27 [parse]: found '}' expected something else, expression, redirect, ...
| Y=fallback; echo ${X:-${Y}}
Bash prints fallback.
Cause
The VarRef logos regex is \$\{[^}]+\} — it stops at the first }, so the input lexes as VarRef("${X:-${Y}") + RBrace, and the parser trips on the dangling brace. logos can't express nested-brace matching in a regex, so this isn't a one-character fix.
What already works (workarounds)
- Quoted:
echo "${X:-${Y}}" → fallback. The in-string interpolation parser hand-rolls brace-depth matching (find_default_separator in parser.rs handles nesting), so the quoted form is fine.
- Simple ref in the default:
echo ${X:-$Y} → fallback (no inner braces, regex is happy).
So the gap is narrow: a bare (unquoted) ${...} whose default word contains a braced reference.
Fix directions (not prescribing)
The post-#95 scanner (scan() in lexer.rs) already tracks ${...} regions with a brace-depth counter — that's how $((..)) inside a bare ${...} gets its loud ArithmeticInVarRef error. The same region tracking could hand logos a pre-delimited varref (or synthesize the token directly) so the regex's first-} limitation stops mattering. Alternatively a token-level repair pass could stitch VarRef + balanced tail back together, but that's the kind of adjacency-fishing #95 just removed.
Related context: ${X:-$((1+2))} in the same bare position is now a deliberate loud error (ArithmeticInVarRef, PR #172) rather than a silent marker leak. If nested braced refs become legal here, that error's message ("assign it to a variable first") stays the right guidance for the arithmetic case.
Severity: loud parse error (not corruption), but it's a bash-idiomatic form agents reach for, and the error message gives no hint that quoting fixes it.
Found during the GH #95 lexer-overhaul census (PR #172); pre-existing and unchanged by the rewrite — reproduces identically on the old and new pipeline.
Repro
Bash prints
fallback.Cause
The
VarReflogos regex is\$\{[^}]+\}— it stops at the first}, so the input lexes asVarRef("${X:-${Y}")+RBrace, and the parser trips on the dangling brace. logos can't express nested-brace matching in a regex, so this isn't a one-character fix.What already works (workarounds)
echo "${X:-${Y}}"→fallback. The in-string interpolation parser hand-rolls brace-depth matching (find_default_separatorin parser.rs handles nesting), so the quoted form is fine.echo ${X:-$Y}→fallback(no inner braces, regex is happy).So the gap is narrow: a bare (unquoted)
${...}whose default word contains a braced reference.Fix directions (not prescribing)
The post-#95 scanner (
scan()in lexer.rs) already tracks${...}regions with a brace-depth counter — that's how$((..))inside a bare${...}gets its loudArithmeticInVarReferror. The same region tracking could hand logos a pre-delimited varref (or synthesize the token directly) so the regex's first-}limitation stops mattering. Alternatively a token-level repair pass could stitchVarRef+ balanced tail back together, but that's the kind of adjacency-fishing #95 just removed.Related context:
${X:-$((1+2))}in the same bare position is now a deliberate loud error (ArithmeticInVarRef, PR #172) rather than a silent marker leak. If nested braced refs become legal here, that error's message ("assign it to a variable first") stays the right guidance for the arithmetic case.Severity: loud parse error (not corruption), but it's a bash-idiomatic form agents reach for, and the error message gives no hint that quoting fixes it.