diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 305bcd2..84c2301 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -287,12 +287,16 @@ priorities. The PowerShell manifest owns all 491 entries and round-trips them exactly, including case-specific isolated-state inputs. Explicit false/null assertions remain opt-in and generator-preserved. -- [x] Promote the remaining 21 stable Bash design cases into the executable - corpus with complete compatibility, syntax, occurrence, value, ancestry, +- [x] Promote every landed stable Bash design case into the executable corpus + with complete compatibility, syntax, occurrence, value, ancestry, redirect, and completeness assertions. Nine compatibility-only entries - now carry the v0.3 projections and entries 281-292 cover the inputs that - had no exact executable-corpus case. The three Bash future-scope design - cases remain non-gating. Promotion also reconciled the unquoted wildcard + carry the v0.3 projections, entries 281-292 cover the first inputs that + had no exact executable-corpus case, and entries 294-308 close the + remaining exact-input gap for substitutions, cwd joins, bounded loops, + descriptor duplication, and literal heredoc data. Empty occurrence-level + redirect projections are explicit in the new cases. The three Bash + future-scope design cases remain non-gating. + Promotion also reconciled the unquoted wildcard redirect story with the fail-closed completeness contract, publishes sparse exact/unknown effective-value overlays, and pins quoted, escaped, and continued tilde-prefix behavior against Bash. The PowerShell promotion diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/294_v03_design_simple_command_substitution.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/294_v03_design_simple_command_substitution.json new file mode 100644 index 0000000..c2c7b3f --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/294_v03_design_simple_command_substitution.json @@ -0,0 +1,222 @@ +{ + "name": "v0.3 Bash design promotion: Simple command substitution", + "input": "rm \"$(find /tmp)\"", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "find" + ], + "args": [ + { + "raw": "/tmp", + "kind": "Literal", + "isPath": true, + "resolved": "/tmp", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "find", + "value": "find", + "role": "Verb", + "sourceStart": 6, + "sourceLength": 4, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "/tmp", + "value": "/tmp", + "role": "Argument", + "sourceStart": 11, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/tmp" + } + ] + }, + { + "operator": "None", + "verb": [ + "rm" + ], + "args": [ + { + "raw": "\"$(find /tmp)\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "rm", + "value": "rm", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 2, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$(find /tmp)\"", + "value": "$(find /tmp)", + "role": "Argument", + "sourceStart": 3, + "sourceLength": 14, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 17, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 17, + "clauseIndex": 1, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandSubstitution", + "parentIndex": 1, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 4, + "sourceLength": 12, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 2, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 6, + "sourceLength": 9, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 6, + "sourceLength": 9, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Substitution", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 17 + }, + { + "ancestorKind": "CommandSubstitution", + "region": "Substitution", + "childIndex": 0, + "sourceStart": 4, + "sourceLength": 12 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 6, + "sourceLength": 9 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 17 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 1, + "value": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-simple-command-substitution into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/295_v03_design_multiple_command_substitutions.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/295_v03_design_multiple_command_substitutions.json new file mode 100644 index 0000000..7f96227 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/295_v03_design_multiple_command_substitutions.json @@ -0,0 +1,339 @@ +{ + "name": "v0.3 Bash design promotion: Multiple command substitutions", + "input": "printf '%s %s' \"$(first)\" \"$(second)\"", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "first" + ], + "args": [], + "redirects": [], + "elements": [ + { + "raw": "first", + "value": "first", + "role": "Verb", + "sourceStart": 18, + "sourceLength": 5, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "None", + "verb": [ + "second" + ], + "args": [], + "redirects": [], + "elements": [ + { + "raw": "second", + "value": "second", + "role": "Verb", + "sourceStart": 29, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "None", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s %s'", + "kind": "Literal", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + }, + { + "raw": "\"$(first)\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + }, + { + "raw": "\"$(second)\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s %s'", + "value": "%s %s", + "role": "Argument", + "sourceStart": 7, + "sourceLength": 7, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$(first)\"", + "value": "$(first)", + "role": "Argument", + "sourceStart": 15, + "sourceLength": 10, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$(second)\"", + "value": "$(second)", + "role": "Argument", + "sourceStart": 26, + "sourceLength": 11, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 37, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37, + "clauseIndex": 2, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandSubstitution", + "parentIndex": 1, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 16, + "sourceLength": 8, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 2, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 18, + "sourceLength": 5, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 18, + "sourceLength": 5, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandSubstitution", + "parentIndex": 1, + "region": "Substitution", + "childIndex": 1, + "sourceStart": 27, + "sourceLength": 9, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 5, + "region": "Substitution", + "childIndex": 1, + "sourceStart": 29, + "sourceLength": 6, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 6, + "region": "Statement", + "childIndex": 0, + "sourceStart": 29, + "sourceLength": 6, + "clauseIndex": 1, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Substitution", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37 + }, + { + "ancestorKind": "CommandSubstitution", + "region": "Substitution", + "childIndex": 0, + "sourceStart": 16, + "sourceLength": 8 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 18, + "sourceLength": 5 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "Substitution", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37 + }, + { + "ancestorKind": "CommandSubstitution", + "region": "Substitution", + "childIndex": 1, + "sourceStart": 27, + "sourceLength": 9 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 29, + "sourceLength": 6 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 2, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + } + }, + { + "clauseElementIndex": 3, + "value": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-multiple-command-substitutions into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/296_v03_design_backtick_substitution_gated.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/296_v03_design_backtick_substitution_gated.json new file mode 100644 index 0000000..961ed7e --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/296_v03_design_backtick_substitution_gated.json @@ -0,0 +1,9 @@ +{ + "name": "v0.3 Bash design promotion: Backtick substitution remains gated", + "input": "echo `whoami`", + "expected": { + "isUnparseable": true, + "unparseableReasonContains": "legacy backtick command substitution is not supported" + }, + "notes": "Promotes stable design case bash-backtick-substitution-gated into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/297_v03_design_command_name_substitution_gated.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/297_v03_design_command_name_substitution_gated.json new file mode 100644 index 0000000..9f01285 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/297_v03_design_command_name_substitution_gated.json @@ -0,0 +1,9 @@ +{ + "name": "v0.3 Bash design promotion: Dynamic command identity remains gated", + "input": "r$(printf m) file", + "expected": { + "isUnparseable": true, + "unparseableReasonContains": "Bash command-name substitution is not supported" + }, + "notes": "Promotes stable design case bash-command-name-substitution-gated into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/298_v03_design_command_substitution_isolated_cwd.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/298_v03_design_command_substitution_isolated_cwd.json new file mode 100644 index 0000000..90361df --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/298_v03_design_command_substitution_isolated_cwd.json @@ -0,0 +1,459 @@ +{ + "name": "v0.3 Bash design promotion: Substitution cwd isolation", + "input": "printf '%s' \"$(cd /tmp && pwd)\"; cat relative.txt", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "cd" + ], + "args": [ + { + "raw": "/tmp", + "kind": "Literal", + "isPath": true, + "resolved": "/tmp", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "cd", + "value": "cd", + "role": "Verb", + "sourceStart": 15, + "sourceLength": 2, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "/tmp", + "value": "/tmp", + "role": "Argument", + "sourceStart": 18, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/tmp" + } + ] + }, + { + "operator": "AndIf", + "verb": [ + "pwd" + ], + "args": [ + { + "raw": "/tmp", + "kind": "Literal", + "isPath": true, + "resolved": "/tmp", + "isFlag": false, + "isCwdAttribution": true + } + ], + "redirects": [], + "elements": [ + { + "raw": "pwd", + "value": "pwd", + "role": "Verb", + "sourceStart": 26, + "sourceLength": 3, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "None", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s'", + "kind": "Literal", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + }, + { + "raw": "\"$(cd /tmp && pwd)\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s'", + "value": "%s", + "role": "Argument", + "sourceStart": 7, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$(cd /tmp && pwd)\"", + "value": "$(cd /tmp && pwd)", + "role": "Argument", + "sourceStart": 12, + "sourceLength": 19, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "Sequence", + "verb": [ + "cat" + ], + "args": [ + { + "raw": "relative.txt", + "kind": "Literal", + "isPath": true, + "resolved": "/work/relative.txt", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "cat", + "value": "cat", + "role": "Verb", + "sourceStart": 33, + "sourceLength": 3, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "relative.txt", + "value": "relative.txt", + "role": "Argument", + "sourceStart": 37, + "sourceLength": 12, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/work/relative.txt" + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 49, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandList", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 1, + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 31, + "clauseIndex": 2, + "groupKind": null, + "listOperator": "None" + }, + { + "kind": "CommandSubstitution", + "parentIndex": 2, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 13, + "sourceLength": 17, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 3, + "region": "Substitution", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 14, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandList", + "parentIndex": 4, + "region": "Statement", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 14, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 5, + "region": "Statement", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 7, + "clauseIndex": 0, + "groupKind": null, + "listOperator": "None" + }, + { + "kind": "SimpleCommand", + "parentIndex": 5, + "region": "Statement", + "childIndex": 1, + "sourceStart": 26, + "sourceLength": 3, + "clauseIndex": 1, + "groupKind": null, + "listOperator": "AndIf" + }, + { + "kind": "SimpleCommand", + "parentIndex": 1, + "region": "Statement", + "childIndex": 1, + "sourceStart": 33, + "sourceLength": 16, + "clauseIndex": 3, + "groupKind": null, + "listOperator": "Sequence" + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Substitution", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandSubstitution", + "region": "Substitution", + "childIndex": 0, + "sourceStart": 13, + "sourceLength": 17 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 14 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 14 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "Substitution", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandSubstitution", + "region": "Substitution", + "childIndex": 0, + "sourceStart": 13, + "sourceLength": 17 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 15, + "sourceLength": 14 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 1, + "sourceStart": 15, + "sourceLength": 14 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/tmp" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 2, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 3, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 49 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 1, + "sourceStart": 0, + "sourceLength": 49 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-command-substitution-isolated-cwd into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/299_v03_design_cd_sequence_failure_join.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/299_v03_design_cd_sequence_failure_join.json new file mode 100644 index 0000000..438e2ae --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/299_v03_design_cd_sequence_failure_join.json @@ -0,0 +1,189 @@ +{ + "name": "v0.3 Bash design promotion: cd failure-state join", + "input": "cd /maybe; pwd", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "cd" + ], + "args": [ + { + "raw": "/maybe", + "kind": "Literal", + "isPath": true, + "resolved": "/maybe", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "cd", + "value": "cd", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 2, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "/maybe", + "value": "/maybe", + "role": "Argument", + "sourceStart": 3, + "sourceLength": 6, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/maybe" + } + ] + }, + { + "operator": "Sequence", + "verb": [ + "pwd" + ], + "args": [ + { + "raw": "", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false, + "isCwdAttribution": true + } + ], + "redirects": [], + "elements": [ + { + "raw": "pwd", + "value": "pwd", + "role": "Verb", + "sourceStart": 11, + "sourceLength": 3, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 14, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandList", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 14, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 1, + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 9, + "clauseIndex": 0, + "groupKind": null, + "listOperator": "None" + }, + { + "kind": "SimpleCommand", + "parentIndex": 1, + "region": "Statement", + "childIndex": 1, + "sourceStart": 11, + "sourceLength": 3, + "clauseIndex": 1, + "groupKind": null, + "listOperator": "Sequence" + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 14 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 14 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 14 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 1, + "sourceStart": 0, + "sourceLength": 14 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-cd-sequence-failure-join into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/300_v03_design_for_duplicate_order_final_binding.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/300_v03_design_for_duplicate_order_final_binding.json new file mode 100644 index 0000000..0007989 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/300_v03_design_for_duplicate_order_final_binding.json @@ -0,0 +1,265 @@ +{ + "name": "v0.3 Bash design promotion: Ordered loop final binding", + "input": "for f in a b a; do :; done; printf '%s' \"$f\"", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + ":" + ], + "args": [], + "redirects": [], + "elements": [ + { + "raw": ":", + "value": ":", + "role": "Verb", + "sourceStart": 19, + "sourceLength": 1, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "Sequence", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s'", + "kind": "Literal", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + }, + { + "raw": "\"$f\"", + "kind": "EnvVar", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 28, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s'", + "value": "%s", + "role": "Argument", + "sourceStart": 35, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$f\"", + "value": "$f", + "role": "Argument", + "sourceStart": 40, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "EnvVar", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 44, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "CommandList", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 44, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 1, + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 26, + "clauseIndex": null, + "groupKind": null, + "listOperator": "None", + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "a b a", + "iterableSourceStart": 9, + "iterableSourceLength": 5 + }, + { + "kind": "Block", + "parentIndex": 2, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 5, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 2, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 18, + "sourceLength": 4, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 4, + "region": "Statement", + "childIndex": 0, + "sourceStart": 19, + "sourceLength": 1, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 1, + "region": "Statement", + "childIndex": 1, + "sourceStart": 28, + "sourceLength": 16, + "clauseIndex": 1, + "groupKind": null, + "listOperator": "Sequence" + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "LoopBody", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 44 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 44 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 26 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 18, + "sourceLength": 4 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 44 + }, + { + "ancestorKind": "CommandList", + "region": "Statement", + "childIndex": 1, + "sourceStart": 0, + "sourceLength": 44 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "Exact", + "values": [ + "a" + ], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-for-duplicate-order-controls-final-binding into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/301_v03_design_for_native_option_injection.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/301_v03_design_for_native_option_injection.json new file mode 100644 index 0000000..ba7c86a --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/301_v03_design_for_native_option_injection.json @@ -0,0 +1,167 @@ +{ + "name": "v0.3 Bash design promotion: Loop option injection", + "input": "for f in -rf /tmp/x; do rm \"$f\"; done", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "rm" + ], + "args": [ + { + "raw": "\"$f\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "rm", + "value": "rm", + "role": "Verb", + "sourceStart": 24, + "sourceLength": 2, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$f\"", + "value": "$f", + "role": "Argument", + "sourceStart": 27, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 37, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "-rf /tmp/x", + "iterableSourceStart": 9, + "iterableSourceLength": 10 + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 10, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 23, + "sourceLength": 10, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 24, + "sourceLength": 7, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "LoopBody", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 37 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 37 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 23, + "sourceLength": 10 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 1, + "value": { + "kind": "FiniteSet", + "values": [ + "-rf", + "/tmp/x" + ], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-for-native-option-injection into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/302_v03_design_nested_for_cross_product.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/302_v03_design_nested_for_cross_product.json new file mode 100644 index 0000000..ac8eeca --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/302_v03_design_nested_for_cross_product.json @@ -0,0 +1,223 @@ +{ + "name": "v0.3 Bash design promotion: Nested loop cross product", + "input": "for d in a b; do for f in x y; do echo \"$d/$f\"; done; done", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "echo" + ], + "args": [ + { + "raw": "\"$d/$f\"", + "kind": "DynamicSkip", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "echo", + "value": "echo", + "role": "Verb", + "sourceStart": 34, + "sourceLength": 4, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "\"$d/$f\"", + "value": "$d/$f", + "role": "Argument", + "sourceStart": 39, + "sourceLength": 7, + "precedingVerbElementCount": 1, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 58, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 58, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "d", + "bindingRaw": "d", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "a b", + "iterableSourceStart": 9, + "iterableSourceLength": 3 + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 3, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 16, + "sourceLength": 38, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 17, + "sourceLength": 35, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 21, + "bindingSourceLength": 1, + "iterableRaw": "x y", + "iterableSourceStart": 26, + "iterableSourceLength": 3 + }, + { + "kind": "Block", + "parentIndex": 4, + "region": "Iterator", + "childIndex": null, + "sourceStart": 26, + "sourceLength": 3, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 4, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 33, + "sourceLength": 15, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 6, + "region": "Statement", + "childIndex": 0, + "sourceStart": 34, + "sourceLength": 12, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "LoopBody", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 58 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 58 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 16, + "sourceLength": 38 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 17, + "sourceLength": 35 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 33, + "sourceLength": 15 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 1, + "value": { + "kind": "FiniteSet", + "values": [ + "a/x", + "a/y", + "b/x", + "b/y" + ], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-nested-for-cross-product into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/303_v03_design_for_body_pipeline.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/303_v03_design_for_body_pipeline.json new file mode 100644 index 0000000..119ad2e --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/303_v03_design_for_body_pipeline.json @@ -0,0 +1,281 @@ +{ + "name": "v0.3 Bash design promotion: Loop body pipeline", + "input": "for f in a b; do printf '%s\\n' \"$f\" | sort; done", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s\\n'", + "kind": "Literal", + "isPath": true, + "resolved": "/work/%s/n", + "isFlag": false + }, + { + "raw": "\"$f\"", + "kind": "EnvVar", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 17, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s\\n'", + "value": "%s\\n", + "role": "Argument", + "sourceStart": 24, + "sourceLength": 6, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/work/%s/n" + }, + { + "raw": "\"$f\"", + "value": "$f", + "role": "Argument", + "sourceStart": 31, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "EnvVar", + "isFlag": false, + "isPath": false + } + ] + }, + { + "operator": "Pipe", + "verb": [ + "sort" + ], + "args": [], + "redirects": [], + "elements": [ + { + "raw": "sort", + "value": "sort", + "role": "Verb", + "sourceStart": 38, + "sourceLength": 4, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 48, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 48, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "a b", + "iterableSourceStart": 9, + "iterableSourceLength": 3 + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 3, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 16, + "sourceLength": 28, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Pipeline", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 17, + "sourceLength": 25, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 4, + "region": "PipelineStage", + "childIndex": 0, + "sourceStart": 17, + "sourceLength": 18, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 4, + "region": "PipelineStage", + "childIndex": 1, + "sourceStart": 38, + "sourceLength": 4, + "clauseIndex": 1, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "PipelineStage", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 48 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 48 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 16, + "sourceLength": 28 + }, + { + "ancestorKind": "Pipeline", + "region": "PipelineStage", + "childIndex": 0, + "sourceStart": 17, + "sourceLength": 25 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "FiniteSet", + "values": [ + "a", + "b" + ], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + }, + { + "clauseIndex": 1, + "immediateRole": "PipelineStage", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 48 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 48 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 16, + "sourceLength": 28 + }, + { + "ancestorKind": "Pipeline", + "region": "PipelineStage", + "childIndex": 1, + "sourceStart": 17, + "sourceLength": 25 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-for-body-pipeline into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/304_v03_design_malformed_for_missing_done.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/304_v03_design_malformed_for_missing_done.json new file mode 100644 index 0000000..7951527 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/304_v03_design_malformed_for_missing_done.json @@ -0,0 +1,9 @@ +{ + "name": "v0.3 Bash design promotion: Missing done fails closed", + "input": "for f in a b; do rm -- \"$f\"", + "expected": { + "isUnparseable": true, + "unparseableReasonContains": "Bash for-in loop is missing 'done'" + }, + "notes": "Promotes stable design case bash-malformed-for-missing-done into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/305_v03_design_for_candidate_cap_32.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/305_v03_design_for_candidate_cap_32.json new file mode 100644 index 0000000..f4429d2 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/305_v03_design_for_candidate_cap_32.json @@ -0,0 +1,216 @@ +{ + "name": "v0.3 Bash design promotion: Candidate cap", + "input": "for f in v01 v02 v03 v04 v05 v06 v07 v08 v09 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32; do printf '%s\\n' \"$f\"; done", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s\\n'", + "kind": "Literal", + "isPath": true, + "resolved": "/work/%s/n", + "isFlag": false + }, + { + "raw": "\"$f\"", + "kind": "EnvVar", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 141, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s\\n'", + "value": "%s\\n", + "role": "Argument", + "sourceStart": 148, + "sourceLength": 6, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/work/%s/n" + }, + { + "raw": "\"$f\"", + "value": "$f", + "role": "Argument", + "sourceStart": 155, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "EnvVar", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 165, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 165, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "v01 v02 v03 v04 v05 v06 v07 v08 v09 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32", + "iterableSourceStart": 9, + "iterableSourceLength": 127 + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 127, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 140, + "sourceLength": 21, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 141, + "sourceLength": 18, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "LoopBody", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 165 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 165 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 140, + "sourceLength": 21 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "FiniteSet", + "values": [ + "v01", + "v02", + "v03", + "v04", + "v05", + "v06", + "v07", + "v08", + "v09", + "v10", + "v11", + "v12", + "v13", + "v14", + "v15", + "v16", + "v17", + "v18", + "v19", + "v20", + "v21", + "v22", + "v23", + "v24", + "v25", + "v26", + "v27", + "v28", + "v29", + "v30", + "v31", + "v32" + ], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-for-candidate-cap-32 into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/306_v03_design_for_candidate_overflow_33.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/306_v03_design_for_candidate_overflow_33.json new file mode 100644 index 0000000..69034b8 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/306_v03_design_for_candidate_overflow_33.json @@ -0,0 +1,183 @@ +{ + "name": "v0.3 Bash design promotion: Candidate overflow", + "input": "for f in v01 v02 v03 v04 v05 v06 v07 v08 v09 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32 v33; do printf '%s\\n' \"$f\"; done", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "printf" + ], + "args": [ + { + "raw": "'%s\\n'", + "kind": "Literal", + "isPath": true, + "resolved": "/work/%s/n", + "isFlag": false + }, + { + "raw": "\"$f\"", + "kind": "EnvVar", + "isPath": false, + "resolved": "__NULL__", + "isFlag": false + } + ], + "redirects": [], + "elements": [ + { + "raw": "printf", + "value": "printf", + "role": "Verb", + "sourceStart": 145, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "'%s\\n'", + "value": "%s\\n", + "role": "Argument", + "sourceStart": 152, + "sourceLength": 6, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/work/%s/n" + }, + { + "raw": "\"$f\"", + "value": "$f", + "role": "Argument", + "sourceStart": 159, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "EnvVar", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 169, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "ForEach", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 169, + "clauseIndex": null, + "groupKind": null, + "listOperator": null, + "bindingName": "f", + "bindingRaw": "f", + "bindingSourceStart": 4, + "bindingSourceLength": 1, + "iterableRaw": "v01 v02 v03 v04 v05 v06 v07 v08 v09 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32 v33", + "iterableSourceStart": 9, + "iterableSourceLength": 131 + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "Iterator", + "childIndex": null, + "sourceStart": 9, + "sourceLength": 131, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "Block", + "parentIndex": 1, + "region": "LoopBody", + "childIndex": null, + "sourceStart": 144, + "sourceLength": 21, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 3, + "region": "Statement", + "childIndex": 0, + "sourceStart": 145, + "sourceLength": 18, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "LoopBody", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 169 + }, + { + "ancestorKind": "ForEach", + "region": "LoopBody", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 169 + }, + { + "ancestorKind": "Block", + "region": "Statement", + "childIndex": 0, + "sourceStart": 144, + "sourceLength": 21 + } + ], + "effectiveArguments": [ + { + "clauseElementIndex": 2, + "value": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + } + } + ], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [] + } + ] + }, + "notes": "Promotes stable design case bash-for-candidate-overflow-33 into the executable corpus with exact compatibility, syntax, occurrence, value, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/307_v03_design_static_fd_duplication.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/307_v03_design_static_fd_duplication.json new file mode 100644 index 0000000..5d0e5b7 --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/307_v03_design_static_fd_duplication.json @@ -0,0 +1,126 @@ +{ + "name": "v0.3 Bash design promotion: Static descriptor duplication", + "input": "dotnet test 2>&1", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "dotnet", + "test" + ], + "args": [], + "redirects": [ + { + "direction": "ErrOut", + "target": "&1", + "isDynamicSkip": true + } + ], + "elements": [ + { + "raw": "dotnet", + "value": "dotnet", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 6, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "test", + "value": "test", + "role": "Verb", + "sourceStart": 7, + "sourceLength": 4, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "2>&1", + "value": "&1", + "role": "Redirect", + "sourceStart": 12, + "sourceLength": 4, + "precedingVerbElementCount": 2, + "kind": "DynamicSkip", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 16, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 16, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 16 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [ + { + "redirectIndex": 0, + "sourceKind": "Descriptor", + "sourceDescriptor": 2, + "operation": "DescriptorDuplicate", + "targetDescriptor": 1, + "target": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + }, + "isPathRelevant": false, + "isComplete": true + } + ] + } + ] + }, + "notes": "Promotes stable design case bash-static-fd-duplication into the executable corpus with exact compatibility, syntax, occurrence, value, redirect, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/Corpus/bash/308_v03_design_heredoc_body_is_data.json b/tests/ShellSyntaxTree.Tests/Corpus/bash/308_v03_design_heredoc_body_is_data.json new file mode 100644 index 0000000..9b382ee --- /dev/null +++ b/tests/ShellSyntaxTree.Tests/Corpus/bash/308_v03_design_heredoc_body_is_data.json @@ -0,0 +1,163 @@ +{ + "name": "v0.3 Bash design promotion: Literal heredoc body is data", + "input": "cat > output.txt <<'EOF'\nhello\nEOF\n", + "expected": { + "isUnparseable": false, + "clauses": [ + { + "operator": "None", + "verb": [ + "cat" + ], + "args": [], + "redirects": [ + { + "direction": "Out", + "target": "/work/output.txt", + "isDynamicSkip": false + }, + { + "direction": "In", + "target": "<", + "isDynamicSkip": false + } + ], + "elements": [ + { + "raw": "cat", + "value": "cat", + "role": "Verb", + "sourceStart": 0, + "sourceLength": 3, + "precedingVerbElementCount": 0, + "kind": "Literal", + "isFlag": false, + "isPath": false + }, + { + "raw": "> output.txt", + "value": "output.txt", + "role": "Redirect", + "sourceStart": 4, + "sourceLength": 12, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": true, + "resolved": "/work/output.txt" + }, + { + "raw": "<<'EOF'", + "value": "EOF", + "role": "Redirect", + "sourceStart": 17, + "sourceLength": 7, + "precedingVerbElementCount": 1, + "kind": "Literal", + "isFlag": false, + "isPath": false + } + ] + } + ], + "syntax": [ + { + "kind": "Block", + "parentIndex": null, + "region": "Unknown", + "childIndex": null, + "sourceStart": 0, + "sourceLength": 35, + "clauseIndex": null, + "groupKind": null, + "listOperator": null + }, + { + "kind": "SimpleCommand", + "parentIndex": 0, + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 34, + "clauseIndex": 0, + "groupKind": null, + "listOperator": null + } + ], + "commands": [ + { + "clauseIndex": 0, + "immediateRole": "Ordinary", + "isComplete": true, + "ancestry": [ + { + "ancestorKind": "Block", + "region": "Root", + "childIndex": 0, + "sourceStart": 0, + "sourceLength": 35 + } + ], + "effectiveArguments": [], + "workingDirectory": { + "kind": "Exact", + "values": [ + "/work" + ], + "pattern": null, + "coveringDirectory": null + }, + "redirects": [ + { + "redirectIndex": 0, + "sourceKind": "Default", + "sourceDescriptor": null, + "operation": "FileOutput", + "targetDescriptor": null, + "target": { + "kind": "Exact", + "values": [ + "/work/output.txt" + ], + "pattern": null, + "coveringDirectory": null + }, + "isPathRelevant": true, + "isComplete": true + }, + { + "redirectIndex": 1, + "sourceKind": "Default", + "sourceDescriptor": null, + "operation": "HereDocument", + "targetDescriptor": null, + "target": { + "kind": "Unknown", + "values": [], + "pattern": null, + "coveringDirectory": null + }, + "hereDocument": { + "delimiter": { + "raw": "'EOF'", + "sourceStart": 19, + "sourceLength": 5 + }, + "body": { + "raw": "hello\n", + "sourceStart": 25, + "sourceLength": 6 + }, + "expansionMode": "Literal", + "stripLeadingTabs": false, + "isComplete": true + }, + "isPathRelevant": false, + "isComplete": true + } + ] + } + ] + }, + "notes": "Promotes stable design case bash-heredoc-body-is-data into the executable corpus with exact compatibility, syntax, occurrence, value, redirect, and completeness assertions." +} diff --git a/tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/bash.json b/tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/bash.json index cbcc3fd..204ceb0 100644 --- a/tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/bash.json +++ b/tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/bash.json @@ -741,6 +741,7 @@ { "id": "bash-static-fd-duplication", "concern": "Static descriptor operation is not dynamic input", + "compatibilityProjectionLanded": true, "input": "dotnet test 2>&1", "current": { "isUnparseable": false }, "desired": { @@ -853,6 +854,7 @@ { "id": "bash-heredoc-body-is-data", "concern": "Literal heredoc data does not create hidden commands or unnecessary approval scope", + "compatibilityProjectionLanded": true, "input": "cat > output.txt <<'EOF'\nhello\nEOF\n", "current": { "isUnparseable": false }, "desired": {