1use std::collections::{HashMap, HashSet};
2use std::fmt::Write;
3
4use crate::analysis::registry::{FieldDef, TypeDef, TypeRegistry};
5use crate::analysis::policy::PolicyRegistry;
6use crate::analysis::types::RustNames;
7use crate::ast::stmt::{Expr, Stmt, TypeExpr};
8use crate::optimization::{Opt, OptimizationConfig};
9use crate::intern::{Interner, Symbol};
10use crate::sourcemap::{OwnershipRole, SourceMap, SourceMapBuilder};
11use crate::token::Span as LogosSpan;
12use crate::registry::SymbolRegistry;
13
14use super::context::{RefinementContext, VariableCapabilities, analyze_variable_capabilities};
15use crate::analysis::callgraph::CallGraph;
16
17fn program_uses_count_ones(stmts: &[Stmt], interner: &Interner) -> bool {
21 fn in_expr(e: &Expr, it: &Interner) -> bool {
22 match e {
23 Expr::Call { function, args } => {
24 it.resolve(*function) == "count_ones" || args.iter().any(|a| in_expr(a, it))
25 }
26 Expr::BinaryOp { left, right, .. } => in_expr(left, it) || in_expr(right, it),
27 Expr::Not { operand } => in_expr(operand, it),
28 Expr::Index { collection, index } => in_expr(collection, it) || in_expr(index, it),
29 Expr::Length { collection } => in_expr(collection, it),
30 _ => false,
31 }
32 }
33 fn in_block(b: &[Stmt], it: &Interner) -> bool {
34 b.iter().any(|s| match s {
35 Stmt::Let { value, .. } | Stmt::Set { value, .. } => in_expr(value, it),
36 Stmt::Return { value } => value.map_or(false, |e| in_expr(e, it)),
37 Stmt::If { cond, then_block, else_block } => {
38 in_expr(cond, it)
39 || in_block(then_block, it)
40 || else_block.map_or(false, |b| in_block(b, it))
41 }
42 Stmt::While { cond, body, .. } => in_expr(cond, it) || in_block(body, it),
43 Stmt::FunctionDef { body, .. } => in_block(body, it),
44 _ => false,
45 })
46 }
47 in_block(stmts, interner)
48}
49use crate::analysis::liveness::LivenessResult;
50use crate::analysis::readonly::{ReadonlyParams, MutableBorrowParams};
51
52use super::detection::{
53 requires_async, requires_vfs, collect_mutable_vars,
54 collect_crdt_register_fields, collect_boxed_fields, collect_async_functions,
55 collect_pure_functions, count_self_calls, is_hashable_type, is_copy_type_expr,
56 should_memoize, body_contains_self_call, should_inline,
57 collect_pipe_sender_params, collect_pipe_vars,
58 collect_mutable_vars_stmt, is_result_type,
59 vec_to_slice_type, vec_to_mut_slice_type, collect_give_arg_indices, is_vec_type_expr,
60 collect_single_char_text_vars, collect_escaping_collection_vars,
61 collect_scalarizable_seqs, collect_interleaved_groups, collect_de_rc_seqs, collect_vec_return_fns,
62 detect_double_recursion_closed_form,
63};
64use super::expr::{codegen_expr, codegen_expr_with_async};
65use super::ffi::{
66 has_wasm_exports, has_c_exports, has_c_exports_with_text,
67 codegen_logos_runtime_preamble, collect_c_export_reference_types,
68 collect_c_export_value_type_structs,
69};
70use super::marshal::{is_text_type, is_char_type, codegen_c_export_with_marshaling};
71use super::policy::codegen_policy_impls;
72use super::stmt::codegen_stmt;
73use super::tce::{
74 is_tail_recursive, body_has_top_level_tail_pair, codegen_tce_loopback,
75 codegen_stmt_acc,
76 detect_mutual_tce_pairs, codegen_mutual_tce_pair, codegen_stmt_tce,
77};
78use crate::tail_call::detect_accumulator_pattern;
79use super::types::{
80 codegen_type_expr, infer_return_type_from_body,
81 codegen_struct_def, codegen_enum_def,
82};
83use super::{escape_rust_ident, is_rust_keyword};
84use super::{
85 collect_c_export_ref_structs, codegen_c_accessors,
86 try_emit_vec_fill_pattern, try_emit_for_range_pattern, try_emit_swap_pattern,
87 try_emit_prefix_reverse,
88 try_emit_seq_copy_pattern, try_emit_seq_from_slice_pattern,
89 try_emit_bare_slice_push_pattern,
90 try_emit_vec_with_capacity_pattern, try_emit_merge_capacity_pattern,
91 try_emit_string_with_capacity_pattern,
92 try_emit_rotate_left_pattern,
93 try_emit_buffer_reuse_while,
94 classify_type_for_c_abi, CAbiClass,
95};
96
97pub(crate) fn body_contains_escape(body: &[Stmt]) -> bool {
101 body.iter().any(|stmt| stmt_contains_escape(stmt))
102}
103
104fn stmt_contains_escape(stmt: &Stmt) -> bool {
105 match stmt {
106 Stmt::Escape { .. } => true,
107 Stmt::Let { value, .. } => expr_contains_escape(value),
108 Stmt::Set { value, .. } => expr_contains_escape(value),
109 Stmt::If { then_block, else_block, .. } => {
110 body_contains_escape(then_block)
111 || else_block.as_ref().map_or(false, |eb| body_contains_escape(eb))
112 }
113 Stmt::While { body, .. } | Stmt::Repeat { body, .. } => body_contains_escape(body),
114 Stmt::Inspect { arms, .. } => arms.iter().any(|arm| body_contains_escape(arm.body)),
115 _ => false,
116 }
117}
118
119fn expr_contains_escape(expr: &Expr) -> bool {
120 matches!(expr, Expr::Escape { .. })
121}
122
123fn is_affine_array_decl(stmt: &Stmt, ctx: &RefinementContext) -> bool {
151 matches!(stmt, Stmt::Let { var, value, .. }
152 if matches!(value, Expr::New { .. }) && ctx.affine_array(*var).is_some())
153}
154
155fn is_const_table_stmt(stmt: &Stmt, ctx: &RefinementContext) -> bool {
159 match stmt {
160 Stmt::Let { var, .. } => ctx.const_table(*var).is_some(),
161 Stmt::Push { collection: Expr::Identifier(c), .. } => ctx.const_table(*c).is_some(),
162 _ => false,
163 }
164}
165
166fn collect_named_syms(stmts: &[Stmt], name: &str, interner: &Interner, out: &mut std::collections::HashSet<Symbol>) {
171 for s in stmts {
172 super::worklist::for_each_stmt_expr(s, &mut |e| {
173 super::worklist::visit_idents(e, &mut |sym| {
174 if name == interner.resolve(sym) {
175 out.insert(sym);
176 }
177 });
178 });
179 match s {
180 Stmt::If { then_block, else_block, .. } => {
181 collect_named_syms(then_block, name, interner, out);
182 if let Some(eb) = else_block {
183 collect_named_syms(eb, name, interner, out);
184 }
185 }
186 Stmt::While { body, .. } | Stmt::Repeat { body, .. } => {
187 collect_named_syms(body, name, interner, out);
188 }
189 Stmt::Inspect { arms, .. } => {
190 for arm in arms {
191 collect_named_syms(arm.body, name, interner, out);
192 }
193 }
194 _ => {}
195 }
196 }
197}
198
199fn narrow_seqs<'a>(
204 body: &'a [Stmt<'a>],
205 de_rc: &std::collections::HashSet<Symbol>,
206 affine: &HashMap<Symbol, super::affine_array::AffineArrayInfo>,
207 worklists: &HashMap<Symbol, super::worklist::WorklistInfo>,
208 interner: &Interner,
209) -> HashMap<Symbol, super::narrow::NarrowInfo> {
210 if !crate::optimize::active_config().is_on(crate::optimization::Opt::Narrow) {
211 return HashMap::new();
212 }
213 let mut n = super::narrow::detect_narrowable(body, de_rc, interner);
214 n.retain(|sym, _| {
215 if affine.contains_key(sym) {
217 crate::optimize::mark_preempted(
218 crate::optimization::Opt::Affine,
219 crate::optimization::Opt::Narrow,
220 );
221 return false;
222 }
223 !worklists.contains_key(sym)
224 });
225 if !n.is_empty() {
226 crate::optimize::mark_fired(crate::optimization::Opt::Narrow);
227 }
228 if std::env::var_os("LOGOS_NARROW_TRACE").is_some() {
229 for (sym, info) in &n {
230 eprintln!(
231 "LOGOS_NARROW: `{}` → Vec<i32>{}",
232 interner.resolve(*sym),
233 if info.guards.is_empty() {
234 " (static range)".to_string()
235 } else {
236 format!(" (guards: {})", info.guards.join(" && "))
237 }
238 );
239 }
240 }
241 n
242}
243
244fn register_fn_roles(
251 ctx: &mut RefinementContext,
252 borrow_params_map: &HashMap<Symbol, HashSet<usize>>,
253 mut_borrow_params_map: &HashMap<Symbol, HashSet<usize>>,
254 value_mutable_params_map: &HashMap<Symbol, HashSet<usize>>,
255) {
256 let mut role_fns: HashSet<Symbol> = HashSet::new();
257 role_fns.extend(borrow_params_map.keys().copied());
258 role_fns.extend(mut_borrow_params_map.keys().copied());
259 role_fns.extend(value_mutable_params_map.keys().copied());
260 let empty = HashSet::new();
261 for fn_sym in role_fns {
262 let b = borrow_params_map.get(&fn_sym).unwrap_or(&empty);
263 let m = mut_borrow_params_map.get(&fn_sym).unwrap_or(&empty);
264 let v = value_mutable_params_map.get(&fn_sym).unwrap_or(&empty);
265 ctx.register_variable_type(fn_sym, super::encode_fn_roles(b, m, v));
266 }
267}
268
269fn scope_array_sizes(
274 body: &[Stmt],
275 all_stmts: &[Stmt],
276 is_main: bool,
277 returns_vec: bool,
278 this_ret: Option<&super::affine_array::ArrayReturnInfo>,
279 borrow_params: &HashMap<Symbol, HashSet<usize>>,
280 mut_borrow_params: &HashMap<Symbol, HashSet<usize>>,
281 vec_return_fns: &HashSet<Symbol>,
282 array_return_fns: &HashMap<Symbol, super::affine_array::ArrayReturnInfo>,
283 interner: &Interner,
284) -> HashMap<String, usize> {
285 let de_rc = collect_de_rc_seqs(body, interner, borrow_params, mut_borrow_params, vec_return_fns, returns_vec);
286 let mut m: HashMap<String, usize> = HashMap::new();
287 let mut put = |sym: Symbol, n: usize| { m.insert(interner.resolve(sym).to_string(), n); };
288 if is_main {
289 for (v, info) in collect_scalarizable_seqs(body, interner) { put(v, info.len); }
293 } else {
294 for (v, info) in super::affine_array::detect_const_tables(body, all_stmts, &de_rc, borrow_params, interner) { put(v, info.values.len()); }
295 for (v, info) in super::affine_array::detect_scratch_buffers(body, &de_rc, borrow_params, interner) { put(v, info.len); }
296 for (v, info) in super::affine_array::detect_indexed_buffers(body, &de_rc, interner) { put(v, info.len); }
297 }
298 for (v, (_, len)) in super::affine_array::detect_straightline_buffers(body, &de_rc, borrow_params, interner) { put(v, len); }
299 for (v, ty) in super::affine_array::array_var_types(body, this_ret, array_return_fns) {
300 if let Some(n) = ty.strip_prefix('[').and_then(|s| s.rsplit_once("; ")).and_then(|(_, n)| n.strip_suffix(']')).and_then(|n| n.parse::<usize>().ok()) {
301 put(v, n);
302 }
303 }
304 m
305}
306
307fn record_call_arg_sizes(
310 e: &Expr,
311 borrow_params: &HashMap<Symbol, HashSet<usize>>,
312 sizes: &HashMap<String, usize>,
313 interner: &Interner,
314 agg: &mut HashMap<(Symbol, usize), Option<usize>>,
315) {
316 match e {
317 Expr::Call { function, args } => {
318 if let Some(bset) = borrow_params.get(function) {
319 for (i, a) in args.iter().enumerate() {
320 if bset.contains(&i) {
321 let val = if let Expr::Identifier(v) = a { sizes.get(interner.resolve(*v)).copied() } else { None };
322 agg.entry((*function, i)).and_modify(|cur| { if *cur != val { *cur = None; } }).or_insert(val);
323 }
324 }
325 }
326 for a in args {
327 record_call_arg_sizes(a, borrow_params, sizes, interner, agg);
328 }
329 }
330 Expr::BinaryOp { left, right, .. } | Expr::Union { left, right } | Expr::Intersection { left, right } | Expr::Range { start: left, end: right } => {
331 record_call_arg_sizes(left, borrow_params, sizes, interner, agg);
332 record_call_arg_sizes(right, borrow_params, sizes, interner, agg);
333 }
334 Expr::Index { collection, index } => {
335 record_call_arg_sizes(collection, borrow_params, sizes, interner, agg);
336 record_call_arg_sizes(index, borrow_params, sizes, interner, agg);
337 }
338 Expr::Not { operand } => record_call_arg_sizes(operand, borrow_params, sizes, interner, agg),
339 Expr::Length { collection } | Expr::Copy { expr: collection } | Expr::Give { value: collection } | Expr::OptionSome { value: collection } | Expr::FieldAccess { object: collection, .. } => {
340 record_call_arg_sizes(collection, borrow_params, sizes, interner, agg)
341 }
342 Expr::CallExpr { callee, args } => {
343 record_call_arg_sizes(callee, borrow_params, sizes, interner, agg);
344 for a in args {
345 record_call_arg_sizes(a, borrow_params, sizes, interner, agg);
346 }
347 }
348 Expr::List(items) | Expr::Tuple(items) => {
349 for it in items {
350 record_call_arg_sizes(it, borrow_params, sizes, interner, agg);
351 }
352 }
353 _ => {}
354 }
355}
356
357fn walk_call_sizes<'a>(
358 scope: &[Stmt<'a>],
359 borrow_params: &HashMap<Symbol, HashSet<usize>>,
360 sizes: &HashMap<String, usize>,
361 interner: &Interner,
362 agg: &mut HashMap<(Symbol, usize), Option<usize>>,
363) {
364 for s in scope {
365 super::worklist::for_each_stmt_expr(s, &mut |e| record_call_arg_sizes(e, borrow_params, sizes, interner, agg));
366 match s {
367 Stmt::If { then_block, else_block, .. } => {
368 walk_call_sizes(then_block, borrow_params, sizes, interner, agg);
369 if let Some(eb) = else_block {
370 walk_call_sizes(eb, borrow_params, sizes, interner, agg);
371 }
372 }
373 Stmt::While { body, .. } | Stmt::Repeat { body, .. } => walk_call_sizes(body, borrow_params, sizes, interner, agg),
374 Stmt::Inspect { arms, .. } => {
375 for arm in arms {
376 walk_call_sizes(arm.body, borrow_params, sizes, interner, agg);
377 }
378 }
379 _ => {}
380 }
381 }
382}
383
384fn fixed_array_params(
388 stmts: &[Stmt],
389 borrow_params: &HashMap<Symbol, HashSet<usize>>,
390 mut_borrow_params: &HashMap<Symbol, HashSet<usize>>,
391 vec_return_fns: &HashSet<Symbol>,
392 array_return_fns: &HashMap<Symbol, super::affine_array::ArrayReturnInfo>,
393 interner: &Interner,
394) -> HashMap<(Symbol, usize), usize> {
395 if !crate::optimize::active_config().is_on(crate::optimization::Opt::Scalarize) {
396 return HashMap::new();
397 }
398 let mut agg: HashMap<(Symbol, usize), Option<usize>> = HashMap::new();
399 let main_sizes = scope_array_sizes(stmts, stmts, true, false, None, borrow_params, mut_borrow_params, vec_return_fns, array_return_fns, interner);
400 walk_call_sizes(stmts, borrow_params, &main_sizes, interner, &mut agg);
401 for s in stmts {
402 if let Stmt::FunctionDef { name, body, is_native: false, .. } = s {
403 let rv = vec_return_fns.contains(name);
404 let sizes = scope_array_sizes(body, stmts, false, rv, array_return_fns.get(name), borrow_params, mut_borrow_params, vec_return_fns, array_return_fns, interner);
405 walk_call_sizes(body, borrow_params, &sizes, interner, &mut agg);
406 }
407 }
408 agg.into_iter().filter_map(|(k, v)| v.map(|n| (k, n))).collect()
409}
410
411pub fn codegen_program(stmts: &[Stmt], registry: &TypeRegistry, policies: &PolicyRegistry, interner: &Interner, type_env: &crate::analysis::types::TypeEnv, cfg: &OptimizationConfig) -> String {
412 codegen_program_with_proven(stmts, registry, policies, interner, type_env, cfg, "proven", None)
413}
414
415pub fn codegen_program_with_proven(stmts: &[Stmt], registry: &TypeRegistry, policies: &PolicyRegistry, interner: &Interner, type_env: &crate::analysis::types::TypeEnv, cfg: &OptimizationConfig, module_name: &str, proven: Option<&str>) -> String {
425 codegen_program_inner(stmts, registry, policies, interner, type_env, cfg, module_name, proven, None).0
426}
427
428pub fn codegen_program_mapped(
434 stmts: &[Stmt],
435 registry: &TypeRegistry,
436 policies: &PolicyRegistry,
437 interner: &Interner,
438 type_env: &crate::analysis::types::TypeEnv,
439 cfg: &OptimizationConfig,
440 stmt_spans: &[LogosSpan],
441 logos_source: &str,
442) -> (String, SourceMap) {
443 let (code, map) = codegen_program_inner(
444 stmts, registry, policies, interner, type_env, cfg, "proven", None,
445 Some((stmt_spans, logos_source)),
446 );
447 (code, map.expect("mapping was requested"))
448}
449
450#[allow(clippy::too_many_arguments)]
451fn codegen_program_inner(stmts: &[Stmt], registry: &TypeRegistry, policies: &PolicyRegistry, interner: &Interner, type_env: &crate::analysis::types::TypeEnv, cfg: &OptimizationConfig, module_name: &str, proven: Option<&str>, mapping: Option<(&[LogosSpan], &str)>) -> (String, Option<SourceMap>) {
452 crate::optimize::set_active_config(*cfg);
453 let mut output = String::new();
454 let mut line_records: Vec<(u32, LogosSpan)> = Vec::new();
457
458 writeln!(output, "#[allow(unused_imports)]").unwrap();
461 writeln!(output, "use std::fmt::Write as _;").unwrap();
462 writeln!(output, "use logicaffeine_data::*;").unwrap();
463 writeln!(output, "use logicaffeine_system::*;\n").unwrap();
464 if program_uses_count_ones(stmts, interner) {
469 writeln!(
470 output,
471 "#[inline(always)]\nfn count_ones(x: i64) -> i64 {{ (x as u64).count_ones() as i64 }}\n"
472 )
473 .unwrap();
474 }
475 if super::peephole::stmts_contain_naive_search(stmts, interner) {
481 writeln!(output, "{}", super::strsearch::RUNTIME_SRC).unwrap();
482 }
483
484 if has_wasm_exports(stmts, interner) {
486 writeln!(output, "use wasm_bindgen::prelude::*;\n").unwrap();
487 }
488
489 if has_c_exports_with_text(stmts, interner) {
491 writeln!(output, "use std::ffi::{{CStr, CString}};\n").unwrap();
492 }
493
494 let c_exports_exist = has_c_exports(stmts, interner);
496 if c_exports_exist {
497 output.push_str(&codegen_logos_runtime_preamble());
498 }
499
500 if let Some(proven) = proven {
507 if !proven.trim().is_empty() {
508 writeln!(output, "pub mod {module_name} {{").unwrap();
509 writeln!(output, " #![allow(dead_code, unused, non_snake_case)]").unwrap();
510 writeln!(output, " use super::*;").unwrap();
511 output.push_str(proven);
512 if !proven.ends_with('\n') {
513 writeln!(output).unwrap();
514 }
515 writeln!(output, "}}").unwrap();
516 writeln!(output, "use {module_name}::*;\n").unwrap();
517 }
518 }
519
520 let (lww_fields, mv_fields) = collect_crdt_register_fields(registry, interner);
523
524 let async_functions = collect_async_functions(stmts);
526
527 let pure_functions = collect_pure_functions(stmts);
529
530 let main_pipe_vars = collect_pipe_vars(stmts);
532
533 let boxed_fields = collect_boxed_fields(registry, interner);
535
536 let c_abi_value_structs: HashSet<Symbol> = if c_exports_exist {
538 collect_c_export_value_type_structs(stmts, interner, registry)
539 } else {
540 HashSet::new()
541 };
542
543 let c_abi_ref_structs: HashSet<Symbol> = if c_exports_exist {
545 collect_c_export_ref_structs(stmts, interner, registry)
546 } else {
547 HashSet::new()
548 };
549
550 let mut structs: Vec<_> = registry.iter_types()
552 .filter_map(|(name, def)| {
553 if let TypeDef::Struct { fields, generics, is_portable, is_shared } = def {
554 if !fields.is_empty() || !generics.is_empty() {
555 Some((*name, fields.clone(), generics.clone(), *is_portable, *is_shared))
556 } else {
557 None
558 }
559 } else {
560 None
561 }
562 })
563 .collect();
564 structs.sort_by(|a, b| interner.resolve(a.0).cmp(interner.resolve(b.0)));
568
569 let mut enums: Vec<_> = registry.iter_types()
571 .filter_map(|(name, def)| {
572 if let TypeDef::Enum { variants, generics, is_portable, is_shared } = def {
573 if !variants.is_empty() || !generics.is_empty() {
574 Some((*name, variants.clone(), generics.clone(), *is_portable, *is_shared))
575 } else {
576 None
577 }
578 } else {
579 None
580 }
581 })
582 .collect();
583 enums.sort_by(|a, b| interner.resolve(a.0).cmp(interner.resolve(b.0)));
584
585 if !structs.is_empty() || !enums.is_empty() {
587 writeln!(output, "pub mod user_types {{").unwrap();
588 writeln!(output, " use super::*;\n").unwrap();
589
590 for (name, fields, generics, is_portable, is_shared) in &structs {
591 output.push_str(&codegen_struct_def(*name, fields, generics, *is_portable, *is_shared, interner, 4, &c_abi_value_structs, &c_abi_ref_structs));
592 }
593
594 for (name, variants, generics, is_portable, is_shared) in &enums {
595 output.push_str(&codegen_enum_def(*name, variants, generics, *is_portable, *is_shared, interner, 4));
596 }
597
598 writeln!(output, "}}\n").unwrap();
599 writeln!(output, "use user_types::*;\n").unwrap();
600 }
601
602 output.push_str(&codegen_policy_impls(policies, interner));
604
605 let mutual_tce_pairs = detect_mutual_tce_pairs(stmts, interner);
607 let mut mutual_tce_members: HashSet<Symbol> = HashSet::new();
608 for (a, b) in &mutual_tce_pairs {
609 mutual_tce_members.insert(*a);
610 mutual_tce_members.insert(*b);
611 }
612 let mut mutual_tce_emitted: HashSet<Symbol> = HashSet::new();
613
614 let callgraph = CallGraph::build(stmts, interner);
620 let readonly_params = ReadonlyParams::analyze(stmts, &callgraph, type_env);
621
622 let mut borrow_params_map: HashMap<Symbol, HashSet<usize>> = HashMap::new();
623 for stmt in stmts {
624 if let Stmt::FunctionDef { name, params, body, is_native, is_exported, opt_flags, .. } = stmt {
625 if *is_native {
630 if crate::optimize::active_config().merged(opt_flags).is_on(Opt::Borrow) {
631 let indices: HashSet<usize> = params.iter().enumerate()
632 .filter(|(_, (_, param_type))| is_vec_type_expr(param_type, interner))
633 .map(|(i, _)| i)
634 .collect();
635 if !indices.is_empty() {
636 borrow_params_map.insert(*name, indices);
637 }
638 }
639 continue;
640 }
641 if *is_exported || mutual_tce_members.contains(name) {
643 continue;
644 }
645 if !crate::optimize::active_config().merged(opt_flags).is_on(Opt::Borrow) {
647 continue;
648 }
649 if is_tail_recursive(*name, body) {
653 continue;
654 }
655 if detect_accumulator_pattern(*name, body).is_some() {
656 continue;
657 }
658 if body_contains_escape(body) {
660 continue;
661 }
662 let indices: HashSet<usize> = params.iter().enumerate()
663 .filter(|(_, (sym, param_type))| {
664 readonly_params.is_readonly(*name, *sym)
665 && is_vec_type_expr(param_type, interner)
666 })
667 .map(|(i, _)| i)
668 .collect();
669 if !indices.is_empty() {
670 let give_indices = collect_give_arg_indices(*name, stmts);
671 let filtered: HashSet<usize> = indices.difference(&give_indices).copied().collect();
672 if !filtered.is_empty() {
673 borrow_params_map.insert(*name, filtered);
674 crate::optimize::mark_fired(Opt::Borrow);
675 }
676 }
677 }
678 }
679
680 let mutable_borrow_params = MutableBorrowParams::analyze(stmts, &callgraph, type_env);
683
684 let mut mut_borrow_params_map: HashMap<Symbol, HashSet<usize>> = HashMap::new();
685 for stmt in stmts {
686 if let Stmt::FunctionDef { name, params, body, is_native, is_exported, opt_flags, .. } = stmt {
687 if *is_native || *is_exported || mutual_tce_members.contains(name) {
688 continue;
689 }
690 if !crate::optimize::active_config().merged(opt_flags).is_on(Opt::Borrow) {
692 continue;
693 }
694 if is_tail_recursive(*name, body) || detect_accumulator_pattern(*name, body).is_some() {
695 continue;
696 }
697 if body_contains_escape(body) {
698 continue;
699 }
700 let readonly_indices = borrow_params_map.get(name).cloned().unwrap_or_default();
702 let indices: HashSet<usize> = params.iter().enumerate()
703 .filter(|(i, (sym, param_type))| {
704 mutable_borrow_params.is_mutable_borrow(*name, *sym)
711 && !readonly_indices.contains(i)
712 && is_vec_type_expr(param_type, interner)
713 })
714 .map(|(i, _)| i)
715 .collect();
716 if !indices.is_empty() {
717 mut_borrow_params_map.insert(*name, indices);
718 crate::optimize::mark_fired(Opt::Borrow);
719 }
720 }
721 }
722
723 let mut value_mutable_params_map: HashMap<Symbol, HashSet<usize>> = HashMap::new();
729 if crate::semantics::collections::value_semantics_enabled() {
730 for stmt in stmts {
731 if let Stmt::FunctionDef { name, params, is_native: false, .. } = stmt {
732 let idx: HashSet<usize> = params.iter().enumerate()
733 .filter(|(_, (_, ty))| {
734 matches!(ty, crate::ast::stmt::TypeExpr::Mutable { .. })
735 })
736 .map(|(i, _)| i)
737 .collect();
738 if !idx.is_empty() {
739 value_mutable_params_map.insert(*name, idx);
740 }
741 }
742 }
743 }
744
745 let liveness = LivenessResult::analyze(stmts);
748
749 let mut vec_return_fns = collect_vec_return_fns(stmts, interner, &borrow_params_map, &mut_borrow_params_map);
754 let array_return_fns = super::affine_array::collect_array_return_fns(stmts, &borrow_params_map, interner);
758 vec_return_fns.retain(|f| !array_return_fns.contains_key(f));
759 let fixed_array_param_map = fixed_array_params(stmts, &borrow_params_map, &mut_borrow_params_map, &vec_return_fns, &array_return_fns, interner);
762
763 let mut fn_returns_map: HashMap<Symbol, String> = stmts.iter().filter_map(|s| {
768 if let Stmt::FunctionDef { name, return_type: Some(rt), .. } = s {
769 let ty = codegen_type_expr(rt, interner);
770 let ty = if let Some(info) = array_return_fns.get(name) {
771 format!("[{}; {}]", info.elem_ty, info.len)
772 } else if vec_return_fns.contains(name) {
773 ty.replacen("LogosSeq<", "Vec<", 1)
774 } else {
775 ty
776 };
777 Some((*name, ty))
778 } else {
779 None
780 }
781 }).collect();
782
783 let bigint_fns = super::bigint_promote::bigint_returning_fns(stmts, interner);
788 for f in &bigint_fns {
789 fn_returns_map.insert(*f, "i64|__bigint".to_string());
790 }
791 super::expr::set_bigint_returning_fns(&bigint_fns);
795
796 const MAX_HOIST_ORACLE_STMTS: usize = 5_000;
801 let oracle: Option<std::rc::Rc<crate::optimize::OracleFacts>> =
802 if super::hoist::hoisting_disabled() || stmts.len() > MAX_HOIST_ORACLE_STMTS {
803 None
804 } else {
805 Some(std::rc::Rc::new(crate::optimize::oracle_analyze_with_entry_guards(stmts, interner)))
806 };
807
808 for (top_idx, stmt) in stmts.iter().enumerate() {
810 let fn_emit_start = line_count(&output) + 1;
811 if let Stmt::FunctionDef { name, params, generics, body, return_type, is_native, native_path, is_exported, export_target, opt_flags } = stmt {
812 if mutual_tce_members.contains(name) {
813 if !mutual_tce_emitted.contains(name) {
815 if let Some((a, b)) = mutual_tce_pairs.iter().find(|(a, b)| *a == *name || *b == *name) {
817 output.push_str(&codegen_mutual_tce_pair(*a, *b, stmts, interner, &lww_fields, &mv_fields, &async_functions, &boxed_fields, registry, type_env));
818 mutual_tce_emitted.insert(*a);
819 mutual_tce_emitted.insert(*b);
820 }
821 }
822 } else {
824 output.push_str(&codegen_function_def(*name, generics, params, body, stmts, return_type.as_ref().copied(), *is_native, *native_path, *is_exported, *export_target, interner, &lww_fields, &mv_fields, &async_functions, &boxed_fields, registry, &pure_functions, type_env, &borrow_params_map, &mut_borrow_params_map, &value_mutable_params_map, &liveness, opt_flags, &fn_returns_map, &vec_return_fns, &array_return_fns, &fixed_array_param_map, oracle.as_ref(), &bigint_fns));
825 }
826 if let Some((spans, _)) = mapping {
827 record_emitted_lines(&output, fn_emit_start, spans.get(top_idx).copied(), &mut line_records);
828 }
829 }
830 }
831
832 if c_exports_exist {
834 let ref_types = collect_c_export_reference_types(stmts, interner, registry);
835 for ref_ty in &ref_types {
836 output.push_str(&codegen_c_accessors(ref_ty, interner, registry));
837 }
838 }
839
840 let main_stmts: Vec<&Stmt> = stmts.iter()
842 .filter(|s| !matches!(s, Stmt::FunctionDef { .. }))
843 .collect();
844 let mut main_mutable_vars = HashSet::new();
845 for stmt in &main_stmts {
846 collect_mutable_vars_stmt(stmt, &mut main_mutable_vars);
847 }
848
849 let single_char_vars = collect_single_char_text_vars(stmts, interner);
851
852 if requires_async(stmts) {
855 writeln!(output, "#[tokio::main]").unwrap();
856 writeln!(output, "async fn main() {{").unwrap();
857 } else {
858 writeln!(output, "fn main() {{").unwrap();
859 writeln!(output, " std::thread::Builder::new()").unwrap();
860 writeln!(output, " .stack_size(67_108_864)").unwrap();
861 writeln!(output, " .spawn(_logos_main)").unwrap();
862 writeln!(output, " .unwrap().join().unwrap();").unwrap();
863 writeln!(output, "}}").unwrap();
864 writeln!(output, "fn _logos_main() {{").unwrap();
865 }
866 if requires_vfs(stmts) {
868 writeln!(output, " let vfs: std::sync::Arc<dyn logicaffeine_system::fs::Vfs + Send + Sync> = std::sync::Arc::from(logicaffeine_system::fs::get_platform_vfs());").unwrap();
869 }
870 let mut main_ctx = RefinementContext::from_type_env(type_env);
871 if let Some(o) = &oracle {
874 main_ctx.set_oracle(o.clone());
875 }
876 let main_escaping = collect_escaping_collection_vars(stmts, interner);
878 main_ctx.set_escaping_vars(main_escaping);
879 main_ctx.set_promotable_candidates(crate::codegen::bigint_promote::promotable_int_vars(stmts, &bigint_fns));
881 for sym in &single_char_vars {
883 main_ctx.register_variable_type(*sym, "__single_char_u8".to_string());
884 }
885 let scalarizable_seqs = collect_scalarizable_seqs(stmts, interner);
887 let aos_groups = collect_interleaved_groups(stmts, &scalarizable_seqs, interner);
893 let aos_names = RustNames::new(interner);
894 let mut aos_member_syms: HashSet<Symbol> = HashSet::new();
895 for group in &aos_groups {
896 let width = group.members.len();
897 let backing = aos_names.ident(group.members[0]);
901 for (col, m) in group.members.iter().enumerate() {
902 main_ctx.register_variable_type(
903 *m,
904 format!("__aos:{}:{}:{}:{}:{}", backing, col, width, group.len, group.elem_ty),
905 );
906 main_ctx.init_array_fill(*m);
907 aos_member_syms.insert(*m);
908 }
909 }
910 for (sym, info) in &scalarizable_seqs {
911 if aos_member_syms.contains(sym) {
912 continue; }
914 main_ctx.register_variable_type(*sym, format!("[{}; {}]", info.elem_ty, info.len));
915 main_ctx.init_array_fill(*sym);
916 }
917 for (sym, ty) in super::affine_array::array_var_types(stmts, None, &array_return_fns) {
920 let name = interner.resolve(sym).to_string();
921 let mut syms: HashSet<Symbol> = HashSet::new();
922 collect_named_syms(stmts, &name, interner, &mut syms);
923 for s in syms {
924 main_ctx.register_variable_type(s, ty.clone());
925 }
926 }
927 let mut de_rc_seqs = collect_de_rc_seqs(stmts, interner, &borrow_params_map, &mut_borrow_params_map, &vec_return_fns, false);
930 for (sym, _) in &scalarizable_seqs {
931 if de_rc_seqs.remove(sym) {
933 crate::optimize::mark_preempted(Opt::Scalarize, Opt::Unbox);
934 }
935 }
936 let main_sl = super::affine_array::detect_straightline_buffers(stmts, &de_rc_seqs, &borrow_params_map, interner);
940 for (sym, (elem_ty, len)) in &main_sl {
941 let ty = format!("[{}; {}]", elem_ty, len);
942 de_rc_seqs.remove(sym);
943 let name = interner.resolve(*sym).to_string();
944 let mut syms: HashSet<Symbol> = HashSet::new();
945 collect_named_syms(stmts, &name, interner, &mut syms);
946 for s in syms {
947 main_ctx.register_variable_type(s, ty.clone());
948 }
949 }
950 let main_worklists = super::worklist::detect_worklists(stmts, &de_rc_seqs, interner);
952 let mut main_affine = super::affine_array::detect_affine_arrays(stmts, &de_rc_seqs, interner);
956 main_affine.retain(|sym, _| {
957 if scalarizable_seqs.contains_key(sym) {
959 crate::optimize::mark_preempted(Opt::Scalarize, Opt::Affine);
960 return false;
961 }
962 !main_worklists.contains_key(sym)
963 });
964 for (sym, info) in &main_affine {
965 main_ctx.register_variable_type(
966 *sym,
967 format!("__affine_array:{}:{}:{}", info.coeff, info.offset, info.trip),
968 );
969 }
970 let main_narrowed = narrow_seqs(stmts, &de_rc_seqs, &main_affine, &main_worklists, interner);
974 for sym in main_narrowed.keys() {
975 main_ctx.register_variable_type(*sym, "Vec<i32>".to_string());
979 }
980 main_ctx.set_de_rc_vars(de_rc_seqs);
981 main_ctx.set_worklists(main_worklists);
982 main_ctx.set_affine_arrays(main_affine);
983 main_ctx.set_narrowed(main_narrowed);
984 let main_i64 = super::i64_map::detect_i64_maps(stmts, interner);
987 if let Some(o) = oracle.as_deref() {
990 let dense = super::i64_map::detect_dense_i64_maps(&main_i64, o, interner);
991 let (i32m, i32s) = super::i64_map::detect_i32_maps(&main_i64, &dense, o);
992 main_ctx.set_dense_i64(dense);
993 main_ctx.set_i32_maps(i32m, i32s);
994 }
995 main_ctx.set_i64_sets(main_i64.sets);
996 main_ctx.set_i64_maps(main_i64.maps);
997 let mut main_presize = super::peephole::detect_vec_presize(stmts, interner);
1000 main_presize.retain(|sym, _| main_ctx.affine_array(*sym).is_none());
1001 main_ctx.set_vec_presize(main_presize);
1002 main_ctx.set_fast_div(super::fast_div::detect_fast_div(stmts, oracle.as_deref(), interner));
1004 register_fn_roles(&mut main_ctx, &borrow_params_map, &mut_borrow_params_map, &value_mutable_params_map);
1010 for (fn_sym, rt_str) in &fn_returns_map {
1012 main_ctx.register_fn_return(*fn_sym, rt_str.clone());
1013 }
1014 let mut main_synced_vars = HashSet::new(); let main_var_caps = analyze_variable_capabilities(stmts, interner);
1017 {
1018 let stmt_refs: Vec<&Stmt> = stmts.iter().collect();
1019 let mut i = 0;
1020 while i < stmt_refs.len() {
1021 if matches!(stmt_refs[i], Stmt::FunctionDef { .. }) {
1023 i += 1;
1024 continue;
1025 }
1026 if let Stmt::Let { var, value, .. } = stmt_refs[i] {
1031 if matches!(value, Expr::New { .. }) && main_ctx.affine_array(*var).is_some() {
1032 i += 1;
1033 continue;
1034 }
1035 }
1036 if let Some((code, skip)) = super::peephole::try_block_peepholes(&stmt_refs, i, interner, 1, &main_mutable_vars, &mut main_ctx, &lww_fields, &mv_fields, &mut main_synced_vars, &main_var_caps, &async_functions, &main_pipe_vars, &boxed_fields, registry, type_env) {
1039 let emit_start = line_count(&output) + 1;
1040 output.push_str(&code);
1041 if let Some((spans, _)) = mapping {
1042 let merged = match (spans.get(i), spans.get(i + skip)) {
1045 (Some(a), Some(b)) if a.start < b.end => Some(LogosSpan::new(a.start, b.end)),
1046 (Some(a), _) => Some(*a),
1047 _ => None,
1048 };
1049 record_emitted_lines(&output, emit_start, merged, &mut line_records);
1050 }
1051 i += 1 + skip;
1052 continue;
1053 }
1054 let emit_start = line_count(&output) + 1;
1055 output.push_str(&codegen_stmt(stmt_refs[i], interner, 1, &main_mutable_vars, &mut main_ctx, &lww_fields, &mv_fields, &mut main_synced_vars, &main_var_caps, &async_functions, &main_pipe_vars, &boxed_fields, registry, type_env));
1056 if let Some((spans, _)) = mapping {
1057 record_emitted_lines(&output, emit_start, spans.get(i).copied(), &mut line_records);
1058 }
1059 i += 1;
1060 }
1061 }
1062 writeln!(output, "}}").unwrap();
1063
1064 let map = mapping.map(|(spans, logos_source)| {
1065 let mut builder = SourceMapBuilder::new(logos_source);
1066 for (line, span) in line_records {
1067 builder.record_line_at(line, span);
1068 }
1069 record_var_origins(stmts, spans, interner, &mut builder);
1070 builder.build()
1071 });
1072 (output, map)
1073}
1074
1075fn line_count(s: &str) -> u32 {
1077 s.bytes().filter(|&b| b == b'\n').count() as u32
1078}
1079
1080fn record_emitted_lines(
1084 output: &str,
1085 start_line: u32,
1086 span: Option<LogosSpan>,
1087 records: &mut Vec<(u32, LogosSpan)>,
1088) {
1089 let Some(span) = span else { return };
1090 if span.start >= span.end {
1091 return;
1092 }
1093 let mut end_line = line_count(output);
1094 if !output.ends_with('\n') {
1095 end_line += 1;
1096 }
1097 for line in start_line..=end_line.max(start_line) {
1098 records.push((line, span));
1099 }
1100}
1101
1102fn role_rank(role: OwnershipRole) -> u8 {
1105 match role {
1106 OwnershipRole::GiveObject => 7,
1108 OwnershipRole::ZoneLocal => 6,
1111 OwnershipRole::ShowObject => 5,
1112 OwnershipRole::SetTarget => 4,
1113 OwnershipRole::GiveRecipient => 3,
1114 OwnershipRole::ShowRecipient => 2,
1115 OwnershipRole::LetBinding => 1,
1116 }
1117}
1118
1119fn record_var_origins(
1123 stmts: &[Stmt],
1124 stmt_spans: &[LogosSpan],
1125 interner: &Interner,
1126 builder: &mut SourceMapBuilder,
1127) {
1128 use std::collections::HashMap as Map;
1129 let mut best: Map<String, (u8, Symbol, LogosSpan, OwnershipRole)> = Map::new();
1130
1131 fn ident_of(expr: &Expr, interner: &Interner) -> Option<(String, Symbol)> {
1132 if let Expr::Identifier(sym) = expr {
1133 Some((super::escape_rust_ident(interner.resolve(*sym)), *sym))
1134 } else {
1135 None
1136 }
1137 }
1138
1139 fn note(
1140 best: &mut Map<String, (u8, Symbol, LogosSpan, OwnershipRole)>,
1141 name: String,
1142 sym: Symbol,
1143 span: LogosSpan,
1144 role: OwnershipRole,
1145 ) {
1146 let rank = role_rank(role);
1147 match best.get(&name) {
1148 Some((existing, ..)) if *existing >= rank => {}
1149 _ => {
1150 best.insert(name, (rank, sym, span, role));
1151 }
1152 }
1153 }
1154
1155 fn walk(
1156 stmts: &[Stmt],
1157 span: LogosSpan,
1158 in_zone: bool,
1159 interner: &Interner,
1160 best: &mut Map<String, (u8, Symbol, LogosSpan, OwnershipRole)>,
1161 ) {
1162 for stmt in stmts {
1163 match stmt {
1164 Stmt::Let { var, .. } => {
1165 let role = if in_zone { OwnershipRole::ZoneLocal } else { OwnershipRole::LetBinding };
1166 let name = super::escape_rust_ident(interner.resolve(*var));
1167 note(best, name, *var, span, role);
1168 }
1169 Stmt::Set { target, .. } => {
1170 let name = super::escape_rust_ident(interner.resolve(*target));
1171 note(best, name, *target, span, OwnershipRole::SetTarget);
1172 }
1173 Stmt::Give { object, recipient } => {
1174 if let Some((name, sym)) = ident_of(object, interner) {
1175 note(best, name, sym, span, OwnershipRole::GiveObject);
1176 }
1177 if let Some((name, sym)) = ident_of(recipient, interner) {
1178 note(best, name, sym, span, OwnershipRole::GiveRecipient);
1179 }
1180 }
1181 Stmt::Show { object, recipient } => {
1182 if let Some((name, sym)) = ident_of(object, interner) {
1183 note(best, name, sym, span, OwnershipRole::ShowObject);
1184 }
1185 if let Some((name, sym)) = ident_of(recipient, interner) {
1186 note(best, name, sym, span, OwnershipRole::ShowRecipient);
1187 }
1188 }
1189 Stmt::Zone { body, .. } => walk(body, span, true, interner, best),
1190 Stmt::If { then_block, else_block, .. } => {
1191 walk(then_block, span, in_zone, interner, best);
1192 if let Some(else_block) = else_block {
1193 walk(else_block, span, in_zone, interner, best);
1194 }
1195 }
1196 Stmt::While { body, .. } => walk(body, span, in_zone, interner, best),
1197 Stmt::Repeat { body, .. } => walk(body, span, in_zone, interner, best),
1198 Stmt::FunctionDef { body, .. } => walk(body, span, in_zone, interner, best),
1199 _ => {}
1200 }
1201 }
1202 }
1203
1204 for (i, stmt) in stmts.iter().enumerate() {
1205 let Some(span) = stmt_spans.get(i).copied() else { continue };
1206 if span.start >= span.end {
1207 continue;
1208 }
1209 walk(std::slice::from_ref(stmt), span, false, interner, &mut best);
1210 }
1211
1212 for (name, (_, sym, span, role)) in best {
1213 builder.record_var(&name, sym, span, role);
1214 }
1215}
1216
1217fn codegen_function_def(
1222 name: Symbol,
1223 generics: &[Symbol],
1224 params: &[(Symbol, &TypeExpr)],
1225 body: &[Stmt],
1226 all_stmts: &[Stmt],
1227 return_type: Option<&TypeExpr>,
1228 is_native: bool,
1229 native_path: Option<Symbol>,
1230 is_exported: bool,
1231 export_target: Option<Symbol>,
1232 interner: &Interner,
1233 lww_fields: &HashSet<(String, String)>,
1234 mv_fields: &HashSet<(String, String)>, async_functions: &HashSet<Symbol>, boxed_fields: &HashSet<(String, String, String)>, registry: &TypeRegistry, pure_functions: &HashSet<Symbol>,
1239 type_env: &crate::analysis::types::TypeEnv,
1240 borrow_params_map: &HashMap<Symbol, HashSet<usize>>,
1241 mut_borrow_params_map: &HashMap<Symbol, HashSet<usize>>,
1242 value_mutable_params_map: &HashMap<Symbol, HashSet<usize>>,
1243 liveness: &LivenessResult,
1244 opt_flags: &OptimizationConfig,
1245 fn_returns_map: &HashMap<Symbol, String>,
1246 vec_return_fns: &HashSet<Symbol>,
1247 array_return_fns: &HashMap<Symbol, super::affine_array::ArrayReturnInfo>,
1248 fixed_array_param_map: &HashMap<(Symbol, usize), usize>,
1249 oracle: Option<&std::rc::Rc<crate::optimize::OracleFacts>>,
1250 bigint_fns: &HashSet<Symbol>,
1251) -> String {
1252 let mut output = String::new();
1253 let returns_bigint = bigint_fns.contains(&name);
1256 let returns_vec = vec_return_fns.contains(&name);
1259 let array_return = array_return_fns.get(&name);
1261 let names = RustNames::new(interner);
1262 let raw_name = names.raw(name);
1263 let func_name = names.ident(name);
1264 let export_target_lower = export_target.map(|s| interner.resolve(s).to_lowercase());
1265
1266 let pipe_sender_params = collect_pipe_sender_params(body);
1268
1269 let is_c_export_early = is_exported && matches!(export_target_lower.as_deref(), None | Some("c"));
1271
1272 let no_tco = !crate::optimize::active_config().merged(opt_flags).is_on(Opt::Tco);
1274 let has_tail_pair = body_has_top_level_tail_pair(name, body, params.len());
1281 if has_tail_pair
1284 && (borrow_params_map.contains_key(&name) || mut_borrow_params_map.contains_key(&name))
1285 {
1286 crate::optimize::mark_preempted(Opt::Borrow, Opt::Tco);
1287 }
1288 let pair_tce_ok = has_tail_pair
1289 && !borrow_params_map.contains_key(&name)
1290 && !mut_borrow_params_map.contains_key(&name);
1291 let is_tce = !is_native && !is_c_export_early && !no_tco
1292 && (is_tail_recursive(name, body) || pair_tce_ok);
1293 if is_tce {
1294 crate::optimize::mark_fired(Opt::Tco);
1295 }
1296 let param_syms: Vec<Symbol> = params.iter().map(|(s, _)| *s).collect();
1297
1298 let acc_info = if !is_tce && !is_native && !is_c_export_early {
1300 detect_accumulator_pattern(name, body)
1301 } else {
1302 None
1303 };
1304 let is_acc = acc_info.is_some();
1305
1306 let closed_form_info = if !is_tce && !is_acc && !is_native && !is_c_export_early {
1309 detect_double_recursion_closed_form(name, params, body, interner)
1310 } else {
1311 None
1312 };
1313 let is_closed_form = closed_form_info.is_some();
1314
1315 let no_memo = !crate::optimize::active_config().merged(opt_flags).is_on(Opt::Memo);
1318 let is_memo = !is_tce && !is_acc && !is_closed_form && !is_native && !is_c_export_early && !no_memo
1319 && should_memoize(name, body, params, return_type, pure_functions.contains(&name), interner);
1320 if is_memo {
1321 crate::optimize::mark_fired(Opt::Memo);
1322 }
1323 if is_tce
1327 && !no_memo
1328 && should_memoize(name, body, params, return_type, pure_functions.contains(&name), interner)
1329 {
1330 crate::optimize::mark_preempted(Opt::Tco, Opt::Memo);
1331 }
1332
1333 let needs_mut_params = is_tce || is_acc;
1334
1335 let no_peephole = !crate::optimize::active_config().merged(opt_flags).is_on(Opt::Peephole);
1337
1338 let borrow_indices = borrow_params_map.get(&name).cloned().unwrap_or_default();
1340
1341 let mut_borrow_indices = mut_borrow_params_map.get(&name).cloned().unwrap_or_default();
1343
1344 let func_mutable_vars = collect_mutable_vars(body);
1346
1347 let params_str: Vec<String> = params.iter().enumerate()
1349 .map(|(i, (param_name, param_type))| {
1350 let pname = names.ident(*param_name);
1351 let ty = codegen_type_expr(param_type, interner);
1352 if crate::semantics::collections::value_semantics_enabled()
1356 && matches!(param_type, crate::ast::stmt::TypeExpr::Mutable { .. })
1357 {
1358 format!("{}: &{}", pname, ty)
1359 } else if pipe_sender_params.contains(param_name) {
1360 format!("{}: tokio::sync::mpsc::Sender<{}>", pname, ty)
1361 } else if borrow_indices.contains(&i) {
1362 let slice_ty = vec_to_slice_type(&ty);
1365 let final_ty = match fixed_array_param_map.get(&(name, i)) {
1366 Some(n) => slice_ty.strip_prefix("&[").and_then(|s| s.strip_suffix(']'))
1367 .map(|elem| format!("&[{}; {}]", elem, n)).unwrap_or(slice_ty),
1368 None => slice_ty,
1369 };
1370 format!("{}: {}", pname, final_ty)
1371 } else if mut_borrow_indices.contains(&i) {
1372 let slice_ty = vec_to_mut_slice_type(&ty);
1374 format!("{}: {}", pname, slice_ty)
1375 } else if needs_mut_params || func_mutable_vars.contains(param_name) {
1376 format!("mut {}: {}", pname, ty)
1377 } else {
1378 format!("{}: {}", pname, ty)
1379 }
1380 })
1381 .collect();
1382
1383 let has_mut_borrow = !mut_borrow_indices.is_empty();
1387 let return_type_str = if returns_bigint {
1388 Some("logicaffeine_data::LogosInt".to_string())
1390 } else if has_mut_borrow {
1391 None } else if let Some(info) = array_return {
1393 Some(format!("[{}; {}]", info.elem_ty, info.len))
1395 } else if returns_vec {
1396 return_type
1399 .map(|t| codegen_type_expr(t, interner).replacen("LogosSeq<", "Vec<", 1))
1400 } else {
1401 return_type
1402 .map(|t| codegen_type_expr(t, interner))
1403 .or_else(|| infer_return_type_from_body(body, params, interner))
1404 };
1405
1406 let is_async = async_functions.contains(&name);
1408 let fn_keyword = if is_async { "async fn" } else { "fn" };
1409
1410 let is_c_export = is_c_export_early;
1412
1413 let needs_c_marshaling = is_c_export && {
1416 let has_text_param = params.iter().any(|(_, ty)| is_text_type(ty, interner));
1417 let has_text_return = return_type.map_or(false, |ty| is_text_type(ty, interner));
1418 let has_ref_param = params.iter().any(|(_, ty)| {
1419 classify_type_for_c_abi(ty, interner, registry) == CAbiClass::ReferenceType
1420 });
1421 let has_ref_return = return_type.map_or(false, |ty| {
1422 classify_type_for_c_abi(ty, interner, registry) == CAbiClass::ReferenceType
1423 });
1424 let has_result_return = return_type.map_or(false, |ty| is_result_type(ty, interner));
1425 let has_refinement_param = params.iter().any(|(_, ty)| {
1426 matches!(ty, TypeExpr::Refinement { .. })
1427 });
1428 let has_char_param = params.iter().any(|(_, ty)| is_char_type(ty, interner));
1432 let has_char_return = return_type.map_or(false, |ty| is_char_type(ty, interner));
1433 has_text_param || has_text_return || has_ref_param || has_ref_return
1434 || has_result_return || has_refinement_param || has_char_param || has_char_return
1435 };
1436
1437 if needs_c_marshaling {
1438 return codegen_c_export_with_marshaling(
1440 name, params, body, return_type, interner,
1441 lww_fields, mv_fields, async_functions, boxed_fields, registry, type_env,
1442 );
1443 }
1444
1445 let (vis_prefix, abi_prefix) = if is_exported {
1447 match export_target_lower.as_deref() {
1448 None | Some("c") => ("pub ", "extern \"C\" "),
1449 Some("wasm") => ("pub ", ""),
1450 _ => ("pub ", ""),
1451 }
1452 } else {
1453 ("", "")
1454 };
1455
1456 let generics_str = if generics.is_empty() {
1458 String::new()
1459 } else {
1460 let params_list: Vec<&str> = generics.iter()
1461 .map(|sym| interner.resolve(*sym))
1462 .collect();
1463 format!("<{}>", params_list.join(", "))
1464 };
1465
1466 let signature = if let Some(ref ret_ty) = return_type_str {
1467 if ret_ty != "()" {
1468 format!("{}{}{} {}{}({}) -> {}", vis_prefix, abi_prefix, fn_keyword, func_name, generics_str, params_str.join(", "), ret_ty)
1469 } else {
1470 format!("{}{}{} {}{}({})", vis_prefix, abi_prefix, fn_keyword, func_name, generics_str, params_str.join(", "))
1471 }
1472 } else {
1473 format!("{}{}{} {}{}({})", vis_prefix, abi_prefix, fn_keyword, func_name, generics_str, params_str.join(", "))
1474 };
1475
1476 if is_closed_form || (!is_tce && !is_acc && should_inline(name, body, is_native, is_exported, is_async)) {
1479 writeln!(output, "#[inline]").unwrap();
1480 }
1481
1482 if is_exported {
1484 match export_target_lower.as_deref() {
1485 None | Some("c") => {
1486 writeln!(output, "#[export_name = \"logos_{}\"]", raw_name).unwrap();
1487 }
1488 Some("wasm") => {
1489 writeln!(output, "#[wasm_bindgen]").unwrap();
1490 }
1491 _ => {}
1492 }
1493 }
1494
1495 if is_native {
1497 let arg_names: Vec<&str> = params.iter()
1498 .map(|(n, _)| interner.resolve(*n))
1499 .collect();
1500
1501 if let Some(path_sym) = native_path {
1502 let path = interner.resolve(path_sym);
1504 let is_valid_path = !path.is_empty() && path.split("::").all(|seg| {
1506 !seg.is_empty() && seg.chars().all(|c| c.is_alphanumeric() || c == '_')
1507 });
1508 if is_valid_path {
1509 writeln!(output, "{} {{", signature).unwrap();
1510 writeln!(output, " {}({})", path, arg_names.join(", ")).unwrap();
1511 writeln!(output, "}}\n").unwrap();
1512 } else {
1513 writeln!(output, "{} {{", signature).unwrap();
1514 writeln!(output, " compile_error!(\"Invalid native function path: '{}'. Path must be a valid Rust path like \\\"crate::module::function\\\".\")", path).unwrap();
1515 writeln!(output, "}}\n").unwrap();
1516 }
1517 } else {
1518 if let Some((module, core_fn)) = map_native_function(raw_name) {
1520 writeln!(output, "{} {{", signature).unwrap();
1521 writeln!(output, " logicaffeine_system::{}::{}({})", module, core_fn, arg_names.join(", ")).unwrap();
1522 writeln!(output, "}}\n").unwrap();
1523 } else {
1524 writeln!(output, "{} {{", signature).unwrap();
1525 writeln!(output, " compile_error!(\"Unknown system native function: '{}'. Use `is native \\\"crate::path\\\"` syntax for user-defined native functions.\")", raw_name).unwrap();
1526 writeln!(output, "}}\n").unwrap();
1527 }
1528 }
1529 } else {
1530 writeln!(output, "{} {{", signature).unwrap();
1532
1533 if !is_acc {
1544 if let Some(g) = super::entry_guard::detect_entry_guard(params, body, interner) {
1545 let arr = names.ident(g.arr);
1546 let lo = names.ident(g.lo);
1547 let hi = names.ident(g.hi);
1548 writeln!(
1549 output,
1550 " if ({lo}) < ({hi}) {{ let __{arr}_glen = {arr}.len() as i64; assert!(({lo}) >= 1 && ({hi}) <= __{arr}_glen, \"LOGOS precondition guard: 1-based index range\"); }}"
1551 )
1552 .unwrap();
1553 }
1554 }
1555
1556 let wrap_catch_unwind = is_c_export;
1558 if wrap_catch_unwind {
1559 writeln!(output, " match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {{").unwrap();
1560 }
1561
1562 let mut func_ctx = RefinementContext::new();
1563 if let Some(o) = oracle {
1566 func_ctx.set_oracle(o.clone());
1567 }
1568 let func_escaping = collect_escaping_collection_vars(body, interner);
1570 func_ctx.set_escaping_vars(func_escaping);
1571 func_ctx.set_promotable_candidates(crate::codegen::bigint_promote::promotable_int_vars(body, bigint_fns));
1575 let func_de_rc = collect_de_rc_seqs(body, interner, borrow_params_map, mut_borrow_params_map, vec_return_fns, returns_vec);
1580 let func_worklists = super::worklist::detect_worklists(body, &func_de_rc, interner);
1581 let mut func_affine = super::affine_array::detect_affine_arrays(body, &func_de_rc, interner);
1582 func_affine.retain(|sym, _| !func_worklists.contains_key(sym));
1583 let func_const_tables = super::affine_array::detect_const_tables(body, all_stmts, &func_de_rc, borrow_params_map, interner);
1587 let mut func_scratch = super::affine_array::detect_scratch_buffers(body, &func_de_rc, borrow_params_map, interner);
1590 func_scratch.retain(|sym, _| !func_const_tables.contains_key(sym));
1591 let mut func_indexed = super::affine_array::detect_indexed_buffers(body, &func_de_rc, interner);
1594 func_indexed.retain(|sym, _| !func_const_tables.contains_key(sym) && !func_scratch.contains_key(sym));
1595 func_scratch.retain(|sym, _| !func_indexed.contains_key(sym));
1596 let mut func_sl = super::affine_array::detect_straightline_buffers(body, &func_de_rc, borrow_params_map, interner);
1599 func_sl.retain(|sym, _| !func_const_tables.contains_key(sym) && !func_scratch.contains_key(sym) && !func_indexed.contains_key(sym));
1600 func_affine.retain(|sym, _| !func_const_tables.contains_key(sym) && !func_scratch.contains_key(sym));
1601 for (sym, info) in &func_affine {
1602 func_ctx.register_variable_type(
1603 *sym,
1604 format!("__affine_array:{}:{}:{}", info.coeff, info.offset, info.trip),
1605 );
1606 }
1607 let mut func_narrowed = narrow_seqs(body, &func_de_rc, &func_affine, &func_worklists, interner);
1608 func_narrowed.retain(|sym, _| !func_const_tables.contains_key(sym) && !func_scratch.contains_key(sym) && !func_indexed.contains_key(sym) && !func_sl.contains_key(sym));
1609 for sym in func_narrowed.keys() {
1610 func_ctx.register_variable_type(*sym, "Vec<i32>".to_string());
1611 }
1612 func_ctx.set_de_rc_vars(func_de_rc);
1613 func_ctx.set_worklists(func_worklists);
1614 func_ctx.set_affine_arrays(func_affine);
1615 func_ctx.set_narrowed(func_narrowed);
1616 let func_i64 = super::i64_map::detect_i64_maps(body, interner);
1617 if let Some(o) = oracle {
1618 let dense = super::i64_map::detect_dense_i64_maps(&func_i64, o.as_ref(), interner);
1619 let (i32m, i32s) = super::i64_map::detect_i32_maps(&func_i64, &dense, o.as_ref());
1620 func_ctx.set_dense_i64(dense);
1621 func_ctx.set_i32_maps(i32m, i32s);
1622 }
1623 func_ctx.set_i64_sets(func_i64.sets);
1624 func_ctx.set_i64_maps(func_i64.maps);
1625 let mut func_presize = super::peephole::detect_vec_presize(body, interner);
1626 func_presize.retain(|sym, _| func_ctx.affine_array(*sym).is_none() && !func_const_tables.contains_key(sym) && !func_scratch.contains_key(sym) && !func_indexed.contains_key(sym) && !func_sl.contains_key(sym));
1627 func_ctx.set_vec_presize(func_presize);
1628 func_ctx.set_fast_div(super::fast_div::detect_fast_div(body, oracle.map(|o| o.as_ref()), interner));
1629 func_ctx.set_returns_vec(returns_vec);
1630 func_ctx.set_returns_bigint(returns_bigint);
1631 let func_single_char_vars = collect_single_char_text_vars(body, interner);
1633 for sym in &func_single_char_vars {
1634 func_ctx.register_variable_type(*sym, "__single_char_u8".to_string());
1635 }
1636 let mut func_synced_vars = HashSet::new(); let func_var_caps = analyze_variable_capabilities(body, interner);
1639
1640 let value_mutable_indices = value_mutable_params_map.get(&name).cloned().unwrap_or_default();
1643 for (i, (param_name, param_type)) in params.iter().enumerate() {
1644 let type_name = codegen_type_expr(param_type, interner);
1645 if borrow_indices.contains(&i) {
1646 let slice_ty = vec_to_slice_type(&type_name);
1647 let reg_ty = match fixed_array_param_map.get(&(name, i)) {
1648 Some(n) => slice_ty.strip_prefix("&[").and_then(|s| s.strip_suffix(']'))
1649 .map(|elem| format!("&[{}; {}]", elem, n)).unwrap_or(slice_ty),
1650 None => slice_ty,
1651 };
1652 func_ctx.register_variable_type(*param_name, reg_ty);
1653 } else if mut_borrow_indices.contains(&i) {
1654 func_ctx.register_variable_type(*param_name, vec_to_mut_slice_type(&type_name));
1655 } else {
1656 func_ctx.register_variable_type(*param_name, type_name);
1657 }
1658 if value_mutable_indices.contains(&i) {
1662 func_ctx.register_mutable_collection_param(*param_name);
1663 }
1664 }
1665
1666 register_fn_roles(&mut func_ctx, borrow_params_map, mut_borrow_params_map, value_mutable_params_map);
1670 for (fn_sym, rt_str) in fn_returns_map {
1672 func_ctx.register_fn_return(*fn_sym, rt_str.clone());
1673 }
1674
1675 let func_pipe_vars = HashSet::new();
1677
1678 for (sym, info) in &func_const_tables {
1682 writeln!(
1683 output,
1684 " let {}: [{}; {}] = [{}];",
1685 names.ident(*sym),
1686 info.elem_ty,
1687 info.values.len(),
1688 info.values.join(", ")
1689 )
1690 .unwrap();
1691 let ty = format!("[{}; {}]", info.elem_ty, info.values.len());
1697 let name = interner.resolve(*sym).to_string();
1698 let mut syms: HashSet<Symbol> = HashSet::new();
1699 collect_named_syms(body, &name, interner, &mut syms);
1700 for s in syms {
1701 func_ctx.register_variable_type(s, ty.clone());
1702 }
1703 }
1704 func_ctx.set_const_tables(func_const_tables);
1705
1706 for (sym, info) in &func_scratch {
1711 let ty = format!("[{}; {}]", info.elem_ty, info.len);
1712 let name = interner.resolve(*sym).to_string();
1713 let mut syms: HashSet<Symbol> = HashSet::new();
1714 collect_named_syms(body, &name, interner, &mut syms);
1715 for s in syms {
1716 func_ctx.register_variable_type(s, ty.clone());
1717 }
1718 }
1719 func_ctx.set_scratch_buffers(func_scratch);
1720
1721 for (sym, info) in &func_indexed {
1724 let ty = format!("[{}; {}]", info.elem_ty, info.len);
1725 let name = interner.resolve(*sym).to_string();
1726 let mut syms: HashSet<Symbol> = HashSet::new();
1727 collect_named_syms(body, &name, interner, &mut syms);
1728 for s in syms {
1729 func_ctx.register_variable_type(s, ty.clone());
1730 }
1731 }
1732 func_ctx.set_indexed_buffers(func_indexed);
1733
1734 for (sym, (elem_ty, len)) in &func_sl {
1737 let ty = format!("[{}; {}]", elem_ty, len);
1738 let name = interner.resolve(*sym).to_string();
1739 let mut syms: HashSet<Symbol> = HashSet::new();
1740 collect_named_syms(body, &name, interner, &mut syms);
1741 for s in syms {
1742 func_ctx.register_variable_type(s, ty.clone());
1743 }
1744 }
1745
1746 for (sym, ty) in super::affine_array::array_var_types(body, array_return, array_return_fns) {
1751 let name = interner.resolve(sym).to_string();
1752 let mut syms: HashSet<Symbol> = HashSet::new();
1753 collect_named_syms(body, &name, interner, &mut syms);
1754 for s in syms {
1755 func_ctx.register_variable_type(s, ty.clone());
1756 }
1757 }
1758 if array_return.map_or(false, |i| i.loop_built) {
1763 if let Some(Stmt::Return { value: Some(Expr::Identifier(out)) }) = body.last() {
1764 let cursor = format!("__{}_fill", names.ident(*out));
1765 let name = interner.resolve(*out).to_string();
1766 let mut syms: HashSet<Symbol> = HashSet::new();
1767 collect_named_syms(body, &name, interner, &mut syms);
1768 for s in syms {
1769 func_ctx.set_loop_fill_array(s, cursor.clone());
1770 }
1771 }
1772 }
1773
1774 if is_tce {
1775 writeln!(output, " loop {{").unwrap();
1777 let stmt_refs: Vec<&Stmt> = body.iter().filter(|s| !is_affine_array_decl(s, &func_ctx) && !is_const_table_stmt(s, &func_ctx)).collect();
1778 let mut si = 0;
1779 while si < stmt_refs.len() {
1780 if si + 1 < stmt_refs.len() {
1784 if let Some(call_args) = crate::tail_call::tail_pair_args(
1785 stmt_refs[si],
1786 stmt_refs[si + 1],
1787 name,
1788 param_syms.len(),
1789 ) {
1790 output.push_str(&codegen_tce_loopback(
1791 call_args,
1792 ¶m_syms,
1793 interner,
1794 2,
1795 &mut func_ctx,
1796 &mut func_synced_vars,
1797 async_functions,
1798 ));
1799 si += 2;
1800 continue;
1801 }
1802 }
1803 if !no_peephole {
1804 if let Some((code, skip)) = super::peephole::try_block_peepholes(&stmt_refs, si, interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env) {
1805 output.push_str(&code);
1806 si += 1 + skip;
1807 continue;
1808 }
1809 }
1810 output.push_str(&codegen_stmt_tce(stmt_refs[si], name, ¶m_syms, interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env));
1811 si += 1;
1812 }
1813 writeln!(output, " }}").unwrap();
1814 } else if let Some(ref acc) = acc_info {
1815 writeln!(output, " let mut __acc: i64 = {};", acc.identity).unwrap();
1817 writeln!(output, " loop {{").unwrap();
1818 let stmt_refs: Vec<&Stmt> = body.iter().filter(|s| !is_affine_array_decl(s, &func_ctx) && !is_const_table_stmt(s, &func_ctx)).collect();
1819 let mut si = 0;
1820 while si < stmt_refs.len() {
1821 if !no_peephole {
1822 if let Some((code, skip)) = super::peephole::try_block_peepholes(&stmt_refs, si, interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env) {
1823 output.push_str(&code);
1824 si += 1 + skip;
1825 continue;
1826 }
1827 }
1828 output.push_str(&codegen_stmt_acc(stmt_refs[si], name, ¶m_syms, acc, interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env));
1829 si += 1;
1830 }
1831 writeln!(output, " }}").unwrap();
1832 } else if let Some(ref cf) = closed_form_info {
1833 let param_name = names.ident(params[0].0);
1835 let base_plus_k = cf.base + cf.k;
1836 writeln!(output, " if {} == 0 {{ return {}; }}", param_name, cf.base).unwrap();
1837 let pow2d = format!(
1842 "(if ({p} as u64) >= 64 {{ 0i64 }} else {{ 1i64 << {p} }})",
1843 p = param_name
1844 );
1845 if cf.k == 0 {
1846 writeln!(output, " {}i64.wrapping_mul({})", base_plus_k, pow2d).unwrap();
1847 } else {
1848 writeln!(output, " ({}i64.wrapping_mul({})).wrapping_sub({})", base_plus_k, pow2d, cf.k).unwrap();
1849 }
1850 } else if is_memo {
1851 let ret_ty = return_type_str.as_deref().unwrap_or("i64");
1853 let memo_name = format!("__MEMO_{}", func_name.to_uppercase());
1854
1855 let (key_type, key_expr, copy_method) = if params.len() == 1 {
1857 let ty = codegen_type_expr(params[0].1, interner);
1858 let pname = interner.resolve(params[0].0).to_string();
1859 let copy = if is_copy_type_expr(params[0].1, interner) { "copied" } else { "cloned" };
1860 (ty, pname, copy)
1861 } else {
1862 let types: Vec<String> = params.iter().map(|(_, t)| codegen_type_expr(t, interner)).collect();
1863 let names: Vec<String> = params.iter().map(|(n, _)| interner.resolve(*n).to_string()).collect();
1864 let copy = if params.iter().all(|(_, t)| is_copy_type_expr(t, interner)) { "copied" } else { "cloned" };
1865 (format!("({})", types.join(", ")), format!("({})", names.join(", ")), copy)
1866 };
1867
1868 writeln!(output, " use std::cell::RefCell;").unwrap();
1869 writeln!(output, " thread_local! {{").unwrap();
1870 writeln!(output, " static {}: RefCell<FxHashMap<{}, {}>> = RefCell::new(FxHashMap::default());", memo_name, key_type, ret_ty).unwrap();
1871 writeln!(output, " }}").unwrap();
1872 writeln!(output, " if let Some(__v) = {}.with(|c| c.borrow().get(&{}).{}()) {{", memo_name, key_expr, copy_method).unwrap();
1873 writeln!(output, " return __v;").unwrap();
1874 writeln!(output, " }}").unwrap();
1875 writeln!(output, " let __memo_result = (|| -> {} {{", ret_ty).unwrap();
1876 let stmt_refs: Vec<&Stmt> = body.iter().filter(|s| !is_affine_array_decl(s, &func_ctx) && !is_const_table_stmt(s, &func_ctx)).collect();
1877 let mut si = 0;
1878 while si < stmt_refs.len() {
1879 if !no_peephole {
1880 if let Some((code, skip)) = super::peephole::try_block_peepholes(&stmt_refs, si, interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env) {
1881 output.push_str(&code);
1882 si += 1 + skip;
1883 continue;
1884 }
1885 }
1886 output.push_str(&codegen_stmt(stmt_refs[si], interner, 2, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env));
1887 si += 1;
1888 }
1889 writeln!(output, " }})();").unwrap();
1890 writeln!(output, " {}.with(|c| c.borrow_mut().insert({}, __memo_result));", memo_name, key_expr).unwrap();
1891 writeln!(output, " __memo_result").unwrap();
1892 } else {
1893 let stmt_refs: Vec<&Stmt> = body.iter().filter(|s| !is_affine_array_decl(s, &func_ctx) && !is_const_table_stmt(s, &func_ctx)).collect();
1894 let mut si = 0;
1895 while si < stmt_refs.len() {
1896 if !no_peephole {
1897 if let Some((code, skip)) = super::peephole::try_block_peepholes(&stmt_refs, si, interner, 1, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env) {
1898 output.push_str(&code);
1899 si += 1 + skip;
1900 continue;
1901 }
1902 }
1903 func_ctx.set_live_vars_after(liveness.live_after(name, si).clone());
1906 output.push_str(&codegen_stmt(stmt_refs[si], interner, 1, &func_mutable_vars, &mut func_ctx, lww_fields, mv_fields, &mut func_synced_vars, &func_var_caps, async_functions, &func_pipe_vars, boxed_fields, registry, type_env));
1907 si += 1;
1908 }
1909 }
1910
1911 if wrap_catch_unwind {
1912 writeln!(output, " }})) {{").unwrap();
1913 writeln!(output, " Ok(__v) => __v,").unwrap();
1914 writeln!(output, " Err(__panic) => {{").unwrap();
1915 writeln!(output, " let __msg = if let Some(s) = __panic.downcast_ref::<String>() {{ s.clone() }} else if let Some(s) = __panic.downcast_ref::<&str>() {{ s.to_string() }} else {{ \"Unknown panic\".to_string() }};").unwrap();
1916 writeln!(output, " logos_set_last_error(__msg);").unwrap();
1917 if let Some(ref ret_str) = return_type_str {
1919 if ret_str != "()" {
1920 writeln!(output, " Default::default()").unwrap();
1921 }
1922 }
1923 writeln!(output, " }}").unwrap();
1924 writeln!(output, " }}").unwrap();
1925 }
1926
1927 writeln!(output, "}}\n").unwrap();
1928 }
1929
1930 output
1931}
1932
1933fn map_native_function(name: &str) -> Option<(&'static str, &'static str)> {
1937 match name {
1938 "read" => Some(("file", "read")),
1939 "write" => Some(("file", "write")),
1940 "now" => Some(("time", "now")),
1941 "sleep" => Some(("time", "sleep")),
1942 "randomInt" => Some(("random", "randomInt")),
1943 "randomFloat" => Some(("random", "randomFloat")),
1944 "get" => Some(("env", "get")),
1945 "args" => Some(("env", "args")),
1946 "parseInt" => Some(("text", "parseInt")),
1947 "parseFloat" => Some(("text", "parseFloat")),
1948 "chr" => Some(("text", "chr")),
1949 "format" => Some(("fmt", "format")),
1950 "mlkemNtt" => Some(("ntt", "mlkem_ntt")),
1952 "mlkemBaseMulW16" => Some(("ntt", "mlkem_base_mul_w16_seq")),
1956 "toMontW16" => Some(("ntt", "mlkem_to_mont_w16_seq")),
1957 "cbd2W16" => Some(("ntt", "mlkem_cbd2_w16_from_int")),
1958 "compressW16" => Some(("ntt", "mlkem_compress_w16_seq")),
1959 "decompressW16" => Some(("ntt", "mlkem_decompress_w16_seq")),
1960 "byteEncodeW16" => Some(("ntt", "mlkem_byte_encode_w16_to_int")),
1961 "byteDecodeW16" => Some(("ntt", "mlkem_byte_decode_w16_from_int")),
1962 "sampleAW16" => Some(("ntt", "mlkem_sample_a_w16_from_int")),
1963 "sampleMatrixW16" => Some(("ntt", "mlkem_sample_matrix_w16_from_int")),
1964 "mlkemNoiseBatch" => Some(("mlkem", "mlkem_noise_batch_from_int")),
1967 "mlkemKeypair" => Some(("mlkem", "mlkem_keypair_seq")),
1969 "mlkemEncapsKem" => Some(("mlkem", "mlkem_encaps_seq")),
1970 "mlkemDecapsKem" => Some(("mlkem", "mlkem_decaps_seq")),
1971 "mldsaKeypair" => Some(("mldsa", "mldsa_keypair_seq")),
1972 "mldsaSign" => Some(("mldsa", "mldsa_sign_seq")),
1973 "mldsaVerify" => Some(("mldsa", "mldsa_verify_seq")),
1974 "addModQW16" => Some(("ntt", "mlkem_add_mod_q_w16")),
1979 "subModQW16" => Some(("ntt", "mlkem_sub_mod_q_w16")),
1980 "zerosW16" => Some(("ntt", "mlkem_zeros_w16")),
1981 "mlkemInvNtt" => Some(("ntt", "mlkem_inv_ntt")),
1982 "mlkemBaseMul" => Some(("ntt", "mlkem_base_mul")),
1983 "cbd2" => Some(("ntt", "mlkem_cbd2")),
1985 "cbd3" => Some(("ntt", "mlkem_cbd3")),
1986 "compress" => Some(("ntt", "mlkem_compress")),
1988 "decompress" => Some(("ntt", "mlkem_decompress")),
1989 "byteEncode" => Some(("ntt", "mlkem_byte_encode")),
1990 "byteDecode" => Some(("ntt", "mlkem_byte_decode")),
1991 "sampleNtt" => Some(("ntt", "mlkem_sample_ntt")),
1993 "sampleA" => Some(("ntt", "mlkem_sample_a")),
1994 "toMont" => Some(("ntt", "mlkem_to_mont")),
1996 "sha3_256" => Some(("keccak", "sha3_256")),
1998 "sha3_512" => Some(("keccak", "sha3_512")),
1999 "shake128" => Some(("keccak", "shake128")),
2000 "shake256" => Some(("keccak", "shake256")),
2001 _ => None,
2002 }
2003}