From fc706c8b691ca168aba9751487d92e0c82d801cd Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 19 Jun 2026 23:12:35 +0000 Subject: [PATCH] =?UTF-8?q?WIP:=20Bash=20dissolution=20slice=205d=20(Exit?= =?UTF-8?q?=20=E2=80=94=20LAST=20emit-vocab=20construct):=20migrate=20Sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manual/bash_emit_command_test.dag | 64 ++++++++- src/v2/extdeps/languages/bash.dag | 136 +++++++++++++++++- 2 files changed, 193 insertions(+), 7 deletions(-) diff --git a/src/v2/compiler/manual/bash_emit_command_test.dag b/src/v2/compiler/manual/bash_emit_command_test.dag index 5eb45056d35..18e735006ed 100644 --- a/src/v2/compiler/manual/bash_emit_command_test.dag +++ b/src/v2/compiler/manual/bash_emit_command_test.dag @@ -7,7 +7,8 @@ module v2.test.manual.bash_emit_command // Slice 4: AndOr / Pipe / WithRedir compound constructs. // Slice 5a: Conj-positional emitted + FormalProduction lhs-exact structural rows. // Slice 5b: If / Subshell / Heredoc + pipe|precedence brace-group keystone. -// Slice 5c: Assign / EnvPrefixed / CmdSubst + Concat (FINAL emit-vocab). +// Slice 5c: Assign / EnvPrefixed / CmdSubst + Concat. +// Slice 5d: Exit { code: Int } (LAST emit-vocab construct). // // Run: // gunbc run --source-root src/v2 \ @@ -79,7 +80,16 @@ import v2.extdeps.languages.bash { bash_assign_concat_gunbc_spaced_wrong_target_model, bash_env_prefixed_cargo_emitted, bash_env_prefixed_cargo_source_text, - bash_env_prefixed_cargo_target_model + bash_env_prefixed_cargo_target_model, + bash_exit_code_1_emitted, + bash_exit_code_1_source_text, + bash_exit_code_1_target_model, + bash_exit_code_0_emitted, + bash_exit_code_0_source_text, + bash_exit_code_0_target_model, + bash_exit_code_1_quoted_wrong_emitted, + bash_exit_code_1_quoted_wrong_source_text, + bash_exit_code_1_quoted_wrong_target_model } import v2.std.collection { Map, empty_map } import v2.std.host_transport { target_emit_host_runtime_row_unconfigured } @@ -481,3 +491,53 @@ test fn bash_emit_env_prefixed_cargo_holds() -> Bool { target: bash_env_prefixed_cargo_target_model() ) } + +// Slice 5d — Exit { code: Int } (LAST emit-vocab construct). + +// Exit { code: 1 } — host_prelude OrElse failure arm; byte-identical to serialize_bash. +test fn bash_emit_exit_code_1_holds() -> Bool { + bash_emit_slice4_holds( + emitted: bash_exit_code_1_emitted, + source_text: bash_exit_code_1_source_text, + target: bash_exit_code_1_target_model() + ) +} + +// Exit { code: 0 } — dsl_compile_clean_transport success terminator. +test fn bash_emit_exit_code_0_holds() -> Bool { + bash_emit_slice4_holds( + emitted: bash_exit_code_0_emitted, + source_text: bash_exit_code_0_source_text, + target: bash_exit_code_0_target_model() + ) +} + +// Discriminating — exit code is bare decimal, not single-quoted. +test fn bash_emit_exit_code_1_quoted_wrong_ne_correct_holds() -> Bool { + bash_exit_code_1_quoted_wrong_source_text != bash_exit_code_1_source_text +} + +test fn bash_emit_exit_code_1_quoted_wrong_model_holds() -> Bool { + bash_emit_slice4_holds( + emitted: bash_exit_code_1_quoted_wrong_emitted, + source_text: bash_exit_code_1_quoted_wrong_source_text, + target: bash_exit_code_1_quoted_wrong_target_model() + ) +} + +// RED — correct unquoted exit code through quoted-wrong model must not fabricate bare decimal. +fn bash_emit_exit_code_1_wrong_quoted_model_rejects() -> Bool { + let tree = InferredTree { + root: bash_exit_code_1_emitted, + facts: Map { lookup: bash_facts_lookup } + } + match emit(tree: tree, target: bash_exit_code_1_quoted_wrong_target_model()) { + Accepted { value: source, diagnostics: d } => + (source.carried != bash_exit_code_1_source_text) && (d == None) + Rejected { diagnostics: _ } => true + } +} + +test fn bash_emit_exit_code_1_wrong_quoted_model_rejects_holds() -> Bool { + bash_emit_exit_code_1_wrong_quoted_model_rejects() +} diff --git a/src/v2/extdeps/languages/bash.dag b/src/v2/extdeps/languages/bash.dag index ed2f63e7881..c8ae04bd6b7 100644 --- a/src/v2/extdeps/languages/bash.dag +++ b/src/v2/extdeps/languages/bash.dag @@ -31,9 +31,11 @@ // MIGRATION SLICE 5b — If / Subshell / Heredoc + pipe|precedence brace-group keystone // (`Pipe { AndOr left }` must emit `{ a && b; } | c`, not flat `a && b | c`). Subshell // nesting AndOr is a separate recursion fixture. Witnesses in bash_emit_command_test. -// MIGRATION SLICE 5c — Assign / EnvPrefixed / CmdSubst + Concat (FINAL emit-vocab before -// Exit). Byte-identical to serialize_bash for each fixture; witnesses in bash_emit_command_test. -// Next slices: Exit → migrate sidecar consumers → delete program.dag. +// MIGRATION SLICE 5c — Assign / EnvPrefixed / CmdSubst + Concat. Byte-identical to +// serialize_bash for each fixture; witnesses in bash_emit_command_test. +// MIGRATION SLICE 5d — Exit { code: Int } (LAST emit-vocab construct; host_prelude uses +// `Exit { code: 1 }` → `exit 1`). Byte-identical to serialize_bash; witnesses in +// bash_emit_command_test. Next slices: migrate sidecar consumers → delete program.dag. // // v2-clean (no std.render / std.unicode imports) so witnesses execute under the v1 interpreter. @@ -800,7 +802,7 @@ fn bash_pipe_and_or_flat_wrong_target_model() -> TargetModel { } // ========================================================================= -// Slice 5c — Assign / EnvPrefixed / CmdSubst + Concat (FINAL emit-vocab before Exit). +// Slice 5c — Assign / EnvPrefixed / CmdSubst + Concat. // Byte-identical to serialize_bash for each fixture. // Shared operator tokens: ^bash_token_assign_name (BoundToken + binding_spellings), // ^bash_token_assign_eq ("="), ^bash_token_cmdsubst_open ("$(") — one row per construct, @@ -1012,6 +1014,128 @@ fn bash_env_prefixed_cargo_target_model() -> TargetModel { ) } +// ========================================================================= +// Slice 5d — Exit { code: Int } (LAST emit-vocab construct). +// `Exit { code: 1 }` — host_prelude OrElse failure arm; `Exit { code: 0 }` — compile-clean +// success path. Byte-identical to serialize_bash(Exit { code: c }) => concat("exit ", to_string(c)). +// Shared operator token: ^bash_token_kw_exit ("exit ") — one row per construct, not per code (§2). +// ========================================================================= + +// Exit { code: 1 } — host_prelude `|| exit 1` failure arm. +fn bash_exit_code_1_concrete_tokens() -> List { + [ + FixedToken { token_class: ^bash_token_kw_exit }, + BoundToken { token_class: ^bash_token_exit_code, binding: ^bash_binding_exit_code_1 } + ] +} + +data bash_exit_code_1_emitted: Node = bash_conj_emitted_from_tokens( + tokens: bash_exit_code_1_concrete_tokens() +) + +data bash_exit_code_1_source_text: String = "exit 1" + +fn bash_exit_code_1_translation_rules_node() -> Node { + bash_relation_translation_rules_node( + rule_name: ^bash_relation_rule_exit_code_1, + lhs: ^bash_production_exit_code_1, + tokens: bash_exit_code_1_concrete_tokens(), + emitted: bash_exit_code_1_emitted + ) +} + +// Exit { code: 0 } — dsl_compile_clean_transport success terminator. +fn bash_exit_code_0_concrete_tokens() -> List { + [ + FixedToken { token_class: ^bash_token_kw_exit }, + BoundToken { token_class: ^bash_token_exit_code, binding: ^bash_binding_exit_code_0 } + ] +} + +data bash_exit_code_0_emitted: Node = bash_conj_emitted_from_tokens( + tokens: bash_exit_code_0_concrete_tokens() +) + +data bash_exit_code_0_source_text: String = "exit 0" + +fn bash_exit_code_0_translation_rules_node() -> Node { + bash_relation_translation_rules_node( + rule_name: ^bash_relation_rule_exit_code_0, + lhs: ^bash_production_exit_code_0, + tokens: bash_exit_code_0_concrete_tokens(), + emitted: bash_exit_code_0_emitted + ) +} + +// Discriminating — exit code is a bare decimal word, not a single-quoted lit. +fn bash_exit_code_1_quoted_wrong_concrete_tokens() -> List { + [ + FixedToken { token_class: ^bash_token_kw_exit }, + BoundToken { token_class: ^bash_token_lit, binding: ^bash_binding_exit_code_1 } + ] +} + +data bash_exit_code_1_quoted_wrong_emitted: Node = bash_conj_emitted_from_tokens( + tokens: bash_exit_code_1_quoted_wrong_concrete_tokens() +) + +data bash_exit_code_1_quoted_wrong_source_text: String = "exit '1'" + +fn bash_exit_code_1_quoted_wrong_translation_rules_node() -> Node { + bash_relation_translation_rules_node( + rule_name: ^bash_relation_rule_exit_code_1_quoted_wrong, + lhs: ^bash_production_exit_code_1_quoted_wrong, + tokens: bash_exit_code_1_quoted_wrong_concrete_tokens(), + emitted: bash_exit_code_1_quoted_wrong_emitted + ) +} + +fn bash_exit_code_lex() -> LexRules { + ModeledLexRules { + root: LexRuleSet { + rules: [ + bash_lex_rule(token_class: ^bash_token_kw_exit, text: "exit ") + ] + } + } +} + +fn bash_exit_code_1_target_model() -> TargetModel { + bash_make_bound_tokens_target_model( + rules: bash_exit_code_1_translation_rules_node(), + source_literal: ^bash_exit_code_1_source_literal, + production_name: ^bash_production_exit_code_1, + tokens: bash_exit_code_1_concrete_tokens(), + source_text: bash_exit_code_1_source_text, + lex: bash_exit_code_lex(), + binding_spellings: bash_binding_spellings() + ) +} + +fn bash_exit_code_0_target_model() -> TargetModel { + bash_make_bound_tokens_target_model( + rules: bash_exit_code_0_translation_rules_node(), + source_literal: ^bash_exit_code_0_source_literal, + production_name: ^bash_production_exit_code_0, + tokens: bash_exit_code_0_concrete_tokens(), + source_text: bash_exit_code_0_source_text, + lex: bash_exit_code_lex(), + binding_spellings: bash_binding_spellings() + ) +} + +fn bash_exit_code_1_quoted_wrong_target_model() -> TargetModel { + bash_make_bound_tokens_target_model( + rules: bash_exit_code_1_quoted_wrong_translation_rules_node(), + source_literal: ^bash_exit_code_1_quoted_wrong_source_literal, + production_name: ^bash_production_exit_code_1_quoted_wrong, + tokens: bash_exit_code_1_quoted_wrong_concrete_tokens(), + source_text: bash_exit_code_1_quoted_wrong_source_text, + lex: bash_exit_code_lex(), + binding_spellings: bash_binding_spellings() + ) +} + fn bash_binding_spellings() -> Map { let m0 = map_insert(empty_map(), ^bash_binding_var_ROOT, "ROOT") let m1 = map_insert(m0, ^bash_binding_lit_ROOT, "ROOT") @@ -1021,7 +1145,9 @@ fn bash_binding_spellings() -> Map { let m5 = map_insert(m4, ^bash_binding_var_GUNBC, "GUNBC") let m6 = map_insert(m5, ^bash_binding_var_CARGO_TARGET_DIR, "CARGO_TARGET_DIR") let m7 = map_insert(m6, ^bash_binding_lit_target_release_gunbc, "/target/release/gunbc") - map_insert(m7, ^bash_binding_lit_target, "/target") + let m8 = map_insert(m7, ^bash_binding_lit_target, "/target") + let m9 = map_insert(m8, ^bash_binding_exit_code_1, "1") + map_insert(m9, ^bash_binding_exit_code_0, "0") } // POSIX §2.2.2 — inside single quotes every character is literal; embedded `'` → `'\''`.