PR 5: cd-attribution + subshell isolation + bash -c recursion#8
Merged
Conversation
Completes the SPEC §9 + §10 behaviors deferred from earlier PRs. Locked interpretations #4 (bash -c overflow → outer ParsedCommand.IsUnparseable), #5 (only cd/chdir propagate; pushd/popd parse but don't), and #6 (cd $VAR → synthetic DynamicSkip attribution arg) now fully materialized. What's wired: - Internal/Bash/Parsing/CdAttributionContext.cs (parser-internal, mutable): * SubshellStack of monotonic IDs handles sibling subshells cleanly (depth alone doesn't distinguish (a) && (b)) * SetLiteralAttribution / SetDynamicAttribution * HasAttribution flag - BashCommandParser updates: * Only cd/chdir update attribution context (interp #5) * Subsequent clauses get synthetic IsCwdAttribution arg: - Literal cd target → Kind=Literal, IsPath=true, Resolved=<cwd> - DynamicSkip cd target → Kind=DynamicSkip, IsPath=false, Raw="<dynamic-cwd>" (interp #6) * Subshell ( ... ) entry pushes attribution stack, exit pops; clauses inside get IsSubshell=true; subshell mutations don't leak out * bash -c / sh -c real recursion (was single-clause framework in PR 3): inner ParsedCommand surfaced with IsBashCWrapped=true on each clause; outer bash -c clause consumed (not emitted) * Recursion depth cap at 5 → outer ParsedCommand.IsUnparseable=true with reason "bash -c recursion depth exceeded (>5)" (interp #4) * Outer cd attribution does NOT leak into bash -c inner clauses (v0.1 decision; tracked for v0.1.x revisit) - BashResolver internal overload Resolve(raw, treatAsPath, options, workingDirectoryUnknown): lets the propagator force DynamicSkip on relative-path args under dynamic cd (interp #6) without polluting the public BashParserOptions surface. Tests: - 8 new parser tests: attribution propagation, subshell isolation, sequential cd, pushd non-propagation, dynamic cd, sibling subshells, bash -c depth-2 success, bash -c depth-6 overflow. - CorpusRunnerTests: added IsCwdAttribution field on ExpectedArg. - 30 new corpus entries (71-100): 10 cd-in-compound + 10 subshell + 10 bash -c. 5 PR 3-4 corpus entries refreshed (25, 28, 34, 35, 52). - Total: 337/337 passing (was 296 at PR 4 baseline). SPEC.md updated: - §9 rule 3 explicit on which CwdVerbs propagate (only cd/chdir); added "Dynamic-cd attribution" subsection per interp #6 - §10 subshell flattening rephrased; bash -c recursion-limit replaced with "set ParsedCommand.IsUnparseable=true" per interp #4 Public API surface unchanged. PublicApiSnapshotTests still 18/18 green.
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
PR 5 of the v0.1.0-alpha shipping plan. Completes SPEC §9 (cd-in-compound propagation) and §10 (subshell isolation +
bash -crecursion) behaviors. Locked interpretations #4 (bash -c overflow), #5 (only cd/chdir propagate), and #6 (cd $VAR → DynamicSkip attribution) now fully materialized.What landed
Internal/Bash/Parsing/CdAttributionContext.cs— parser-internal mutable context withSubshellStackof monotonic IDs (handles sibling subshells like(a) && (b)cleanly).BashCommandParserupdates:cd/chdirupdate attribution (interp PR 2: BashLexer + opaque-region scanner #5)IsCwdAttributionarg on subsequent clauses;Kind=Literalwhen resolved,Kind=DynamicSkipwhen target was dynamic (interp PR 3: verb tables + BashCommandParser core #6, withRaw="<dynamic-cwd>"sentinel)( ... )push/pop attribution stack;IsSubshell=trueon inner clauses; subshell mutations don't leak outwardbash -c/sh -crecursion (replaces PR 3's single-clause framework): outer consumed, inner surfaced withIsBashCWrapped=trueParsedCommand.IsUnparseable=true(interp PR 1: bootstrap projects + locked public API + OpenSpec scaffolding #4)BashResolverinternal overloadResolve(raw, treatAsPath, options, workingDirectoryUnknown)— lets the propagator force DynamicSkip on relative paths under dynamic cd without changing the publicBashParserOptionssurface.SPEC.md updates
ParsedCommand.IsUnparseable=true" per interp PR 1: bootstrap projects + locked public API + OpenSpec scaffolding #4Tests + corpus
Deferred to v0.1.x
bash -cinner clauses (v0.1: doesn't propagate; v0.1.x or v0.2 may revisit)cd -jump-to-previous-dir explicit handling (currently no-op since-is detected as a flag)Verification
dotnet build -c Release— clean (TreatWarningsAsErrors=true)dotnet test -c Release— 337/337 passingpwsh ./scripts/Add-FileHeaders.ps1 -Verify— all files have headersopenspec validate v0.1-locked-interpretations --strict— passesPath.GetFullPathregressions (PR 4 fix preserved)Test plan
Test-ubuntu-latestTest-windows-latestNext
PR 6 — corpus completeness (add ~5 more entries to hit 105+ across all SPEC §13 categories), polished
AstAssert.Equalhelper, PII audit[Fact]per SPEC §14, final cross-platform corpus pass. After that: PR 7 release prep + tag.