From bade3e6c46ad5d5d33946a20c444335851622e5b Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 11:22:27 -0400 Subject: [PATCH 1/8] CG: unify TLC-2 dual authority, mark transport/config complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SimpleMethodSpec co-locates template + wraps_result on one type (same pattern as HigherOrderMethodSpec). Both rust_method_templates() and rust_method_wraps_result() now derive from rust_simple_method_specs — single authority, no parallel maps. Transport/config centralization marked complete. Remaining per-backend rendering is inherent language differences addressed by 3→1 homomorphism. Flag Go op_children filter inconsistency (Rust/Python don't filter). Co-Authored-By: Claude Opus 4.6 (1M context) --- ROADMAP.md | 34 +++++++------ dsl/extdeps/languages/rust/emit.dag | 44 +++++++++++----- src/v2/05_emit_go.dag | 4 +- src/v2/05_emit_rust.dag | 7 ++- src/v2/languages.dag | 2 +- .../stage0/src/extdeps_languages_rust_emit.rs | 41 ++++++--------- src/v2/tests/src/source_audit.rs | 51 +++++++++++++++++++ 7 files changed, 124 insertions(+), 59 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0bce2112e7d..6b5aeb2b3b3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -269,14 +269,14 @@ correct-but-suboptimal code and blocks new backends. fuses Node → String in one pass, consuming coercion data directly. Clone semantics unified in SharingStrategy (CloneTemplates removed). TLC-1 complete: ExprVar → ExprCall normalization at inference time -(PR #329). TLC-3 done: all three backends dispatch per collection type -via `IndexingSemantics` templates. TLC-4 partial: -`emit_let_binding_annotated` infrastructure exists but disabled for -bootstrap convergence (.dag type inference produces `()` for empty -collection element types). TLC-2 partial: `wraps_result` on -`RuntimeFunction` registry but consumers still read parallel maps. -Higher-order method templates (filter/any/all/flat_map) data-driven -via `HigherOrderMethodSpec`. +(PR #329). TLC-2 complete: `SimpleMethodSpec` co-locates template + +wrapping flag, both maps derive from single authority. TLC-3 done: all +three backends dispatch per collection type via `IndexingSemantics` +templates. TLC-4 partial: `emit_let_binding_annotated` infrastructure +exists but disabled for bootstrap convergence (.dag type inference +produces `()` for empty collection element types). Higher-order method +templates (filter/any/all/flat_map) data-driven via +`HigherOrderMethodSpec`. One root cause, two symptoms: 1. Facts that exist upstream are lost before emit — emission compensates @@ -331,12 +331,14 @@ backends. ExprVar → ExprCall for zero-arg function references (PR #329). All three backends emit `name()` via existing ExprCall handling. `is_zero_arg_callable_ref` dissolved (L1 33→32). Imported zero-arg function refs untested. -- [~] **TLC-2: Runtime bridge signature derivation.** Runtime helper +- [x] **TLC-2: Runtime bridge signature derivation.** Runtime helper return types and wrapping conventions must derive from the same type/coercion authority as emission. `wraps_result` field added to `RuntimeFunction` registry (PR #331); `rt_wraps_result()` derives - from registry. Remaining: `rust_method_wraps_result` is a parallel - map for method templates — should unify into single spec authority. + from registry. `SimpleMethodSpec` type co-locates template + wrapping + flag for method templates (same pattern as `HigherOrderMethodSpec`). + Both `rust_method_templates()` and `rust_method_wraps_result()` now + derive from `rust_simple_method_specs` — single authority, no parallel maps. - [x] **TLC-3: Indexing / character access semantics.** `IndexingSemantics` in LanguageSpec — per-collection-type templates (list/map/string index/slice). All three backends dispatch per collection type via shared @@ -361,7 +363,7 @@ Make emission fully data-driven. Adding a backend = adding data. with `method_name`, `inline_template`, `fn_ref_template`, `wraps_in_sharing`. Shared `emit_rust_higher_order_method` replaces 4 hardcoded emitters (filter/any/all/flat_map). Data-driven dispatch via method name lookup. -- [~] Transport/config: `TransportKind` enum + `classify_transport()` centralize dispatch; `ServiceFieldSet` + `compute_service_fields()` centralize field queries. Remaining per-backend sites are inherent rendering differences. +- [x] Transport/config: `TransportKind` enum + `classify_transport()` centralize dispatch; `ServiceFieldSet` + `compute_service_fields()` centralize field queries. Remaining per-backend rendering is inherent language differences (HTTP clients, shell runners, file I/O) — addressed by the 3→1 homomorphism. - [ ] LanguageSpec completion — all target-language facts data-driven (see LS lane below) - [x] TypeRendering dissolved — `render_node_type` consumes coercion data directly (PR #331) - [ ] 3 backends → 1 parameterized homomorphism (~2,500 lines eliminated) @@ -385,10 +387,10 @@ Remaining parallel authorities: than Copy (excludes Unit; PR #333) - [x] Dead code: deleted `try_target_primitive_type`, `target_primitive_type`, `target_container_template`, `is_value_type`, `emit_primitive_type` + unused imports -- [~] Runtime bridge wrapping: `wraps_result` field on `RuntimeFunction` registry - (map_keys, map_values, append data-driven; method templates split/enumerate/chars/skip/take - use `rust_method_wraps_result` data map — consumer still reads parallel maps - instead of a single spec type) +- [x] Runtime bridge wrapping: `wraps_result` field on `RuntimeFunction` registry + (map_keys, map_values, append) and `SimpleMethodSpec.wraps_result` for method + templates (split/enumerate/chars/skip/take). Both derived maps come from their + respective single authorities — no parallel maps. ### Acceptance diff --git a/dsl/extdeps/languages/rust/emit.dag b/dsl/extdeps/languages/rust/emit.dag index ab610ab7671..4676082f1e4 100644 --- a/dsl/extdeps/languages/rust/emit.dag +++ b/dsl/extdeps/languages/rust/emit.dag @@ -48,20 +48,40 @@ data rust_container_templates: Map = { // Named-placeholder templates for simple algebra method calls. // Templates use {recv} (receiver) and {arg} (first argument). // Applied via apply_named_template in shared emit. -data rust_method_templates: Map = { - "count": "(\{recv\}.len() as i64)", - "join": "\{recv\}.join(&\{arg\})", - "split": "\{recv\}.split(&\{arg\}).map(|s| s.to_string()).collect::>()", - "last": "\{recv\}.last().cloned()", - "first": "\{recv\}.first().cloned()", - "enumerate": "\{recv\}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", - "chars": "\{recv\}.chars().map(|c| c as i64).collect::>()", - "skip": "\{recv\}.iter().cloned().skip(\{arg\} as usize).collect::>()", - "take": "\{recv\}.iter().cloned().take(\{arg\} as usize).collect::>()" +// +// Single authority: SimpleMethodSpec carries both the template and +// wraps_result flag. Derived maps feed LanguageSpec (template only) +// and Rust emitter (wrapping). Same pattern as HigherOrderMethodSpec. + +type SimpleMethodSpec { + method_name: String + template: String + wraps_result: Bool +} + +data rust_simple_method_specs: List = [ + { method_name: "count", template: "(\{recv\}.len() as i64)", wraps_result: false }, + { method_name: "join", template: "\{recv\}.join(&\{arg\})", wraps_result: false }, + { method_name: "split", template: "\{recv\}.split(&\{arg\}).map(|s| s.to_string()).collect::>()", wraps_result: true }, + { method_name: "last", template: "\{recv\}.last().cloned()", wraps_result: false }, + { method_name: "first", template: "\{recv\}.first().cloned()", wraps_result: false }, + { method_name: "enumerate", template: "\{recv\}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", wraps_result: true }, + { method_name: "chars", template: "\{recv\}.chars().map(|c| c as i64).collect::>()", wraps_result: true }, + { method_name: "skip", template: "\{recv\}.iter().cloned().skip(\{arg\} as usize).collect::>()", wraps_result: true }, + { method_name: "take", template: "\{recv\}.iter().cloned().take(\{arg\} as usize).collect::>()", wraps_result: true } +] + +// Derived: template map for LanguageSpec consumption (backend-neutral). +fn rust_method_templates() -> Map { + rust_simple_method_specs + |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, spec.template)) } -data rust_method_wraps_result: Map = { - "split": true, "enumerate": true, "chars": true, "skip": true, "take": true +// Derived: wraps_result map for Rust Rc-wrapping decisions. +fn rust_method_wraps_result() -> Map { + rust_simple_method_specs + |> filter(s => s.wraps_result) + |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, true)) } // -- Reserved words ------------------------------------------------------ diff --git a/src/v2/05_emit_go.dag b/src/v2/05_emit_go.dag index 16ecdae456d..f974e4f26db 100644 --- a/src/v2/05_emit_go.dag +++ b/src/v2/05_emit_go.dag @@ -1234,7 +1234,9 @@ fn emit_go_service_def( ) -> String { let safe_name = sanitize_service_name(name: authored_name(env: env, node: item)) let transport = service_fallback_transport(item: item) - // After dissolution, operation children are identified by having params + // BUG: Go filters op_children by having params, but Rust/Python use + // item.children unfiltered. This inconsistency should be aligned — + // either all backends filter or none do. let op_children = item.children |> filter(c => c.params |> count > 0) let struct_def = emit_go_service_struct(name: safe_name, fallback_transport: transport, op_children: op_children) let methods = op_children |> map(op_node => diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index c11ce507f26..efe701c7f93 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -1924,11 +1924,10 @@ fn rust_empty_map_value_type_str(map_type: Node, shared_types: Map // for non-Copy types. lookup/map_get return the correct type directly. fn rust_runtime_bridge_wraps_collection_result_in_rc(function_name: String) -> Bool { - // Two authorities: rt_wraps_result() derived from RuntimeFunction.wraps_result, - // rust_method_wraps_result for method templates. Each authority derives from - // its own structural source. + // Two derived maps, single authority each: RuntimeFunction.wraps_result + // for runtime functions, SimpleMethodSpec.wraps_result for method templates. map_contains_key(rt_wraps_result(), function_name) - || map_contains_key(rust_method_wraps_result, function_name) + || map_contains_key(rust_method_wraps_result(), function_name) } fn rust_runtime_bridge_collection_result_needs_rc_elements(function_name: String, result_type: InferredNode?) -> Bool { diff --git a/src/v2/languages.dag b/src/v2/languages.dag index 567b5b86e34..5f65041c9a5 100644 --- a/src/v2/languages.dag +++ b/src/v2/languages.dag @@ -231,7 +231,7 @@ fn rust_spec() -> LanguageSpec { lambda_param_typed: "{0}: {1}", lambda_param_untyped: "{0}" }, - method_templates: rust_method_templates, + method_templates: rust_method_templates(), service_fields: ServiceFieldTemplates { rest_decl: " pub base_url: String,\n", auth_decl: " pub auth_token: String,\n", diff --git a/src/v2/stage0/src/extdeps_languages_rust_emit.rs b/src/v2/stage0/src/extdeps_languages_rust_emit.rs index 7445b61c90b..8543ba85ca4 100644 --- a/src/v2/stage0/src/extdeps_languages_rust_emit.rs +++ b/src/v2/stage0/src/extdeps_languages_rust_emit.rs @@ -101,38 +101,29 @@ pub fn rust_container_templates() -> Rc> { CACHED.with(|c| c.clone()) } -pub fn rust_method_templates() -> Rc> { +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct SimpleMethodSpec { + pub method_name: String, + pub template: String, + pub wraps_result: bool, +} + +pub fn rust_simple_method_specs() -> Rc>> { thread_local! { - static CACHED: Rc> = { - let mut __m = HashMap::new(); - __m.insert("count".to_string(), "({recv}.len() as i64)".to_string()); - __m.insert("join".to_string(), "{recv}.join(&{arg})".to_string()); - __m.insert("split".to_string(), "{recv}.split(&{arg}).map(|s| s.to_string()).collect::>()".to_string()); - __m.insert("last".to_string(), "{recv}.last().cloned()".to_string()); - __m.insert("first".to_string(), "{recv}.first().cloned()".to_string()); - __m.insert("enumerate".to_string(), "{recv}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()".to_string()); - __m.insert("chars".to_string(), "{recv}.chars().map(|c| c as i64).collect::>()".to_string()); - __m.insert("skip".to_string(), "{recv}.iter().cloned().skip({arg} as usize).collect::>()".to_string()); - __m.insert("take".to_string(), "{recv}.iter().cloned().take({arg} as usize).collect::>()".to_string()); - Rc::new(__m) + static CACHED: Rc>> = { + serde_json::from_value(serde_json::json!([{"method_name": "count", "template": "({recv}.len() as i64)", "wraps_result": false}, {"method_name": "join", "template": "{recv}.join(&{arg})", "wraps_result": false}, {"method_name": "split", "template": "{recv}.split(&{arg}).map(|s| s.to_string()).collect::>()", "wraps_result": true}, {"method_name": "last", "template": "{recv}.last().cloned()", "wraps_result": false}, {"method_name": "first", "template": "{recv}.first().cloned()", "wraps_result": false}, {"method_name": "enumerate", "template": "{recv}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", "wraps_result": true}, {"method_name": "chars", "template": "{recv}.chars().map(|c| c as i64).collect::>()", "wraps_result": true}, {"method_name": "skip", "template": "{recv}.iter().cloned().skip({arg} as usize).collect::>()", "wraps_result": true}, {"method_name": "take", "template": "{recv}.iter().cloned().take({arg} as usize).collect::>()", "wraps_result": true}])) + .expect("valid data definition") }; } CACHED.with(|c| c.clone()) } +pub fn rust_method_templates() -> Rc> { + rust_simple_method_specs().iter().cloned().fold(v2_rt::rc_empty_map::(), |acc: Rc>, spec: Rc| v2_rt::rc_map_insert(acc.clone(), spec.method_name.clone(), spec.template.clone())) +} + pub fn rust_method_wraps_result() -> Rc> { - thread_local! { - static CACHED: Rc> = { - let mut __m = HashMap::new(); - __m.insert("split".to_string(), true); - __m.insert("enumerate".to_string(), true); - __m.insert("chars".to_string(), true); - __m.insert("skip".to_string(), true); - __m.insert("take".to_string(), true); - Rc::new(__m) - }; - } - CACHED.with(|c| c.clone()) + Rc::new({ let mut __result = Vec::new(); for s in rust_simple_method_specs().iter().cloned() { if s.wraps_result.clone() { __result.push(s); } } __result }).iter().cloned().fold(v2_rt::rc_empty_map::(), |acc: Rc>, spec: Rc| v2_rt::rc_map_insert(acc.clone(), spec.method_name.clone(), true)) } pub fn rust_reserved() -> Rc> { diff --git a/src/v2/tests/src/source_audit.rs b/src/v2/tests/src/source_audit.rs index 83d37440bf2..6fd51eae132 100644 --- a/src/v2/tests/src/source_audit.rs +++ b/src/v2/tests/src/source_audit.rs @@ -960,6 +960,57 @@ fn rt_wraps_result_derived_from_registry() { } } +#[test] +fn method_wraps_result_derived_from_specs() { + // rust_method_wraps_result() is derived from SimpleMethodSpec.wraps_result via fold. + // Verify exact parity: every spec entry with wraps_result: true appears, + // and no extra entries exist. + use v2_compiler::extdeps_languages_rust_emit::{rust_simple_method_specs, rust_method_wraps_result}; + + let specs = rust_simple_method_specs(); + let wraps_map = rust_method_wraps_result(); + + let spec_wraps: Vec = specs.iter() + .filter(|s| s.wraps_result) + .map(|s| s.method_name.clone()) + .collect(); + + assert!(!spec_wraps.is_empty(), "specs should have wraps_result entries"); + + // Every spec wraps_result: true must appear in derived map + for name in &spec_wraps { + assert!(wraps_map.contains_key(name), + "SimpleMethodSpec '{}' has wraps_result: true but missing from rust_method_wraps_result()", name); + } + + // No extra entries in derived map + for (name, _) in wraps_map.iter() { + assert!(spec_wraps.contains(name), + "rust_method_wraps_result() contains '{}' but no matching spec entry with wraps_result: true", name); + } +} + +#[test] +fn method_templates_derived_from_specs() { + // rust_method_templates() is derived from SimpleMethodSpec list. + // Verify exact parity: every spec entry appears in template map. + use v2_compiler::extdeps_languages_rust_emit::{rust_simple_method_specs, rust_method_templates}; + + let specs = rust_simple_method_specs(); + let templates = rust_method_templates(); + + assert_eq!(specs.len(), templates.len(), + "spec count ({}) != template map count ({})", specs.len(), templates.len()); + + for spec in specs.iter() { + match templates.get(&spec.method_name) { + Some(tmpl) => assert_eq!(*tmpl, spec.template, + "template mismatch for '{}': spec='{}', map='{}'", spec.method_name, spec.template, tmpl), + None => panic!("SimpleMethodSpec '{}' missing from rust_method_templates()", spec.method_name), + } + } +} + #[test] fn is_copy_checkpoint_parity() { // Derive all assertions from rust_type_checkpoints — single authority. From 2501f367619f9fe7cdfe4860b57f8bff643decb6 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 11:47:47 -0400 Subject: [PATCH 2/8] =?UTF-8?q?CG-3:=20Phase=201=20=E2=80=94=20shared=20ex?= =?UTF-8?q?pression=20wrappers=20for=20Go=20+=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 30 redundant ExprData-matching wrapper functions (15 per backend) with thin delegates that call shared helpers or typed handlers directly via accessor functions. New shared helpers in 05_emit.dag: - emit_expr_var_shared: target-parameterized var emission - emit_expr_field_access_shared: service-receiver check + delegate - extract_string_interp_parts: StringPart extraction from children New accessors in 00_core.dag: - expr_field_access_summary: extract FieldSummary from ExprFieldAccess - expr_method_call_semantics: extract MethodSemantics from ExprMethodCall Net: 159 lines removed from .dag source (-237/+78), 371 lines removed from stage0 (-532/+161). No Rust emission changes (bootstrap safe). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/v2/00_core.dag | 6 + src/v2/05_emit.dag | 38 ++++ src/v2/05_emit_go.dag | 140 ++------------- src/v2/05_emit_python.dag | 131 ++------------ src/v2/stage0/src/v2_compiler_emit.rs | 37 ++++ src/v2/stage0/src/v2_compiler_emit_go.rs | 177 ++----------------- src/v2/stage0/src/v2_compiler_emit_python.rs | 150 ++-------------- src/v2/stage0/src/v2_std_core.rs | 14 ++ 8 files changed, 161 insertions(+), 532 deletions(-) diff --git a/src/v2/00_core.dag b/src/v2/00_core.dag index 82b3a27655e..b1b772769ea 100644 --- a/src/v2/00_core.dag +++ b/src/v2/00_core.dag @@ -982,6 +982,9 @@ fn expr_var_name_at(texpr: Node, source_index: NewlineIndex?) -> String { author fn field_access_base(texpr: Node) -> Node { expr_child_at(texpr: texpr, index: 0, role: "field access base") } fn field_access_field(texpr: Node) -> String { texpr.name } fn field_access_field_at(texpr: Node, source_index: NewlineIndex?) -> String { authored_name_at(source_index: source_index, node: texpr) } +fn expr_field_access_summary(texpr: Node) -> FieldSummary? { + match texpr.expr_data { ExprFieldAccess { summary: s } => s _ => none } +} // -- ExprCall (D3: func dissolved into Node.name) -- fn expr_call_func(texpr: Node) -> String { texpr.name } @@ -992,6 +995,9 @@ fn method_receiver(texpr: Node) -> Node { expr_child_at(texpr: texpr, index: 0, fn method_arg_nodes(texpr: Node) -> List { texpr.children |> skip(1) } fn expr_method_name(texpr: Node) -> String { texpr.name } fn expr_method_name_at(texpr: Node, source_index: NewlineIndex?) -> String { authored_name_at(source_index: source_index, node: texpr) } +fn expr_method_call_semantics(texpr: Node) -> MethodSemantics? { + match texpr.expr_data { ExprMethodCall { method_semantics: ms } => ms _ => none } +} // -- ExprLambda (D3: params dissolved into child Nodes after body) -- fn lambda_body(texpr: Node) -> Node { expr_child_at(texpr: texpr, index: 0, role: "lambda body") } diff --git a/src/v2/05_emit.dag b/src/v2/05_emit.dag index 35f705b165d..73bc906bc8c 100644 --- a/src/v2/05_emit.dag +++ b/src/v2/05_emit.dag @@ -1664,6 +1664,44 @@ fn emit_null_coalesce(l_str: String, r_str: String, target: RenderTarget) -> Str } +// ========================================================================= +// Shared expression handler helpers (CG-3: 3→1 homomorphism) +// +// These replace duplicated per-backend wrapper functions. Since +// emit_shared_expr already dispatches on ExprData, wrapper functions +// that re-match are redundant. Backends inline child extraction into +// closures; these helpers share non-trivial logic. +// ========================================================================= + +// Shared ExprVar emission — target-parameterized, no backend-specific logic. +fn emit_expr_var_shared(expr: Node, target: RenderTarget, source_index: NewlineIndex?) -> String { + let n = expr_var_name_at(texpr: expr, source_index: source_index) + if n == "none" { emit_keyword(key: "null", target: target) } + else if n == "true" || n == "false" { emit_keyword(key: n, target: target) } + else { emit_ident(name: n, target: target) } +} + +// Shared ExprFieldAccess service-receiver check. Delegates to emit_field +// for the backend-specific field access rendering. +fn emit_expr_field_access_shared(expr: Node, target: RenderTarget, emit_field: fn(Node) -> String) -> String { + if is_typed_service_call_receiver(receiver: expr) { + match extract_typed_service_name(receiver: expr) { + Some { value: svc_name } => service_var_name(service_name: svc_name) + None => emit_field(expr) + } + } else { + emit_field(expr) + } +} + +// Extract StringPart list from ExprStringInterp children. +fn extract_string_interp_parts(expr: Node) -> List { + expr.children |> map(child => match child.expr_data { + ExprLiteral { value: LitStr { value: text } } => Text { value: text } + _ => Interpolation { expr: arg_value(n: child) } + }) +} + // ========================================================================= // emit_shared_expr — full shared ExprData dispatcher (P4.2 step 5) // diff --git a/src/v2/05_emit_go.dag b/src/v2/05_emit_go.dag index f974e4f26db..a3adcd20f6f 100644 --- a/src/v2/05_emit_go.dag +++ b/src/v2/05_emit_go.dag @@ -54,7 +54,7 @@ import v2.std.core { if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, - field_access_base, method_receiver, + field_access_base, method_receiver, expr_field_access_summary, expr_method_call_semantics, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, @@ -117,7 +117,8 @@ import v2.compiler.emit { service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, RestKind, ShellKind, FileKind, LocalKind, classify_transport, - seed_bindings + seed_bindings, + emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts } // ========================================================================= // Go language facts -- from std.languages spec (go_language, go_literals) @@ -592,166 +593,59 @@ fn emit_go_field_access(base: Node, field: String, summary: FieldSummary?, regis } fn emit_go_expr_var(expr: Node, depth: Int, source_index: NewlineIndex?) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprVar { binding_kind: _ } => - let n = expr_var_name_at(texpr: expr, source_index: source_index) - if n == "none" { concat(prefix, emit_keyword(key: "null", target: Go)) } - else if n == "true" || n == "false" { concat(prefix, emit_keyword(key: n, target: Go)) } - else { - concat(prefix, emit_ident(name: n, target: Go)) - } - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_var expected ExprVar", target: Go)) - } + concat(make_indent(level: depth), emit_expr_var_shared(expr: expr, target: Go, source_index: source_index)) } fn emit_go_expr_field_access(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprFieldAccess { summary: summary } => - let f = expr.name - let b = field_access_base(texpr: expr) - if is_typed_service_call_receiver(receiver: expr) { - match extract_typed_service_name(receiver: expr) { - Some { value: svc_name } => concat(prefix, service_var_name(service_name: svc_name)) - None => concat(prefix, emit_go_field_access(base: b, field: f, summary: summary, registry: registry, scope: scope)) - } - } else { - concat(prefix, emit_go_field_access(base: b, field: f, summary: summary, registry: registry, scope: scope)) - } - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_field_access expected ExprFieldAccess", target: Go)) - } + concat(make_indent(level: depth), emit_expr_field_access_shared(expr: expr, target: Go, emit_field: e => emit_go_field_access(base: field_access_base(texpr: e), field: e.name, summary: expr_field_access_summary(texpr: e), registry: registry, scope: scope))) } fn emit_go_expr_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprCall { call_semantics: _ } => - let f = expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index) - concat(prefix, emit_go_typed_call(func: f, args: expr.children, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_call expected ExprCall", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_call(func: expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index), args: expr.children, registry: registry, scope: scope)) } fn emit_go_expr_method_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprMethodCall { method_semantics: method_semantics } => - let r = method_receiver(texpr: expr) - let a = method_arg_nodes(texpr: expr) - let m = expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index) - concat(prefix, emit_go_typed_method_call(receiver: r, method: m, args: a, method_semantics: method_semantics, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_method_call expected ExprMethodCall", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_method_call(receiver: method_receiver(texpr: expr), method: expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index), args: method_arg_nodes(texpr: expr), method_semantics: expr_method_call_semantics(texpr: expr), registry: registry, scope: scope)) } fn emit_go_expr_match(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprMatch => - let s = match_scrutinee(texpr: expr) - let arm_list = match_arm_nodes(texpr: expr) - emit_go_typed_match(scrutinee: s, arms: arm_list, registry: registry, scope: scope, depth: depth) - _ => concat(make_indent(level: depth), emit_error_expr(message: "emit_go_expr_match expected ExprMatch", target: Go)) - } + emit_go_typed_match(scrutinee: match_scrutinee(texpr: expr), arms: match_arm_nodes(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_if(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprIf => - let c = if_condition(texpr: expr) - let t = if_then_branch(texpr: expr) - let e = if_else_branch(texpr: expr) - emit_go_typed_if(condition: c, then_branch: t, else_branch: e, registry: registry, scope: scope, depth: depth) - _ => concat(make_indent(level: depth), emit_error_expr(message: "emit_go_expr_if expected ExprIf", target: Go)) - } + emit_go_typed_if(condition: if_condition(texpr: expr), then_branch: if_then_branch(texpr: expr), else_branch: if_else_branch(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_let(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprLet => - let n = let_binding_name_at(texpr: expr, source_index: scope.type_env.source_index) - let v = let_value(texpr: expr) - let bd = let_body(texpr: expr) - emit_go_typed_let(name: n, value: v, body: bd, registry: registry, scope: scope, depth: depth) - _ => concat(make_indent(level: depth), emit_error_expr(message: "emit_go_expr_let expected ExprLet", target: Go)) - } + emit_go_typed_let(name: let_binding_name_at(texpr: expr, source_index: scope.type_env.source_index), value: let_value(texpr: expr), body: let_body(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_record_lit(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprRecordLit { parent_enum: _ } => - let tn = record_lit_type_name(texpr: expr) - let fs = expr.children - concat(prefix, emit_go_typed_record_lit(type_name: tn, fields: fs, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_record_lit expected ExprRecordLit", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_record_lit(type_name: record_lit_type_name(texpr: expr), fields: expr.children, registry: registry, scope: scope)) } fn emit_go_expr_string_interp(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprStringInterp => - let ps = expr.children |> map(child => match child.expr_data { - ExprLiteral { value: LitStr { value: text } } => Text { value: text } - _ => Interpolation { expr: arg_value(n: child) } - }) - concat(prefix, emit_go_typed_string_interp(parts: ps, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_string_interp expected ExprStringInterp", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_string_interp(parts: extract_string_interp_parts(expr: expr), registry: registry, scope: scope)) } fn emit_go_expr_block(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprBlock => - emit_go_typed_block(stmts: expr.children, registry: registry, scope: scope, depth: depth) - _ => concat(make_indent(level: depth), emit_error_expr(message: "emit_go_expr_block expected ExprBlock", target: Go)) - } + emit_go_typed_block(stmts: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_go_expr_cast(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprCast => - let e = cast_expr(texpr: expr) - let t = cast_target(texpr: expr) - concat(prefix, emit_go_typed_cast(expr: e, target: t, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_cast expected ExprCast", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_cast(expr: cast_expr(texpr: expr), target: cast_target(texpr: expr), registry: registry, scope: scope)) } fn emit_go_expr_for_each(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprForEach => - let v = foreach_variable(texpr: expr) - let c = foreach_collection(texpr: expr) - let bd = foreach_body(texpr: expr) - emit_go_typed_for_each(variable: v, collection: c, body: bd, registry: registry, scope: scope, depth: depth) - _ => concat(make_indent(level: depth), emit_error_expr(message: "emit_go_expr_for_each expected ExprForEach", target: Go)) - } + emit_go_typed_for_each(variable: foreach_variable(texpr: expr), collection: foreach_collection(texpr: expr), body: foreach_body(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_index(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprIndex => - let b = index_base(texpr: expr) - let i = index_expr(texpr: expr) - concat(prefix, emit_go_typed_index(base: b, index: i, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_index expected ExprIndex", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_index(base: index_base(texpr: expr), index: index_expr(texpr: expr), registry: registry, scope: scope)) } fn emit_go_expr_slice(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - match expr.expr_data { - ExprSlice => - let b = slice_base(texpr: expr) - let s = slice_start(texpr: expr) - let e = slice_end(texpr: expr) - concat(prefix, emit_go_typed_slice(base: b, start: s, end: e, registry: registry, scope: scope)) - _ => concat(prefix, emit_error_expr(message: "emit_go_expr_slice expected ExprSlice", target: Go)) - } + concat(make_indent(level: depth), emit_go_typed_slice(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), registry: registry, scope: scope)) } fn emit_go_typed_expr(texpr: Node, registry: Map, scope: InferScope, depth: Int, fuel: Int) -> String { diff --git a/src/v2/05_emit_python.dag b/src/v2/05_emit_python.dag index 9508852f015..4577ab38b00 100644 --- a/src/v2/05_emit_python.dag +++ b/src/v2/05_emit_python.dag @@ -44,7 +44,7 @@ import v2.std.core { if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, - field_access_base, method_receiver, + field_access_base, method_receiver, expr_field_access_summary, expr_method_call_semantics, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, @@ -107,7 +107,8 @@ import v2.compiler.emit { service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, RestKind, ShellKind, FileKind, LocalKind, classify_transport, - seed_bindings + seed_bindings, + emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts } // ========================================================================= @@ -574,157 +575,59 @@ fn emit_py_field_access(base: Node, field: String, summary: FieldSummary?, regis } fn emit_py_expr_var(expr: Node, source_index: NewlineIndex?) -> String { - match expr.expr_data { - ExprVar { binding_kind: _ } => - let n = expr_var_name_at(texpr: expr, source_index: source_index) - if n == "none" { emit_keyword(key: "null", target: Python) } - else if n == "true" || n == "false" { emit_keyword(key: n, target: Python) } - else { - emit_ident(name: n, target: Python) - } - _ => emit_error_expr(message: "emit_py_expr_var expected ExprVar", target: Python) - } + emit_expr_var_shared(expr: expr, target: Python, source_index: source_index) } fn emit_py_expr_field_access(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprFieldAccess { summary: summary } => - let f = expr.name - let b = field_access_base(texpr: expr) - if is_typed_service_call_receiver(receiver: expr) { - match extract_typed_service_name(receiver: expr) { - Some { value: svc_name } => service_var_name(service_name: svc_name) - None => emit_py_field_access(base: b, field: f, summary: summary, registry: registry, scope: scope, depth: depth) - } - } else { - emit_py_field_access(base: b, field: f, summary: summary, registry: registry, scope: scope, depth: depth) - } - _ => emit_error_expr(message: "emit_py_expr_field_access expected ExprFieldAccess", target: Python) - } + emit_expr_field_access_shared(expr: expr, target: Python, emit_field: e => emit_py_field_access(base: field_access_base(texpr: e), field: e.name, summary: expr_field_access_summary(texpr: e), registry: registry, scope: scope, depth: depth)) } fn emit_py_expr_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprCall { call_semantics: _ } => - let f = expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index) - emit_py_typed_call(func: f, args: expr.children, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_call expected ExprCall", target: Python) - } + emit_py_typed_call(func: expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index), args: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_py_expr_method_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprMethodCall { method_semantics: method_semantics } => - let r = method_receiver(texpr: expr) - let a = method_arg_nodes(texpr: expr) - let m = expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index) - emit_py_typed_method_call(receiver: r, method: m, args: a, method_semantics: method_semantics, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_method_call expected ExprMethodCall", target: Python) - } + emit_py_typed_method_call(receiver: method_receiver(texpr: expr), method: expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index), args: method_arg_nodes(texpr: expr), method_semantics: expr_method_call_semantics(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_match(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprMatch => - let s = match_scrutinee(texpr: expr) - let arm_list = match_arm_nodes(texpr: expr) - emit_py_typed_match(scrutinee: s, arms: arm_list, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_match expected ExprMatch", target: Python) - } + emit_py_typed_match(scrutinee: match_scrutinee(texpr: expr), arms: match_arm_nodes(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_if(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprIf => - let c = if_condition(texpr: expr) - let t = if_then_branch(texpr: expr) - let e = if_else_branch(texpr: expr) - emit_py_typed_if(condition: c, then_branch: t, else_branch: e, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_if expected ExprIf", target: Python) - } + emit_py_typed_if(condition: if_condition(texpr: expr), then_branch: if_then_branch(texpr: expr), else_branch: if_else_branch(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_let(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprLet => - let n = let_binding_name_at(texpr: expr, source_index: scope.type_env.source_index) - let v = let_value(texpr: expr) - let bd = let_body(texpr: expr) - emit_py_typed_let(name: n, value: v, body: bd, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_let expected ExprLet", target: Python) - } + emit_py_typed_let(name: let_binding_name_at(texpr: expr, source_index: scope.type_env.source_index), value: let_value(texpr: expr), body: let_body(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_record_lit(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprRecordLit { parent_enum: _ } => - let tn = record_lit_type_name(texpr: expr) - let fs = expr.children - emit_py_typed_record_lit(type_name: tn, fields: fs, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_record_lit expected ExprRecordLit", target: Python) - } + emit_py_typed_record_lit(type_name: record_lit_type_name(texpr: expr), fields: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_py_expr_string_interp(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprStringInterp => - let ps = expr.children |> map(child => match child.expr_data { - ExprLiteral { value: LitStr { value: text } } => Text { value: text } - _ => Interpolation { expr: arg_value(n: child) } - }) - emit_py_typed_string_interp(parts: ps, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_string_interp expected ExprStringInterp", target: Python) - } + emit_py_typed_string_interp(parts: extract_string_interp_parts(expr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_block(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprBlock => - emit_py_typed_block(stmts: expr.children, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_block expected ExprBlock", target: Python) - } + emit_py_typed_block(stmts: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_py_expr_cast(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprCast => - let e = cast_expr(texpr: expr) - let t = cast_target(texpr: expr) - emit_py_typed_cast(expr: e, target: t, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_cast expected ExprCast", target: Python) - } + emit_py_typed_cast(expr: cast_expr(texpr: expr), target: cast_target(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_for_each(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprForEach => - let v = foreach_variable(texpr: expr) - let c = foreach_collection(texpr: expr) - let bd = foreach_body(texpr: expr) - emit_py_typed_for_each(variable: v, collection: c, body: bd, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_for_each expected ExprForEach", target: Python) - } + emit_py_typed_for_each(variable: foreach_variable(texpr: expr), collection: foreach_collection(texpr: expr), body: foreach_body(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_index(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprIndex => - let b = index_base(texpr: expr) - let i = index_expr(texpr: expr) - emit_py_typed_index(base: b, index: i, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_index expected ExprIndex", target: Python) - } + emit_py_typed_index(base: index_base(texpr: expr), index: index_expr(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_expr_slice(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - match expr.expr_data { - ExprSlice => - let b = slice_base(texpr: expr) - let s = slice_start(texpr: expr) - let e = slice_end(texpr: expr) - emit_py_typed_slice(base: b, start: s, end: e, registry: registry, scope: scope, depth: depth) - _ => emit_error_expr(message: "emit_py_expr_slice expected ExprSlice", target: Python) - } + emit_py_typed_slice(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_py_typed_expr(texpr: Node, registry: Map, scope: InferScope, depth: Int, fuel: Int) -> String { diff --git a/src/v2/stage0/src/v2_compiler_emit.rs b/src/v2/stage0/src/v2_compiler_emit.rs index 5a89ebbe841..5329a842e34 100644 --- a/src/v2/stage0/src/v2_compiler_emit.rs +++ b/src/v2/stage0/src/v2_compiler_emit.rs @@ -1760,6 +1760,43 @@ pub fn emit_null_coalesce(l_str: String, r_str: String, target: RenderTarget) -> } } +pub fn emit_expr_var_shared(expr: Rc, target: RenderTarget, source_index: Option>) -> String { + { + let n = expr_var_name_at(expr, source_index); +if (n.clone().as_str() == "none".to_string().as_str()) { + emit_keyword("null".to_string(), target) +} else { + if ((n.clone().as_str() == "true".to_string().as_str()) || (n.clone().as_str() == "false".to_string().as_str())) { + emit_keyword(n.clone(), target) +} else { + emit_ident(n.clone(), target) +} +} +} +} + +pub fn emit_expr_field_access_shared(expr: Rc, target: RenderTarget, emit_field: impl Fn(Rc) -> String + Clone) -> String { + if is_typed_service_call_receiver(expr.clone()) { + match extract_typed_service_name(expr.clone()) { + Some(svc_name) => service_var_name(svc_name.clone()), + None => emit_field(expr.clone()), +} +} else { + emit_field(expr.clone()) +} +} + +pub fn extract_string_interp_parts(expr: Rc) -> Rc>> { + Rc::new({ let mut __result = Vec::new(); for child in expr.children.clone().iter().cloned() { __result.push(match (*child.expr_data.clone()).clone() { + ExprData::ExprLiteral { ref value, .. } => { let LiteralValue::LitStr { value: text, .. } = value.as_ref() else { unreachable!() }; Rc::new(StringPart::Text { + value: text.clone(), +}) }, + _ => Rc::new(StringPart::Interpolation { + expr: arg_value(child.clone()), +}), +}); } __result }) +} + pub fn emit_shared_expr(texpr: Rc, target: RenderTarget, source_index: Option>, wrap_result: impl Fn(String) -> String + Clone, recurse: impl Fn(Rc) -> String + Clone, emit_var: impl Fn(Rc) -> String + Clone, emit_field_access: impl Fn(Rc) -> String + Clone, emit_call: impl Fn(Rc) -> String + Clone, emit_method_call: impl Fn(Rc) -> String + Clone, emit_match: impl Fn(Rc) -> String + Clone, emit_if: impl Fn(Rc) -> String + Clone, emit_let: impl Fn(Rc) -> String + Clone, emit_record_lit: impl Fn(Rc) -> String + Clone, emit_string_interp: impl Fn(Rc) -> String + Clone, emit_block: impl Fn(Rc) -> String + Clone, emit_cast: impl Fn(Rc) -> String + Clone, emit_for_each: impl Fn(Rc) -> String + Clone, emit_index: impl Fn(Rc) -> String + Clone, emit_slice: impl Fn(Rc) -> String + Clone, emit_bin_op: impl Fn(Rc) -> String + Clone) -> String { match (*texpr.expr_data.clone()).clone() { ExprData::ExprLiteral { value: v, .. } => wrap_result(emit_literal(v.clone(), target.clone())), diff --git a/src/v2/stage0/src/v2_compiler_emit_go.rs b/src/v2/stage0/src/v2_compiler_emit_go.rs index 3b83a653394..66e626fc734 100644 --- a/src/v2/stage0/src/v2_compiler_emit_go.rs +++ b/src/v2/stage0/src/v2_compiler_emit_go.rs @@ -46,7 +46,7 @@ impl NonEmptyBTreeSet { self.0 } } -pub use crate::v2_std_core::{Node, InferredNode, VarBindingKind, is_import_node, import_is_all, import_specific_names, module_imports, module_items, param_node_type_expr, authored_name_at, NewlineIndex, expr_var_name_at, expr_call_func_at, expr_method_name_at, let_binding_name_at, param_node_name_at, resource_use_name_at, MatchPattern, LiteralValue, field_binding_pattern, TextFile, SourceSpan, resource_use_resource, BinOp, UnaryOpKind, StringPart, DeclaredFuncSig, transport_has_auth, transport_auth_header_name, transport_headers, transport_env, ExprData, make_expr_node, MethodSemantics, FieldSummary, FieldAccessStyle, arg_name, arg_value, arm_body, arm_pattern, arm_guard, field_init_node_name, field_init_node_value, if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, field_access_base, method_receiver, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, index_base, index_expr, slice_base, slice_start, slice_end, leaf_node, with_required_cardinality, Connective, is_rest_transport, is_shell_transport, is_file_transport, is_local_transport, Cardinality}; +pub use crate::v2_std_core::{Node, InferredNode, VarBindingKind, is_import_node, import_is_all, import_specific_names, module_imports, module_items, param_node_type_expr, authored_name_at, NewlineIndex, expr_var_name_at, expr_call_func_at, expr_method_name_at, let_binding_name_at, param_node_name_at, resource_use_name_at, MatchPattern, LiteralValue, field_binding_pattern, TextFile, SourceSpan, resource_use_resource, BinOp, UnaryOpKind, StringPart, DeclaredFuncSig, transport_has_auth, transport_auth_header_name, transport_headers, transport_env, ExprData, make_expr_node, MethodSemantics, FieldSummary, FieldAccessStyle, arg_name, arg_value, arm_body, arm_pattern, arm_guard, field_init_node_name, field_init_node_value, if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, field_access_base, method_receiver, expr_field_access_summary, expr_method_call_semantics, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, index_base, index_expr, slice_base, slice_start, slice_end, leaf_node, with_required_cardinality, Connective, is_rest_transport, is_shell_transport, is_file_transport, is_local_transport, Cardinality}; use crate::v2_std_core::InferredNode::{Resolved, CompilerError}; use crate::v2_std_core::VarBindingKind::{FunctionValueBinding}; use crate::v2_std_core::BinOp::{NullCoalesce}; @@ -70,7 +70,7 @@ pub use crate::v2_compiler_infer_items::{ResolvedGraph, TypedModule, ItemInfo, I use crate::v2_compiler_infer_items::ItemKind::{FuncItem}; pub use crate::v2_compiler_infer_service::{is_typed_service_call_receiver, extract_typed_service_name}; pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope, expr_span}; -pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_go_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, unique_strings, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, has_nested_records_node, is_service_item, typed_named_arg_matches, order_typed_call_args, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, classify_transport, seed_bindings}; +pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_go_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, unique_strings, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, has_nested_records_node, is_service_item, typed_named_arg_matches, order_typed_call_args, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts}; use crate::v2_compiler_emit::TransportKind::{RestKind, ShellKind, FileKind, LocalKind}; pub fn emit_go_block_stmts(mut remaining: Rc>>, mut text: Rc>, mut scope: Rc, mut registry: Rc>>, mut depth: i64) -> Rc { @@ -531,204 +531,59 @@ match summary { } pub fn emit_go_expr_var(expr: Rc, depth: i64, source_index: Option>) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprVar { .. } => { - let n = expr_var_name_at(expr.clone(), source_index); -if (n.clone().as_str() == "none".to_string().as_str()) { - v2_rt::concat(prefix, emit_keyword("null".to_string(), RenderTarget::Go)) -} else { - if ((n.clone().as_str() == "true".to_string().as_str()) || (n.clone().as_str() == "false".to_string().as_str())) { - v2_rt::concat(prefix, emit_keyword(n.clone(), RenderTarget::Go)) -} else { - v2_rt::concat(prefix, emit_ident(n.clone(), RenderTarget::Go)) -} -} -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_var expected ExprVar".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_expr_var_shared(expr, RenderTarget::Go, source_index)) } pub fn emit_go_expr_field_access(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprFieldAccess { summary, .. } => { - let f = expr.name.clone(); -let b = field_access_base(expr.clone()); -if is_typed_service_call_receiver(expr.clone()) { - match extract_typed_service_name(expr.clone()) { - Some(svc_name) => v2_rt::concat(prefix, service_var_name(svc_name.clone())), - None => v2_rt::concat(prefix, emit_go_field_access(b, f, summary.clone(), registry, scope)), -} -} else { - v2_rt::concat(prefix, emit_go_field_access(b, f, summary.clone(), registry, scope)) -} -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_field_access expected ExprFieldAccess".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_expr_field_access_shared(expr, RenderTarget::Go, |e| emit_go_field_access(field_access_base(e.clone()), e.name.clone(), expr_field_access_summary(e.clone()), registry.clone(), scope.clone()))) } pub fn emit_go_expr_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprCall { .. } => { - let f = expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()); -v2_rt::concat(prefix, emit_go_typed_call(f, expr.children.clone(), registry, scope.clone())) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_call expected ExprCall".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_call(expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()), expr.children.clone(), registry, scope.clone())) } pub fn emit_go_expr_method_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprMethodCall { method_semantics, .. } => { - let r = method_receiver(expr.clone()); -let a = method_arg_nodes(expr.clone()); -let m = expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()); -v2_rt::concat(prefix, emit_go_typed_method_call(r, m, a, method_semantics.clone(), registry, scope.clone())) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_method_call expected ExprMethodCall".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_method_call(method_receiver(expr.clone()), expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), method_arg_nodes(expr.clone()), expr_method_call_semantics(expr.clone()), registry, scope.clone())) } pub fn emit_go_expr_match(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprMatch => { - let s = match_scrutinee(expr.clone()); -let arm_list = match_arm_nodes(expr.clone()); -emit_go_typed_match(s, arm_list, registry, scope, depth) -}, - _ => v2_rt::concat(make_indent(depth), emit_error_expr("emit_go_expr_match expected ExprMatch".to_string(), RenderTarget::Go)), -} + emit_go_typed_match(match_scrutinee(expr.clone()), match_arm_nodes(expr.clone()), registry, scope, depth) } pub fn emit_go_expr_if(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprIf => { - let c = if_condition(expr.clone()); -let t = if_then_branch(expr.clone()); -let e = if_else_branch(expr.clone()); -emit_go_typed_if(c, t, e, registry, scope, depth) -}, - _ => v2_rt::concat(make_indent(depth), emit_error_expr("emit_go_expr_if expected ExprIf".to_string(), RenderTarget::Go)), -} + emit_go_typed_if(if_condition(expr.clone()), if_then_branch(expr.clone()), if_else_branch(expr.clone()), registry, scope, depth) } pub fn emit_go_expr_let(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprLet => { - let n = let_binding_name_at(expr.clone(), scope.type_env.clone().source_index.clone()); -let v = let_value(expr.clone()); -let bd = let_body(expr.clone()); -emit_go_typed_let(n, v, bd, registry, scope.clone(), depth) -}, - _ => v2_rt::concat(make_indent(depth), emit_error_expr("emit_go_expr_let expected ExprLet".to_string(), RenderTarget::Go)), -} + emit_go_typed_let(let_binding_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), let_value(expr.clone()), let_body(expr.clone()), registry, scope.clone(), depth) } pub fn emit_go_expr_record_lit(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprRecordLit { .. } => { - let tn = record_lit_type_name(expr.clone()); -let fs = expr.children.clone(); -v2_rt::concat(prefix, emit_go_typed_record_lit(tn, fs, registry, scope)) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_record_lit expected ExprRecordLit".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_record_lit(record_lit_type_name(expr.clone()), expr.children.clone(), registry, scope)) } pub fn emit_go_expr_string_interp(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprStringInterp => { - let ps = Rc::new({ let mut __result = Vec::new(); for child in expr.children.clone().iter().cloned() { __result.push(match (*child.expr_data.clone()).clone() { - ExprData::ExprLiteral { ref value, .. } => { let LiteralValue::LitStr { value: text, .. } = value.as_ref() else { unreachable!() }; Rc::new(StringPart::Text { - value: text.clone(), -}) }, - _ => Rc::new(StringPart::Interpolation { - expr: arg_value(child.clone()), -}), -}); } __result }); -v2_rt::concat(prefix, emit_go_typed_string_interp(ps, registry, scope)) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_string_interp expected ExprStringInterp".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_string_interp(extract_string_interp_parts(expr), registry, scope)) } pub fn emit_go_expr_block(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprBlock => emit_go_typed_block(expr.children.clone(), registry, scope, depth), - _ => v2_rt::concat(make_indent(depth), emit_error_expr("emit_go_expr_block expected ExprBlock".to_string(), RenderTarget::Go)), -} + emit_go_typed_block(expr.children.clone(), registry, scope, depth) } pub fn emit_go_expr_cast(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprCast => { - let e = cast_expr(expr.clone()); -let t = cast_target(expr.clone()); -v2_rt::concat(prefix, emit_go_typed_cast(e, t, registry, scope)) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_cast expected ExprCast".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_cast(cast_expr(expr.clone()), cast_target(expr.clone()), registry, scope)) } pub fn emit_go_expr_for_each(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprForEach => { - let v = foreach_variable(expr.clone()); -let c = foreach_collection(expr.clone()); -let bd = foreach_body(expr.clone()); -emit_go_typed_for_each(v, c, bd, registry, scope, depth) -}, - _ => v2_rt::concat(make_indent(depth), emit_error_expr("emit_go_expr_for_each expected ExprForEach".to_string(), RenderTarget::Go)), -} + emit_go_typed_for_each(foreach_variable(expr.clone()), foreach_collection(expr.clone()), foreach_body(expr.clone()), registry, scope, depth) } pub fn emit_go_expr_index(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprIndex => { - let b = index_base(expr.clone()); -let i = index_expr(expr.clone()); -v2_rt::concat(prefix, emit_go_typed_index(b, i, registry, scope)) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_index expected ExprIndex".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_index(index_base(expr.clone()), index_expr(expr.clone()), registry, scope)) } pub fn emit_go_expr_slice(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let prefix = make_indent(depth); -match (*expr.expr_data.clone()).clone() { - ExprData::ExprSlice => { - let b = slice_base(expr.clone()); -let s = slice_start(expr.clone()); -let e = slice_end(expr.clone()); -v2_rt::concat(prefix, emit_go_typed_slice(b, s, e, registry, scope)) -}, - _ => v2_rt::concat(prefix, emit_error_expr("emit_go_expr_slice expected ExprSlice".to_string(), RenderTarget::Go)), -} -} + v2_rt::concat(make_indent(depth), emit_go_typed_slice(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), registry, scope)) } pub fn emit_go_typed_expr(texpr: Rc, registry: Rc>>, scope: Rc, depth: i64, fuel: i64) -> String { diff --git a/src/v2/stage0/src/v2_compiler_emit_python.rs b/src/v2/stage0/src/v2_compiler_emit_python.rs index 7a672adc6ba..3917ea82073 100644 --- a/src/v2/stage0/src/v2_compiler_emit_python.rs +++ b/src/v2/stage0/src/v2_compiler_emit_python.rs @@ -46,7 +46,7 @@ impl NonEmptyBTreeSet { self.0 } } -pub use crate::v2_std_core::{Node, InferredNode, VarBindingKind, is_import_node, import_is_all, import_specific_names, module_imports, module_items, param_node_type_expr, authored_name_at, NewlineIndex, expr_var_name_at, expr_call_func_at, expr_method_name_at, let_binding_name_at, param_node_name_at, resource_use_name_at, field_binding_name_at, MatchPattern, LiteralValue, field_binding_pattern, TextFile, SourceSpan, resource_use_resource, BinOp, UnaryOpKind, StringPart, DeclaredFuncSig, transport_has_auth, transport_auth_header_name, transport_headers, transport_env, ExprData, make_expr_node, MethodSemantics, FieldSummary, arg_name, arg_value, arm_body, arm_pattern, arm_guard, field_init_node_name, field_init_node_value, if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, field_access_base, method_receiver, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, index_base, index_expr, slice_base, slice_start, slice_end, leaf_node, with_required_cardinality, Connective, is_rest_transport, is_shell_transport, is_file_transport, is_local_transport, FieldAccessStyle, Cardinality}; +pub use crate::v2_std_core::{Node, InferredNode, VarBindingKind, is_import_node, import_is_all, import_specific_names, module_imports, module_items, param_node_type_expr, authored_name_at, NewlineIndex, expr_var_name_at, expr_call_func_at, expr_method_name_at, let_binding_name_at, param_node_name_at, resource_use_name_at, field_binding_name_at, MatchPattern, LiteralValue, field_binding_pattern, TextFile, SourceSpan, resource_use_resource, BinOp, UnaryOpKind, StringPart, DeclaredFuncSig, transport_has_auth, transport_auth_header_name, transport_headers, transport_env, ExprData, make_expr_node, MethodSemantics, FieldSummary, arg_name, arg_value, arm_body, arm_pattern, arm_guard, field_init_node_name, field_init_node_value, if_condition, if_then_branch, if_else_branch, match_scrutinee, match_arm_nodes, let_value, let_body, field_access_base, method_receiver, expr_field_access_summary, expr_method_call_semantics, record_lit_type_name, lambda_body, cast_expr, cast_target, return_value, foreach_variable, foreach_collection, foreach_body, method_arg_nodes, index_base, index_expr, slice_base, slice_start, slice_end, leaf_node, with_required_cardinality, Connective, is_rest_transport, is_shell_transport, is_file_transport, is_local_transport, FieldAccessStyle, Cardinality}; use crate::v2_std_core::InferredNode::{Resolved, CompilerError}; use crate::v2_std_core::VarBindingKind::{FunctionValueBinding}; use crate::v2_std_core::BinOp::{NullCoalesce}; @@ -69,7 +69,7 @@ pub use crate::v2_compiler_infer_items::{ResolvedGraph, TypedModule, ItemInfo, I use crate::v2_compiler_infer_items::ItemKind::{FuncItem}; pub use crate::v2_compiler_infer_service::{is_typed_service_call_receiver, extract_typed_service_name}; pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope, expr_span}; -pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_python_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, typed_named_arg_matches, order_typed_call_args, unique_strings, has_nested_records_node, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, is_service_item, has_service_items, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, classify_transport, seed_bindings}; +pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_python_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, typed_named_arg_matches, order_typed_call_args, unique_strings, has_nested_records_node, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, is_service_item, has_service_items, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts}; use crate::v2_compiler_emit::TransportKind::{RestKind, ShellKind, FileKind, LocalKind}; pub fn emit_py_block_stmts(mut remaining: Rc>>, mut text: Rc>, mut scope: Rc, mut registry: Rc>>, mut depth: i64) -> Rc { @@ -539,177 +539,59 @@ match summary { } pub fn emit_py_expr_var(expr: Rc, source_index: Option>) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprVar { .. } => { - let n = expr_var_name_at(expr.clone(), source_index); -if (n.clone().as_str() == "none".to_string().as_str()) { - emit_keyword("null".to_string(), RenderTarget::Python) -} else { - if ((n.clone().as_str() == "true".to_string().as_str()) || (n.clone().as_str() == "false".to_string().as_str())) { - emit_keyword(n.clone(), RenderTarget::Python) -} else { - emit_ident(n.clone(), RenderTarget::Python) -} -} -}, - _ => emit_error_expr("emit_py_expr_var expected ExprVar".to_string(), RenderTarget::Python), -} + emit_expr_var_shared(expr, RenderTarget::Python, source_index) } pub fn emit_py_expr_field_access(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprFieldAccess { summary, .. } => { - let f = expr.name.clone(); -let b = field_access_base(expr.clone()); -if is_typed_service_call_receiver(expr.clone()) { - match extract_typed_service_name(expr.clone()) { - Some(svc_name) => service_var_name(svc_name.clone()), - None => emit_py_field_access(b, f, summary.clone(), registry, scope, depth), -} -} else { - emit_py_field_access(b, f, summary.clone(), registry, scope, depth) -} -}, - _ => emit_error_expr("emit_py_expr_field_access expected ExprFieldAccess".to_string(), RenderTarget::Python), -} + emit_expr_field_access_shared(expr, RenderTarget::Python, |e| emit_py_field_access(field_access_base(e.clone()), e.name.clone(), expr_field_access_summary(e.clone()), registry.clone(), scope.clone(), depth.clone())) } pub fn emit_py_expr_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprCall { .. } => { - let f = expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()); -emit_py_typed_call(f, expr.children.clone(), registry, scope.clone(), depth) -}, - _ => emit_error_expr("emit_py_expr_call expected ExprCall".to_string(), RenderTarget::Python), -} + emit_py_typed_call(expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()), expr.children.clone(), registry, scope.clone(), depth) } pub fn emit_py_expr_method_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprMethodCall { method_semantics, .. } => { - let r = method_receiver(expr.clone()); -let a = method_arg_nodes(expr.clone()); -let m = expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()); -emit_py_typed_method_call(r, m, a, method_semantics.clone(), registry, scope.clone(), depth) -}, - _ => emit_error_expr("emit_py_expr_method_call expected ExprMethodCall".to_string(), RenderTarget::Python), -} + emit_py_typed_method_call(method_receiver(expr.clone()), expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), method_arg_nodes(expr.clone()), expr_method_call_semantics(expr.clone()), registry, scope.clone(), depth) } pub fn emit_py_expr_match(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprMatch => { - let s = match_scrutinee(expr.clone()); -let arm_list = match_arm_nodes(expr.clone()); -emit_py_typed_match(s, arm_list, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_match expected ExprMatch".to_string(), RenderTarget::Python), -} + emit_py_typed_match(match_scrutinee(expr.clone()), match_arm_nodes(expr.clone()), registry, scope, depth) } pub fn emit_py_expr_if(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprIf => { - let c = if_condition(expr.clone()); -let t = if_then_branch(expr.clone()); -let e = if_else_branch(expr.clone()); -emit_py_typed_if(c, t, e, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_if expected ExprIf".to_string(), RenderTarget::Python), -} + emit_py_typed_if(if_condition(expr.clone()), if_then_branch(expr.clone()), if_else_branch(expr.clone()), registry, scope, depth) } pub fn emit_py_expr_let(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprLet => { - let n = let_binding_name_at(expr.clone(), scope.type_env.clone().source_index.clone()); -let v = let_value(expr.clone()); -let bd = let_body(expr.clone()); -emit_py_typed_let(n, v, bd, registry, scope.clone(), depth) -}, - _ => emit_error_expr("emit_py_expr_let expected ExprLet".to_string(), RenderTarget::Python), -} + emit_py_typed_let(let_binding_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), let_value(expr.clone()), let_body(expr.clone()), registry, scope.clone(), depth) } pub fn emit_py_expr_record_lit(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprRecordLit { .. } => { - let tn = record_lit_type_name(expr.clone()); -let fs = expr.children.clone(); -emit_py_typed_record_lit(tn, fs, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_record_lit expected ExprRecordLit".to_string(), RenderTarget::Python), -} + emit_py_typed_record_lit(record_lit_type_name(expr.clone()), expr.children.clone(), registry, scope, depth) } pub fn emit_py_expr_string_interp(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprStringInterp => { - let ps = Rc::new({ let mut __result = Vec::new(); for child in expr.children.clone().iter().cloned() { __result.push(match (*child.expr_data.clone()).clone() { - ExprData::ExprLiteral { ref value, .. } => { let LiteralValue::LitStr { value: text, .. } = value.as_ref() else { unreachable!() }; Rc::new(StringPart::Text { - value: text.clone(), -}) }, - _ => Rc::new(StringPart::Interpolation { - expr: arg_value(child.clone()), -}), -}); } __result }); -emit_py_typed_string_interp(ps, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_string_interp expected ExprStringInterp".to_string(), RenderTarget::Python), -} + emit_py_typed_string_interp(extract_string_interp_parts(expr), registry, scope, depth) } pub fn emit_py_expr_block(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprBlock => emit_py_typed_block(expr.children.clone(), registry, scope, depth), - _ => emit_error_expr("emit_py_expr_block expected ExprBlock".to_string(), RenderTarget::Python), -} + emit_py_typed_block(expr.children.clone(), registry, scope, depth) } pub fn emit_py_expr_cast(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprCast => { - let e = cast_expr(expr.clone()); -let t = cast_target(expr.clone()); -emit_py_typed_cast(e, t, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_cast expected ExprCast".to_string(), RenderTarget::Python), -} + emit_py_typed_cast(cast_expr(expr.clone()), cast_target(expr.clone()), registry, scope, depth) } pub fn emit_py_expr_for_each(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprForEach => { - let v = foreach_variable(expr.clone()); -let c = foreach_collection(expr.clone()); -let bd = foreach_body(expr.clone()); -emit_py_typed_for_each(v, c, bd, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_for_each expected ExprForEach".to_string(), RenderTarget::Python), -} + emit_py_typed_for_each(foreach_variable(expr.clone()), foreach_collection(expr.clone()), foreach_body(expr.clone()), registry, scope, depth) } pub fn emit_py_expr_index(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprIndex => { - let b = index_base(expr.clone()); -let i = index_expr(expr.clone()); -emit_py_typed_index(b, i, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_index expected ExprIndex".to_string(), RenderTarget::Python), -} + emit_py_typed_index(index_base(expr.clone()), index_expr(expr.clone()), registry, scope, depth) } pub fn emit_py_expr_slice(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - match (*expr.expr_data.clone()).clone() { - ExprData::ExprSlice => { - let b = slice_base(expr.clone()); -let s = slice_start(expr.clone()); -let e = slice_end(expr.clone()); -emit_py_typed_slice(b, s, e, registry, scope, depth) -}, - _ => emit_error_expr("emit_py_expr_slice expected ExprSlice".to_string(), RenderTarget::Python), -} + emit_py_typed_slice(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), registry, scope, depth) } pub fn emit_py_typed_expr(texpr: Rc, registry: Rc>>, scope: Rc, depth: i64, fuel: i64) -> String { diff --git a/src/v2/stage0/src/v2_std_core.rs b/src/v2/stage0/src/v2_std_core.rs index f21c17a2ec8..7a2b7657c48 100644 --- a/src/v2/stage0/src/v2_std_core.rs +++ b/src/v2/stage0/src/v2_std_core.rs @@ -1283,6 +1283,13 @@ pub fn field_access_field_at(texpr: Rc, source_index: Option) -> Option> { + match (*texpr.expr_data.clone()).clone() { + ExprData::ExprFieldAccess { summary: s, .. } => s.clone(), + _ => None, +} +} + pub fn expr_call_func(texpr: Rc) -> String { texpr.name.clone() } @@ -1307,6 +1314,13 @@ pub fn expr_method_name_at(texpr: Rc, source_index: Option) -> Option> { + match (*texpr.expr_data.clone()).clone() { + ExprData::ExprMethodCall { method_semantics: ms, .. } => ms.clone(), + _ => None, +} +} + pub fn lambda_body(texpr: Rc) -> Rc { expr_child_at(texpr, 0, "lambda body".to_string()) } From 04c7b45eb91a279156e83147f57d13b276127f4a Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 11:49:18 -0400 Subject: [PATCH 3/8] fix: align Go op_children with Rust/Python (review feedback) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove Go-only params filter on service operation children. Rust and Python use item.children unfiltered — Go now matches. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/v2/05_emit_go.dag | 5 +---- src/v2/stage0/src/v2_compiler_emit_go.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/v2/05_emit_go.dag b/src/v2/05_emit_go.dag index a3adcd20f6f..32df45039b7 100644 --- a/src/v2/05_emit_go.dag +++ b/src/v2/05_emit_go.dag @@ -1128,10 +1128,7 @@ fn emit_go_service_def( ) -> String { let safe_name = sanitize_service_name(name: authored_name(env: env, node: item)) let transport = service_fallback_transport(item: item) - // BUG: Go filters op_children by having params, but Rust/Python use - // item.children unfiltered. This inconsistency should be aligned — - // either all backends filter or none do. - let op_children = item.children |> filter(c => c.params |> count > 0) + let op_children = item.children let struct_def = emit_go_service_struct(name: safe_name, fallback_transport: transport, op_children: op_children) let methods = op_children |> map(op_node => emit_go_operation_method(service_name: safe_name, transport: transport, op_node: op_node, registry: registry, env: env) diff --git a/src/v2/stage0/src/v2_compiler_emit_go.rs b/src/v2/stage0/src/v2_compiler_emit_go.rs index 66e626fc734..e45d29967a4 100644 --- a/src/v2/stage0/src/v2_compiler_emit_go.rs +++ b/src/v2/stage0/src/v2_compiler_emit_go.rs @@ -1101,7 +1101,7 @@ pub fn emit_go_service_def(item: Rc, registry: Rc 0) { __result.push(c); } } __result }); +let op_children = item.children.clone(); let struct_def = emit_go_service_struct(safe_name.clone(), transport.clone(), op_children.clone()); let methods = Rc::new({ let mut __result = Vec::new(); for op_node in op_children.clone().iter().cloned() { __result.push(emit_go_operation_method(safe_name.clone(), transport.clone(), op_node.clone(), registry.clone(), env.clone())); } __result }); let methods_str = methods.join(&"\n\n".to_string()); From f7bdf78cde0423b22580a83f9aee9925cc236808 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 11:57:11 -0400 Subject: [PATCH 4/8] =?UTF-8?q?CG-3:=20Phase=202+3=20=E2=80=94=20shared=20?= =?UTF-8?q?typed=20handlers=20+=20dead=20code=20deletion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Share cast/index/slice handlers via target-parameterized functions: - emit_typed_cast_shared: type(expr) rendering - emit_typed_index_shared: string/map/list dispatch via IndexingSemantics - emit_typed_slice_shared: string/list dispatch via IndexingSemantics Delete dead code: - emit_go_typed_bin_op (emit_default_bin_op used directly) - emit_go_typed_cast, emit_go_typed_index, emit_go_typed_slice - emit_py_typed_cast, emit_py_typed_index, emit_py_typed_slice Net: 47 lines removed from .dag source (-102/+55). No Rust emission changes (bootstrap safe). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/v2/05_emit.dag | 47 ++++++++++++- src/v2/05_emit_go.dag | 61 ++--------------- src/v2/05_emit_python.dag | 49 ++------------ src/v2/stage0/src/v2_compiler_emit.rs | 52 +++++++++++++- src/v2/stage0/src/v2_compiler_emit_go.rs | 71 ++------------------ src/v2/stage0/src/v2_compiler_emit_python.rs | 56 ++------------- 6 files changed, 113 insertions(+), 223 deletions(-) diff --git a/src/v2/05_emit.dag b/src/v2/05_emit.dag index 73bc906bc8c..a080ed74394 100644 --- a/src/v2/05_emit.dag +++ b/src/v2/05_emit.dag @@ -59,7 +59,7 @@ import v2.std.core { } import v2.compiler.infer_env { TypeEnv, TypeBinding, RecursiveVariantFieldWitness } -import v2.compiler.infer_types { rt_type, emit_map_has, node_is_collection, node_is_keyed_collection, node_is_element_collection } +import v2.compiler.infer_types { rt_type, emit_map_has, node_is_collection, node_is_keyed_collection, node_is_element_collection, normalize_access_type_node } import std.types { is_container_type, container_to_algebra_name } import v2.compiler.coercion { coerce_primitive_type, coerce_container_template, target_optional_template, target_callable } import v2.compiler.infer_sigs { ResolvedFuncSig, ResolvedFuncEnv } @@ -81,7 +81,7 @@ import v2.compiler.languages { ImportRule, TypeUsageTrigger, TraitImplTrigger, DeriveMacroTrigger, ContainerUsageTrigger, AsyncUsageTrigger, - language_spec_for_target, + language_spec_for_target, is_string_like, test_conventions_for_target, target_keyword, wrap_shared_type @@ -1702,6 +1702,49 @@ fn extract_string_interp_parts(expr: Node) -> List { }) } +// Shared ExprCast — target-parameterized, recurse for sub-expression. +fn emit_typed_cast_shared(expr: Node, cast_target_node: Node, target: RenderTarget, recurse: fn(Node) -> String) -> String { + let expr_str = recurse(expr) + let ty_str = emit_node_type(n: cast_target_node, target: target) + concat(ty_str, "(", expr_str, ")") +} + +// Shared ExprIndex — dispatches on string/map/list via LanguageSpec.indexing. +fn emit_typed_index_shared(base: Node, index: Node, target: RenderTarget, recurse: fn(Node) -> String) -> String { + let spec = language_spec(target: target) + let base_str = recurse(base) + let index_str = recurse(index) + let base_node = normalize_access_type_node(n: rt_type(n: base)) + let is_map = node_is_keyed_collection(n: base_node) + if is_string_like(target: target, name: base_node.name) { + apply_type_template2(template: spec.indexing.string_index, arg0: base_str, arg1: index_str) + } else if is_map { + apply_type_template2(template: spec.indexing.map_index, arg0: base_str, arg1: index_str) + } else { + apply_type_template2(template: spec.indexing.list_index, arg0: base_str, arg1: index_str) + } +} + +// Shared ExprSlice — dispatches on string/list via LanguageSpec.indexing. +fn emit_typed_slice_shared(base: Node, start: Node, end: Node, target: RenderTarget, recurse: fn(Node) -> String) -> String { + let spec = language_spec(target: target) + let base_str = recurse(base) + let start_str = recurse(start) + let end_str = recurse(end) + let base_node = normalize_access_type_node(n: rt_type(n: base)) + if is_string_like(target: target, name: base_node.name) { + match spec.indexing.string_slice { + Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) + None => emit_error_expr(message: "unsupported string slice for target", target: target) + } + } else { + match spec.indexing.list_slice { + Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) + None => emit_error_expr(message: "unsupported slice for target", target: target) + } + } +} + // ========================================================================= // emit_shared_expr — full shared ExprData dispatcher (P4.2 step 5) // diff --git a/src/v2/05_emit_go.dag b/src/v2/05_emit_go.dag index 32df45039b7..f22fe3b3b18 100644 --- a/src/v2/05_emit_go.dag +++ b/src/v2/05_emit_go.dag @@ -118,7 +118,8 @@ import v2.compiler.emit { ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, RestKind, ShellKind, FileKind, LocalKind, classify_transport, seed_bindings, - emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts + emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts, + emit_typed_cast_shared, emit_typed_index_shared, emit_typed_slice_shared } // ========================================================================= // Go language facts -- from std.languages spec (go_language, go_literals) @@ -633,7 +634,7 @@ fn emit_go_expr_block(expr: Node, registry: Map, scope: InferS } fn emit_go_expr_cast(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_cast(expr: cast_expr(texpr: expr), target: cast_target(texpr: expr), registry: registry, scope: scope)) + concat(make_indent(level: depth), emit_typed_cast_shared(expr: cast_expr(texpr: expr), cast_target_node: cast_target(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) } fn emit_go_expr_for_each(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -641,11 +642,11 @@ fn emit_go_expr_for_each(expr: Node, registry: Map, scope: Inf } fn emit_go_expr_index(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_index(base: index_base(texpr: expr), index: index_expr(texpr: expr), registry: registry, scope: scope)) + concat(make_indent(level: depth), emit_typed_index_shared(base: index_base(texpr: expr), index: index_expr(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) } fn emit_go_expr_slice(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_slice(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), registry: registry, scope: scope)) + concat(make_indent(level: depth), emit_typed_slice_shared(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) } fn emit_go_typed_expr(texpr: Node, registry: Map, scope: InferScope, depth: Int, fuel: Int) -> String { @@ -699,40 +700,6 @@ fn emit_go_typed_for_each(variable: String, collection: Node, body: Node, regist body_str, "\n", make_indent(level: depth), "}") } -fn emit_go_typed_index(base: Node, index: Node, registry: Map, scope: InferScope) -> String { - let spec = language_spec(target: Go) - let base_str = emit_go_typed_expr(texpr: base, registry: registry, scope: scope, depth: 0, fuel: 1024) - let index_str = emit_go_typed_expr(texpr: index, registry: registry, scope: scope, depth: 0, fuel: 1024) - let base_node = normalize_access_type_node(n: rt_type(n: base)) - let is_map = node_is_keyed_collection(n: base_node) - if is_string_like(target: Go, name: base_node.name) { - apply_type_template2(template: spec.indexing.string_index, arg0: base_str, arg1: index_str) - } else if is_map { - apply_type_template2(template: spec.indexing.map_index, arg0: base_str, arg1: index_str) - } else { - apply_type_template2(template: spec.indexing.list_index, arg0: base_str, arg1: index_str) - } -} - -fn emit_go_typed_slice(base: Node, start: Node, end: Node, registry: Map, scope: InferScope) -> String { - let spec = language_spec(target: Go) - let base_str = emit_go_typed_expr(texpr: base, registry: registry, scope: scope, depth: 0, fuel: 1024) - let start_str = emit_go_typed_expr(texpr: start, registry: registry, scope: scope, depth: 0, fuel: 1024) - let end_str = emit_go_typed_expr(texpr: end, registry: registry, scope: scope, depth: 0, fuel: 1024) - let base_node = normalize_access_type_node(n: rt_type(n: base)) - if is_string_like(target: Go, name: base_node.name) { - match spec.indexing.string_slice { - Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) - None => emit_error_expr(message: "unsupported string slice for target", target: Go) - } - } else { - match spec.indexing.list_slice { - Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) - None => emit_error_expr(message: "unsupported slice for target", target: Go) - } - } -} - fn go_bridge_method_name(method_name: String) -> String { // Derive PascalCase from the canonical snake_case method name. let parts = method_name |> split(delimiter: "_") @@ -882,18 +849,6 @@ fn emit_go_typed_record_lit(type_name: String?, fields: List, registry: Ma } -fn emit_go_typed_bin_op(op: BinOp, left: Node, right: Node, registry: Map, scope: InferScope) -> String { - let l_str = emit_go_typed_expr(texpr: left, registry: registry, scope: scope, depth: 0, fuel: 1024) - let r_str = emit_go_typed_expr(texpr: right, registry: registry, scope: scope, depth: 0, fuel: 1024) - if is_null_coalesce(op: op) { - emit_null_coalesce(l_str: l_str, r_str: r_str, target: Go) - } else { - let op_str = emit_bin_op_symbol(op: op, target: Go) - concat("(", l_str, " ", op_str, " ", r_str, ")") - } -} - - fn emit_go_typed_string_interp(parts: List, registry: Map, scope: InferScope) -> String { let has_interpolations = parts |> any(p => match p { Interpolation { expr: _ } => true _ => false }) let fmt_parts = parts |> map(p => go_typed_interp_segment(part: p, registry: registry, scope: scope, has_interpolations: has_interpolations)) @@ -925,12 +880,6 @@ fn emit_go_typed_block(stmts: List, registry: Map, scope state.text |> join(separator: "\n") } -fn emit_go_typed_cast(expr: Node, target: Node, registry: Map, scope: InferScope) -> String { - let expr_str = emit_go_typed_expr(texpr: expr, registry: registry, scope: scope, depth: 0, fuel: 1024) - let ty_str = emit_node_type(n: target, target: Go) - concat(ty_str, "(", expr_str, ")") -} - // ========================================================================= // Func body -- for func (workflow) emission // ========================================================================= diff --git a/src/v2/05_emit_python.dag b/src/v2/05_emit_python.dag index 4577ab38b00..cda99773eb3 100644 --- a/src/v2/05_emit_python.dag +++ b/src/v2/05_emit_python.dag @@ -108,7 +108,8 @@ import v2.compiler.emit { ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, RestKind, ShellKind, FileKind, LocalKind, classify_transport, seed_bindings, - emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts + emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts, + emit_typed_cast_shared, emit_typed_index_shared, emit_typed_slice_shared } // ========================================================================= @@ -615,7 +616,7 @@ fn emit_py_expr_block(expr: Node, registry: Map, scope: InferS } fn emit_py_expr_cast(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - emit_py_typed_cast(expr: cast_expr(texpr: expr), target: cast_target(texpr: expr), registry: registry, scope: scope, depth: depth) + emit_typed_cast_shared(expr: cast_expr(texpr: expr), cast_target_node: cast_target(texpr: expr), target: Python, recurse: child => emit_py_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_py_expr_for_each(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -623,11 +624,11 @@ fn emit_py_expr_for_each(expr: Node, registry: Map, scope: Inf } fn emit_py_expr_index(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - emit_py_typed_index(base: index_base(texpr: expr), index: index_expr(texpr: expr), registry: registry, scope: scope, depth: depth) + emit_typed_index_shared(base: index_base(texpr: expr), index: index_expr(texpr: expr), target: Python, recurse: child => emit_py_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_py_expr_slice(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - emit_py_typed_slice(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), registry: registry, scope: scope, depth: depth) + emit_typed_slice_shared(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), target: Python, recurse: child => emit_py_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_py_typed_expr(texpr: Node, registry: Map, scope: InferScope, depth: Int, fuel: Int) -> String { @@ -686,40 +687,6 @@ fn emit_py_typed_for_each(variable: String, collection: Node, body: Node, regist make_indent(level: depth + 1), body_str) } -fn emit_py_typed_index(base: Node, index: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let spec = language_spec(target: Python) - let base_str = emit_py_typed_expr(texpr: base, registry: registry, scope: scope, depth: depth, fuel: 1024) - let index_str = emit_py_typed_expr(texpr: index, registry: registry, scope: scope, depth: depth, fuel: 1024) - let base_node = normalize_access_type_node(n: rt_type(n: base)) - let is_map = node_is_keyed_collection(n: base_node) - if is_string_like(target: Python, name: base_node.name) { - apply_type_template2(template: spec.indexing.string_index, arg0: base_str, arg1: index_str) - } else if is_map { - apply_type_template2(template: spec.indexing.map_index, arg0: base_str, arg1: index_str) - } else { - apply_type_template2(template: spec.indexing.list_index, arg0: base_str, arg1: index_str) - } -} - -fn emit_py_typed_slice(base: Node, start: Node, end: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let spec = language_spec(target: Python) - let base_str = emit_py_typed_expr(texpr: base, registry: registry, scope: scope, depth: depth, fuel: 1024) - let start_str = emit_py_typed_expr(texpr: start, registry: registry, scope: scope, depth: depth, fuel: 1024) - let end_str = emit_py_typed_expr(texpr: end, registry: registry, scope: scope, depth: depth, fuel: 1024) - let base_node = normalize_access_type_node(n: rt_type(n: base)) - if is_string_like(target: Python, name: base_node.name) { - match spec.indexing.string_slice { - Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) - None => emit_error_expr(message: "unsupported string slice for target", target: Python) - } - } else { - match spec.indexing.list_slice { - Some { value: tmpl } => apply_type_template3(template: tmpl, arg0: base_str, arg1: start_str, arg2: end_str) - None => emit_error_expr(message: "unsupported slice for target", target: Python) - } - } -} - fn py_bridge_method_name(method_name: String) -> String { // Python reserved word `with` requires override; all others use method name directly. if method_name == "with" { "with_update" } else { method_name } @@ -896,12 +863,6 @@ fn emit_py_typed_block(stmts: List, registry: Map, scope state.text |> join(separator: "\n") } -fn emit_py_typed_cast(expr: Node, target: Node, registry: Map, scope: InferScope, depth: Int) -> String { - let expr_str = emit_py_typed_expr(texpr: expr, registry: registry, scope: scope, depth: depth, fuel: 1024) - let ty_str = emit_node_type(n: target, target: Python) - concat(ty_str, "(", expr_str, ")") -} - // ========================================================================= // Node func body -- async def body emission using Node.expr_data. // ========================================================================= diff --git a/src/v2/stage0/src/v2_compiler_emit.rs b/src/v2/stage0/src/v2_compiler_emit.rs index 5329a842e34..236bf24d0f3 100644 --- a/src/v2/stage0/src/v2_compiler_emit.rs +++ b/src/v2/stage0/src/v2_compiler_emit.rs @@ -57,7 +57,7 @@ use crate::v2_std_core::VarBindingKind::*; use crate::v2_std_core::LiteralValue::*; use crate::v2_std_core::UnaryOpKind::*; pub use crate::v2_compiler_infer_env::{TypeEnv, TypeBinding, RecursiveVariantFieldWitness}; -pub use crate::v2_compiler_infer_types::{rt_type, emit_map_has, node_is_collection, node_is_keyed_collection, node_is_element_collection}; +pub use crate::v2_compiler_infer_types::{rt_type, emit_map_has, node_is_collection, node_is_keyed_collection, node_is_element_collection, normalize_access_type_node}; pub use crate::std_types::{is_container_type, container_to_algebra_name}; pub use crate::v2_compiler_coercion::{coerce_primitive_type, coerce_container_template, target_optional_template, target_callable}; pub use crate::v2_compiler_infer_sigs::{ResolvedFuncSig, ResolvedFuncEnv}; @@ -67,7 +67,7 @@ pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope} pub use crate::v2_compiler_infer_emit_info::{TypeSummary, EmitGraphInfo}; pub use crate::v2_compiler_artifact::{RenderTarget}; use crate::v2_compiler_artifact::RenderTarget::{Rust, Python, Go, Dag}; -pub use crate::v2_compiler_languages::{LanguageSpec, TestConventions, ServiceFieldTemplates, ReservedWordStrategy, ImportRule, language_spec_for_target, test_conventions_for_target, target_keyword, wrap_shared_type, TestNameStyle, ImportTrigger}; +pub use crate::v2_compiler_languages::{LanguageSpec, TestConventions, ServiceFieldTemplates, ReservedWordStrategy, ImportRule, language_spec_for_target, is_string_like, test_conventions_for_target, target_keyword, wrap_shared_type, TestNameStyle, ImportTrigger}; use crate::v2_compiler_languages::TestNameStyle::{SnakeCaseTestNames, PascalCaseTestNames}; use crate::v2_compiler_languages::ReservedWordStrategy::{PrefixEscape, SuffixEscape, NoEscape}; use crate::v2_compiler_languages::ImportTrigger::{TypeUsageTrigger, TraitImplTrigger, DeriveMacroTrigger, ContainerUsageTrigger, AsyncUsageTrigger}; @@ -1797,6 +1797,54 @@ pub fn extract_string_interp_parts(expr: Rc) -> Rc>> { }); } __result }) } +pub fn emit_typed_cast_shared(expr: Rc, cast_target_node: Rc, target: RenderTarget, recurse: impl Fn(Rc) -> String + Clone) -> String { + { + let expr_str = recurse(expr); +let ty_str = emit_node_type(cast_target_node, target); +v2_rt::concat(v2_rt::concat(v2_rt::concat(ty_str, "(".to_string()), expr_str), ")".to_string()) +} +} + +pub fn emit_typed_index_shared(base: Rc, index: Rc, target: RenderTarget, recurse: impl Fn(Rc) -> String + Clone) -> String { + { + let spec = language_spec(target.clone()); +let base_str = recurse(base.clone()); +let index_str = recurse(index); +let base_node = normalize_access_type_node(rt_type(base.clone())); +let is_map = node_is_keyed_collection(base_node.clone()); +if is_string_like(target.clone(), base_node.name.clone()) { + apply_type_template2(spec.indexing.clone().string_index.clone(), base_str, index_str) +} else { + if is_map { + apply_type_template2(spec.indexing.clone().map_index.clone(), base_str, index_str) +} else { + apply_type_template2(spec.indexing.clone().list_index.clone(), base_str, index_str) +} +} +} +} + +pub fn emit_typed_slice_shared(base: Rc, start: Rc, end: Rc, target: RenderTarget, recurse: impl Fn(Rc) -> String + Clone) -> String { + { + let spec = language_spec(target.clone()); +let base_str = recurse(base.clone()); +let start_str = recurse(start); +let end_str = recurse(end); +let base_node = normalize_access_type_node(rt_type(base.clone())); +if is_string_like(target.clone(), base_node.name.clone()) { + match spec.indexing.clone().string_slice.clone() { + Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), + None => emit_error_expr("unsupported string slice for target".to_string(), target.clone()), +} +} else { + match spec.indexing.clone().list_slice.clone() { + Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), + None => emit_error_expr("unsupported slice for target".to_string(), target.clone()), +} +} +} +} + pub fn emit_shared_expr(texpr: Rc, target: RenderTarget, source_index: Option>, wrap_result: impl Fn(String) -> String + Clone, recurse: impl Fn(Rc) -> String + Clone, emit_var: impl Fn(Rc) -> String + Clone, emit_field_access: impl Fn(Rc) -> String + Clone, emit_call: impl Fn(Rc) -> String + Clone, emit_method_call: impl Fn(Rc) -> String + Clone, emit_match: impl Fn(Rc) -> String + Clone, emit_if: impl Fn(Rc) -> String + Clone, emit_let: impl Fn(Rc) -> String + Clone, emit_record_lit: impl Fn(Rc) -> String + Clone, emit_string_interp: impl Fn(Rc) -> String + Clone, emit_block: impl Fn(Rc) -> String + Clone, emit_cast: impl Fn(Rc) -> String + Clone, emit_for_each: impl Fn(Rc) -> String + Clone, emit_index: impl Fn(Rc) -> String + Clone, emit_slice: impl Fn(Rc) -> String + Clone, emit_bin_op: impl Fn(Rc) -> String + Clone) -> String { match (*texpr.expr_data.clone()).clone() { ExprData::ExprLiteral { value: v, .. } => wrap_result(emit_literal(v.clone(), target.clone())), diff --git a/src/v2/stage0/src/v2_compiler_emit_go.rs b/src/v2/stage0/src/v2_compiler_emit_go.rs index e45d29967a4..99a455c6b28 100644 --- a/src/v2/stage0/src/v2_compiler_emit_go.rs +++ b/src/v2/stage0/src/v2_compiler_emit_go.rs @@ -70,7 +70,7 @@ pub use crate::v2_compiler_infer_items::{ResolvedGraph, TypedModule, ItemInfo, I use crate::v2_compiler_infer_items::ItemKind::{FuncItem}; pub use crate::v2_compiler_infer_service::{is_typed_service_call_receiver, extract_typed_service_name}; pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope, expr_span}; -pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_go_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, unique_strings, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, has_nested_records_node, is_service_item, typed_named_arg_matches, order_typed_call_args, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts}; +pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_go_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, unique_strings, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, has_nested_records_node, is_service_item, typed_named_arg_matches, order_typed_call_args, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts, emit_typed_cast_shared, emit_typed_index_shared, emit_typed_slice_shared}; use crate::v2_compiler_emit::TransportKind::{RestKind, ShellKind, FileKind, LocalKind}; pub fn emit_go_block_stmts(mut remaining: Rc>>, mut text: Rc>, mut scope: Rc, mut registry: Rc>>, mut depth: i64) -> Rc { @@ -571,7 +571,7 @@ pub fn emit_go_expr_block(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_cast(cast_expr(expr.clone()), cast_target(expr.clone()), registry, scope)) + v2_rt::concat(make_indent(depth), emit_typed_cast_shared(cast_expr(expr.clone()), cast_target(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) } pub fn emit_go_expr_for_each(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { @@ -579,11 +579,11 @@ pub fn emit_go_expr_for_each(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_index(index_base(expr.clone()), index_expr(expr.clone()), registry, scope)) + v2_rt::concat(make_indent(depth), emit_typed_index_shared(index_base(expr.clone()), index_expr(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) } pub fn emit_go_expr_slice(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_slice(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), registry, scope)) + v2_rt::concat(make_indent(depth), emit_typed_slice_shared(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) } pub fn emit_go_typed_expr(texpr: Rc, registry: Rc>>, scope: Rc, depth: i64, fuel: i64) -> String { @@ -635,46 +635,6 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::con } } -pub fn emit_go_typed_index(base: Rc, index: Rc, registry: Rc>>, scope: Rc) -> String { - { - let spec = language_spec(RenderTarget::Go); -let base_str = emit_go_typed_expr(base.clone(), registry.clone(), scope.clone(), 0, 1024); -let index_str = emit_go_typed_expr(index, registry.clone(), scope.clone(), 0, 1024); -let base_node = normalize_access_type_node(rt_type(base.clone())); -let is_map = node_is_keyed_collection(base_node.clone()); -if is_string_like(RenderTarget::Go, base_node.name.clone()) { - apply_type_template2(spec.indexing.clone().string_index.clone(), base_str, index_str) -} else { - if is_map { - apply_type_template2(spec.indexing.clone().map_index.clone(), base_str, index_str) -} else { - apply_type_template2(spec.indexing.clone().list_index.clone(), base_str, index_str) -} -} -} -} - -pub fn emit_go_typed_slice(base: Rc, start: Rc, end: Rc, registry: Rc>>, scope: Rc) -> String { - { - let spec = language_spec(RenderTarget::Go); -let base_str = emit_go_typed_expr(base.clone(), registry.clone(), scope.clone(), 0, 1024); -let start_str = emit_go_typed_expr(start, registry.clone(), scope.clone(), 0, 1024); -let end_str = emit_go_typed_expr(end, registry.clone(), scope.clone(), 0, 1024); -let base_node = normalize_access_type_node(rt_type(base.clone())); -if is_string_like(RenderTarget::Go, base_node.name.clone()) { - match spec.indexing.clone().string_slice.clone() { - Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), - None => emit_error_expr("unsupported string slice for target".to_string(), RenderTarget::Go), -} -} else { - match spec.indexing.clone().list_slice.clone() { - Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), - None => emit_error_expr("unsupported slice for target".to_string(), RenderTarget::Go), -} -} -} -} - pub fn go_bridge_method_name(method_name: String) -> String { { let parts = Rc::new(method_name.split(&"_".to_string()).map(|s| s.to_string()).collect::>()); @@ -838,21 +798,6 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(tn.clone(), "{".to_string()), fields_s } } -pub fn emit_go_typed_bin_op(op: BinOp, left: Rc, right: Rc, registry: Rc>>, scope: Rc) -> String { - { - let l_str = emit_go_typed_expr(left, registry.clone(), scope.clone(), 0, 1024); -let r_str = emit_go_typed_expr(right, registry.clone(), scope.clone(), 0, 1024); -if is_null_coalesce(op.clone()) { - emit_null_coalesce(l_str, r_str, RenderTarget::Go) -} else { - { - let op_str = emit_bin_op_symbol(op.clone(), RenderTarget::Go); -v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("(".to_string(), l_str), " ".to_string()), op_str), " ".to_string()), r_str), ")".to_string()) -} -} -} -} - pub fn emit_go_typed_string_interp(parts: Rc>>, registry: Rc>>, scope: Rc) -> String { { let has_interpolations = { let mut __found = false; for p in parts.clone().iter().cloned() { if match (*p.clone()).clone() { @@ -900,14 +845,6 @@ state.text.clone().join(&"\n".to_string()) } } -pub fn emit_go_typed_cast(expr: Rc, target: Rc, registry: Rc>>, scope: Rc) -> String { - { - let expr_str = emit_go_typed_expr(expr, registry, scope, 0, 1024); -let ty_str = emit_node_type(target, RenderTarget::Go); -v2_rt::concat(v2_rt::concat(v2_rt::concat(ty_str, "(".to_string()), expr_str), ")".to_string()) -} -} - pub fn emit_go_typed_func_body(body: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { { diff --git a/src/v2/stage0/src/v2_compiler_emit_python.rs b/src/v2/stage0/src/v2_compiler_emit_python.rs index 3917ea82073..654512e5ff9 100644 --- a/src/v2/stage0/src/v2_compiler_emit_python.rs +++ b/src/v2/stage0/src/v2_compiler_emit_python.rs @@ -69,7 +69,7 @@ pub use crate::v2_compiler_infer_items::{ResolvedGraph, TypedModule, ItemInfo, I use crate::v2_compiler_infer_items::ItemKind::{FuncItem}; pub use crate::v2_compiler_infer_service::{is_typed_service_call_receiver, extract_typed_service_name}; pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope, expr_span}; -pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_python_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, typed_named_arg_matches, order_typed_call_args, unique_strings, has_nested_records_node, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, is_service_item, has_service_items, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts}; +pub use crate::v2_compiler_emit::{EmitResult, BlockEmitState, InterpPart, TestProjection, TcoFrame, TcoReassignInput, emit_literal, emit_bin_op_symbol, emit_keyword, emit_container, emit_map_type, emit_node_type, emit_ident, emit_let_binding, emit_simple_expr, emit_unary_op, emit_lambda, emit_error_expr, emit_return, emit_lambda_params, emit_list_lit_expr, emit_shared_expr, emit_default_bin_op, emit_string_literal, escape_python_interp_text, escape_string_literal_body, empty_emit_scope, module_emit_scope, scope_after_expr, lookup_item, typed_named_arg_matches, order_typed_call_args, unique_strings, has_nested_records_node, escape_json_string, module_to_filename, make_indent, to_string, to_string_helper, to_snake, to_screaming_snake, is_upper, to_lower_char, to_upper_char, capitalize_first, sanitize_service_name, service_var_name, test_function_name, apply_type_template1, apply_type_template2, apply_type_template3, apply_named_template, language_spec, is_null_coalesce, emit_null_coalesce, is_type_alias_return_node, is_service_item, has_service_items, is_type_def_item, is_type_alias_item, is_type_decl_item, is_function_item, is_data_def_item, is_service_def_item, is_resource_def_item, extract_test_projections, is_tco_eligible, emit_shared_tco_expr, tco_reassign_core, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, service_field_ctors, TransportKind, classify_transport, seed_bindings, emit_expr_var_shared, emit_expr_field_access_shared, extract_string_interp_parts, emit_typed_cast_shared, emit_typed_index_shared, emit_typed_slice_shared}; use crate::v2_compiler_emit::TransportKind::{RestKind, ShellKind, FileKind, LocalKind}; pub fn emit_py_block_stmts(mut remaining: Rc>>, mut text: Rc>, mut scope: Rc, mut registry: Rc>>, mut depth: i64) -> Rc { @@ -579,7 +579,7 @@ pub fn emit_py_expr_block(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - emit_py_typed_cast(cast_expr(expr.clone()), cast_target(expr.clone()), registry, scope, depth) + emit_typed_cast_shared(cast_expr(expr.clone()), cast_target(expr.clone()), RenderTarget::Python, |child| emit_py_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_py_expr_for_each(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { @@ -587,11 +587,11 @@ pub fn emit_py_expr_for_each(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - emit_py_typed_index(index_base(expr.clone()), index_expr(expr.clone()), registry, scope, depth) + emit_typed_index_shared(index_base(expr.clone()), index_expr(expr.clone()), RenderTarget::Python, |child| emit_py_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_py_expr_slice(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - emit_py_typed_slice(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), registry, scope, depth) + emit_typed_slice_shared(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), RenderTarget::Python, |child| emit_py_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_py_typed_expr(texpr: Rc, registry: Rc>>, scope: Rc, depth: i64, fuel: i64) -> String { @@ -643,46 +643,6 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::con } } -pub fn emit_py_typed_index(base: Rc, index: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let spec = language_spec(RenderTarget::Python); -let base_str = emit_py_typed_expr(base.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); -let index_str = emit_py_typed_expr(index, registry.clone(), scope.clone(), depth.clone(), 1024); -let base_node = normalize_access_type_node(rt_type(base.clone())); -let is_map = node_is_keyed_collection(base_node.clone()); -if is_string_like(RenderTarget::Python, base_node.name.clone()) { - apply_type_template2(spec.indexing.clone().string_index.clone(), base_str, index_str) -} else { - if is_map { - apply_type_template2(spec.indexing.clone().map_index.clone(), base_str, index_str) -} else { - apply_type_template2(spec.indexing.clone().list_index.clone(), base_str, index_str) -} -} -} -} - -pub fn emit_py_typed_slice(base: Rc, start: Rc, end: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let spec = language_spec(RenderTarget::Python); -let base_str = emit_py_typed_expr(base.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); -let start_str = emit_py_typed_expr(start, registry.clone(), scope.clone(), depth.clone(), 1024); -let end_str = emit_py_typed_expr(end, registry.clone(), scope.clone(), depth.clone(), 1024); -let base_node = normalize_access_type_node(rt_type(base.clone())); -if is_string_like(RenderTarget::Python, base_node.name.clone()) { - match spec.indexing.clone().string_slice.clone() { - Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), - None => emit_error_expr("unsupported string slice for target".to_string(), RenderTarget::Python), -} -} else { - match spec.indexing.clone().list_slice.clone() { - Some(tmpl) => apply_type_template3(tmpl.clone(), base_str, start_str, end_str), - None => emit_error_expr("unsupported slice for target".to_string(), RenderTarget::Python), -} -} -} -} - pub fn py_bridge_method_name(method_name: String) -> String { if (method_name.clone().as_str() == "with".to_string().as_str()) { "with_update".to_string() @@ -884,14 +844,6 @@ state.text.clone().join(&"\n".to_string()) } } -pub fn emit_py_typed_cast(expr: Rc, target: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - { - let expr_str = emit_py_typed_expr(expr, registry, scope, depth, 1024); -let ty_str = emit_node_type(target, RenderTarget::Python); -v2_rt::concat(v2_rt::concat(v2_rt::concat(ty_str, "(".to_string()), expr_str), ")".to_string()) -} -} - pub fn emit_py_typed_func_body(body: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { { From d3d8527a8266b3d041d7d912933ab38dac3f31e8 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 12:06:18 -0400 Subject: [PATCH 5/8] CG-3: update ROADMAP with homomorphism progress and blocker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1-3 complete: -206 .dag lines, -481 stage0 lines. Remaining phases deferred — Go/Python depth/indent asymmetry (Go: depth:0 + prefix, Python: depth:depth) blocks clean parameterization of TCO, method dispatch, and item handlers. Co-Authored-By: Claude Opus 4.6 (1M context) --- ROADMAP.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6b5aeb2b3b3..2a99328ac52 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -366,7 +366,15 @@ Make emission fully data-driven. Adding a backend = adding data. - [x] Transport/config: `TransportKind` enum + `classify_transport()` centralize dispatch; `ServiceFieldSet` + `compute_service_fields()` centralize field queries. Remaining per-backend rendering is inherent language differences (HTTP clients, shell runners, file I/O) — addressed by the 3→1 homomorphism. - [ ] LanguageSpec completion — all target-language facts data-driven (see LS lane below) - [x] TypeRendering dissolved — `render_node_type` consumes coercion data directly (PR #331) -- [ ] 3 backends → 1 parameterized homomorphism (~2,500 lines eliminated) +- [~] 3 backends → 1 parameterized homomorphism. Phase 1-3 landed: + shared expr wrappers (`emit_expr_var_shared`, `emit_expr_field_access_shared`, + `extract_string_interp_parts`), shared typed handlers (`emit_typed_cast_shared`, + `emit_typed_index_shared`, `emit_typed_slice_shared`), ExprData accessors, + dead code deletion. -206 .dag lines, -481 stage0 lines. Remaining phases + (TCO, method dispatch, item dispatch) blocked on Go/Python depth/indent + asymmetry: Go renders at `depth: 0` + prefix, Python threads `depth` through. + Unblocking requires aligning indentation strategies or adding `DepthMode` + to shared layer. ### Coercion infrastructure (reference) From 69e8679c67bd0592a3d912e98ccbb18e4b62f7cc Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 12:19:56 -0400 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20update=20ROADMAP=20=E2=80=94=20test?= =?UTF-8?q?=20counts,=20hand-maintained=20file=20counts,=20depth=20blocker?= =?UTF-8?q?=20detail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tests: 294→316 pass, 41→44 ignored - Hand-maintained files: 9→2 (7 eliminated in PR #316) - Expand depth/indent asymmetry blocker with resolution options - Record PR #338 review feedback (MethodTemplateSpec, method name enum) Co-Authored-By: Claude Opus 4.6 (1M context) --- ROADMAP.md | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2a99328ac52..9824ec21435 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -87,7 +87,7 @@ Previously eliminated: | Gate | Command | Status | |------|---------|--------| | Lint | `cargo clippy --workspace -- -D warnings` | GREEN | -| Tests | `cargo test -p v2-compiler-tests` | GREEN (294 pass, 0 fail, 41 ignored) | +| Tests | `cargo test -p v2-compiler-tests` | GREEN (316 pass, 0 fail, 44 ignored) | | Full DSL | `full_dsl_compiles -- --ignored` | GREEN (93 dsl + 29 v2) | | Diagnostic ratchet | `strict_compile_diagnostic_count -- --ignored` | 314 (all complexity violations) | | L1 ratchet | `scripts/l1-ratchet.sh --check` | 37 (target: 0) | @@ -116,7 +116,7 @@ Previously eliminated: - **Fixed-point:** `regen pass N == regen pass N+1`. Two-pass bootstrap required when the emitter changes its own output. - **External dependencies:** cargo, rustc (opaque transforms, not modeled). -- **Hand-maintained files (9):** Copied back during regen, not overwritten. +- **Hand-maintained files (2):** Copied back during regen, not overwritten. These are source, not derived. See Bootstrap Status for list. **Merge workflow problem:** Stage0 `.rs` files are derived, but git @@ -366,15 +366,49 @@ Make emission fully data-driven. Adding a backend = adding data. - [x] Transport/config: `TransportKind` enum + `classify_transport()` centralize dispatch; `ServiceFieldSet` + `compute_service_fields()` centralize field queries. Remaining per-backend rendering is inherent language differences (HTTP clients, shell runners, file I/O) — addressed by the 3→1 homomorphism. - [ ] LanguageSpec completion — all target-language facts data-driven (see LS lane below) - [x] TypeRendering dissolved — `render_node_type` consumes coercion data directly (PR #331) -- [~] 3 backends → 1 parameterized homomorphism. Phase 1-3 landed: +- [~] 3 backends → 1 parameterized homomorphism (PR #338). + **Phase 1-3 complete** (-206 .dag lines, -481 stage0 lines): shared expr wrappers (`emit_expr_var_shared`, `emit_expr_field_access_shared`, `extract_string_interp_parts`), shared typed handlers (`emit_typed_cast_shared`, - `emit_typed_index_shared`, `emit_typed_slice_shared`), ExprData accessors, - dead code deletion. -206 .dag lines, -481 stage0 lines. Remaining phases - (TCO, method dispatch, item dispatch) blocked on Go/Python depth/indent - asymmetry: Go renders at `depth: 0` + prefix, Python threads `depth` through. - Unblocking requires aligning indentation strategies or adding `DepthMode` - to shared layer. + `emit_typed_index_shared`, `emit_typed_slice_shared`), ExprData accessors + (`expr_field_access_summary`, `expr_method_call_semantics`), dead code + deletion (`emit_*_typed_bin_op/cast/index/slice`). + **Phases 4-6 deferred** — blocked on depth/indent asymmetry (see below). + **Review feedback** (recorded, not yet addressed): + (a) Unify `SimpleMethodSpec` + `HigherOrderMethodSpec` into shared + `MethodTemplateSpec` to reduce schema drift across method families. + (b) Method names could be a structural enum (M4 direction) rather than + strings for clearer algebraic dispatch across language extdeps. + +### Depth/indent asymmetry (cross-cutting blocker) + +Go renders sub-expressions at `depth: 0` and manually prepends +`make_indent(level: depth)` at the wrapper level. Python threads +`depth` through all recursive calls. This fundamental difference +pervades every handler and prevents clean parameterization of: +- TCO handlers (~10 functions per backend, ~130 lines potential) +- Method call dispatch (~4 functions per backend, ~80 lines potential) +- Block statement emitters (scope-threading + depth) +- `emit_typed_let`, `emit_typed_for_each` + +**Resolution options:** +1. **Align Go to Python's strategy.** Go's `wrap_result` callback in + `emit_shared_expr` already handles indentation for simple expressions. + If Go switched to `depth: depth` recursion and removed per-wrapper + `prefix` wrapping, the two backends would become structurally + identical. Risk: changes Go's emitted output formatting (whitespace + only, not semantics). +2. **Add `DepthMode` to shared layer.** Shared handlers take a depth + resolver: `sub_depth: fn(Int) -> Int` where Go passes `d => 0` and + Python passes `d => d`. More complex but preserves current behavior. +3. **Accept current state.** -206 lines is the practical limit without + resolving this asymmetry. The remaining ~210 lines of savings may + not justify the design cost. + +**LanguageSpec extensions needed** (once depth is resolved): +- `async_call_prefix: String` — Python: `"await "`, Go/Rust: `""` +- `TcoSyntax` — loop_open, loop_close, break_keyword, continue_str, + stmt_terminator (data-driven TCO formatting) ### Coercion infrastructure (reference) @@ -1091,7 +1125,7 @@ distinction as structural data. - [ ] **BP-1b: Bootstrap cycle.** Model the self-compile cycle: stage0 as bootstrap seed, the fixed-point condition (pass N == pass N+1), and the two-pass rule (required when emitter changes its own output). - Hand-maintained files (9) enumerated as source artifacts distinct + Hand-maintained files (2) enumerated as source artifacts distinct from generated artifacts. - [ ] **BP-1c: `.gitattributes` generation.** Files the pipeline model marks as "generated" get `-merge` in `.gitattributes`. The From 0355f69c55d30677d85ff460620d51434c232f70 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 13:32:14 -0400 Subject: [PATCH 7/8] CG-3: add BlockSyntax to LanguageSpec (data only, no consumers) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model block formatting as data per target language: - block_open/close: braces (Go/Rust) vs colon (Python) - else_clause, match_keyword, case_keyword, arm_separator - stmt_terminator: ";" (Rust) vs "" (Go/Python) - significant_whitespace: true (Python) vs false (Go/Rust) Python's whitespace is a language-spec correctness fact. Go/Rust's whitespace is a readability correctness fact. Both modeled as data on LanguageSpec — the emitter reads, never decides. Add Style Emission (SE) exploratory direction to ROADMAP. Co-Authored-By: Claude Opus 4.6 (1M context) --- ROADMAP.md | 10 +++++ src/v2/languages.dag | 40 ++++++++++++++++++++ src/v2/stage0/src/v2_compiler_languages.rs | 43 ++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 9824ec21435..36c4b5e3253 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1160,6 +1160,16 @@ distinction as structural data. - **Cost algebra extensions**: Pow, Sqrt, Exp; amortized analysis via potential functions; space as peer dimension. See `docs/cost-algebra.md`. +- **Style emission**: Emission formatting (indentation, braces, + statement terminators) should be data-driven from two authorities: + (1) Language spec — significant whitespace (Python), block delimiters, + statement terminators. These are correctness requirements. + (2) Style spec — indent unit, brace placement, readability conventions. + These are readability requirements (correctness during bootstrap, + optional post-bootstrap via external formatters like gofmt/rustfmt). + `BlockSyntax` on `LanguageSpec` is the first step. Future work: + TCO syntax templates, async call prefix, identifier escaping + conventions, post-emission formatting pass. - **Post-Rust path**: .dag → native code (LLVM/Cranelift) directly, no Rust intermediate. Optional — Rust/Go as intermediates may suffice indefinitely. diff --git a/src/v2/languages.dag b/src/v2/languages.dag index 5f65041c9a5..171f1fcb8f2 100644 --- a/src/v2/languages.dag +++ b/src/v2/languages.dag @@ -159,6 +159,24 @@ type ServiceFieldTemplates { // and first argument. Higher-order methods (map, filter, fold, etc.) that need // lambda/closure structure remain as dedicated emitter functions. +// -- Block syntax: structural formatting facts per target language ----------- +// Two authorities: +// Language spec — block delimiters, statement terminators, significant +// whitespace. These are correctness requirements (Python). +// Style spec — indent unit, readability conventions. These are readability +// requirements (correctness during bootstrap; optional post-bootstrap +// via gofmt/rustfmt). +type BlockSyntax { + block_open: String // " {\n" (Go/Rust) or ":\n" (Python) + block_close: String // "}" (Go/Rust) or "" (Python) + else_clause: String // "} else {\n" (Go/Rust) or "else:\n" (Python) + match_keyword: String // "match " (Rust/Python) or "switch " (Go) + case_keyword: String // "" (Rust) or "case " (Go/Python) + arm_separator: String // "," (Rust) or "\n" (Go/Python) + stmt_terminator: String // ";" (Rust) or "" (Go/Python) + significant_whitespace: Bool // true (Python) or false (Go/Rust) +} + type LanguageSpec { target_name: String reserved_words: ReservedWords @@ -171,6 +189,7 @@ type LanguageSpec { annotations: AnnotationRequirements method_templates: Map? service_fields: ServiceFieldTemplates + block_syntax: BlockSyntax } // ========================================================================= @@ -241,6 +260,13 @@ fn rust_spec() -> LanguageSpec { auth_ctor: " auth_token: String::new(),\n", shell_ctor: " working_dir: None,\n", file_ctor: " base_path: \".\".to_string(),\n" + }, + block_syntax: BlockSyntax { + block_open: " \{\n", block_close: "\}", + else_clause: "\} else \{\n", + match_keyword: "match ", case_keyword: "", + arm_separator: ",", stmt_terminator: ";", + significant_whitespace: false } } } @@ -308,6 +334,13 @@ fn python_spec() -> LanguageSpec { auth_ctor: "self.auth_token = auth_token", shell_ctor: "self.working_dir = working_dir", file_ctor: "self.base_path = base_path" + }, + block_syntax: BlockSyntax { + block_open: ":\n", block_close: "", + else_clause: "else:\n", + match_keyword: "match ", case_keyword: "case ", + arm_separator: "\n", stmt_terminator: "", + significant_whitespace: true } } } @@ -375,6 +408,13 @@ fn go_spec() -> LanguageSpec { auth_ctor: "", shell_ctor: "", file_ctor: "" + }, + block_syntax: BlockSyntax { + block_open: " \{\n", block_close: "\}", + else_clause: "\} else \{\n", + match_keyword: "switch ", case_keyword: "case ", + arm_separator: "\n", stmt_terminator: "", + significant_whitespace: false } } } diff --git a/src/v2/stage0/src/v2_compiler_languages.rs b/src/v2/stage0/src/v2_compiler_languages.rs index 96f0a21c5df..0694a18b8ce 100644 --- a/src/v2/stage0/src/v2_compiler_languages.rs +++ b/src/v2/stage0/src/v2_compiler_languages.rs @@ -178,6 +178,18 @@ pub struct ServiceFieldTemplates { pub file_ctor: String, } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct BlockSyntax { + pub block_open: String, + pub block_close: String, + pub else_clause: String, + pub match_keyword: String, + pub case_keyword: String, + pub arm_separator: String, + pub stmt_terminator: String, + pub significant_whitespace: bool, +} + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct LanguageSpec { pub target_name: String, @@ -191,6 +203,7 @@ pub struct LanguageSpec { pub annotations: Rc, pub method_templates: Option>>, pub service_fields: Rc, + pub block_syntax: Rc, } pub fn rust_spec() -> Rc { @@ -258,6 +271,16 @@ pub fn rust_spec() -> Rc { auth_ctor: " auth_token: String::new(),\n".to_string(), shell_ctor: " working_dir: None,\n".to_string(), file_ctor: " base_path: \".\".to_string(),\n".to_string(), +}), + block_syntax: Rc::new(BlockSyntax { + block_open: " {\n".to_string(), + block_close: "}".to_string(), + else_clause: "} else {\n".to_string(), + match_keyword: "match ".to_string(), + case_keyword: "".to_string(), + arm_separator: ",".to_string(), + stmt_terminator: ";".to_string(), + significant_whitespace: false, }), }) } @@ -327,6 +350,16 @@ pub fn python_spec() -> Rc { auth_ctor: "self.auth_token = auth_token".to_string(), shell_ctor: "self.working_dir = working_dir".to_string(), file_ctor: "self.base_path = base_path".to_string(), +}), + block_syntax: Rc::new(BlockSyntax { + block_open: ":\n".to_string(), + block_close: "".to_string(), + else_clause: "else:\n".to_string(), + match_keyword: "match ".to_string(), + case_keyword: "case ".to_string(), + arm_separator: "\n".to_string(), + stmt_terminator: "".to_string(), + significant_whitespace: true, }), }) } @@ -396,6 +429,16 @@ pub fn go_spec() -> Rc { auth_ctor: "".to_string(), shell_ctor: "".to_string(), file_ctor: "".to_string(), +}), + block_syntax: Rc::new(BlockSyntax { + block_open: " {\n".to_string(), + block_close: "}".to_string(), + else_clause: "} else {\n".to_string(), + match_keyword: "switch ".to_string(), + case_keyword: "case ".to_string(), + arm_separator: "\n".to_string(), + stmt_terminator: "".to_string(), + significant_whitespace: false, }), }) } From a7acfa8dc784992306ef8edd1250090932e2a329 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 7 Apr 2026 13:50:46 -0400 Subject: [PATCH 8/8] CG-3: align Go depth threading with Rust/Python convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Go emitter now threads depth:depth for sub-expression recursion, matching Rust and Python's eager depth-threading convention. Previously Go used depth:0 + lazy prefix wrapping via wrap_result. Changes (all in 05_emit_go.dag): - emit_go_typed_expr: wrap_result → identity, recurse depth:0 → depth:depth - 9 simple bridge functions: remove make_indent wrapping - 4 compound handlers: remove first-line indent (keep closing brace indent) - 8 functions gain depth:Int parameter (field_access, typed_call, method_call, algebra_method_call, plain_method_call, first_arg, record_lit, string_interp + interp_segment) - 35 depth:0 sites → depth:depth (except test gen + top-level data_def) - 2 containers (block_stmts, init_block_stmts) add per-statement indent Motivation: Go's indentation is a readability/style concern, not language-spec correctness (unlike Python's significant whitespace). Both are modeled as data on BlockSyntax. Aligning the depth strategy unblocks homomorphism Phases 4-6. Output change: Go emitted code has cosmetic whitespace differences only. Remains valid, readable Go. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/v2/05_emit_go.dag | 148 +++++++++++------------ src/v2/stage0/src/v2_compiler_emit_go.rs | 146 +++++++++++----------- 2 files changed, 142 insertions(+), 152 deletions(-) diff --git a/src/v2/05_emit_go.dag b/src/v2/05_emit_go.dag index f22fe3b3b18..f102c9960cf 100644 --- a/src/v2/05_emit_go.dag +++ b/src/v2/05_emit_go.dag @@ -142,7 +142,8 @@ fn emit_go_block_stmts(remaining: List, text: List, match remaining |> first { None => BlockEmitState { text: text, scope: scope } Some { value: stmt } => - let line = emit_go_typed_expr(texpr: stmt, registry: registry, scope: scope, depth: depth, fuel: 1024) + let raw = emit_go_typed_expr(texpr: stmt, registry: registry, scope: scope, depth: depth, fuel: 1024) + let line = concat(make_indent(level: depth), raw) let next_scope = scope_after_expr(texpr: stmt, scope: scope) emit_go_block_stmts(remaining: remaining |> skip(1), text: list_push(text, line), scope: next_scope, @@ -159,7 +160,8 @@ fn emit_go_init_block_stmts(remaining: List, text: List, match rest |> first { None => BlockEmitState { text: text, scope: scope } Some { value: _ } => - let line = emit_go_typed_expr(texpr: stmt, registry: registry, scope: scope, depth: depth, fuel: 1024) + let raw = emit_go_typed_expr(texpr: stmt, registry: registry, scope: scope, depth: depth, fuel: 1024) + let line = concat(make_indent(level: depth), raw) let next_scope = scope_after_expr(texpr: stmt, scope: scope) emit_go_init_block_stmts(remaining: rest, text: list_push(text, line), scope: next_scope, @@ -376,7 +378,7 @@ fn emit_go_typed_item(item: Node, registry: Map, scope: InferS emit_go_fn_def(name: item_text, params: item.params, inferred: rt_type(n: item), body: item.body.value, registry: registry, scope: scope) } } else if is_data_def_item(item: item) { - emit_go_data_def(name: item_text, type_node: item.type_annotation.value, value: item.body.value, registry: registry, scope: scope) + emit_go_data_def(name: item_text, type_node: item.type_annotation.value, value: item.body.value, registry: registry, scope: scope, depth: 0) } else if is_service_def_item(item: item) { emit_go_service_def(item: item, registry: registry, env: env) } else if is_resource_def_item(item: item) { @@ -493,7 +495,7 @@ fn emit_go_fn_def(name: String, params: List, inferred: Node, body: Node, concat("func ", go_export_ident(name: name), "(", params_str, ")", ret_str, " {\n", body_str, "\n}") } else { - let body_str = emit_go_typed_expr(texpr: body, registry: registry, scope: body_scope, depth: 0, fuel: 1024) + let body_str = emit_go_typed_expr(texpr: body, registry: registry, scope: body_scope, depth: 1, fuel: 1024) concat("func ", go_export_ident(name: name), "(", params_str, ")", ret_str, " {\n", make_indent(level: 1), "return ", body_str, "\n}") } @@ -580,8 +582,8 @@ fn emit_go_variant_pattern(name: String, field_bindings: List) -> String { // Go type switch: case TypeName: name } -fn emit_go_field_access(base: Node, field: String, summary: FieldSummary?, registry: Map, scope: InferScope) -> String { - let base_str = emit_go_typed_expr(texpr: base, registry: registry, scope: scope, depth: 0, fuel: 1024) +fn emit_go_field_access(base: Node, field: String, summary: FieldSummary?, registry: Map, scope: InferScope, depth: Int) -> String { + let base_str = emit_go_typed_expr(texpr: base, registry: registry, scope: scope, depth: depth, fuel: 1024) match summary { Some { value: fs } => match fs.access_style { @@ -593,20 +595,20 @@ fn emit_go_field_access(base: Node, field: String, summary: FieldSummary?, regis } } -fn emit_go_expr_var(expr: Node, depth: Int, source_index: NewlineIndex?) -> String { - concat(make_indent(level: depth), emit_expr_var_shared(expr: expr, target: Go, source_index: source_index)) +fn emit_go_expr_var(expr: Node, source_index: NewlineIndex?) -> String { + emit_expr_var_shared(expr: expr, target: Go, source_index: source_index) } fn emit_go_expr_field_access(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_expr_field_access_shared(expr: expr, target: Go, emit_field: e => emit_go_field_access(base: field_access_base(texpr: e), field: e.name, summary: expr_field_access_summary(texpr: e), registry: registry, scope: scope))) + emit_expr_field_access_shared(expr: expr, target: Go, emit_field: e => emit_go_field_access(base: field_access_base(texpr: e), field: e.name, summary: expr_field_access_summary(texpr: e), registry: registry, scope: scope, depth: depth)) } fn emit_go_expr_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_call(func: expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index), args: expr.children, registry: registry, scope: scope)) + emit_go_typed_call(func: expr_call_func_at(texpr: expr, source_index: scope.type_env.source_index), args: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_go_expr_method_call(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_method_call(receiver: method_receiver(texpr: expr), method: expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index), args: method_arg_nodes(texpr: expr), method_semantics: expr_method_call_semantics(texpr: expr), registry: registry, scope: scope)) + emit_go_typed_method_call(receiver: method_receiver(texpr: expr), method: expr_method_name_at(texpr: expr, source_index: scope.type_env.source_index), args: method_arg_nodes(texpr: expr), method_semantics: expr_method_call_semantics(texpr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_match(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -622,11 +624,11 @@ fn emit_go_expr_let(expr: Node, registry: Map, scope: InferSco } fn emit_go_expr_record_lit(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_record_lit(type_name: record_lit_type_name(texpr: expr), fields: expr.children, registry: registry, scope: scope)) + emit_go_typed_record_lit(type_name: record_lit_type_name(texpr: expr), fields: expr.children, registry: registry, scope: scope, depth: depth) } fn emit_go_expr_string_interp(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_go_typed_string_interp(parts: extract_string_interp_parts(expr: expr), registry: registry, scope: scope)) + emit_go_typed_string_interp(parts: extract_string_interp_parts(expr: expr), registry: registry, scope: scope, depth: depth) } fn emit_go_expr_block(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -634,7 +636,7 @@ fn emit_go_expr_block(expr: Node, registry: Map, scope: InferS } fn emit_go_expr_cast(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_typed_cast_shared(expr: cast_expr(texpr: expr), cast_target_node: cast_target(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) + emit_typed_cast_shared(expr: cast_expr(texpr: expr), cast_target_node: cast_target(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_go_expr_for_each(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -642,22 +644,21 @@ fn emit_go_expr_for_each(expr: Node, registry: Map, scope: Inf } fn emit_go_expr_index(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_typed_index_shared(base: index_base(texpr: expr), index: index_expr(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) + emit_typed_index_shared(base: index_base(texpr: expr), index: index_expr(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_go_expr_slice(expr: Node, registry: Map, scope: InferScope, depth: Int) -> String { - concat(make_indent(level: depth), emit_typed_slice_shared(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: 1024))) + emit_typed_slice_shared(base: slice_base(texpr: expr), start: slice_start(texpr: expr), end: slice_end(texpr: expr), target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: 1024)) } fn emit_go_typed_expr(texpr: Node, registry: Map, scope: InferScope, depth: Int, fuel: Int) -> String { - let prefix = make_indent(level: depth) emit_shared_expr( texpr: texpr, target: Go, source_index: scope.type_env.source_index, - wrap_result: result => if result == "" { "" } else { concat(prefix, result) }, - recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: fuel - 1), - emit_var: expr => emit_go_expr_var(expr: expr, depth: depth, source_index: scope.type_env.source_index), + wrap_result: result => result, + recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: fuel - 1), + emit_var: expr => emit_go_expr_var(expr: expr, source_index: scope.type_env.source_index), emit_field_access: expr => emit_go_expr_field_access(expr: expr, registry: registry, scope: scope, depth: depth), emit_call: expr => emit_go_expr_call(expr: expr, registry: registry, scope: scope, depth: depth), emit_method_call: expr => emit_go_expr_method_call(expr: expr, registry: registry, scope: scope, depth: depth), @@ -671,12 +672,12 @@ fn emit_go_typed_expr(texpr: Node, registry: Map, scope: Infer emit_for_each: expr => emit_go_expr_for_each(expr: expr, registry: registry, scope: scope, depth: depth), emit_index: expr => emit_go_expr_index(expr: expr, registry: registry, scope: scope, depth: depth), emit_slice: expr => emit_go_expr_slice(expr: expr, registry: registry, scope: scope, depth: depth), - emit_bin_op: expr => emit_default_bin_op(texpr: expr, target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: 0, fuel: fuel - 1), wrap_result: result => if result == "" { "" } else { concat(prefix, result) })) + emit_bin_op: expr => emit_default_bin_op(texpr: expr, target: Go, recurse: child => emit_go_typed_expr(texpr: child, registry: registry, scope: scope, depth: depth, fuel: fuel - 1), wrap_result: result => result)) } -fn emit_go_typed_call(func: String, args: List, registry: Map, scope: InferScope) -> String { +fn emit_go_typed_call(func: String, args: List, registry: Map, scope: InferScope, depth: Int) -> String { let ordered_args = order_typed_call_args(args: args, func: func, scope: scope) - let arg_strs = ordered_args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let arg_strs = ordered_args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let callee = lookup_item(registry: registry, name: func) let extra_args = match callee { Some { value: info } => @@ -692,12 +693,12 @@ fn emit_go_typed_call(func: String, args: List, registry: Map, scope: InferScope, depth: Int) -> String { - let coll_str = emit_go_typed_expr(texpr: collection, registry: registry, scope: scope, depth: 0, fuel: 1024) + let coll_str = emit_go_typed_expr(texpr: collection, registry: registry, scope: scope, depth: depth, fuel: 1024) let elem_type = for_each_element_type_node(n: rt_type(n: collection)) let body_scope = extend_scope(scope: scope, name: variable, resolved: elem_type) let body_str = emit_go_typed_expr(texpr: body, registry: registry, scope: body_scope, depth: depth + 1, fuel: 1024) - concat(make_indent(level: depth), "for _, ", emit_ident(name: variable, target: Go), " := range ", coll_str, " {\n", - body_str, "\n", make_indent(level: depth), "}") + concat("for _, ", emit_ident(name: variable, target: Go), " := range ", coll_str, " {\n", + make_indent(level: depth + 1), body_str, "\n", make_indent(level: depth), "}") } fn go_bridge_method_name(method_name: String) -> String { @@ -707,9 +708,9 @@ fn go_bridge_method_name(method_name: String) -> String { pascal_parts |> join(separator: "") } -fn emit_go_algebra_method_call(method_name: String, receiver: Node, args: List, registry: Map, scope: InferScope) -> String { - let recv_str = emit_go_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: 0, fuel: 1024) - let first_arg_str = emit_go_typed_first_arg(args: args, registry: registry, scope: scope) +fn emit_go_algebra_method_call(method_name: String, receiver: Node, args: List, registry: Map, scope: InferScope, depth: Int) -> String { + let recv_str = emit_go_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: depth, fuel: 1024) + let first_arg_str = emit_go_typed_first_arg(args: args, registry: registry, scope: scope, depth: depth) let spec = language_spec(target: Go) match spec.method_templates { Some { value: templates } => match map_get(templates, method_name) { @@ -718,69 +719,69 @@ fn emit_go_algebra_method_call(method_name: String, receiver: Node, args: List let go_name = go_bridge_method_name(method_name: method_name) - let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let all_args = concat([recv_str], arg_strs) let args_str = all_args |> join(separator: ", ") concat("v2rt.", go_name, "(", args_str, ")") } None => let go_name = go_bridge_method_name(method_name: method_name) - let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let all_args = concat([recv_str], arg_strs) let args_str = all_args |> join(separator: ", ") concat("v2rt.", go_name, "(", args_str, ")") } } -fn emit_go_plain_method_call(receiver: Node, method: String, args: List, registry: Map, scope: InferScope) -> String { - let recv_str = emit_go_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: 0, fuel: 1024) - let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) +fn emit_go_plain_method_call(receiver: Node, method: String, args: List, registry: Map, scope: InferScope, depth: Int) -> String { + let recv_str = emit_go_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: depth, fuel: 1024) + let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let args_str = arg_strs |> join(separator: ", ") concat(recv_str, ".", go_export_ident(name: method), "(", args_str, ")") } -fn emit_go_typed_method_call(receiver: Node, method: String, args: List, method_semantics: MethodSemantics?, registry: Map, scope: InferScope) -> String { +fn emit_go_typed_method_call(receiver: Node, method: String, args: List, method_semantics: MethodSemantics?, registry: Map, scope: InferScope, depth: Int) -> String { if method_semantics != none { match method_semantics.value { ServiceMethodSemantics { service_name: svc_name } => { let var_name = service_var_name(service_name: svc_name) - let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let args_str = arg_strs |> join(separator: ", ") concat(var_name, ".", go_export_ident(name: method), "(", args_str, ")") } AlgebraMethodSemantics { method_def: method_def, fold_accumulator_type: _, size_effect: _, cost_shape: _, algebra_template: _ } => let mn = method_def.name - emit_go_algebra_method_call(method_name: mn, receiver: receiver, args: args, registry: registry, scope: scope) + emit_go_algebra_method_call(method_name: mn, receiver: receiver, args: args, registry: registry, scope: scope, depth: depth) PlainMethodSemantics => - emit_go_plain_method_call(receiver: receiver, method: method, args: args, registry: registry, scope: scope) + emit_go_plain_method_call(receiver: receiver, method: method, args: args, registry: registry, scope: scope, depth: depth) } } else { if is_typed_service_call_receiver(receiver: receiver) { match extract_typed_service_name(receiver: receiver) { Some { value: svc_name } => let var_name = service_var_name(service_name: svc_name) - let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let arg_strs = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let args_str = arg_strs |> join(separator: ", ") concat(var_name, ".", go_export_ident(name: method), "(", args_str, ")") None => emit_error_expr(message: "unsupported service receiver", target: Go) } } else { - emit_go_plain_method_call(receiver: receiver, method: method, args: args, registry: registry, scope: scope) + emit_go_plain_method_call(receiver: receiver, method: method, args: args, registry: registry, scope: scope, depth: depth) } } } -fn emit_go_typed_first_arg(args: List, registry: Map, scope: InferScope) -> String { +fn emit_go_typed_first_arg(args: List, registry: Map, scope: InferScope, depth: Int) -> String { match args |> first { - Some { value: a } => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024) + Some { value: a } => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024) None => "panic(\"missing method argument\")" } } fn emit_go_typed_match(scrutinee: Node, arms: List, registry: Map, scope: InferScope, depth: Int) -> String { - let scrut_str = emit_go_typed_expr(texpr: scrutinee, registry: registry, scope: scope, depth: 0, fuel: 1024) + let scrut_str = emit_go_typed_expr(texpr: scrutinee, registry: registry, scope: scope, depth: depth, fuel: 1024) let arm_strs = arms |> map(arm => emit_go_typed_switch_case(arm: arm, registry: registry, scope: scope, depth: depth)) let arms_str = arm_strs |> join(separator: "\n") - concat(make_indent(level: depth), "switch ", scrut_str, " {\n", arms_str, "\n", make_indent(level: depth), "}") + concat("switch ", scrut_str, " {\n", arms_str, "\n", make_indent(level: depth), "}") } fn emit_go_typed_switch_case(arm: Node, registry: Map, scope: InferScope, depth: Int) -> String { @@ -788,31 +789,30 @@ fn emit_go_typed_switch_case(arm: Node, registry: Map, scope: let body_str = emit_go_typed_expr(texpr: arm_body(n: arm), registry: registry, scope: scope, depth: depth + 1, fuel: 1024) let case_keyword = if pat_str == "_" { "default" } else { concat("case ", pat_str) } concat(make_indent(level: depth), case_keyword, ":\n", - body_str) + make_indent(level: depth + 1), body_str) } fn emit_go_typed_if(condition: Node, then_branch: Node, else_branch: Node?, registry: Map, scope: InferScope, depth: Int) -> String { - let prefix = make_indent(level: depth) - let cond_str = emit_go_typed_expr(texpr: condition, registry: registry, scope: scope, depth: 0, fuel: 1024) + let cond_str = emit_go_typed_expr(texpr: condition, registry: registry, scope: scope, depth: depth, fuel: 1024) match else_branch { Some { value: eb } => { - let then_str = emit_go_typed_expr(texpr: then_branch, registry: registry, scope: scope, depth: 0, fuel: 1024) - let else_str = emit_go_typed_expr(texpr: eb, registry: registry, scope: scope, depth: 0, fuel: 1024) - concat(prefix, "func() interface{} { if ", cond_str, " {\n", - make_indent(level: depth + 1), "return ", then_str, "\n", prefix, "} else {\n", - make_indent(level: depth + 1), "return ", else_str, "\n", prefix, "} }()") + let then_str = emit_go_typed_expr(texpr: then_branch, registry: registry, scope: scope, depth: depth, fuel: 1024) + let else_str = emit_go_typed_expr(texpr: eb, registry: registry, scope: scope, depth: depth, fuel: 1024) + concat("func() interface{} { if ", cond_str, " {\n", + make_indent(level: depth + 1), "return ", then_str, "\n", make_indent(level: depth), "} else {\n", + make_indent(level: depth + 1), "return ", else_str, "\n", make_indent(level: depth), "} }()") } None => { let then_str = emit_go_typed_expr(texpr: then_branch, registry: registry, scope: scope, depth: depth + 1, fuel: 1024) - concat(prefix, "if ", cond_str, " {\n", - then_str, "\n", prefix, "}") + concat("if ", cond_str, " {\n", + make_indent(level: depth + 1), then_str, "\n", make_indent(level: depth), "}") } } } fn emit_go_typed_let(name: String, value: Node, body: Node?, registry: Map, scope: InferScope, depth: Int) -> String { - let val_str = emit_go_typed_expr(texpr: value, registry: registry, scope: scope, depth: 0, fuel: 1024) - let let_line = concat(make_indent(level: depth), emit_let_binding(name: name, value: val_str, target: Go)) + let val_str = emit_go_typed_expr(texpr: value, registry: registry, scope: scope, depth: depth, fuel: 1024) + let let_line = emit_let_binding(name: name, value: val_str, target: Go) match body { Some { value: bd } => let next_scope = extend_scope(scope: scope, name: name, resolved: rt_type(n: value)) @@ -821,7 +821,7 @@ fn emit_go_typed_let(name: String, value: Node, body: Node?, registry: Map, registry: Map, scope: InferScope) -> String { +fn emit_go_typed_record_lit(type_name: String?, fields: List, registry: Map, scope: InferScope, depth: Int) -> String { match type_name { None => { // Anonymous record -> map literal @@ -829,7 +829,7 @@ fn emit_go_typed_record_lit(type_name: String?, fields: List, registry: Ma "map[string]interface{}{}" } else { let field_strs = fields |> map(f => - concat("\t\"", field_init_node_name(n: f), "\": ", emit_go_typed_expr(texpr: field_init_node_value(n: f), registry: registry, scope: scope, depth: 0, fuel: 1024), ",") + concat("\t\"", field_init_node_name(n: f), "\": ", emit_go_typed_expr(texpr: field_init_node_value(n: f), registry: registry, scope: scope, depth: depth, fuel: 1024), ",") ) let fields_str = field_strs |> join(separator: "\n") concat("map[string]interface{}{\n", fields_str, "\n}") @@ -840,7 +840,7 @@ fn emit_go_typed_record_lit(type_name: String?, fields: List, registry: Ma concat(tn, "{}") } else { let field_strs = fields |> map(f => - concat(go_export_ident(name: field_init_node_name(n: f)), ": ", emit_go_typed_expr(texpr: field_init_node_value(n: f), registry: registry, scope: scope, depth: 0, fuel: 1024)) + concat(go_export_ident(name: field_init_node_name(n: f)), ": ", emit_go_typed_expr(texpr: field_init_node_value(n: f), registry: registry, scope: scope, depth: depth, fuel: 1024)) ) let fields_str = field_strs |> join(separator: ", ") concat(tn, "{", fields_str, "}") @@ -849,9 +849,9 @@ fn emit_go_typed_record_lit(type_name: String?, fields: List, registry: Ma } -fn emit_go_typed_string_interp(parts: List, registry: Map, scope: InferScope) -> String { +fn emit_go_typed_string_interp(parts: List, registry: Map, scope: InferScope, depth: Int) -> String { let has_interpolations = parts |> any(p => match p { Interpolation { expr: _ } => true _ => false }) - let fmt_parts = parts |> map(p => go_typed_interp_segment(part: p, registry: registry, scope: scope, has_interpolations: has_interpolations)) + let fmt_parts = parts |> map(p => go_typed_interp_segment(part: p, registry: registry, scope: scope, depth: depth, has_interpolations: has_interpolations)) let fmt_str = fmt_parts |> map(p => p.format_segment) |> join(separator: "") let args = fmt_parts |> map(p => p.arg_expr) @@ -864,13 +864,13 @@ fn emit_go_typed_string_interp(parts: List, registry: Map, scope: InferScope, has_interpolations: Bool) -> InterpPart { +fn go_typed_interp_segment(part: StringPart, registry: Map, scope: InferScope, depth: Int, has_interpolations: Bool) -> InterpPart { match part { Text { value: v } => let escaped = if has_interpolations { escape_go_interp_text(s: v) } else { escape_string_literal_body(s: v) } InterpPart { format_segment: escaped, arg_expr: "" } Interpolation { expr: e } => - InterpPart { format_segment: "%v", arg_expr: emit_go_typed_expr(texpr: e, registry: registry, scope: scope, depth: 0, fuel: 1024) } + InterpPart { format_segment: "%v", arg_expr: emit_go_typed_expr(texpr: e, registry: registry, scope: scope, depth: depth, fuel: 1024) } } } @@ -893,7 +893,7 @@ fn emit_go_typed_func_body(body: Node, registry: Map, scope: I let ch = body.children let v = let_value(texpr: body) let inner = let_body(texpr: body) - let val_str = emit_go_typed_expr(texpr: v, registry: registry, scope: scope, depth: 0, fuel: 1024) + let val_str = emit_go_typed_expr(texpr: v, registry: registry, scope: scope, depth: depth, fuel: 1024) let let_line = concat(prefix, emit_let_binding(name: n, value: val_str, target: Go)) let next_scope = extend_scope(scope: scope, name: n, resolved: rt_type(n: v)) match inner { @@ -911,13 +911,13 @@ fn emit_go_typed_func_body(body: Node, registry: Map, scope: I remaining: ss, text: [], scope: scope, registry: registry, depth: depth) let last_stmt = ss |> last let last_str = match last_stmt { - Some { value: s } => concat(prefix, "return ", emit_go_typed_expr(texpr: s, registry: registry, scope: init_state.scope, depth: 0, fuel: 1024), ", nil") + Some { value: s } => concat(prefix, "return ", emit_go_typed_expr(texpr: s, registry: registry, scope: init_state.scope, depth: depth, fuel: 1024), ", nil") None => concat(prefix, "return struct{}{}, nil") } if init_state.text |> count == 0 { last_str } else { concat(init_state.text |> join(separator: "\n"), "\n", last_str) } } } - _ => concat(prefix, "return ", emit_go_typed_expr(texpr: body, registry: registry, scope: scope, depth: 0, fuel: 1024), ", nil") + _ => concat(prefix, "return ", emit_go_typed_expr(texpr: body, registry: registry, scope: scope, depth: depth, fuel: 1024), ", nil") } } @@ -938,7 +938,7 @@ fn emit_go_tco_non_self_call(frame: TcoFrame, registry: Map) - match frame.expr.expr_data { ExprCall { call_semantics: _ } => let f = expr_call_func_at(texpr: frame.expr, source_index: frame.scope.type_env.source_index) - let call_str = emit_go_typed_call(func: f, args: frame.expr.children, registry: registry, scope: frame.scope) + let call_str = emit_go_typed_call(func: f, args: frame.expr.children, registry: registry, scope: frame.scope, depth: frame.depth) concat(prefix, "return ", call_str) _ => concat(prefix, emit_error_expr(message: "emit_go_tco_non_self_call expected ExprCall", target: Go)) } @@ -951,7 +951,7 @@ fn emit_go_tco_if(frame: TcoFrame, fn_name: String, params: List, registry let c = if_condition(texpr: frame.expr) let t = if_then_branch(texpr: frame.expr) let e = if_else_branch(texpr: frame.expr) - let cond_str = emit_go_typed_expr(texpr: c, registry: registry, scope: frame.scope, depth: 0, fuel: 1024) + let cond_str = emit_go_typed_expr(texpr: c, registry: registry, scope: frame.scope, depth: frame.depth, fuel: 1024) let then_str = emit_go_typed_tco_expr(texpr: t, fn_name: fn_name, params: params, registry: registry, scope: frame.scope, depth: frame.depth + 1) match e { Some { value: eb } => @@ -973,7 +973,7 @@ fn emit_go_tco_match(frame: TcoFrame, fn_name: String, params: List, regis ExprMatch => let s = match_scrutinee(texpr: frame.expr) let arm_list = match_arm_nodes(texpr: frame.expr) - let scrut_str = emit_go_typed_expr(texpr: s, registry: registry, scope: frame.scope, depth: 0, fuel: 1024) + let scrut_str = emit_go_typed_expr(texpr: s, registry: registry, scope: frame.scope, depth: frame.depth, fuel: 1024) let arm_strs = arm_list |> map(arm => emit_go_typed_tco_switch_case(arm: arm, fn_name: fn_name, params: params, registry: registry, scope: frame.scope, depth: frame.depth)) let arms_str = arm_strs |> join(separator: "\n") @@ -989,7 +989,7 @@ fn emit_go_tco_let(frame: TcoFrame, fn_name: String, params: List, registr let n = let_binding_name_at(texpr: frame.expr, source_index: frame.scope.type_env.source_index) let v = let_value(texpr: frame.expr) let bd = let_body(texpr: frame.expr) - let val_str = emit_go_typed_expr(texpr: v, registry: registry, scope: frame.scope, depth: 0, fuel: 1024) + let val_str = emit_go_typed_expr(texpr: v, registry: registry, scope: frame.scope, depth: frame.depth, fuel: 1024) let let_line = concat(prefix, emit_let_binding(name: n, value: val_str, target: Go)) let next_scope = extend_scope(scope: frame.scope, name: n, resolved: rt_type(n: v)) match bd { @@ -1024,7 +1024,7 @@ fn emit_go_tco_block(frame: TcoFrame, fn_name: String, params: List, regis fn emit_go_tco_default_return(frame: TcoFrame, registry: Map) -> String { let prefix = make_indent(level: frame.depth) - let val_str = emit_go_typed_expr(texpr: frame.expr, registry: registry, scope: frame.scope, depth: 0, fuel: 1024) + let val_str = emit_go_typed_expr(texpr: frame.expr, registry: registry, scope: frame.scope, depth: frame.depth, fuel: 1024) concat(prefix, "return ", val_str) } @@ -1049,7 +1049,7 @@ fn emit_go_typed_tco_switch_case(arm: Node, fn_name: String, params: List, } fn emit_go_typed_tco_reassign(args: List, params: List, registry: Map, scope: InferScope, depth: Int) -> String { - let ordered_args = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: 0, fuel: 1024)) + let ordered_args = args |> map(a => emit_go_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, fuel: 1024)) let si = scope.type_env.source_index let param_names = params |> map(p => emit_ident(name: param_node_name_at(n: p, source_index: si), target: Go)) let all_lines = tco_reassign_core( @@ -1221,9 +1221,9 @@ fn emit_go_capability_method(cap_node: Node, depth: Int, env: TypeEnv) -> String // data name: Type = value -> Go package-level var // ========================================================================= -fn emit_go_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope) -> String { +fn emit_go_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int) -> String { let ty_str = emit_node_type(n: type_node, target: Go) - let val_str = emit_go_typed_expr(texpr: value, registry: registry, scope: scope, depth: 0, fuel: 1024) + let val_str = emit_go_typed_expr(texpr: value, registry: registry, scope: scope, depth: depth, fuel: 1024) concat("var ", go_export_ident(name: name), " ", ty_str, " = ", val_str) } diff --git a/src/v2/stage0/src/v2_compiler_emit_go.rs b/src/v2/stage0/src/v2_compiler_emit_go.rs index 99a455c6b28..65722c014d9 100644 --- a/src/v2/stage0/src/v2_compiler_emit_go.rs +++ b/src/v2/stage0/src/v2_compiler_emit_go.rs @@ -80,7 +80,8 @@ pub fn emit_go_block_stmts(mut remaining: Rc>>, mut text: Rc { let line = emit_go_typed_expr(stmt.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); + Some(stmt) => { let raw = emit_go_typed_expr(stmt.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); +let line = v2_rt::concat(make_indent(depth.clone()), raw.clone()); let next_scope = scope_after_expr(stmt.clone(), scope.clone()); { let __tco_0 = Rc::new(remaining.iter().cloned().skip(1 as usize).collect::>()); @@ -112,7 +113,8 @@ match rest.clone().first().cloned() { text: text.clone(), scope: scope.clone(), }); }, - Some(_) => { let line = emit_go_typed_expr(stmt.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); + Some(_) => { let raw = emit_go_typed_expr(stmt.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); +let line = v2_rt::concat(make_indent(depth.clone()), raw.clone()); let next_scope = scope_after_expr(stmt.clone(), scope.clone()); { let __tco_0 = rest.clone(); @@ -330,7 +332,7 @@ if is_type_def_item(item.clone()) { } } else { if is_data_def_item(item.clone()) { - emit_go_data_def(item_text, item.type_annotation.clone().clone().unwrap(), item.body.clone().clone().unwrap(), registry, scope.clone()) + emit_go_data_def(item_text, item.type_annotation.clone().clone().unwrap(), item.body.clone().clone().unwrap(), registry, scope.clone(), 0) } else { if is_service_def_item(item.clone()) { emit_go_service_def(item.clone(), registry, env.clone()) @@ -445,7 +447,7 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::con } } else { { - let body_str = emit_go_typed_expr(body.clone(), registry.clone(), body_scope, 0, 1024); + let body_str = emit_go_typed_expr(body.clone(), registry.clone(), body_scope, 1, 1024); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("func ".to_string(), go_export_ident(name.clone())), "(".to_string()), params_str), ")".to_string()), ret_str), " {\n".to_string()), make_indent(1)), "return ".to_string()), body_str), "\n}".to_string()) } } @@ -516,9 +518,9 @@ pub fn emit_go_variant_pattern(name: String, field_bindings: Rc>>) name } -pub fn emit_go_field_access(base: Rc, field: String, summary: Option>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_field_access(base: Rc, field: String, summary: Option>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let base_str = emit_go_typed_expr(base, registry, scope, 0, 1024); + let base_str = emit_go_typed_expr(base, registry, scope, depth, 1024); match summary { Some(fs) => match fs.access_style.clone() { FieldAccessStyle::TupleFirst => v2_rt::concat(base_str, ".First".to_string()), @@ -530,20 +532,20 @@ match summary { } } -pub fn emit_go_expr_var(expr: Rc, depth: i64, source_index: Option>) -> String { - v2_rt::concat(make_indent(depth), emit_expr_var_shared(expr, RenderTarget::Go, source_index)) +pub fn emit_go_expr_var(expr: Rc, source_index: Option>) -> String { + emit_expr_var_shared(expr, RenderTarget::Go, source_index) } pub fn emit_go_expr_field_access(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_expr_field_access_shared(expr, RenderTarget::Go, |e| emit_go_field_access(field_access_base(e.clone()), e.name.clone(), expr_field_access_summary(e.clone()), registry.clone(), scope.clone()))) + emit_expr_field_access_shared(expr, RenderTarget::Go, |e| emit_go_field_access(field_access_base(e.clone()), e.name.clone(), expr_field_access_summary(e.clone()), registry.clone(), scope.clone(), depth.clone())) } pub fn emit_go_expr_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_call(expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()), expr.children.clone(), registry, scope.clone())) + emit_go_typed_call(expr_call_func_at(expr.clone(), scope.type_env.clone().source_index.clone()), expr.children.clone(), registry, scope.clone(), depth) } pub fn emit_go_expr_method_call(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_method_call(method_receiver(expr.clone()), expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), method_arg_nodes(expr.clone()), expr_method_call_semantics(expr.clone()), registry, scope.clone())) + emit_go_typed_method_call(method_receiver(expr.clone()), expr_method_name_at(expr.clone(), scope.type_env.clone().source_index.clone()), method_arg_nodes(expr.clone()), expr_method_call_semantics(expr.clone()), registry, scope.clone(), depth) } pub fn emit_go_expr_match(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { @@ -559,11 +561,11 @@ pub fn emit_go_expr_let(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_record_lit(record_lit_type_name(expr.clone()), expr.children.clone(), registry, scope)) + emit_go_typed_record_lit(record_lit_type_name(expr.clone()), expr.children.clone(), registry, scope, depth) } pub fn emit_go_expr_string_interp(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_go_typed_string_interp(extract_string_interp_parts(expr), registry, scope)) + emit_go_typed_string_interp(extract_string_interp_parts(expr), registry, scope, depth) } pub fn emit_go_expr_block(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { @@ -571,7 +573,7 @@ pub fn emit_go_expr_block(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_typed_cast_shared(cast_expr(expr.clone()), cast_target(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) + emit_typed_cast_shared(cast_expr(expr.clone()), cast_target(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_go_expr_for_each(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { @@ -579,34 +581,23 @@ pub fn emit_go_expr_for_each(expr: Rc, registry: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_typed_index_shared(index_base(expr.clone()), index_expr(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) + emit_typed_index_shared(index_base(expr.clone()), index_expr(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_go_expr_slice(expr: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { - v2_rt::concat(make_indent(depth), emit_typed_slice_shared(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, 1024))) + emit_typed_slice_shared(slice_base(expr.clone()), slice_start(expr.clone()), slice_end(expr.clone()), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)) } pub fn emit_go_typed_expr(texpr: Rc, registry: Rc>>, scope: Rc, depth: i64, fuel: i64) -> String { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { - { - let prefix = make_indent(depth.clone()); -emit_shared_expr(texpr, RenderTarget::Go, scope.type_env.clone().source_index.clone(), |result| if (result.clone().as_str() == "".to_string().as_str()) { - "".to_string() -} else { - v2_rt::concat(prefix.clone(), result.clone()) -}, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, (fuel.clone() - 1)), |expr| emit_go_expr_var(expr.clone(), depth.clone(), scope.type_env.clone().source_index.clone()), |expr| emit_go_expr_field_access(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_call(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_method_call(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_match(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_if(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_let(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_record_lit(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_string_interp(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_block(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_cast(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_for_each(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_index(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_slice(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_default_bin_op(expr.clone(), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), 0, (fuel.clone() - 1)), |result| if (result.clone().as_str() == "".to_string().as_str()) { - "".to_string() -} else { - v2_rt::concat(prefix.clone(), result.clone()) -})) -} + emit_shared_expr(texpr, RenderTarget::Go, scope.type_env.clone().source_index.clone(), |result| result.clone(), |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), (fuel.clone() - 1)), |expr| emit_go_expr_var(expr.clone(), scope.type_env.clone().source_index.clone()), |expr| emit_go_expr_field_access(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_call(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_method_call(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_match(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_if(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_let(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_record_lit(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_string_interp(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_block(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_cast(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_for_each(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_index(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_go_expr_slice(expr.clone(), registry.clone(), scope.clone(), depth.clone()), |expr| emit_default_bin_op(expr.clone(), RenderTarget::Go, |child| emit_go_typed_expr(child.clone(), registry.clone(), scope.clone(), depth.clone(), (fuel.clone() - 1)), |result| result.clone())) }) } -pub fn emit_go_typed_call(func: String, args: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_typed_call(func: String, args: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { let ordered_args = order_typed_call_args(args, func.clone(), scope.clone()); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in ordered_args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in ordered_args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let callee = lookup_item(registry.clone(), func.clone()); let extra_args = match callee { Some(info) => { @@ -627,11 +618,11 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(go_export_ident(func.clone()), "(".to_ pub fn emit_go_typed_for_each(variable: String, collection: Rc, body: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let coll_str = emit_go_typed_expr(collection.clone(), registry.clone(), scope.clone(), 0, 1024); + let coll_str = emit_go_typed_expr(collection.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); let elem_type = for_each_element_type_node(rt_type(collection.clone())); let body_scope = extend_scope(scope.clone(), variable.clone(), elem_type); let body_str = emit_go_typed_expr(body, registry.clone(), body_scope, (depth.clone() + 1), 1024); -v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(make_indent(depth.clone()), "for _, ".to_string()), emit_ident(variable.clone(), RenderTarget::Go)), " := range ".to_string()), coll_str), " {\n".to_string()), body_str), "\n".to_string()), make_indent(depth.clone())), "}".to_string()) +v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("for _, ".to_string(), emit_ident(variable.clone(), RenderTarget::Go)), " := range ".to_string()), coll_str), " {\n".to_string()), make_indent((depth.clone() + 1))), body_str), "\n".to_string()), make_indent(depth.clone())), "}".to_string()) } } @@ -643,10 +634,10 @@ pascal_parts.join(&"".to_string()) } } -pub fn emit_go_algebra_method_call(method_name: String, receiver: Rc, args: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_algebra_method_call(method_name: String, receiver: Rc, args: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let recv_str = emit_go_typed_expr(receiver, registry.clone(), scope.clone(), 0, 1024); -let first_arg_str = emit_go_typed_first_arg(args.clone(), registry.clone(), scope.clone()); + let recv_str = emit_go_typed_expr(receiver, registry.clone(), scope.clone(), depth.clone(), 1024); +let first_arg_str = emit_go_typed_first_arg(args.clone(), registry.clone(), scope.clone(), depth.clone()); let spec = language_spec(RenderTarget::Go); match spec.method_templates.clone() { Some(templates) => match v2_rt::map_get(&templates, method_name.clone()) { @@ -656,7 +647,7 @@ apply_named_template(tmpl.clone(), bindings) }, None => { let go_name = go_bridge_method_name(method_name.clone()); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.clone().iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.clone().iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let all_args = v2_rt::concat(Rc::new(vec![recv_str]), arg_strs); let args_str = all_args.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("v2rt.".to_string(), go_name), "(".to_string()), args_str), ")".to_string()) @@ -664,7 +655,7 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("v2rt.".to_string(), go_ }, None => { let go_name = go_bridge_method_name(method_name.clone()); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.clone().iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.clone().iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let all_args = v2_rt::concat(Rc::new(vec![recv_str]), arg_strs); let args_str = all_args.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("v2rt.".to_string(), go_name), "(".to_string()), args_str), ")".to_string()) @@ -673,60 +664,60 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("v2rt.".to_string(), go_ } } -pub fn emit_go_plain_method_call(receiver: Rc, method: String, args: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_plain_method_call(receiver: Rc, method: String, args: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let recv_str = emit_go_typed_expr(receiver, registry.clone(), scope.clone(), 0, 1024); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); + let recv_str = emit_go_typed_expr(receiver, registry.clone(), scope.clone(), depth.clone(), 1024); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let args_str = arg_strs.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(recv_str, ".".to_string()), go_export_ident(method)), "(".to_string()), args_str), ")".to_string()) } } -pub fn emit_go_typed_method_call(receiver: Rc, method: String, args: Rc>>, method_semantics: Option>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_typed_method_call(receiver: Rc, method: String, args: Rc>>, method_semantics: Option>, registry: Rc>>, scope: Rc, depth: i64) -> String { if (method_semantics.clone() != None) { match (*method_semantics.clone().unwrap()).clone() { MethodSemantics::ServiceMethodSemantics { service_name: svc_name, .. } => { let var_name = service_var_name(svc_name.clone()); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let args_str = arg_strs.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(var_name, ".".to_string()), go_export_ident(method)), "(".to_string()), args_str), ")".to_string()) }, MethodSemantics::AlgebraMethodSemantics { method_def, .. } => { let mn = method_def.name.clone(); -emit_go_algebra_method_call(mn, receiver.clone(), args, registry.clone(), scope.clone()) +emit_go_algebra_method_call(mn, receiver.clone(), args, registry.clone(), scope.clone(), depth.clone()) }, - MethodSemantics::PlainMethodSemantics => emit_go_plain_method_call(receiver.clone(), method, args, registry.clone(), scope.clone()), + MethodSemantics::PlainMethodSemantics => emit_go_plain_method_call(receiver.clone(), method, args, registry.clone(), scope.clone(), depth.clone()), } } else { if is_typed_service_call_receiver(receiver.clone()) { match extract_typed_service_name(receiver.clone()) { Some(svc_name) => { let var_name = service_var_name(svc_name.clone()); -let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); +let arg_strs = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let args_str = arg_strs.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(var_name, ".".to_string()), go_export_ident(method)), "(".to_string()), args_str), ")".to_string()) }, None => emit_error_expr("unsupported service receiver".to_string(), RenderTarget::Go), } } else { - emit_go_plain_method_call(receiver.clone(), method, args, registry.clone(), scope.clone()) + emit_go_plain_method_call(receiver.clone(), method, args, registry.clone(), scope.clone(), depth.clone()) } } } -pub fn emit_go_typed_first_arg(args: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_typed_first_arg(args: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { match args.first().cloned() { - Some(a) => emit_go_typed_expr(arg_value(a.clone()), registry, scope, 0, 1024), + Some(a) => emit_go_typed_expr(arg_value(a.clone()), registry, scope, depth, 1024), None => "panic(\"missing method argument\")".to_string(), } } pub fn emit_go_typed_match(scrutinee: Rc, arms: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let scrut_str = emit_go_typed_expr(scrutinee, registry.clone(), scope.clone(), 0, 1024); + let scrut_str = emit_go_typed_expr(scrutinee, registry.clone(), scope.clone(), depth.clone(), 1024); let arm_strs = Rc::new({ let mut __result = Vec::new(); for arm in arms.iter().cloned() { __result.push(emit_go_typed_switch_case(arm.clone(), registry.clone(), scope.clone(), depth.clone())); } __result }); let arms_str = arm_strs.join(&"\n".to_string()); -v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(make_indent(depth.clone()), "switch ".to_string()), scrut_str), " {\n".to_string()), arms_str), "\n".to_string()), make_indent(depth.clone())), "}".to_string()) +v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("switch ".to_string(), scrut_str), " {\n".to_string()), arms_str), "\n".to_string()), make_indent(depth.clone())), "}".to_string()) } } @@ -739,23 +730,22 @@ let case_keyword = if (pat_str.clone().as_str() == "_".to_string().as_str()) { } else { v2_rt::concat("case ".to_string(), pat_str.clone()) }; -v2_rt::concat(v2_rt::concat(v2_rt::concat(make_indent(depth.clone()), case_keyword), ":\n".to_string()), body_str) +v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(make_indent(depth.clone()), case_keyword), ":\n".to_string()), make_indent((depth.clone() + 1))), body_str) } } pub fn emit_go_typed_if(condition: Rc, then_branch: Rc, else_branch: Option>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let prefix = make_indent(depth.clone()); -let cond_str = emit_go_typed_expr(condition, registry.clone(), scope.clone(), 0, 1024); + let cond_str = emit_go_typed_expr(condition, registry.clone(), scope.clone(), depth.clone(), 1024); match else_branch { Some(eb) => { - let then_str = emit_go_typed_expr(then_branch, registry.clone(), scope.clone(), 0, 1024); -let else_str = emit_go_typed_expr(eb.clone(), registry.clone(), scope.clone(), 0, 1024); -v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix.clone(), "func() interface{} { if ".to_string()), cond_str), " {\n".to_string()), make_indent((depth.clone() + 1))), "return ".to_string()), then_str), "\n".to_string()), prefix.clone()), "} else {\n".to_string()), make_indent((depth.clone() + 1))), "return ".to_string()), else_str), "\n".to_string()), prefix.clone()), "} }()".to_string()) + let then_str = emit_go_typed_expr(then_branch, registry.clone(), scope.clone(), depth.clone(), 1024); +let else_str = emit_go_typed_expr(eb.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); +v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("func() interface{} { if ".to_string(), cond_str), " {\n".to_string()), make_indent((depth.clone() + 1))), "return ".to_string()), then_str), "\n".to_string()), make_indent(depth.clone())), "} else {\n".to_string()), make_indent((depth.clone() + 1))), "return ".to_string()), else_str), "\n".to_string()), make_indent(depth.clone())), "} }()".to_string()) }, None => { let then_str = emit_go_typed_expr(then_branch, registry.clone(), scope.clone(), (depth.clone() + 1), 1024); -v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix.clone(), "if ".to_string()), cond_str), " {\n".to_string()), then_str), "\n".to_string()), prefix.clone()), "}".to_string()) +v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("if ".to_string(), cond_str), " {\n".to_string()), make_indent((depth.clone() + 1))), then_str), "\n".to_string()), make_indent(depth.clone())), "}".to_string()) }, } } @@ -763,8 +753,8 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::con pub fn emit_go_typed_let(name: String, value: Rc, body: Option>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let val_str = emit_go_typed_expr(value.clone(), registry.clone(), scope.clone(), 0, 1024); -let let_line = v2_rt::concat(make_indent(depth.clone()), emit_let_binding(name.clone(), val_str, RenderTarget::Go)); + let val_str = emit_go_typed_expr(value.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); +let let_line = emit_let_binding(name.clone(), val_str, RenderTarget::Go); match body { Some(bd) => { let next_scope = extend_scope(scope.clone(), name.clone(), rt_type(value.clone())); @@ -775,13 +765,13 @@ v2_rt::concat(v2_rt::concat(let_line, "\n".to_string()), emit_go_typed_expr(bd.c } } -pub fn emit_go_typed_record_lit(type_name: Option, fields: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_typed_record_lit(type_name: Option, fields: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { match type_name { None => if ((fields.clone().len() as i64) == 0) { "map[string]interface{}{}".to_string() } else { { - let field_strs = Rc::new({ let mut __result = Vec::new(); for f in fields.clone().iter().cloned() { __result.push(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("\t\"".to_string(), field_init_node_name(f.clone())), "\": ".to_string()), emit_go_typed_expr(field_init_node_value(f.clone()), registry.clone(), scope.clone(), 0, 1024)), ",".to_string())); } __result }); + let field_strs = Rc::new({ let mut __result = Vec::new(); for f in fields.clone().iter().cloned() { __result.push(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("\t\"".to_string(), field_init_node_name(f.clone())), "\": ".to_string()), emit_go_typed_expr(field_init_node_value(f.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)), ",".to_string())); } __result }); let fields_str = field_strs.join(&"\n".to_string()); v2_rt::concat(v2_rt::concat("map[string]interface{}{\n".to_string(), fields_str), "\n}".to_string()) } @@ -790,7 +780,7 @@ v2_rt::concat(v2_rt::concat("map[string]interface{}{\n".to_string(), fields_str) v2_rt::concat(tn.clone(), "{}".to_string()) } else { { - let field_strs = Rc::new({ let mut __result = Vec::new(); for f in fields.clone().iter().cloned() { __result.push(v2_rt::concat(v2_rt::concat(go_export_ident(field_init_node_name(f.clone())), ": ".to_string()), emit_go_typed_expr(field_init_node_value(f.clone()), registry.clone(), scope.clone(), 0, 1024))); } __result }); + let field_strs = Rc::new({ let mut __result = Vec::new(); for f in fields.clone().iter().cloned() { __result.push(v2_rt::concat(v2_rt::concat(go_export_ident(field_init_node_name(f.clone())), ": ".to_string()), emit_go_typed_expr(field_init_node_value(f.clone()), registry.clone(), scope.clone(), depth.clone(), 1024))); } __result }); let fields_str = field_strs.join(&", ".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(tn.clone(), "{".to_string()), fields_str), "}".to_string()) } @@ -798,13 +788,13 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(tn.clone(), "{".to_string()), fields_s } } -pub fn emit_go_typed_string_interp(parts: Rc>>, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_typed_string_interp(parts: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { let has_interpolations = { let mut __found = false; for p in parts.clone().iter().cloned() { if match (*p.clone()).clone() { StringPart::Interpolation { .. } => true, _ => false, } { __found = true; break; } } __found }; -let fmt_parts = Rc::new({ let mut __result = Vec::new(); for p in parts.clone().iter().cloned() { __result.push(go_typed_interp_segment(p.clone(), registry.clone(), scope.clone(), has_interpolations.clone())); } __result }); +let fmt_parts = Rc::new({ let mut __result = Vec::new(); for p in parts.clone().iter().cloned() { __result.push(go_typed_interp_segment(p.clone(), registry.clone(), scope.clone(), depth.clone(), has_interpolations.clone())); } __result }); let fmt_str = Rc::new({ let mut __result = Vec::new(); for p in fmt_parts.clone().iter().cloned() { __result.push(p.format_segment.clone()); } __result }).join(&"".to_string()); let args = Rc::new({ let mut __result = Vec::new(); for a in Rc::new({ let mut __result = Vec::new(); for p in fmt_parts.clone().iter().cloned() { __result.push(p.arg_expr.clone()); } __result }).iter().cloned() { if (a.clone().as_str() != "".to_string().as_str()) { __result.push(a); } } __result }); if ((args.clone().len() as i64) == 0) { @@ -818,7 +808,7 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("fmt.Sprintf(\"".to_stri } } -pub fn go_typed_interp_segment(part: Rc, registry: Rc>>, scope: Rc, has_interpolations: bool) -> Rc { +pub fn go_typed_interp_segment(part: Rc, registry: Rc>>, scope: Rc, depth: i64, has_interpolations: bool) -> Rc { match (*part).clone() { StringPart::Text { value: v, .. } => { let escaped = if has_interpolations { @@ -833,7 +823,7 @@ Rc::new(InterpPart { }, StringPart::Interpolation { expr: e, .. } => Rc::new(InterpPart { format_segment: "%v".to_string(), - arg_expr: emit_go_typed_expr(e.clone(), registry, scope, 0, 1024), + arg_expr: emit_go_typed_expr(e.clone(), registry, scope, depth, 1024), }), } } @@ -856,7 +846,7 @@ match (*body.expr_data.clone()).clone() { let ch = body.children.clone(); let v = let_value(body.clone()); let inner = let_body(body.clone()); -let val_str = emit_go_typed_expr(v.clone(), registry.clone(), scope.clone(), 0, 1024); +let val_str = emit_go_typed_expr(v.clone(), registry.clone(), scope.clone(), depth.clone(), 1024); let let_line = v2_rt::concat(prefix, emit_let_binding(n.clone(), val_str, RenderTarget::Go)); let next_scope = extend_scope(scope.clone(), n.clone(), rt_type(v.clone())); match inner { @@ -873,7 +863,7 @@ if ((ss.clone().len() as i64) == 0) { let init_state = emit_go_init_block_stmts(ss.clone(), Rc::new(vec![]), scope.clone(), registry.clone(), depth.clone()); let last_stmt = ss.clone().last().cloned(); let last_str = match last_stmt { - Some(s) => v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), emit_go_typed_expr(s.clone(), registry.clone(), init_state.scope.clone(), 0, 1024)), ", nil".to_string()), + Some(s) => v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), emit_go_typed_expr(s.clone(), registry.clone(), init_state.scope.clone(), depth.clone(), 1024)), ", nil".to_string()), None => v2_rt::concat(prefix, "return struct{}{}, nil".to_string()), }; if ((init_state.text.clone().len() as i64) == 0) { @@ -884,7 +874,7 @@ if ((init_state.text.clone().len() as i64) == 0) { } } }, - _ => v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), emit_go_typed_expr(body.clone(), registry.clone(), scope.clone(), 0, 1024)), ", nil".to_string()), + _ => v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), emit_go_typed_expr(body.clone(), registry.clone(), scope.clone(), depth.clone(), 1024)), ", nil".to_string()), } } }) @@ -903,7 +893,7 @@ pub fn emit_go_tco_non_self_call(frame: Rc, registry: Rc { let f = expr_call_func_at(frame.expr.clone(), frame.scope.clone().type_env.clone().source_index.clone()); -let call_str = emit_go_typed_call(f, frame.expr.clone().children.clone(), registry, frame.scope.clone()); +let call_str = emit_go_typed_call(f, frame.expr.clone().children.clone(), registry, frame.scope.clone(), frame.depth.clone()); v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), call_str) }, _ => v2_rt::concat(prefix, emit_error_expr("emit_go_tco_non_self_call expected ExprCall".to_string(), RenderTarget::Go)), @@ -919,7 +909,7 @@ match (*frame.expr.clone().expr_data.clone()).clone() { let c = if_condition(frame.expr.clone()); let t = if_then_branch(frame.expr.clone()); let e = if_else_branch(frame.expr.clone()); -let cond_str = emit_go_typed_expr(c, registry.clone(), frame.scope.clone(), 0, 1024); +let cond_str = emit_go_typed_expr(c, registry.clone(), frame.scope.clone(), frame.depth.clone(), 1024); let then_str = emit_go_typed_tco_expr(t, fn_name.clone(), params.clone(), registry.clone(), frame.scope.clone(), (frame.depth.clone() + 1)); match e { Some(eb) => { @@ -941,7 +931,7 @@ match (*frame.expr.clone().expr_data.clone()).clone() { ExprData::ExprMatch => { let s = match_scrutinee(frame.expr.clone()); let arm_list = match_arm_nodes(frame.expr.clone()); -let scrut_str = emit_go_typed_expr(s, registry.clone(), frame.scope.clone(), 0, 1024); +let scrut_str = emit_go_typed_expr(s, registry.clone(), frame.scope.clone(), frame.depth.clone(), 1024); let arm_strs = Rc::new({ let mut __result = Vec::new(); for arm in arm_list.iter().cloned() { __result.push(emit_go_typed_tco_switch_case(arm.clone(), fn_name.clone(), params.clone(), registry.clone(), frame.scope.clone(), frame.depth.clone())); } __result }); let arms_str = arm_strs.join(&"\n".to_string()); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(prefix.clone(), "switch ".to_string()), scrut_str), " {\n".to_string()), arms_str), "\n".to_string()), prefix.clone()), "}".to_string()) @@ -959,7 +949,7 @@ match (*frame.expr.clone().expr_data.clone()).clone() { let n = let_binding_name_at(frame.expr.clone(), frame.scope.clone().type_env.clone().source_index.clone()); let v = let_value(frame.expr.clone()); let bd = let_body(frame.expr.clone()); -let val_str = emit_go_typed_expr(v.clone(), registry.clone(), frame.scope.clone(), 0, 1024); +let val_str = emit_go_typed_expr(v.clone(), registry.clone(), frame.scope.clone(), frame.depth.clone(), 1024); let let_line = v2_rt::concat(prefix, emit_let_binding(n.clone(), val_str, RenderTarget::Go)); let next_scope = extend_scope(frame.scope.clone(), n.clone(), rt_type(v.clone())); match bd { @@ -1003,7 +993,7 @@ if ((init_state.text.clone().len() as i64) == 0) { pub fn emit_go_tco_default_return(frame: Rc, registry: Rc>>) -> String { { let prefix = make_indent(frame.depth.clone()); -let val_str = emit_go_typed_expr(frame.expr.clone(), registry, frame.scope.clone(), 0, 1024); +let val_str = emit_go_typed_expr(frame.expr.clone(), registry, frame.scope.clone(), frame.depth.clone(), 1024); v2_rt::concat(v2_rt::concat(prefix, "return ".to_string()), val_str) } } @@ -1026,10 +1016,10 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(make_indent(depth.clone( pub fn emit_go_typed_tco_reassign(args: Rc>>, params: Rc>>, registry: Rc>>, scope: Rc, depth: i64) -> String { { - let ordered_args = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), 0, 1024)); } __result }); + let ordered_args = Rc::new({ let mut __result = Vec::new(); for a in args.iter().cloned() { __result.push(emit_go_typed_expr(arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), 1024)); } __result }); let si = scope.type_env.clone().source_index.clone(); let param_names = Rc::new({ let mut __result = Vec::new(); for p in params.iter().cloned() { __result.push(emit_ident(param_node_name_at(p.clone(), si.clone()), RenderTarget::Go)); } __result }); -let all_lines = tco_reassign_core(ordered_args, param_names, "tco".to_string(), "".to_string(), " := ".to_string(), "".to_string(), "continue".to_string(), make_indent(depth)); +let all_lines = tco_reassign_core(ordered_args, param_names, "tco".to_string(), "".to_string(), " := ".to_string(), "".to_string(), "continue".to_string(), make_indent(depth.clone())); all_lines.join(&"\n".to_string()) } } @@ -1155,10 +1145,10 @@ v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::con } } -pub fn emit_go_data_def(name: String, type_node: Rc, value: Rc, registry: Rc>>, scope: Rc) -> String { +pub fn emit_go_data_def(name: String, type_node: Rc, value: Rc, registry: Rc>>, scope: Rc, depth: i64) -> String { { let ty_str = emit_node_type(type_node, RenderTarget::Go); -let val_str = emit_go_typed_expr(value, registry, scope, 0, 1024); +let val_str = emit_go_typed_expr(value, registry, scope, depth, 1024); v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat("var ".to_string(), go_export_ident(name)), " ".to_string()), ty_str), " = ".to_string()), val_str) } }