fix: single-quote literalness (B2) + LooksLikePath trailing-backslash (B3) - #23
Merged
Aaronontheweb merged 2 commits intoMay 11, 2026
Merged
Conversation
… (B3) Two parser correctness fixes; public API surface unchanged. B2 — single-quote literalness v0.1.0-alpha resolved `$HOME` uniformly regardless of quote style, so `echo '$HOME'` produced Kind=Tilde. Per SPEC §5 single-quoted contents are literal bytes — no variable expansion. Lexer now marks single-quoted QuotedString tokens with an internal IsSingleQuoted flag and the resolver short-circuits tilde / $HOME / $VAR / glob / filesystem:: handling when set. `cat '/etc/passwd'` still resolves a literal absolute path; `echo '$HOME'` stays Kind=Literal. B3 — LooksLikePath trailing-backslash carve-out A double-quoted token like `"foo\\"` lexes to Value `foo\` (escape collapse). The trailing `\` is an artifact, not a meaningful path signal, but the heuristic was returning IsPath=true. Tightened the rule: forward slash anywhere still counts, backslash counts only when it's at a non-trailing position. `dir/` still classifies as a path (trailing `/` is a meaningful bash directory hint). Changes: - src/ShellSyntaxTree/Internal/Bash/Lexing/BashToken.cs: new IsSingleQuoted init-only flag (additive on the internal record). - src/ShellSyntaxTree/Internal/Bash/Lexing/BashLexer.cs: ReadSingleQuoted sets IsSingleQuoted=true on its emitted token. - src/ShellSyntaxTree/Internal/Resolving/BashResolver.cs: new Resolve overload accepting isLiteralBytes; LooksLikePath updated for the backslash carve-out. - src/ShellSyntaxTree/Internal/Bash/Parsing/BashCommandParser.cs: threads token.IsSingleQuoted through to the resolver from the QuotedString case. - SPEC.md §8: new Step 0 (Single-quoted bypass) preamble + LooksLikePath heuristic clarification. - tests/.../Corpus/bash/104, 109: updated to assert corrected outputs. - tests/.../Corpus/bash/119, 120, 121: new regression guards (single-quoted absolute path still resolves, cd dir/ still a path, single-quoted $VAR/file stays literal). - Directory.Build.props + RELEASE_NOTES.md: bump to 0.1.2-alpha. Public API impact: zero. No PublicApiSnapshotTests delta. dotnet build -c Release: 0 warnings, 0 errors. dotnet test -c Release: 359/359 passing (was 356; +3 entries). dotnet pack: ShellSyntaxTree.0.1.2-alpha.nupkg + .snupkg clean.
Aaronontheweb
enabled auto-merge (squash)
May 11, 2026 15:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two parser correctness fixes pulled from the v0.1.x backlog. Public API surface unchanged.
B2 — single-quote literalness
v0.1.0-alpha resolved
$HOMEuniformly regardless of quote style, soecho '$HOME'producedKind=Tilde. Per SPEC §5, single-quoted contents are literal bytes — no variable expansion. The lexer now marks single-quotedQuotedStringtokens with an internalIsSingleQuotedflag, and the resolver short-circuits tilde /$HOME/$VAR/ glob /filesystem::handling when set. Matches bash semantics.echo '$HOME'→Kind=Literal, Resolved=null(wasKind=Tilde)cat '/etc/passwd'→ still resolves to/etc/passwd(literal absolute path inside single quotes)rm '$VAR/file.txt'→Kind=Literal, Resolved="/work/$VAR/file.txt"(literal under cwd)B3 — LooksLikePath trailing-backslash carve-out
A double-quoted token like
"foo\\"lexes to Valuefoo\(escape collapse). The trailing\is an artifact, not a path signal, but the heuristic was returningIsPath=true. Tightened: forward slash anywhere still counts; backslash counts only at a non-trailing position.echo "trailing backslash\\"→IsPath=false(wasIsPath=true, Resolved=/work/trailing backslash)cd dir/→ stillIsPath=true, Resolved=/work/dir(regression guard)path\to\file→ stillIsPath=true(non-trailing backslash)What changed
src/ShellSyntaxTree/Internal/Bash/Lexing/BashToken.csIsSingleQuotedinit-only flag on the internal record (additive).src/ShellSyntaxTree/Internal/Bash/Lexing/BashLexer.csReadSingleQuotedsetsIsSingleQuoted=trueon its emitted token.src/ShellSyntaxTree/Internal/Resolving/BashResolver.csResolveoverload acceptingisLiteralBytes;LooksLikePathupdated for backslash carve-out.src/ShellSyntaxTree/Internal/Bash/Parsing/BashCommandParser.cstoken.IsSingleQuotedthrough to the resolver from theQuotedStringcase.SPEC.md§8tests/.../Corpus/bash/104, 109tests/.../Corpus/bash/119, 120, 121Directory.Build.props+RELEASE_NOTES.md0.1.2-alpha.Public API impact
Zero. No new public types/fields, no signature changes.
PublicApiSnapshotTestscount unchanged.Verification
pwsh ./scripts/Add-FileHeaders.ps1 -Verify— clean.dotnet build -c Release— 0 warnings, 0 errors.dotnet test -c Release— 359 / 359 passing (was 356; +3 new corpus entries).dotnet pack -c Release -o ./bin/nuget—ShellSyntaxTree.0.1.2-alpha.nupkg+.snupkgproduced cleanly.Test plan
What follows this PR
After merge: push
0.1.2-alphatag to fire trusted-publishing → nuget.org.