Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,15 @@ priorities.
precedence, ancestry coordinates, reference identity, span and enum
validity, value/redirect invariants, safe defaults, copied collections,
and the 16-container bound.
- [ ] Adapt the existing Bash and PowerShell grammars to emit the structural
and command-occurrence projections before enabling any control-flow
- [x] Adapt the existing Bash grammar to emit structural and command-occurrence
projections before enabling control flow. The recursive coordinator
preserves pipeline/list precedence, isolated nested groups, decoded
wrapper ownership and nullable spans, compatibility operators, and exact
`Clause` identity; unsupported wrapper tails and depth overflow fail
closed. Redirect-bearing leaves remain incomplete until the explicit
redirect-analysis slice lands.
- [ ] Adapt the existing PowerShell grammar to emit the structural and
command-occurrence projections before enabling any control-flow
construct.
- [ ] Deliver paired Bash and PowerShell `$()` substitution slices for all
locked executable value positions, including ordering, ancestry,
Expand Down
15 changes: 14 additions & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,10 @@ command := clause (compound_op clause)*
compound_op := "&&" | "||" | ";" | "|" | NEWLINE
clause := subshell | bash_c_wrapper | simple_clause
subshell := "(" command ")"
bash_c_wrapper := ("bash" | "sh") "-c" QUOTED_STRING
bash_c_wrapper := ("bash" | "sh") static_flag* "-c" STATIC_QUOTED_STRING
static_flag := exact-one literal Word beginning with "-"
STATIC_QUOTED_STRING := QuotedString whose outer-shell provenance is entirely
literal and exactly one value
simple_clause := verb_chain arg* redirect*
verb_chain := verb_like_word (FW_pair? verb_like_word)*
// greedy walk per §6.1; FW_pair is a
Expand Down Expand Up @@ -1669,6 +1672,16 @@ The outer `bash -c` itself does not appear as a clause — it's "consumed"
by the recursion. Consumers that care that this came from a wrapper can
inspect `IsCommandStringWrapped` on the surfaced clauses.

A `bash` or `sh` clause whose authored arguments are dynamic, contain a decoded
`-c`, or contain a combined short option that may select command-string mode,
but that does not match the complete static wrapper production, remains visible
through its v0.2 compatibility leaf, including its direct outer source spans.
Its v0.3 command occurrence has `IsComplete=false`. Wrapper-control tokens and
the quoted body must each have literal, exactly-one outer-shell provenance;
token kind or decoded spelling alone is insufficient. A proved `--` ends this
conservative option scan. The parser does not claim to have discovered a
dynamic or otherwise unsupported command-string body.

**Recursion limit:** parse `bash -c "bash -c ..."` chains up to depth 5.
Deeper nesting → set the outer `ParsedCommand.IsUnparseable = true` with
reason `"bash -c recursion depth exceeded (>5)"` per locked interpretation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ partial command and compatibility result.
- **THEN** projection fails closed
- **THEN** the occurrence is not published with `IsComplete=true`

#### Scenario: Dynamic Bash command string remains incomplete
- **WHEN** Bash parses a `bash` or `sh` clause with dynamic wrapper-control input, decoded or combined command-string options, or an expanding quoted body that does not match the complete literal exactly-one wrapper production
- **THEN** the existing outer compatibility leaf remains visible with direct source provenance
- **THEN** its command occurrence has `IsComplete=false` because no hidden command-string body was discovered

#### Scenario: While condition and body roles
- **WHEN** Bash parses `while curl URL; do sleep 1; done`
- **THEN** `curl` is identified as a condition occurrence
Expand Down
2 changes: 1 addition & 1 deletion openspec/changes/v0-3-structured-shell-analysis/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
- [x] 3.3 Add `ParsedCommand.Syntax` and `ParsedCommand.Commands` while retaining all v0.2 members.
- [x] 3.4 Build a library-owned traversal that emits each simple command occurrence exactly once in deterministic source order.
- [x] 3.5 Build the conservative `Clauses` compatibility flattener without inventing cross-structure compound operators.
- [ ] 3.6 Adapt the existing Bash grammar to emit the structural model with no newly supported syntax.
- [x] 3.6 Adapt the existing Bash grammar to emit the structural model with no newly supported syntax.
- [ ] 3.7 Adapt the existing PowerShell grammar to emit the structural model with no newly supported syntax.
- [ ] 3.8 Add tests proving existing parser inputs retain their v0.2 leaf and compatibility results.
- [ ] 3.9 Add corpus expectations for syntax shape, occurrences, roles, and completeness for existing constructs.
Expand Down
Loading