1use std::collections::{HashMap, HashSet};
2use std::fmt::Write;
3
4use crate::analysis::registry::{FieldType, TypeDef, TypeRegistry};
5use crate::analysis::types::RustNames;
6use crate::ast::stmt::{BinaryOpKind, Expr, Literal, ReadSource, Stmt, TypeExpr};
7use crate::intern::{Interner, Symbol};
8
9use super::context::{RefinementContext, VariableCapabilities, emit_refinement_check, analyze_variable_capabilities};
10use super::detection::{
11 requires_async_stmt, calls_async_function, collect_mutable_vars, collect_mutable_vars_stmt,
12 collect_crdt_register_fields, collect_boxed_fields, collect_expr_identifiers,
13 collect_stmt_identifiers, expr_debug_prefix, expr_reads_any_collection,
14 get_root_identifier_for_mutability, is_copy_type_expr, is_hashable_type,
15 parse_aos_tag,
16};
17use super::expr::{
18 codegen_expr, codegen_expr_with_async, codegen_expr_boxed,
19 codegen_expr_boxed_with_strings, codegen_expr_boxed_with_types,
20 codegen_expr_with_async_oracle, codegen_expr_boxed_with_types_oracle,
21 codegen_expr_boxed_with_types_oracle_tolerant,
22 codegen_interpolated_string, codegen_literal, codegen_assertion,
23 codegen_expr_with_async_and_strings, is_definitely_string_expr_with_vars,
24 is_definitely_string_expr, is_definitely_numeric_expr,
25 collect_string_concat_operands, is_rational_expr,
26};
27use super::peephole::{
28 try_emit_for_range_pattern, try_emit_vec_fill_pattern, try_emit_swap_pattern,
29 try_emit_prefix_reverse,
30 try_emit_seq_copy_pattern, try_emit_seq_from_slice_pattern,
31 try_emit_vec_with_capacity_pattern, try_emit_merge_capacity_pattern,
32 try_emit_rotate_left_pattern, try_emit_buffer_reuse_while,
33 try_emit_drain_tail_in_while, try_emit_byte_compare_window,
34 body_mutates_collection, body_modifies_var, exprs_equal, simplify_1based_index,
35 plan_bounds_hints, emit_bounds_hint_preheader, emit_bounds_hint_header,
36 is_counter_increment, collect_expr_symbols, BoundsHintPlan,
37 body_has_early_exit, body_resizes_collection,
38};
39use super::types::{
40 codegen_type_expr, infer_rust_type_from_expr, infer_numeric_type,
41 infer_variant_type_annotation,
42};
43use super::i64_map::{dense_type_name, is_logos_map_type, map_rust_type};
44use super::escape_rust_ident;
45
46fn derc_vec_decl<'a>(
51 value: &Expr<'a>,
52 interner: &Interner,
53 synced_vars: &HashSet<Symbol>,
54 boxed_fields: &HashSet<(String, String, String)>,
55 registry: &TypeRegistry,
56 async_functions: &HashSet<Symbol>,
57 ctx: &RefinementContext<'a>,
58) -> Option<(String, String)> {
59 match value {
60 Expr::New { type_name, type_args, init_fields } if init_fields.is_empty() => {
61 match interner.resolve(*type_name) {
62 "Seq" | "List" | "Vec" => {
63 let elem = codegen_type_expr(type_args.first()?, interner);
64 Some((format!("Vec<{}>", elem), "Vec::new()".to_string()))
65 }
66 _ => None,
67 }
68 }
69 Expr::WithCapacity { value: inner, capacity } => {
70 if let Expr::New { type_name, type_args, .. } = inner {
71 if matches!(interner.resolve(*type_name), "Seq" | "List" | "Vec") {
72 let elem = codegen_type_expr(type_args.first()?, interner);
73 let cap = codegen_expr_boxed_with_types(
74 capacity, interner, synced_vars, boxed_fields, registry,
75 async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
76 );
77 return Some((
78 format!("Vec<{}>", elem),
79 format!("Vec::with_capacity(({}) as usize)", cap),
80 ));
81 }
82 }
83 None
84 }
85 Expr::Call { function, .. } => {
90 let ret = ctx.get_fn_return(function)?;
91 if !ret.starts_with("Vec<") {
92 return None;
93 }
94 let vec_ty = ret.clone();
95 let init = codegen_expr_boxed_with_types(
96 value, interner, synced_vars, boxed_fields, registry,
97 async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
98 );
99 Some((vec_ty, init))
100 }
101 Expr::List(items) => {
105 let elem = crate::codegen::detection::homogeneous_scalar_literal_elem(items)?;
106 let item_strs: Vec<String> = items
107 .iter()
108 .map(|i| {
109 codegen_expr_boxed_with_types(
110 i, interner, synced_vars, boxed_fields, registry, async_functions,
111 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
112 )
113 })
114 .collect();
115 Some((format!("Vec<{}>", elem), format!("vec![{}]", item_strs.join(", "))))
116 }
117 _ => None,
118 }
119}
120
121fn i64_map_ctor<'a>(
126 value: &Expr<'a>,
127 ty: &str,
128 dense_lo: Option<i64>,
129 interner: &Interner,
130 synced_vars: &HashSet<Symbol>,
131 boxed_fields: &HashSet<(String, String, String)>,
132 registry: &TypeRegistry,
133 async_functions: &HashSet<Symbol>,
134 ctx: &RefinementContext<'a>,
135) -> Option<String> {
136 match value {
137 Expr::New { type_name, init_fields, .. }
138 if init_fields.is_empty()
139 && matches!(interner.resolve(*type_name), "Map" | "HashMap") =>
140 {
141 Some(format!("{}::new()", ty))
142 }
143 Expr::WithCapacity { value: inner, capacity } => {
144 if let Expr::New { type_name, .. } = inner {
145 if matches!(interner.resolve(*type_name), "Map" | "HashMap") {
146 let cap = codegen_expr_boxed_with_types(
147 capacity, interner, synced_vars, boxed_fields, registry,
148 async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
149 );
150 return Some(match dense_lo {
156 Some(lo) => {
157 format!("{}::with_bounds({}, (({}) + 1) as usize)", ty, lo, cap)
158 }
159 None => format!("{}::with_capacity(({}) as usize)", ty, cap),
160 });
161 }
162 }
163 None
164 }
165 _ => None,
166 }
167}
168
169fn emit_oracle_index_hints<'a>(
175 stmt: &Stmt<'a>,
176 ctx: &RefinementContext<'a>,
177 interner: &Interner,
178 indent_str: &str,
179) -> String {
180 if !crate::optimize::active_config().is_on(crate::optimization::Opt::OracleHints) {
183 return String::new();
184 }
185 let oracle = match ctx.oracle() {
186 Some(o) => o,
187 None => return String::new(),
188 };
189 let mut accesses: Vec<(&Expr, &Expr)> = Vec::new();
190 collect_index_accesses_in_stmt(stmt, &mut accesses);
191 if accesses.is_empty() {
192 return String::new();
193 }
194 let names = RustNames::new(interner);
195 let mut out = String::new();
196 let mut seen: HashSet<usize> = HashSet::new();
197 for (coll, idx) in accesses {
198 let arr = match coll {
199 Expr::Identifier(s) => *s,
200 _ => continue,
201 };
202 if ctx.affine_array(arr).is_some() {
205 continue;
206 }
207 let aos_backing = parse_aos_tag(ctx.get_variable_types().get(&arr)).map(|t| t.backing);
213 if !seen.insert(idx as *const Expr as usize) {
214 continue;
215 }
216 if !oracle.index_provably_in_bounds(coll, idx) {
217 continue;
218 }
219 for &m in oracle.index_positivity_guards(idx) {
226 let mn = names.ident(m);
227 writeln!(
228 out,
229 "{}assert!(({mn}) > 0, \"LOGOS positivity guard: element bound on `% {mn}` requires {mn} > 0\");",
230 indent_str, mn = mn
231 )
232 .unwrap();
233 }
234 let i0 = match idx {
238 Expr::Identifier(c)
239 if ctx
240 .get_variable_types()
241 .get(c)
242 .map_or(false, |t| t == "__zero_based_i64") =>
243 {
244 names.ident(*c)
245 }
246 _ => simplify_1based_index(idx, interner, false, ctx.get_variable_types()),
247 };
248 let arr_name = aos_backing.unwrap_or_else(|| names.ident(arr));
249 let cond = format!("({}) >= 0 && ({}) < ({}.len() as i64)", i0, i0, arr_name);
250 writeln!(out, "{}debug_assert!({}, \"LOGOS oracle bounds hint violated: indexing `{}` out of range\");", indent_str, cond, arr_name).unwrap();
251 writeln!(out, "{}unsafe {{ std::hint::assert_unchecked({}); }}", indent_str, cond).unwrap();
252 }
253 if !out.is_empty() {
254 crate::optimize::mark_fired(crate::optimization::Opt::OracleHints);
255 }
256 out
257}
258
259fn collect_index_accesses_in_stmt<'a>(stmt: &'a Stmt<'a>, out: &mut Vec<(&'a Expr<'a>, &'a Expr<'a>)>) {
260 match stmt {
261 Stmt::Let { value, .. } | Stmt::Set { value, .. } => collect_index_in_expr(value, out),
262 Stmt::SetIndex { collection, index, value } => {
263 out.push((collection, index));
264 collect_index_in_expr(index, out);
265 collect_index_in_expr(value, out);
266 }
267 Stmt::If { cond, .. } | Stmt::While { cond, .. } => collect_index_in_expr(cond, out),
268 Stmt::Show { object, .. } | Stmt::Give { object, .. } => collect_index_in_expr(object, out),
269 Stmt::Return { value: Some(e) } => collect_index_in_expr(e, out),
270 Stmt::Push { value, .. } | Stmt::Add { value, .. } | Stmt::Remove { value, .. } => {
271 collect_index_in_expr(value, out)
272 }
273 _ => {}
274 }
275}
276
277fn collect_index_in_expr<'a>(e: &'a Expr<'a>, out: &mut Vec<(&'a Expr<'a>, &'a Expr<'a>)>) {
278 match e {
279 Expr::Index { collection, index } => {
280 out.push((collection, index));
281 collect_index_in_expr(collection, out);
282 collect_index_in_expr(index, out);
283 }
284 Expr::BinaryOp { left, right, .. } => {
285 collect_index_in_expr(left, out);
286 collect_index_in_expr(right, out);
287 }
288 Expr::Not { operand } => collect_index_in_expr(operand, out),
289 Expr::Call { args, .. } => {
290 for a in args.iter() {
291 collect_index_in_expr(a, out);
292 }
293 }
294 Expr::Length { collection } => collect_index_in_expr(collection, out),
295 _ => {}
296 }
297}
298
299pub(crate) struct AffineOffsetGuard<'a> {
308 arr_sym: Symbol,
309 offset: &'a Expr<'a>,
311 emitted_index: &'a Expr<'a>,
313}
314
315fn match_affine_offset_index<'a>(
319 index: &'a Expr<'a>,
320 counter: Symbol,
321) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
322 if let Expr::BinaryOp { op: BinaryOpKind::Add, left, right } = index {
323 if matches!(right, Expr::Literal(Literal::Number(1))) {
324 if let Expr::BinaryOp { op: BinaryOpKind::Add, left: a, right: b } = left {
325 if matches!(b, Expr::Identifier(s) if *s == counter) {
326 return Some((a, left));
327 }
328 if matches!(a, Expr::Identifier(s) if *s == counter) {
329 return Some((b, left));
330 }
331 }
332 }
333 }
334 None
335}
336
337pub(crate) fn plan_affine_offset_guards<'a>(
344 body: &'a [Stmt<'a>],
345 counter_sym: Symbol,
346 is_exclusive: bool,
347 var_types: &HashMap<Symbol, String>,
348) -> Vec<AffineOffsetGuard<'a>> {
349 if !is_exclusive || body_has_early_exit(body) {
350 return Vec::new();
351 }
352 let mut guards: Vec<AffineOffsetGuard> = Vec::new();
353 let mut seen: HashSet<Symbol> = HashSet::new();
354 for stmt in body {
355 let mut accesses: Vec<(&Expr, &Expr)> = Vec::new();
356 collect_index_accesses_in_stmt(stmt, &mut accesses);
357 for (coll, index) in accesses {
358 let arr_sym = match coll {
359 Expr::Identifier(s) => *s,
360 _ => continue,
361 };
362 let Some((offset, emitted)) = match_affine_offset_index(index, counter_sym) else {
363 continue;
364 };
365 let base_ty = var_types
366 .get(&arr_sym)
367 .map(|t| t.split("|__hl:").next().unwrap_or(t.as_str()));
368 let qualifies = matches!(
369 base_ty,
370 Some(t) if t.starts_with("Vec<") || t.starts_with("LogosSeq")
371 || t.starts_with("&[") || t.starts_with("&mut [")
372 );
373 if !qualifies
374 || body_resizes_collection(body, arr_sym)
375 || body_modifies_var(body, arr_sym)
376 {
377 continue;
378 }
379 let mut osyms = Vec::new();
380 collect_expr_symbols(offset, &mut osyms);
381 if osyms.contains(&counter_sym)
382 || osyms
383 .iter()
384 .any(|s| body_modifies_var(body, *s) || body_mutates_collection(body, *s))
385 {
386 continue;
387 }
388 if seen.insert(arr_sym) {
389 guards.push(AffineOffsetGuard { arr_sym, offset, emitted_index: emitted });
390 }
391 }
392 }
393 guards
394}
395
396pub(crate) fn emit_affine_offset_preheader(
401 guards: &[AffineOffsetGuard],
402 limit_str: &str,
403 interner: &Interner,
404 synced_vars: &HashSet<Symbol>,
405 async_functions: &HashSet<Symbol>,
406 var_types: &HashMap<Symbol, String>,
407 indent_str: &str,
408 output: &mut String,
409) {
410 let names = RustNames::new(interner);
411 for g in guards {
412 let arr = names.ident(g.arr_sym);
413 let off = codegen_expr_with_async(g.offset, interner, synced_vars, async_functions, var_types);
414 writeln!(
415 output,
416 "{}assert!(({off}) >= 0 && (({off}) + ({lim}) - 1) < ({arr}.len() as i64), \"LOGOS bounds guard: indexing `{arr}` (row-major) out of range\");",
417 indent_str, off = off, lim = limit_str, arr = arr
418 ).unwrap();
419 }
420}
421
422pub(crate) fn emit_affine_offset_header(
426 guards: &[AffineOffsetGuard],
427 interner: &Interner,
428 synced_vars: &HashSet<Symbol>,
429 async_functions: &HashSet<Symbol>,
430 var_types: &HashMap<Symbol, String>,
431 body_indent: &str,
432 output: &mut String,
433) {
434 let names = RustNames::new(interner);
435 for g in guards {
436 let arr = names.ident(g.arr_sym);
437 let e = codegen_expr_with_async(g.emitted_index, interner, synced_vars, async_functions, var_types);
438 writeln!(
439 output,
440 "{}unsafe {{ std::hint::assert_unchecked(({e}) >= 0 && ({e}) < ({arr}.len() as i64)); }}",
441 body_indent, e = e, arr = arr
442 ).unwrap();
443 }
444}
445
446#[allow(clippy::too_many_arguments)]
449fn write_tokio_select<'a>(
450 output: &mut String,
451 branches: &[crate::ast::stmt::SelectBranch<'a>],
452 interner: &Interner,
453 indent: usize,
454 mutable_vars: &HashSet<Symbol>,
455 ctx: &mut RefinementContext<'a>,
456 lww_fields: &HashSet<(String, String)>,
457 mv_fields: &HashSet<(String, String)>,
458 synced_vars: &mut HashSet<Symbol>,
459 var_caps: &HashMap<Symbol, VariableCapabilities>,
460 async_functions: &HashSet<Symbol>,
461 pipe_vars: &HashSet<Symbol>,
462 boxed_fields: &HashSet<(String, String, String)>,
463 registry: &TypeRegistry,
464 type_env: &crate::analysis::types::TypeEnv,
465) {
466 use crate::ast::stmt::SelectBranch;
467 let indent_str = " ".repeat(indent);
468 writeln!(output, "{}tokio::select! {{", indent_str).unwrap();
469 for branch in branches {
470 match branch {
471 SelectBranch::Receive { var, pipe, body } => {
472 let var_name = interner.resolve(*var);
473 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
474 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
475 pipe_vars.contains(sym)
476 } else {
477 false
478 };
479 let suffix = if is_local_pipe { "_rx" } else { "" };
480 writeln!(output, "{} {} = {}{}.recv() => {{", indent_str, var_name, pipe_str, suffix).unwrap();
481 writeln!(output, "{} if let Some({}) = {} {{", indent_str, var_name, var_name).unwrap();
482 for stmt in *body {
483 let stmt_code = codegen_stmt(stmt, interner, indent + 3, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
484 write!(output, "{}", stmt_code).unwrap();
485 }
486 writeln!(output, "{} }}", indent_str).unwrap();
487 writeln!(output, "{} }}", indent_str).unwrap();
488 }
489 SelectBranch::Timeout { milliseconds, body } => {
490 let dur = match milliseconds {
491 Expr::Literal(Literal::Duration(_)) => codegen_expr_with_async(
492 milliseconds, interner, synced_vars, async_functions,
493 ctx.get_variable_types(),
494 ),
495 Expr::Literal(Literal::Span { months, days }) => {
496 let secs = ((*months as i64) * 30 + (*days as i64)) * 86_400;
497 format!("std::time::Duration::from_secs({}u64)", secs.max(0))
498 }
499 _ => {
500 let n = codegen_expr_with_async(
501 milliseconds, interner, synced_vars, async_functions,
502 ctx.get_variable_types(),
503 );
504 format!("std::time::Duration::from_secs({} as u64)", n)
505 }
506 };
507 writeln!(output, "{} _ = tokio::time::sleep({}) => {{", indent_str, dur).unwrap();
508 for stmt in *body {
509 let stmt_code = codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
510 write!(output, "{}", stmt_code).unwrap();
511 }
512 writeln!(output, "{} }}", indent_str).unwrap();
513 }
514 }
515 }
516 writeln!(output, "{}}}", indent_str).unwrap();
517}
518
519#[allow(clippy::too_many_arguments)]
526fn write_seeded_select<'a>(
527 output: &mut String,
528 branches: &[crate::ast::stmt::SelectBranch<'a>],
529 interner: &Interner,
530 indent: usize,
531 mutable_vars: &HashSet<Symbol>,
532 ctx: &mut RefinementContext<'a>,
533 lww_fields: &HashSet<(String, String)>,
534 mv_fields: &HashSet<(String, String)>,
535 synced_vars: &mut HashSet<Symbol>,
536 var_caps: &HashMap<Symbol, VariableCapabilities>,
537 async_functions: &HashSet<Symbol>,
538 pipe_vars: &HashSet<Symbol>,
539 boxed_fields: &HashSet<(String, String, String)>,
540 registry: &TypeRegistry,
541 type_env: &crate::analysis::types::TypeEnv,
542) {
543 use crate::ast::stmt::SelectBranch;
544 let indent_str = " ".repeat(indent);
545 writeln!(output, "{}{{", indent_str).unwrap();
546 writeln!(output, "{} let mut __logos_ready: Vec<usize> = Vec::new();", indent_str).unwrap();
547 let mut recv_idx = 0usize;
548 for branch in branches {
549 if let SelectBranch::Receive { pipe, .. } = branch {
550 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
551 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
552 pipe_vars.contains(sym)
553 } else {
554 false
555 };
556 let suffix = if is_local_pipe { "_rx" } else { "" };
557 writeln!(
558 output,
559 "{} if {}{}.len() > 0 {{ __logos_ready.push({}); }}",
560 indent_str, pipe_str, suffix, recv_idx
561 ).unwrap();
562 recv_idx += 1;
563 }
564 }
565 writeln!(output, "{} if __logos_ready.is_empty() {{", indent_str).unwrap();
566 write_tokio_select(
567 output, branches, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields,
568 synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env,
569 );
570 writeln!(output, "{} }} else {{", indent_str).unwrap();
571 writeln!(
572 output,
573 "{} let __logos_pick = __logos_ready[logicaffeine_system::concurrency::seeded_pick(__logos_ready.len())];",
574 indent_str
575 ).unwrap();
576 writeln!(output, "{} match __logos_pick {{", indent_str).unwrap();
577 let mut recv_idx = 0usize;
578 for branch in branches {
579 if let SelectBranch::Receive { var, pipe, body } = branch {
580 let var_name = interner.resolve(*var);
581 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
582 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
583 pipe_vars.contains(sym)
584 } else {
585 false
586 };
587 let suffix = if is_local_pipe { "_rx" } else { "" };
588 writeln!(output, "{} {} => {{", indent_str, recv_idx).unwrap();
589 writeln!(
590 output,
591 "{} if let Some({}) = {}{}.recv().await {{",
592 indent_str, var_name, pipe_str, suffix
593 ).unwrap();
594 for stmt in *body {
595 let stmt_code = codegen_stmt(stmt, interner, indent + 5, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
596 write!(output, "{}", stmt_code).unwrap();
597 }
598 writeln!(output, "{} }}", indent_str).unwrap();
599 writeln!(output, "{} }}", indent_str).unwrap();
600 recv_idx += 1;
601 }
602 }
603 writeln!(output, "{} _ => unreachable!(),", indent_str).unwrap();
604 writeln!(output, "{} }}", indent_str).unwrap();
605 writeln!(output, "{} }}", indent_str).unwrap();
606 writeln!(output, "{}}}", indent_str).unwrap();
607}
608
609fn cow_target(
623 collection: &Expr,
624 ctx: &RefinementContext,
625 names: &RustNames,
626) -> Option<String> {
627 let Expr::Identifier(sym) = collection else { return None };
628 if ctx.is_mutable_collection_param(*sym) {
629 return None;
630 }
631 let ty = ctx.get_variable_types().get(sym)?;
632 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
635 if ty.starts_with("LogosSeq") || ty.starts_with("LogosMap") {
636 Some(names.ident(*sym))
637 } else {
638 None
639 }
640}
641
642fn emit_cow(
650 collection: &Expr,
651 ctx: &RefinementContext,
652 names: &RustNames,
653 indent_str: &str,
654 output: &mut String,
655) {
656 if !crate::semantics::collections::value_semantics_enabled() {
657 return;
658 }
659 if let Some(name) = cow_target(collection, ctx, names) {
660 writeln!(output, "{}{}.cow();", indent_str, name).unwrap();
661 }
662}
663
664fn scratch_fill_target<'a>(
668 body: &[Stmt<'a>],
669 ctx: &RefinementContext<'a>,
670) -> Option<(Symbol, super::affine_array::ScratchInfo)> {
671 for s in body {
672 if let Stmt::Push { collection: Expr::Identifier(c), .. } = s {
673 if let Some(info) = ctx.scratch_buffer(*c) {
674 return Some((*c, info.clone()));
675 }
676 }
677 }
678 None
679}
680
681pub fn codegen_stmt<'a>(
682 stmt: &Stmt<'a>,
683 interner: &Interner,
684 indent: usize,
685 mutable_vars: &HashSet<Symbol>,
686 ctx: &mut RefinementContext<'a>,
687 lww_fields: &HashSet<(String, String)>,
688 mv_fields: &HashSet<(String, String)>, synced_vars: &mut HashSet<Symbol>, var_caps: &HashMap<Symbol, VariableCapabilities>, async_functions: &HashSet<Symbol>, pipe_vars: &HashSet<Symbol>, boxed_fields: &HashSet<(String, String, String)>, registry: &TypeRegistry, type_env: &crate::analysis::types::TypeEnv,
696) -> String {
697 let indent_str = " ".repeat(indent);
698 let mut output = String::new();
699 let names = RustNames::new(interner);
700
701 let live_vars_after: Option<HashSet<Symbol>> = ctx.take_live_vars_after();
705
706 if let Stmt::Let { var, .. } = stmt {
710 if ctx.scratch_buffer(*var).is_some() {
711 return output;
712 }
713 }
714
715 output.push_str(&emit_oracle_index_hints(stmt, ctx, interner, &indent_str));
719
720 match stmt {
721 Stmt::Splice { body } => {
722 for inner in body.iter() {
726 output.push_str(&codegen_stmt(inner, interner, indent, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
727 }
728 }
729 Stmt::Let { var, ty, value, mutable } => {
730 let var_name = names.ident(*var);
731
732 if matches!(value, Expr::New { .. }) {
737 if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(var)) {
738 if tag.col == 0 {
739 let default = match tag.elem.as_str() {
740 "f64" => "0f64",
741 "bool" => "false",
742 _ => "0i64",
743 };
744 writeln!(
745 output,
746 "{}let mut {}: [[{}; {}]; {}] = [[{}; {}]; {}];",
747 indent_str, tag.backing, tag.elem, tag.width, tag.len, default, tag.width, tag.len
748 )
749 .unwrap();
750 }
751 return output;
752 }
753 }
754
755 if ctx.is_scalarized_array(*var) && matches!(value, Expr::New { .. }) {
760 if let Some(arr_ty) = ctx.get_variable_types().get(var).cloned() {
761 let inner = arr_ty.trim_start_matches('[').trim_end_matches(']');
762 let mut parts = inner.split("; ");
763 let elem = parts.next().unwrap_or("i64");
764 let n = parts.next().unwrap_or("0");
765 let default = match elem {
766 "f64" => "0f64",
767 "bool" => "false",
768 "Word8" => "word8(0)",
769 "Word16" => "word16(0)",
770 "Word32" => "word32(0)",
771 "Word64" => "word64(0)",
772 _ => "0i64",
773 };
774 writeln!(output, "{}let mut {}: {} = [{}; {}];",
775 indent_str, var_name, arr_ty, default, n).unwrap();
776 if let Some(cursor) = ctx.loop_fill_cursor(*var).map(|s| s.to_string()) {
779 writeln!(output, "{}let mut {}: usize = 0;", indent_str, cursor).unwrap();
780 }
781 ctx.init_array_fill(*var);
782 return output;
783 }
784 }
785
786 if matches!(value, Expr::New { .. }) && ctx.affine_array(*var).is_some() {
791 return output;
792 }
793
794 if matches!(value, Expr::New { .. }) {
799 if let Some((cap, default, tail)) =
800 ctx.worklist(*var).map(|w| (w.capacity.clone(), w.elem_default.clone(), w.tail_var.clone()))
801 {
802 writeln!(output, "{}let mut {}: Vec<i64> = vec![{}; {}];", indent_str, var_name, default, cap).unwrap();
803 writeln!(output, "{}let mut {}: usize = 0;", indent_str, tail).unwrap();
804 ctx.register_variable_type(*var, format!("Vec<i64>|__hl:({} as i64)", tail));
808 return output;
809 }
810 }
811
812 if ctx.is_de_rc(*var) {
817 if let Some((vec_ty, init)) = derc_vec_decl(
818 value, interner, synced_vars, boxed_fields, registry, async_functions, ctx,
819 ) {
820 let is_mut = *mutable || mutable_vars.contains(var);
821 let kw = if is_mut { "let mut" } else { "let" };
822 let init = match (init.as_str(), ctx.get_vec_presize(*var)) {
826 ("Vec::new()", Some(cap)) => {
827 format!("Vec::with_capacity(({}) as usize)", cap)
828 }
829 _ => init,
830 };
831 let vec_ty = if ctx.is_narrowed(*var) && vec_ty == "Vec<i64>" {
834 "Vec<i32>".to_string()
835 } else {
836 vec_ty
837 };
838 writeln!(output, "{}{} {}: {} = {};", indent_str, kw, var_name, vec_ty, init).unwrap();
839 for g in ctx.narrow_guards(*var).to_vec() {
840 writeln!(output, "{}assert!({}, \"LOGOS i32-narrowing guard: element value must fit i32\");", indent_str, g).unwrap();
841 }
842 ctx.register_variable_type(*var, vec_ty);
843 return output;
844 }
845 }
846
847 if let Some(TypeExpr::Generic { base, params }) = ty {
850 let base_name = interner.resolve(*base);
851 match base_name {
852 "Seq" | "List" | "Vec" => {
853 let rust_type = if !params.is_empty() {
854 format!("LogosSeq<{}>", codegen_type_expr(¶ms[0], interner))
855 } else {
856 "LogosSeq<()>".to_string()
857 };
858 ctx.register_variable_type(*var, rust_type);
859 }
860 "Map" | "HashMap" => {
861 let rust_type = if params.len() >= 2 {
862 map_rust_type(
863 &codegen_type_expr(¶ms[0], interner),
864 &codegen_type_expr(¶ms[1], interner),
865 *var,
866 ctx,
867 )
868 } else {
869 "LogosMap<String, String>".to_string()
870 };
871 ctx.register_variable_type(*var, rust_type);
872 }
873 _ => {}
874 }
875 } else if let Expr::New { type_name, type_args, .. } = value {
876 let type_str = interner.resolve(*type_name);
877 match type_str {
878 "Seq" | "List" | "Vec" => {
879 let rust_type = if !type_args.is_empty() {
880 format!("LogosSeq<{}>", codegen_type_expr(&type_args[0], interner))
881 } else {
882 "LogosSeq<()>".to_string()
883 };
884 ctx.register_variable_type(*var, rust_type);
885 }
886 "Map" | "HashMap" => {
887 let rust_type = if type_args.len() >= 2 {
888 map_rust_type(
889 &codegen_type_expr(&type_args[0], interner),
890 &codegen_type_expr(&type_args[1], interner),
891 *var,
892 ctx,
893 )
894 } else {
895 "LogosMap<String, String>".to_string()
896 };
897 ctx.register_variable_type(*var, rust_type);
898 }
899 _ => {}
900 }
901 } else if let Expr::List(items) = value {
902 let elem_type = items.first()
904 .map(|e| infer_rust_type_from_expr(e, interner))
905 .unwrap_or_else(|| "_".to_string());
906 ctx.register_variable_type(*var, format!("LogosSeq<{}>", elem_type));
907 } else if let Expr::Identifier(src_sym) = value {
908 if let Some(src_type) = ctx.get_variable_types().get(src_sym).cloned() {
911 if src_type.starts_with("&[") {
912 ctx.register_variable_type(*var, src_type);
914 } else if src_type.starts_with("&mut [") {
915 ctx.register_variable_type(*var, src_type);
918 } else if !super::is_fn_role_slot(&src_type) {
919 ctx.register_variable_type(*var, src_type);
920 }
921 }
922 } else if let Expr::Copy { expr: inner } = value {
923 let src_sym = match inner {
925 Expr::Slice { collection, .. } => {
926 if let Expr::Identifier(s) = collection { Some(*s) } else { None }
927 }
928 Expr::Identifier(s) => Some(*s),
929 _ => None,
930 };
931 if let Some(s) = src_sym {
932 if let Some(src_type) = ctx.get_variable_types().get(&s).cloned() {
933 if src_type.starts_with("LogosSeq") || src_type.starts_with("Vec") || src_type.starts_with("&[") {
934 let elem = if src_type.starts_with("LogosSeq<") {
935 src_type.strip_prefix("LogosSeq<").and_then(|t| t.strip_suffix('>')).unwrap_or("_")
936 } else if src_type.starts_with("Vec<") {
937 src_type.strip_prefix("Vec<").and_then(|t| t.strip_suffix('>')).unwrap_or("_")
938 } else {
939 src_type.strip_prefix("&[").and_then(|t| t.strip_suffix(']')).unwrap_or("_")
940 };
941 ctx.register_variable_type(*var, format!("LogosSeq<{}>", elem));
942 } else if src_type.starts_with("LogosMap") {
943 ctx.register_variable_type(*var, src_type);
944 }
945 }
946 }
947 }
948
949 if !ctx.get_variable_types().contains_key(var) {
951 if let Expr::Call { function, .. } = value {
952 if interner.resolve(*function) == "decimal" {
955 ctx.register_variable_type(*var, "LogosDecimal".to_string());
956 } else if interner.resolve(*function) == "complex" {
957 ctx.register_variable_type(*var, "LogosComplex".to_string());
958 } else if interner.resolve(*function) == "modular" {
959 ctx.register_variable_type(*var, "LogosModular".to_string());
960 } else if matches!(interner.resolve(*function), "quantity" | "convert") {
961 ctx.register_variable_type(*var, "LogosQuantity".to_string());
964 } else if interner.resolve(*function) == "money" {
965 ctx.register_variable_type(*var, "LogosMoney".to_string());
968 } else if matches!(
969 interner.resolve(*function),
970 "uuid" | "uuid_nil" | "uuid_max" | "uuid_v3" | "uuid_v5" | "uuid_dns"
971 | "uuid_url" | "uuid_oid" | "uuid_x500"
972 ) {
973 ctx.register_variable_type(*var, "LogosUuid".to_string());
976 } else if let Some(rt) = ctx.get_fn_return(function).cloned() {
977 ctx.register_variable_type(*var, rt);
978 }
979 }
980 }
981
982 if !ctx.get_variable_types().contains_key(var) {
984 let inferred = infer_rust_type_from_expr(value, interner);
985 if inferred != "_" {
986 ctx.register_variable_type(*var, inferred);
987 } else {
988 let numeric = infer_numeric_type(value, interner, ctx.get_variable_types());
990 if numeric != "unknown" {
991 ctx.register_variable_type(*var, numeric.to_string());
992 } else if let crate::analysis::types::LogosType::Map(k, v) =
993 super::types::infer_logos_type(value, interner, ctx.get_variable_types())
994 {
995 ctx.register_variable_type(
1000 *var,
1001 crate::analysis::types::LogosType::Map(k, v).to_rust_type(),
1002 );
1003 }
1004 }
1005 }
1006
1007 if matches!(value, Expr::List(_))
1012 && ctx.get_variable_types().get(var).map_or(false, |t| t == "LogosSeq<_>")
1013 {
1014 if let crate::analysis::types::LogosType::Seq(inner) =
1015 super::types::infer_logos_type(value, interner, ctx.get_variable_types())
1016 {
1017 if matches!(*inner, crate::analysis::types::LogosType::Seq(_)) {
1018 ctx.register_variable_type(
1019 *var,
1020 crate::analysis::types::LogosType::Seq(inner).to_rust_type(),
1021 );
1022 }
1023 }
1024 }
1025
1026 let is_single_char_u8 = ctx.get_variable_types().get(var)
1029 .map_or(false, |t| t == "__single_char_u8");
1030
1031 if is_single_char_u8 {
1032 if let Expr::Literal(Literal::Text(sym)) = value {
1033 let text = interner.resolve(*sym);
1034 if text.len() == 1 {
1035 let ch = text.as_bytes()[0];
1036 let is_mutable = *mutable || mutable_vars.contains(var);
1037 if is_mutable {
1038 writeln!(output, "{}let mut {}: u8 = b'{}';", indent_str, var_name, ch as char).unwrap();
1039 } else {
1040 writeln!(output, "{}let {}: u8 = b'{}';", indent_str, var_name, ch as char).unwrap();
1041 }
1042 return output;
1044 }
1045 }
1046 }
1047
1048 if let Expr::Slice { collection, start, end } = value {
1053 if let Expr::Identifier(coll_sym) = collection {
1054 if let Some(coll_type) = ctx.get_variable_types().get(coll_sym).cloned() {
1055 if coll_type.starts_with("LogosSeq<") {
1056 let elem_type = coll_type.strip_prefix("LogosSeq<")
1057 .and_then(|t| t.strip_suffix('>'))
1058 .unwrap_or("_");
1059 let coll_name = names.ident(*coll_sym);
1060 let start_str = codegen_expr_boxed_with_types(
1061 start, interner, synced_vars, boxed_fields, registry, async_functions,
1062 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1063 );
1064 let end_str = codegen_expr_boxed_with_types(
1065 end, interner, synced_vars, boxed_fields, registry, async_functions,
1066 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1067 );
1068 let is_mutable = *mutable || mutable_vars.contains(var);
1069 let mutk = if is_mutable { "mut " } else { "" };
1070 writeln!(output, "{}let {}{}: Vec<{}> = {}.borrow()[({} - 1) as usize..{} as usize].to_vec();",
1071 indent_str, mutk, var_name, elem_type, coll_name, start_str, end_str).unwrap();
1072 ctx.register_variable_type(*var, format!("Vec<{}>", elem_type));
1075 if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1076 ctx.register_string_var(*var);
1077 }
1078 return output;
1079 } else if coll_type.starts_with("&[") {
1080 let elem_type = coll_type.strip_prefix("&[")
1081 .and_then(|t| t.strip_suffix(']'))
1082 .unwrap_or("_");
1083 let coll_name = names.ident(*coll_sym);
1084 let start_str = codegen_expr_boxed_with_types(
1085 start, interner, synced_vars, boxed_fields, registry, async_functions,
1086 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1087 );
1088 let end_str = codegen_expr_boxed_with_types(
1089 end, interner, synced_vars, boxed_fields, registry, async_functions,
1090 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1091 );
1092 let is_mutable = *mutable || mutable_vars.contains(var);
1093 let mutk = if is_mutable { "mut " } else { "" };
1094 writeln!(output, "{}let {}{}: Vec<{}> = {}[({} - 1) as usize..{} as usize].to_vec();",
1096 indent_str, mutk, var_name, elem_type, coll_name, start_str, end_str).unwrap();
1097 ctx.register_variable_type(*var, format!("Vec<{}>", elem_type));
1098 if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1099 ctx.register_string_var(*var);
1100 }
1101 return output;
1102 }
1103 }
1104 }
1105 }
1106
1107 let is_bigint_binding = ty.is_none()
1112 && ctx.is_promotable_candidate(*var)
1113 && crate::codegen::types::infer_numeric_type(value, interner, ctx.get_variable_types()) == "i64";
1114 if is_bigint_binding {
1115 ctx.register_variable_type(*var, "i64|__bigint".to_string());
1116 }
1117
1118 let mut value_str = if is_bigint_binding {
1120 let raw = codegen_expr_boxed_with_types_oracle_tolerant(
1123 value, interner, synced_vars, boxed_fields, registry, async_functions,
1124 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1125 );
1126 format!("logicaffeine_data::LogosInt::from({})", raw)
1127 } else {
1128 codegen_expr_boxed_with_types_oracle(
1129 value, interner, synced_vars, boxed_fields, registry, async_functions,
1130 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1131 )
1132 };
1133
1134 if ctx.is_i64_map(*var) {
1140 let dense = ctx.dense_info(*var);
1144 let i64_ty = if let Some(info) = dense {
1145 dense_type_name(info.kind)
1146 } else if ctx.is_i32_set(*var) {
1147 "LogosI32Set"
1148 } else if ctx.is_i32_map(*var) {
1149 "LogosI32Map"
1150 } else if ctx.is_i64_set(*var) {
1151 "LogosI64Set"
1152 } else {
1153 "LogosI64Map"
1154 };
1155 if let Some(ctor) = i64_map_ctor(
1156 value, i64_ty, dense.map(|i| i.lo), interner, synced_vars, boxed_fields,
1157 registry, async_functions, ctx,
1158 ) {
1159 value_str = ctor;
1160 ctx.register_variable_type(*var, i64_ty.to_string());
1161 }
1162 }
1163
1164 let is_mutable = *mutable || mutable_vars.contains(var) || ctx.is_i64_map(*var);
1168
1169 if let Expr::Identifier(src_sym) = value {
1172 if let Some(src_type) = ctx.get_variable_types().get(src_sym) {
1173 if src_type.starts_with("LogosSeq") || src_type.starts_with("LogosMap") {
1174 value_str = format!("{}.clone()", value_str);
1175 } else if is_mutable && src_type.starts_with("&[") {
1176 value_str = format!("{}.to_vec()", value_str);
1177 }
1178 }
1179 }
1180
1181 let type_annotation = if is_bigint_binding {
1183 Some("logicaffeine_data::LogosInt".to_string())
1184 } else {
1185 ty.map(|t| codegen_type_expr(t, interner))
1186 .or_else(|| infer_variant_type_annotation(value, registry, interner))
1187 };
1188
1189 if type_annotation.as_deref() == Some("LogosRational") {
1194 if !is_rational_expr(value, ctx.get_variable_types()) {
1195 value_str = format!("LogosRational::from_i64(({}) as i64)", value_str);
1196 }
1197 ctx.register_variable_type(*var, "LogosRational".to_string());
1198 }
1199
1200 match (is_mutable, type_annotation) {
1201 (true, Some(t)) => writeln!(output, "{}let mut {}: {} = {};", indent_str, var_name, t, value_str).unwrap(),
1202 (true, None) => writeln!(output, "{}let mut {} = {};", indent_str, var_name, value_str).unwrap(),
1203 (false, Some(t)) => writeln!(output, "{}let {}: {} = {};", indent_str, var_name, t, value_str).unwrap(),
1204 (false, None) => writeln!(output, "{}let {} = {};", indent_str, var_name, value_str).unwrap(),
1205 }
1206
1207 if let Some(helper) = ctx.get_fast_div().get(var) {
1212 writeln!(
1213 output,
1214 "{}let {} = logicaffeine_data::LogosDivU64::new(({}) as u64);",
1215 indent_str, helper, var_name
1216 )
1217 .unwrap();
1218 }
1219
1220 if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1222 ctx.register_string_var(*var);
1223 }
1224
1225 if let Some(TypeExpr::Refinement { base: _, var: bound_var, predicate }) = ty {
1227 emit_refinement_check(&var_name, *bound_var, predicate, interner, &indent_str, &mut output);
1228 ctx.register(*var, *bound_var, predicate);
1229 }
1230 }
1231
1232 Stmt::Set { target, value } => {
1233 let target_name = names.ident(*target);
1234
1235 if ctx.is_bigint_var(*target) {
1241 let raw = codegen_expr_boxed_with_types_oracle_tolerant(
1242 value, interner, synced_vars, boxed_fields, registry, async_functions,
1243 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1244 );
1245 writeln!(output, "{}{} = logicaffeine_data::LogosInt::from({});", indent_str, target_name, raw).unwrap();
1246 if let Some((bound_var, predicate)) = ctx.get_constraint(*target) {
1247 emit_refinement_check(&target_name, bound_var, predicate, interner, &indent_str, &mut output);
1248 }
1249 return output;
1250 }
1251
1252 if let Some(cursor) = ctx.indexed_string_build(*target).map(|c| c.to_string()) {
1257 if let Expr::BinaryOp { op: BinaryOpKind::Add, right, .. } = value {
1258 match right {
1259 Expr::Literal(Literal::Text(sym)) => {
1260 let lit = interner.resolve(*sym);
1261 let bytes: Vec<String> =
1262 lit.bytes().map(|b| format!("{}u8", b)).collect();
1263 writeln!(
1264 output,
1265 "{ind}unsafe {{ std::ptr::copy_nonoverlapping([{b}].as_ptr(), {t}.as_mut_vec().as_mut_ptr().add(({c}) as usize), {k}); }}",
1266 ind = indent_str, t = target_name, c = cursor, k = lit.len(), b = bytes.join(", ")
1267 )
1268 .unwrap();
1269 return output;
1270 }
1271 Expr::Identifier(v)
1272 if ctx.get_variable_types().get(v).map(String::as_str)
1273 == Some("__single_char_u8") =>
1274 {
1275 let vn = names.ident(*v);
1276 writeln!(
1277 output,
1278 "{ind}unsafe {{ *{t}.as_mut_vec().as_mut_ptr().add(({c}) as usize) = {vn}; }}",
1279 ind = indent_str, t = target_name, c = cursor
1280 )
1281 .unwrap();
1282 return output;
1283 }
1284 _ => {}
1285 }
1286 }
1287 }
1288
1289 if ctx.is_de_rc(*target) {
1292 if let Some((_, init)) = derc_vec_decl(
1293 value, interner, synced_vars, boxed_fields, registry, async_functions, ctx,
1294 ) {
1295 writeln!(output, "{}{} = {};", indent_str, target_name, init).unwrap();
1296 return output;
1297 }
1298 }
1299
1300 let is_target_single_char_u8 = ctx.get_variable_types().get(target)
1302 .map_or(false, |t| t == "__single_char_u8");
1303 if is_target_single_char_u8 {
1304 if let Expr::Literal(Literal::Text(sym)) = value {
1305 let text = interner.resolve(*sym);
1306 if text.len() == 1 {
1307 let ch = text.as_bytes()[0];
1308 writeln!(output, "{}{} = b'{}';", indent_str, target_name, ch as char).unwrap();
1309 return output;
1310 }
1311 }
1312 }
1313
1314 let string_vars = ctx.get_string_vars();
1315 let var_types = ctx.get_variable_types();
1316
1317 let used_write = if ctx.is_string_var(*target)
1321 && is_definitely_string_expr_with_vars(value, string_vars)
1322 {
1323 let mut operands = Vec::new();
1324 collect_string_concat_operands(value, string_vars, &mut operands);
1325
1326 if operands.len() >= 2 && matches!(operands[0], Expr::Identifier(sym) if *sym == *target) {
1328 let tail = &operands[1..];
1330 let mut tail_ids = HashSet::new();
1331 for op in tail {
1332 collect_expr_identifiers(op, &mut tail_ids);
1333 }
1334
1335 if !tail_ids.contains(target) {
1336 if tail.len() == 1 {
1337 let operand = tail[0];
1339 if let Expr::Literal(Literal::Text(sym)) = operand {
1340 let text = interner.resolve(*sym);
1341 if text.len() == 1 {
1342 let ch = text.chars().next().unwrap();
1343 writeln!(output, "{}{}.push('{}');",
1344 indent_str, target_name, ch).unwrap();
1345 } else {
1346 writeln!(output, "{}{}.push_str(\"{}\");",
1347 indent_str, target_name, text).unwrap();
1348 }
1349 } else if let Expr::Identifier(sym) = operand {
1350 if var_types.get(sym).map_or(false, |t| t == "__single_char_u8") {
1351 let val_str = codegen_expr_boxed_with_types(
1353 operand, interner, synced_vars, boxed_fields, registry, async_functions,
1354 string_vars, var_types, ctx.get_fast_div()
1355 );
1356 writeln!(output, "{}{}.push({} as char);",
1357 indent_str, target_name, val_str).unwrap();
1358 } else if string_vars.contains(sym) {
1359 let val_str = codegen_expr_boxed_with_types(
1360 operand, interner, synced_vars, boxed_fields, registry, async_functions,
1361 string_vars, var_types, ctx.get_fast_div()
1362 );
1363 writeln!(output, "{}{}.push_str(&{});",
1364 indent_str, target_name, val_str).unwrap();
1365 } else {
1366 let val_str = codegen_expr_boxed_with_types(
1368 operand, interner, synced_vars, boxed_fields, registry, async_functions,
1369 string_vars, var_types, ctx.get_fast_div()
1370 );
1371 writeln!(output, "{}write!({}, \"{{}}\", {}).unwrap();",
1372 indent_str, target_name, val_str).unwrap();
1373 }
1374 } else {
1375 let val_str = codegen_expr_boxed_with_types(
1377 operand, interner, synced_vars, boxed_fields, registry, async_functions,
1378 string_vars, var_types, ctx.get_fast_div()
1379 );
1380 writeln!(output, "{}write!({}, \"{{}}\", {}).unwrap();",
1381 indent_str, target_name, val_str).unwrap();
1382 }
1383 } else {
1384 let placeholders: String = tail.iter().map(|_| "{}").collect::<Vec<_>>().join("");
1386 let values: Vec<String> = tail.iter().map(|e| {
1387 if let Expr::Literal(Literal::Text(sym)) = e {
1388 format!("\"{}\"", interner.resolve(*sym))
1389 } else {
1390 codegen_expr_boxed_with_types(
1391 e, interner, synced_vars, boxed_fields, registry, async_functions,
1392 string_vars, var_types, ctx.get_fast_div()
1393 )
1394 }
1395 }).collect();
1396 writeln!(output, "{}write!({}, \"{}\", {}).unwrap();",
1397 indent_str, target_name, placeholders, values.join(", ")).unwrap();
1398 }
1399 true
1400 } else {
1401 false
1402 }
1403 } else {
1404 false
1405 }
1406 } else {
1407 false
1408 };
1409
1410 if !used_write {
1411 let mut used_mut_borrow = false;
1415 if let Expr::Call { function, args } = value {
1416 let callee_mut_borrow_indices: HashSet<usize> =
1417 super::fn_role_indices(var_types.get(function), super::FnRole::MutBorrow);
1418 if !callee_mut_borrow_indices.is_empty() {
1419 let target_at_mut_borrow = args.iter().enumerate()
1421 .any(|(i, a)| {
1422 callee_mut_borrow_indices.contains(&i)
1423 && matches!(a, Expr::Identifier(sym) if *sym == *target)
1424 });
1425 if target_at_mut_borrow {
1426 let callee_borrow_indices: HashSet<usize> =
1427 super::fn_role_indices(var_types.get(function), super::FnRole::Borrow);
1428 let func_name = names.ident(*function);
1429 let args_str: Vec<String> = args.iter().enumerate()
1430 .map(|(i, a)| {
1431 let s = codegen_expr_boxed_with_types(
1432 a, interner, synced_vars, boxed_fields, registry,
1433 async_functions, string_vars, var_types, ctx.get_fast_div()
1434 );
1435 if callee_mut_borrow_indices.contains(&i) {
1436 if let Expr::Identifier(sym) = a {
1438 if let Some(ty) = var_types.get(sym) {
1439 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1440 if ty.starts_with("&mut [") {
1441 return s; }
1443 if ty.starts_with("Vec<") {
1446 return format!("&mut {}", s);
1447 }
1448 if ty.starts_with("LogosSeq") {
1449 return format!("&mut *{}.borrow_mut()", s);
1450 }
1451 }
1452 return format!("&mut *{}.borrow_mut()", s);
1454 }
1455 format!("&mut {}", s)
1456 } else if callee_borrow_indices.contains(&i) {
1457 if let Expr::Identifier(sym) = a {
1458 if let Some(ty) = var_types.get(sym) {
1459 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1460 if ty.starts_with("&[") || ty.starts_with("&mut [") {
1461 return s;
1462 }
1463 if ty.starts_with("Vec<") {
1464 return format!("&{}", s);
1465 }
1466 if ty.starts_with('[') {
1467 return format!("&{}", s);
1469 }
1470 if ty.starts_with("LogosSeq") {
1471 return format!("&*{}.borrow()", s);
1472 }
1473 }
1474 return format!("&*{}.borrow()", s);
1476 }
1477 format!("&*{}.borrow()", s)
1478 } else {
1479 s
1480 }
1481 })
1482 .collect();
1483 if crate::semantics::collections::value_semantics_enabled() {
1489 for (i, a) in args.iter().enumerate() {
1490 if !callee_mut_borrow_indices.contains(&i) {
1491 continue;
1492 }
1493 if let Expr::Identifier(sym) = a {
1494 let lends_refcell = match var_types.get(sym) {
1495 Some(t) => t
1496 .split("|__hl:")
1497 .next()
1498 .unwrap_or(t.as_str())
1499 .starts_with("LogosSeq"),
1500 None => true, };
1502 if lends_refcell {
1503 writeln!(output, "{}{}.cow();", indent_str, names.ident(*sym)).unwrap();
1504 }
1505 }
1506 }
1507 }
1508 let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
1509 writeln!(output, "{}{}({}){};", indent_str, func_name, args_str.join(", "), await_suffix).unwrap();
1510 used_mut_borrow = true;
1511 }
1512 }
1513 }
1514
1515 let value_str = if used_mut_borrow {
1520 String::new() } else if let Expr::Call { function, args } = value {
1522 let target_positions: Vec<usize> = args.iter().enumerate()
1523 .filter(|(_, a)| matches!(a, Expr::Identifier(sym) if *sym == *target))
1524 .map(|(i, _)| i)
1525 .collect();
1526
1527 let mut other_ids = HashSet::new();
1528 for (i, a) in args.iter().enumerate() {
1529 if target_positions.contains(&i) { continue; }
1530 collect_expr_identifiers(a, &mut other_ids);
1531 }
1532 let target_in_others = other_ids.contains(target);
1533
1534 let callee_borrow_indices: HashSet<usize> =
1535 super::fn_role_indices(var_types.get(function), super::FnRole::Borrow);
1536
1537 let can_move = target_positions.len() == 1
1538 && !callee_borrow_indices.contains(&target_positions[0])
1539 && !target_in_others
1540 && var_types.get(target).map_or(false, |t| !is_copy_type(t));
1541
1542 if can_move {
1543 let func_name = names.ident(*function);
1544 let move_pos = target_positions[0];
1545 let args_str: Vec<String> = args.iter().enumerate()
1546 .map(|(i, a)| {
1547 let s = codegen_expr_boxed_with_types(
1548 a, interner, synced_vars, boxed_fields, registry,
1549 async_functions, string_vars, var_types, ctx.get_fast_div()
1550 );
1551 if callee_borrow_indices.contains(&i) {
1552 if let Expr::Identifier(sym) = a {
1553 if let Some(ty) = var_types.get(sym) {
1554 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1555 if ty.starts_with("&[") || ty.starts_with("&mut [") {
1556 return s;
1557 }
1558 if ty.starts_with("Vec<") {
1559 return format!("&{}", s);
1560 }
1561 if ty.starts_with('[') {
1562 return format!("&{}", s);
1565 }
1566 if ty.starts_with("LogosSeq") {
1567 if *sym == *target {
1568 return format!("&*{}.clone().borrow()", s);
1569 }
1570 return format!("&*{}.borrow()", s);
1571 }
1572 }
1573 if *sym == *target {
1574 return format!("&*{}.clone().borrow()", s);
1575 }
1576 return format!("&*{}.borrow()", s);
1577 }
1578 format!("&*{}.borrow()", s)
1579 } else if i == move_pos {
1580 s } else {
1582 if let Expr::Identifier(sym) = a {
1583 if let Some(ty) = var_types.get(sym) {
1584 if !is_copy_type(ty) {
1585 return format!("{}.clone()", s);
1586 }
1587 }
1588 }
1589 s
1590 }
1591 })
1592 .collect();
1593 if async_functions.contains(function) {
1594 format!("{}({}).await", func_name, args_str.join(", "))
1595 } else {
1596 format!("{}({})", func_name, args_str.join(", "))
1597 }
1598 } else {
1599 let func_name = names.ident(*function);
1609 let args_str: Vec<String> = args.iter().enumerate()
1610 .map(|(i, a)| {
1611 let s = codegen_expr_boxed_with_types(
1612 a, interner, synced_vars, boxed_fields, registry,
1613 async_functions, string_vars, var_types, ctx.get_fast_div()
1614 );
1615 if callee_borrow_indices.contains(&i) {
1616 if let Expr::Identifier(sym) = a {
1617 if let Some(ty) = var_types.get(sym) {
1618 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1619 if ty.starts_with("&[") || ty.starts_with("&mut [") {
1620 return s;
1621 }
1622 if ty.starts_with("Vec<") {
1623 return format!("&{}", s);
1624 }
1625 if ty.starts_with('[') {
1626 return format!("&{}", s);
1629 }
1630 if ty.starts_with("LogosSeq") {
1631 if *sym == *target {
1632 return format!("&*{}.clone().borrow()", s);
1633 }
1634 return format!("&*{}.borrow()", s);
1635 }
1636 }
1637 if *sym == *target {
1638 return format!("&*{}.clone().borrow()", s);
1639 }
1640 return format!("&*{}.borrow()", s);
1641 }
1642 format!("&*{}.borrow()", s)
1643 } else if let Expr::Identifier(sym) = a {
1644 if let Some(ty) = var_types.get(sym) {
1645 if !is_copy_type(ty) {
1646 let can_move_opt1c = live_vars_after
1649 .as_ref()
1650 .map(|live| {
1651 if live.contains(sym) {
1652 return false;
1653 }
1654 let mut other_ids = HashSet::new();
1656 for (j, other_a) in args.iter().enumerate() {
1657 if j == i { continue; }
1658 collect_expr_identifiers(other_a, &mut other_ids);
1659 }
1660 !other_ids.contains(sym)
1661 })
1662 .unwrap_or(false);
1663 if can_move_opt1c {
1664 return s; }
1666 return format!("{}.clone()", s);
1667 }
1668 }
1669 s
1670 } else {
1671 s
1672 }
1673 })
1674 .collect();
1675 if async_functions.contains(function) {
1676 format!("{}({}).await", func_name, args_str.join(", "))
1677 } else {
1678 format!("{}({})", func_name, args_str.join(", "))
1679 }
1680 }
1681 } else {
1682 let mut vs = codegen_expr_boxed_with_types(
1683 value, interner, synced_vars, boxed_fields, registry,
1684 async_functions, string_vars, var_types, ctx.get_fast_div()
1685 );
1686 if let Expr::Identifier(src_sym) = value {
1688 if let Some(src_type) = var_types.get(src_sym) {
1689 if src_type.starts_with("LogosSeq") || src_type.starts_with("LogosMap") {
1690 vs = format!("{}.clone()", vs);
1691 }
1692 }
1693 }
1694 vs
1695 };
1696 if !used_mut_borrow {
1697 writeln!(output, "{}{} = {};", indent_str, target_name, value_str).unwrap();
1698 }
1699 }
1700
1701 if let Some((bound_var, predicate)) = ctx.get_constraint(*target) {
1703 emit_refinement_check(&target_name, bound_var, predicate, interner, &indent_str, &mut output);
1704 }
1705 }
1706
1707 Stmt::Call { function, args } => {
1708 let func_name = names.ident(*function);
1709 let variable_types = ctx.get_variable_types();
1710 let callee_slot = variable_types.get(function);
1714 let callee_borrow_indices: HashSet<usize> =
1715 super::fn_role_indices(callee_slot, super::FnRole::Borrow);
1716 let callee_mut_borrow_indices: HashSet<usize> =
1717 super::fn_role_indices(callee_slot, super::FnRole::MutBorrow);
1718 let callee_value_mutable: HashSet<usize> =
1722 super::fn_role_indices(callee_slot, super::FnRole::ValueMutable);
1723 let args_str: Vec<String> = args.iter().enumerate().map(|(i, a)| {
1724 let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
1725 if callee_value_mutable.contains(&i) {
1726 if let Expr::Identifier(sym) = a {
1729 if variable_types.get(sym).is_some_and(|t| t.starts_with('&')) {
1730 return s;
1731 }
1732 }
1733 return format!("&{}", s);
1734 }
1735 if callee_mut_borrow_indices.contains(&i) {
1736 if let Expr::Identifier(sym) = a {
1738 if let Some(ty) = variable_types.get(sym) {
1739 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1740 if ty.starts_with("&mut [") {
1741 return s; }
1743 if ty.starts_with("Vec<") {
1745 return format!("&mut {}", s);
1746 }
1747 if ty.starts_with("LogosSeq") {
1748 return format!("&mut *{}.borrow_mut()", s);
1749 }
1750 }
1751 return format!("&mut *{}.borrow_mut()", s);
1753 }
1754 format!("&mut {}", s)
1755 } else if callee_borrow_indices.contains(&i) {
1756 if let Expr::Identifier(sym) = a {
1758 if let Some(ty) = variable_types.get(sym) {
1759 let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1760 if ty.starts_with("&[") || ty.starts_with("&mut [") {
1761 return s; }
1763 if ty.starts_with("Vec<") {
1764 return format!("&{}", s);
1765 }
1766 if ty.starts_with('[') {
1767 return format!("&{}", s);
1769 }
1770 if ty.starts_with("LogosSeq") {
1771 return format!("&*{}.borrow()", s);
1772 }
1773 }
1774 return format!("&*{}.borrow()", s);
1776 }
1777 format!("&*{}.borrow()", s)
1778 } else {
1779 if let Expr::Identifier(sym) = a {
1783 if let Some(ty) = variable_types.get(sym) {
1784 if !is_copy_type(ty) {
1785 return format!("{}.clone()", s);
1786 }
1787 }
1788 }
1789 s
1790 }
1791 }).collect();
1792 let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
1794 writeln!(output, "{}{}({}){};", indent_str, func_name, args_str.join(", "), await_suffix).unwrap();
1795 }
1796
1797 Stmt::If { cond, then_block, else_block } => {
1798 let cond_str = codegen_expr_with_async_oracle(cond, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
1799 let cond_str = truthy_cond_wrap(cond, cond_str, interner, ctx.get_variable_types());
1800 writeln!(output, "{}if {} {{", indent_str, cond_str).unwrap();
1801 ctx.push_scope();
1802 {
1803 let block_refs: Vec<&Stmt> = then_block.iter().collect();
1804 let mut bi = 0;
1805 while bi < block_refs.len() {
1806 if let Some((code, skip)) = super::peephole::try_block_peepholes(&block_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1807 output.push_str(&code);
1808 bi += 1 + skip;
1809 continue;
1810 }
1811 output.push_str(&codegen_stmt(block_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
1812 bi += 1;
1813 }
1814 }
1815 ctx.pop_scope();
1816 if let Some(else_stmts) = else_block {
1817 writeln!(output, "{}}} else {{", indent_str).unwrap();
1818 ctx.push_scope();
1819 {
1820 let block_refs: Vec<&Stmt> = else_stmts.iter().collect();
1821 let mut bi = 0;
1822 while bi < block_refs.len() {
1823 if let Some((code, skip)) = super::peephole::try_block_peepholes(&block_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1824 output.push_str(&code);
1825 bi += 1 + skip;
1826 continue;
1827 }
1828 output.push_str(&codegen_stmt(block_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
1829 bi += 1;
1830 }
1831 }
1832 ctx.pop_scope();
1833 }
1834 writeln!(output, "{}}}", indent_str).unwrap();
1835 }
1836
1837 Stmt::While { cond, body, decreasing: _ } => {
1838 if let Some(code) = try_emit_byte_compare_window(stmt, interner, indent, ctx.get_variable_types(), ctx.oracle()) {
1841 return code;
1842 }
1843 let mut all_length_syms_raw = extract_length_expr_syms(cond);
1851 collect_length_syms_from_stmts(body, &mut all_length_syms_raw);
1852 let mut seen = HashSet::new();
1853 let all_length_syms: Vec<Symbol> = all_length_syms_raw
1854 .into_iter()
1855 .filter(|s| seen.insert(*s))
1856 .collect();
1857
1858 let mut hoisted_syms: Vec<(Symbol, Option<String>)> = Vec::new();
1859 for len_sym in &all_length_syms {
1860 if ctx.affine_array(*len_sym).is_some() {
1863 continue;
1864 }
1865 if !body_mutates_collection(body, *len_sym) && !body_modifies_var(body, *len_sym) {
1866 let name = interner.resolve(*len_sym);
1867 let hoisted_name = format!("{}_len", name);
1868 writeln!(output, "{}let {} = ({}.len() as i64);", indent_str, hoisted_name, name).unwrap();
1869 let old_type = ctx.get_variable_types().get(len_sym).cloned();
1870 let new_type = match &old_type {
1874 Some(existing) => format!("{}|__hl:{}", existing, hoisted_name),
1875 None => format!("|__hl:{}", hoisted_name),
1876 };
1877 ctx.register_variable_type(*len_sym, new_type);
1878 hoisted_syms.push((*len_sym, old_type));
1879 }
1880 }
1881
1882 let mut while_bounds_hints: Vec<BoundsHintPlan> = Vec::new();
1890 let mut affine_guards: Vec<AffineOffsetGuard> = Vec::new();
1891 if let Expr::BinaryOp { op: op @ (BinaryOpKind::LtEq | BinaryOpKind::Lt), left: Expr::Identifier(counter_sym), right: bound_expr } = cond {
1892 let body_sans_inc = if !body.is_empty()
1893 && is_counter_increment(&body[body.len() - 1], *counter_sym)
1894 {
1895 Some(&body[..body.len() - 1])
1896 } else {
1897 None
1898 };
1899 if let Some(body_sans_inc) = body_sans_inc {
1900 let counter_clean = !body_modifies_var(body_sans_inc, *counter_sym);
1901 let mut bound_syms = Vec::new();
1902 collect_expr_symbols(bound_expr, &mut bound_syms);
1903 let bound_invariant = bound_syms.iter().all(|s| {
1904 !body_modifies_var(body, *s) && !body_mutates_collection(body, *s)
1905 });
1906 if counter_clean && bound_invariant {
1907 let bound_str = codegen_expr_with_async(bound_expr, interner, synced_vars, async_functions, ctx.get_variable_types());
1908 while_bounds_hints = plan_bounds_hints(
1909 body_sans_inc,
1910 *counter_sym,
1911 matches!(op, BinaryOpKind::Lt),
1912 false,
1913 bound_expr,
1914 &bound_str,
1915 ctx.get_variable_types(),
1916 );
1917 emit_bounds_hint_preheader(&while_bounds_hints, interner, &indent_str, &mut output);
1918
1919 affine_guards = plan_affine_offset_guards(
1924 body_sans_inc,
1925 *counter_sym,
1926 matches!(op, BinaryOpKind::Lt),
1927 ctx.get_variable_types(),
1928 );
1929 emit_affine_offset_preheader(&affine_guards, &bound_str, interner, synced_vars, async_functions, ctx.get_variable_types(), &indent_str, &mut output);
1930 }
1931 }
1932 }
1933
1934 let scratch_hoisted: Vec<Symbol> =
1942 super::peephole::detect_scratch_hoist_in_body(body, interner, ctx)
1943 .into_iter()
1944 .map(|(dst, elem_type)| {
1945 writeln!(output, "{}let mut {}: Vec<{}> = Vec::new();",
1946 indent_str, interner.resolve(dst), elem_type).unwrap();
1947 ctx.register_variable_type(dst, format!("Vec<{}>", elem_type));
1948 ctx.register_scratch_hoist(dst);
1949 dst
1950 })
1951 .collect();
1952
1953 let hoist_plan = super::hoist::plan_borrow_hoist(stmt, Some(cond), body, ctx, interner);
1958 super::hoist::emit_hoist_open(&hoist_plan, interner, &indent_str, ctx, &mut output);
1959
1960 let cond_str = codegen_expr_with_async_oracle(cond, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
1961 let cond_str = truthy_cond_wrap(cond, cond_str, interner, ctx.get_variable_types());
1962 writeln!(output, "{}while {} {{", indent_str, cond_str).unwrap();
1963 emit_bounds_hint_header(&while_bounds_hints, interner, &" ".repeat(indent + 1), &mut output);
1964 emit_affine_offset_header(&affine_guards, interner, synced_vars, async_functions, ctx.get_variable_types(), &" ".repeat(indent + 1), &mut output);
1965 ctx.push_scope();
1966
1967 let sentinel_ctx: Option<(Symbol, &Expr)> = match cond {
1971 Expr::BinaryOp { op: BinaryOpKind::Lt, left, right } => {
1972 if let Expr::Identifier(sym) = left {
1973 Some((*sym, *right))
1974 } else {
1975 None
1976 }
1977 }
1978 _ => None,
1979 };
1980
1981 let body_refs: Vec<&Stmt> = body.iter().collect();
1983 let mut bi = 0;
1984 while bi < body_refs.len() {
1985 if let Some((code, skip)) = super::peephole::try_block_peepholes(&body_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1986 output.push_str(&code);
1987 bi += 1 + skip;
1988 continue;
1989 }
1990 if let Some(code) = try_emit_drain_tail_in_while(
1994 body_refs[bi], cond, interner, indent + 1,
1995 mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps,
1996 async_functions, pipe_vars, boxed_fields, registry, type_env,
1997 ) {
1998 output.push_str(&code);
1999 bi += 1;
2000 continue;
2001 }
2002 if let Some((counter_sym, limit_expr)) = &sentinel_ctx {
2006 if let Some(code) = try_emit_sentinel_break(
2007 body_refs[bi], *counter_sym, limit_expr, interner, indent + 1,
2008 mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps,
2009 async_functions, pipe_vars, boxed_fields, registry, type_env,
2010 ) {
2011 output.push_str(&emit_oracle_index_hints(
2015 body_refs[bi], ctx, interner, &" ".repeat(indent + 1),
2016 ));
2017 output.push_str(&code);
2018 bi += 1;
2019 continue;
2020 }
2021 }
2022 output.push_str(&codegen_stmt(body_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2023 bi += 1;
2024 }
2025 ctx.pop_scope();
2026
2027 for (sym, old_type) in hoisted_syms {
2030 if let Some(old) = old_type {
2031 ctx.register_variable_type(sym, old);
2032 } else {
2033 ctx.get_variable_types_mut().remove(&sym);
2034 }
2035 }
2036
2037 for dst in scratch_hoisted {
2041 ctx.clear_scratch_hoist(dst);
2042 }
2043
2044 writeln!(output, "{}}}", indent_str).unwrap();
2045 super::hoist::emit_hoist_close(&hoist_plan, &indent_str, ctx, &mut output);
2047 }
2048
2049 Stmt::Repeat { pattern, iterable, body } => {
2050 use crate::ast::stmt::Pattern;
2051
2052 let pattern_str = match pattern {
2054 Pattern::Identifier(sym) => interner.resolve(*sym).to_string(),
2055 Pattern::Tuple(syms) => {
2056 let names = syms.iter()
2057 .map(|s| interner.resolve(*s))
2058 .collect::<Vec<_>>()
2059 .join(", ");
2060 format!("({})", names)
2061 }
2062 };
2063
2064 if super::affine_array::is_indexed_init_loop(body, |s| ctx.is_indexed_buffer(s)) {
2069 return output;
2070 }
2071
2072 if let Pattern::Identifier(loop_var) = pattern {
2078 if let Some((w, info)) = scratch_fill_target(body, ctx) {
2079 let wname = names.ident(w);
2080 writeln!(output, "{}let {}: [{}; {}] = ::std::array::from_fn(|__k: usize| {{",
2081 indent_str, wname, info.elem_ty, info.len).unwrap();
2082 writeln!(output, "{} let {} = ({} as i64) + (__k as i64);",
2083 indent_str, interner.resolve(*loop_var), info.lo).unwrap();
2084 ctx.push_scope();
2085 ctx.register_variable_type(*loop_var, "i64".to_string());
2086 let mut push_val: Option<&Expr> = None;
2087 for s in body.iter() {
2088 match s {
2089 Stmt::Push { collection: Expr::Identifier(c), value } if *c == w => {
2090 push_val = Some(value);
2091 }
2092 other => output.push_str(&codegen_stmt(
2093 other, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields,
2094 synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)),
2095 }
2096 }
2097 let val = codegen_expr_boxed_with_types_oracle(
2098 push_val.expect("scratch fill loop has exactly one push"),
2099 interner, synced_vars, boxed_fields, registry, async_functions,
2100 ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2101 writeln!(output, "{} {}", indent_str, val).unwrap();
2102 ctx.pop_scope();
2103 writeln!(output, "{}}});", indent_str).unwrap();
2104 return output;
2105 }
2106 }
2107
2108 let iter_str = codegen_expr_with_async(iterable, interner, synced_vars, async_functions, ctx.get_variable_types());
2109
2110 let par_emitted = if let Pattern::Identifier(var_sym) = pattern {
2114 if let Some(par_code) = try_emit_parallel_reduction(
2115 *var_sym, &pattern_str, &iter_str, iterable, body,
2116 interner, indent, ctx,
2117 synced_vars, async_functions,
2118 ) {
2119 output.push_str(&par_code);
2120 true
2121 } else {
2122 false
2123 }
2124 } else {
2125 false
2126 };
2127
2128 if par_emitted {
2129 } else if body.iter().any(|s| {
2131 requires_async_stmt(s) || calls_async_function(s, async_functions)
2132 }) {
2133 writeln!(output, "{}let mut __iter = ({}).into_iter();", indent_str, iter_str).unwrap();
2135 writeln!(output, "{}while let Some({}) = __iter.next() {{", indent_str, pattern_str).unwrap();
2136 } else {
2137 let is_logos_seq = if let Expr::Identifier(coll_sym) = iterable {
2139 ctx.get_variable_types().get(coll_sym)
2140 .map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
2141 .map_or(false, |t| t.starts_with("LogosSeq"))
2142 } else {
2143 false
2144 };
2145
2146 if is_logos_seq {
2147 writeln!(output, "{}for {} in {}.to_vec() {{", indent_str, pattern_str, iter_str).unwrap();
2151 } else {
2152 let (use_iter_copied, use_iter_cloned) = if let Expr::Identifier(coll_sym) = iterable {
2156 if let Some(coll_type_raw) = ctx.get_variable_types().get(coll_sym) {
2157 let coll_type = coll_type_raw.split("|__hl:").next().unwrap_or(coll_type_raw.as_str());
2159 if coll_type.starts_with('[') {
2160 let elem = coll_type.strip_prefix('[').and_then(|s| s.split(';').next()).unwrap_or("_").trim();
2162 if is_copy_type(elem) {
2163 (true, false)
2164 } else {
2165 (false, true)
2166 }
2167 } else if coll_type.starts_with("&[") {
2168 let inner = coll_type.strip_prefix("&[").and_then(|s| s.strip_suffix(']')).unwrap_or("_");
2172 let elem = inner.split(';').next().unwrap_or(inner).trim();
2173 if is_copy_type(elem) {
2174 (true, false)
2175 } else {
2176 (false, true)
2177 }
2178 } else if coll_type.starts_with("Vec") && has_copy_element_type(coll_type)
2179 && !body_mutates_collection(body, *coll_sym)
2180 {
2181 (true, false)
2182 } else if coll_type.starts_with("Vec")
2183 && !body_mutates_collection(body, *coll_sym)
2184 {
2185 (false, true)
2189 } else {
2190 (false, false)
2191 }
2192 } else {
2193 (false, false)
2194 }
2195 } else {
2196 (false, false)
2197 };
2198
2199 if use_iter_copied {
2200 writeln!(output, "{}for {} in {}.iter().copied() {{", indent_str, pattern_str, iter_str).unwrap();
2201 } else if use_iter_cloned {
2202 writeln!(output, "{}for {} in {}.iter().cloned() {{", indent_str, pattern_str, iter_str).unwrap();
2203 } else {
2204 writeln!(output, "{}for {} in {}.clone() {{", indent_str, pattern_str, iter_str).unwrap();
2207 }
2208 }
2209 }
2210 if !par_emitted {
2211 ctx.push_scope();
2212 {
2214 let body_refs: Vec<&Stmt> = body.iter().collect();
2215 let mut bi = 0;
2216 while bi < body_refs.len() {
2217 if let Some((code, skip)) = super::peephole::try_block_peepholes(&body_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
2218 output.push_str(&code);
2219 bi += 1 + skip;
2220 continue;
2221 }
2222 output.push_str(&codegen_stmt(body_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2223 bi += 1;
2224 }
2225 }
2226 ctx.pop_scope();
2227 writeln!(output, "{}}}", indent_str).unwrap();
2228 }
2229 }
2230
2231 Stmt::Return { value } => {
2232 if let Some(v) = value {
2233 if ctx.returns_bigint() {
2236 let raw = codegen_expr_boxed_with_types_oracle_tolerant(v, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2237 writeln!(output, "{}return logicaffeine_data::LogosInt::from({});", indent_str, raw).unwrap();
2238 return output;
2239 }
2240 let value_str = codegen_expr_boxed_with_types_oracle(v, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2241 let slice_sym = match v {
2243 Expr::Identifier(sym) => Some(*sym),
2244 Expr::Copy { expr: inner } => {
2245 if let Expr::Identifier(sym) = inner { Some(*sym) } else { None }
2246 }
2247 _ => None,
2248 };
2249 let needs_to_vec = slice_sym
2250 .and_then(|sym| ctx.get_variable_types().get(&sym))
2251 .map(|t| t.starts_with("&["))
2252 .unwrap_or(false);
2253 let is_mut_borrow_return = if let Expr::Identifier(sym) = v {
2255 ctx.get_variable_types().get(sym)
2256 .map(|t| t.starts_with("&mut ["))
2257 .unwrap_or(false)
2258 } else {
2259 false
2260 };
2261 if is_mut_borrow_return {
2262 writeln!(output, "{}return;", indent_str).unwrap();
2263 } else if needs_to_vec && ctx.returns_vec() {
2264 writeln!(output, "{}return {}.to_vec();", indent_str, value_str).unwrap();
2267 } else if needs_to_vec {
2268 writeln!(output, "{}return LogosSeq::from_vec({}.to_vec());", indent_str, value_str).unwrap();
2269 } else {
2270 writeln!(output, "{}return {};", indent_str, value_str).unwrap();
2271 }
2272 } else {
2273 writeln!(output, "{}return;", indent_str).unwrap();
2274 }
2275 }
2276
2277 Stmt::Break => {
2278 writeln!(output, "{}break;", indent_str).unwrap();
2279 }
2280
2281 Stmt::Assert { proposition } => {
2282 let condition = codegen_assertion(proposition, interner);
2283 writeln!(output, "{}debug_assert!({});", indent_str, condition).unwrap();
2284 }
2285
2286 Stmt::Trust { proposition, justification } => {
2288 let reason = interner.resolve(*justification);
2289 let reason_clean = reason.trim_matches('"');
2291 writeln!(output, "{}// TRUST: {}", indent_str, reason_clean).unwrap();
2292 let condition = codegen_assertion(proposition, interner);
2293 writeln!(output, "{}debug_assert!({});", indent_str, condition).unwrap();
2294 }
2295
2296 Stmt::RuntimeAssert { condition, hard } => {
2297 let cond_str = codegen_expr_with_async_oracle(condition, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
2298 let macro_name = if *hard { "assert!" } else { "debug_assert!" };
2301 writeln!(output, "{}{}({});", indent_str, macro_name, cond_str).unwrap();
2302 }
2303
2304 Stmt::Check { subject, predicate, is_capability, object, source_text, span } => {
2306 let subj_name = interner.resolve(*subject);
2307 let pred_name = interner.resolve(*predicate).to_lowercase();
2308
2309 let call = if *is_capability {
2310 let obj_sym = object.expect("capability must have object");
2311 let obj_word = interner.resolve(obj_sym);
2312
2313 let obj_name = ctx.find_variable_by_type(obj_word, interner)
2317 .unwrap_or_else(|| obj_word.to_string());
2318
2319 format!("{}.can_{}(&{})", subj_name, pred_name, obj_name)
2320 } else {
2321 format!("{}.is_{}()", subj_name, pred_name)
2322 };
2323
2324 writeln!(output, "{}if !({}) {{", indent_str, call).unwrap();
2325 writeln!(output, "{} logicaffeine_system::panic_with(\"Security Check Failed at line {}: {}\");",
2326 indent_str, span.start, source_text).unwrap();
2327 writeln!(output, "{}}}", indent_str).unwrap();
2328 }
2329
2330 Stmt::Listen { address, secure } => {
2332 if secure.is_some() {
2335 writeln!(output, "{}compile_error!(\"the PNP one-time pad (`with pad`) is only supported by the interpreter tier, not the native-AOT/transpile backend\");", indent_str).unwrap();
2336 return output;
2337 }
2338 let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2339 writeln!(output, "{}logicaffeine_system::network::listen(&{}).await.expect(\"Failed to listen\");",
2341 indent_str, addr_str).unwrap();
2342 }
2343
2344 Stmt::ConnectTo { address, secure } => {
2346 if secure.is_some() {
2347 writeln!(output, "{}compile_error!(\"the PNP one-time pad (`with pad`) is only supported by the interpreter tier, not the native-AOT/transpile backend\");", indent_str).unwrap();
2348 return output;
2349 }
2350 let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2351 writeln!(output, "{}logicaffeine_system::network::connect(&{}).await.expect(\"Failed to connect\");",
2353 indent_str, addr_str).unwrap();
2354 }
2355
2356 Stmt::LetPeerAgent { var, address } => {
2358 let var_name = interner.resolve(*var);
2359 let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2360 writeln!(output, "{}let {} = logicaffeine_system::network::PeerAgent::new(&{}).expect(\"Invalid address\");",
2362 indent_str, var_name, addr_str).unwrap();
2363 }
2364
2365 Stmt::Sleep { milliseconds } => {
2367 let expr_str = codegen_expr_with_async(milliseconds, interner, synced_vars, async_functions, ctx.get_variable_types());
2368 let inferred_type = infer_rust_type_from_expr(milliseconds, interner);
2369
2370 if inferred_type == "std::time::Duration" {
2371 writeln!(output, "{}tokio::time::sleep({}).await;",
2373 indent_str, expr_str).unwrap();
2374 } else {
2375 writeln!(output, "{}tokio::time::sleep(std::time::Duration::from_millis({} as u64)).await;",
2377 indent_str, expr_str).unwrap();
2378 }
2379 }
2380
2381 Stmt::Sync { var, topic } => {
2383 let var_name = interner.resolve(*var);
2384 let topic_str = codegen_expr_with_async(topic, interner, synced_vars, async_functions, ctx.get_variable_types());
2385
2386 if let Some(caps) = var_caps.get(var) {
2388 if caps.mounted {
2389 synced_vars.insert(*var);
2393 return output; }
2395 }
2396
2397 writeln!(
2399 output,
2400 "{}let {} = logicaffeine_system::crdt::Synced::new({}, &{}).await;",
2401 indent_str, var_name, var_name, topic_str
2402 ).unwrap();
2403 synced_vars.insert(*var);
2404 }
2405
2406 Stmt::Mount { var, path } => {
2408 let var_name = interner.resolve(*var);
2409 let path_str = codegen_expr_with_async(path, interner, synced_vars, async_functions, ctx.get_variable_types());
2410
2411 if let Some(caps) = var_caps.get(var) {
2413 if caps.synced {
2414 let topic_str = caps.sync_topic.as_ref()
2416 .map(|s| s.as_str())
2417 .unwrap_or("\"default\"");
2418 writeln!(
2419 output,
2420 "{}let {} = logicaffeine_system::distributed::Distributed::mount(vfs.clone(), &{}, Some({}.to_string())).await.expect(\"Failed to mount\");",
2421 indent_str, var_name, path_str, topic_str
2422 ).unwrap();
2423 synced_vars.insert(*var);
2424 return output;
2425 }
2426 }
2427
2428 writeln!(
2430 output,
2431 "{}let {} = logicaffeine_system::storage::Persistent::mount(vfs.clone(), &{}).await.expect(\"Failed to mount\");",
2432 indent_str, var_name, path_str
2433 ).unwrap();
2434 synced_vars.insert(*var);
2435 }
2436
2437 Stmt::LaunchTask { function, args } => {
2442 let fn_name = names.ident(*function);
2443 let args_str: Vec<String> = args.iter()
2445 .map(|a| {
2446 if let Expr::Identifier(sym) = a {
2447 if pipe_vars.contains(sym) {
2448 return format!("{}_tx.clone()", interner.resolve(*sym));
2449 }
2450 }
2451 codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types())
2452 })
2453 .collect();
2454 let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
2456 writeln!(
2457 output,
2458 "{}tokio::spawn(async move {{ {}({}){await_suffix}; }});",
2459 indent_str, fn_name, args_str.join(", ")
2460 ).unwrap();
2461 }
2462
2463 Stmt::LaunchTaskWithHandle { handle, function, args } => {
2464 let handle_name = interner.resolve(*handle);
2465 let fn_name = names.ident(*function);
2466 let args_str: Vec<String> = args.iter()
2468 .map(|a| {
2469 if let Expr::Identifier(sym) = a {
2470 if pipe_vars.contains(sym) {
2471 return format!("{}_tx.clone()", interner.resolve(*sym));
2472 }
2473 }
2474 codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types())
2475 })
2476 .collect();
2477 let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
2479 writeln!(
2480 output,
2481 "{}let {} = tokio::spawn(async move {{ {}({}){await_suffix} }});",
2482 indent_str, handle_name, fn_name, args_str.join(", ")
2483 ).unwrap();
2484 }
2485
2486 Stmt::CreatePipe { var, element_type, capacity } => {
2487 let var_name = interner.resolve(*var);
2488 let type_name = interner.resolve(*element_type);
2489 let cap = capacity.unwrap_or(32);
2490 let rust_type = match type_name {
2492 "Int" => "i64",
2493 "Nat" => "u64",
2494 "Text" => "String",
2495 "Bool" => "bool",
2496 _ => type_name,
2497 };
2498 writeln!(
2499 output,
2500 "{}let ({}_tx, mut {}_rx) = tokio::sync::mpsc::channel::<{}>({});",
2501 indent_str, var_name, var_name, rust_type, cap
2502 ).unwrap();
2503 }
2504
2505 Stmt::SendPipe { value, pipe } => {
2506 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2507 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2508 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2510 pipe_vars.contains(sym)
2511 } else {
2512 false
2513 };
2514 if is_local_pipe {
2515 writeln!(
2516 output,
2517 "{}{}_tx.send({}).await.expect(\"pipe send failed\");",
2518 indent_str, pipe_str, val_str
2519 ).unwrap();
2520 } else {
2521 writeln!(
2522 output,
2523 "{}{}.send({}).await.expect(\"pipe send failed\");",
2524 indent_str, pipe_str, val_str
2525 ).unwrap();
2526 }
2527 }
2528
2529 Stmt::ReceivePipe { var, pipe } => {
2530 let var_name = interner.resolve(*var);
2531 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2532 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2534 pipe_vars.contains(sym)
2535 } else {
2536 false
2537 };
2538 if is_local_pipe {
2539 writeln!(
2540 output,
2541 "{}let {} = {}_rx.recv().await.expect(\"pipe closed\");",
2542 indent_str, var_name, pipe_str
2543 ).unwrap();
2544 } else {
2545 writeln!(
2546 output,
2547 "{}let {} = {}.recv().await.expect(\"pipe closed\");",
2548 indent_str, var_name, pipe_str
2549 ).unwrap();
2550 }
2551 }
2552
2553 Stmt::TrySendPipe { value, pipe, result } => {
2554 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2555 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2556 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2558 pipe_vars.contains(sym)
2559 } else {
2560 false
2561 };
2562 let suffix = if is_local_pipe { "_tx" } else { "" };
2563 if let Some(res) = result {
2564 let res_name = interner.resolve(*res);
2565 writeln!(
2566 output,
2567 "{}let {} = {}{}.try_send({}).is_ok();",
2568 indent_str, res_name, pipe_str, suffix, val_str
2569 ).unwrap();
2570 } else {
2571 writeln!(
2572 output,
2573 "{}let _ = {}{}.try_send({});",
2574 indent_str, pipe_str, suffix, val_str
2575 ).unwrap();
2576 }
2577 }
2578
2579 Stmt::TryReceivePipe { var, pipe } => {
2580 let var_name = interner.resolve(*var);
2581 let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2582 let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2584 pipe_vars.contains(sym)
2585 } else {
2586 false
2587 };
2588 let suffix = if is_local_pipe { "_rx" } else { "" };
2589 writeln!(
2590 output,
2591 "{}let {} = {}{}.try_recv().ok();",
2592 indent_str, var_name, pipe_str, suffix
2593 ).unwrap();
2594 }
2595
2596 Stmt::StopTask { handle } => {
2597 let handle_str = codegen_expr_with_async(handle, interner, synced_vars, async_functions, ctx.get_variable_types());
2598 writeln!(output, "{}{}.abort();", indent_str, handle_str).unwrap();
2599 }
2600
2601 Stmt::Select { branches } => {
2602 if crate::codegen::seeded_select_enabled() {
2607 write_seeded_select(
2608 &mut output, branches, interner, indent, mutable_vars, ctx, lww_fields,
2609 mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields,
2610 registry, type_env,
2611 );
2612 } else {
2613 write_tokio_select(
2614 &mut output, branches, interner, indent, mutable_vars, ctx, lww_fields,
2615 mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields,
2616 registry, type_env,
2617 );
2618 }
2619 }
2620
2621 Stmt::Give { object, recipient } => {
2622 let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
2624 let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2625 writeln!(output, "{}{}({});", indent_str, recv_str, obj_str).unwrap();
2626 }
2627
2628 Stmt::Show { object, recipient } => {
2629 if let Expr::Identifier(sym) = object {
2631 if ctx.get_variable_types().get(sym).map_or(false, |t| t == "__single_char_u8") {
2632 let var_name = names.ident(*sym);
2633 writeln!(output, "{}println!(\"{{}}\", {} as char);", indent_str, var_name).unwrap();
2634 return output;
2635 }
2636 }
2637 if let Expr::InterpolatedString(parts) = object {
2639 let recv_name = if let Expr::Identifier(sym) = recipient {
2640 interner.resolve(*sym).to_string()
2641 } else {
2642 String::new()
2643 };
2644 if recv_name == "show" {
2645 let mut fmt_str = String::new();
2647 let mut args = Vec::new();
2648 for part in parts {
2649 match part {
2650 crate::ast::stmt::StringPart::Literal(sym) => {
2651 let text = interner.resolve(*sym);
2652 for ch in text.chars() {
2653 match ch {
2654 '{' => fmt_str.push_str("{{"),
2655 '}' => fmt_str.push_str("}}"),
2656 '\n' => fmt_str.push_str("\\n"),
2657 '\t' => fmt_str.push_str("\\t"),
2658 '\r' => fmt_str.push_str("\\r"),
2659 _ => fmt_str.push(ch),
2660 }
2661 }
2662 }
2663 crate::ast::stmt::StringPart::Expr { value, format_spec, debug } => {
2664 if *debug {
2665 let debug_prefix = expr_debug_prefix(value, interner);
2666 for ch in debug_prefix.chars() {
2667 match ch {
2668 '{' => fmt_str.push_str("{{"),
2669 '}' => fmt_str.push_str("}}"),
2670 _ => fmt_str.push(ch),
2671 }
2672 }
2673 fmt_str.push('=');
2674 }
2675 let needs_float_cast = if let Some(spec) = format_spec {
2676 let spec_str = interner.resolve(*spec);
2677 if spec_str == "$" {
2678 fmt_str.push('$');
2679 fmt_str.push_str("{:.2}");
2680 true
2681 } else if spec_str.starts_with('.') {
2682 fmt_str.push_str(&format!("{{:{}}}", spec_str));
2683 true
2684 } else {
2685 fmt_str.push_str(&format!("{{:{}}}", spec_str));
2686 false
2687 }
2688 } else {
2689 fmt_str.push_str("{}");
2690 false
2691 };
2692 let arg_str = codegen_expr_with_async_and_strings(value, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2693 if needs_float_cast {
2694 args.push(format!("{} as f64", arg_str));
2695 } else {
2696 args.push(arg_str);
2697 }
2698 }
2699 }
2700 }
2701 writeln!(output, "{}println!(\"{}\"{});", indent_str, fmt_str,
2702 args.iter().map(|a| format!(", {}", a)).collect::<String>()).unwrap();
2703 } else {
2704 let obj_str = codegen_expr_with_async_and_strings(object, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2705 let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2706 writeln!(output, "{}{}(&{});", indent_str, recv_str, obj_str).unwrap();
2707 }
2708 } else {
2709 let obj_str = codegen_expr_with_async_and_strings(object, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2712 let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2713 writeln!(output, "{}{}(&{});", indent_str, recv_str, obj_str).unwrap();
2714 }
2715 }
2716
2717 Stmt::SetField { object, field, value } => {
2718 let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
2719 let field_name = interner.resolve(*field);
2720 let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2721
2722 let is_lww = lww_fields.iter().any(|(_, f)| f == field_name);
2725 let is_mv = mv_fields.iter().any(|(_, f)| f == field_name);
2726 if is_lww {
2727 writeln!(output, "{}{}.{}.set({}, std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_micros() as u64);", indent_str, obj_str, field_name, value_str).unwrap();
2729 } else if is_mv {
2730 writeln!(output, "{}{}.{}.set({});", indent_str, obj_str, field_name, value_str).unwrap();
2732 } else {
2733 writeln!(output, "{}{}.{} = {};", indent_str, obj_str, field_name, value_str).unwrap();
2734 }
2735 }
2736
2737 Stmt::StructDef { .. } => {
2738 }
2740
2741 Stmt::FunctionDef { .. } => {
2742 }
2744
2745 Stmt::Inspect { target, arms, .. } => {
2746 let target_str = codegen_expr_with_async(target, interner, synced_vars, async_functions, ctx.get_variable_types());
2747
2748 writeln!(output, "{}match {} {{", indent_str, target_str).unwrap();
2749
2750 for arm in arms {
2751 let mut inner_boxed_binding_names: HashSet<String> = HashSet::new();
2756 if let Some(variant) = arm.variant {
2757 let variant_name = interner.resolve(variant);
2758 let enum_name_str = arm.enum_name.map(|e| interner.resolve(e));
2760 let enum_prefix = enum_name_str
2761 .map(|e| format!("{}::", e))
2762 .unwrap_or_default();
2763
2764 if arm.bindings.is_empty() {
2765 writeln!(output, "{} {}{} => {{", indent_str, enum_prefix, variant_name).unwrap();
2767 } else {
2768 let bindings_str: Vec<String> = arm.bindings.iter()
2771 .map(|(field, binding)| {
2772 let field_name = interner.resolve(*field);
2773 let binding_name = interner.resolve(*binding);
2774
2775 if let Some(enum_name) = enum_name_str {
2777 let key = (enum_name.to_string(), variant_name.to_string(), field_name.to_string());
2778 if boxed_fields.contains(&key) {
2779 inner_boxed_binding_names.insert(binding_name.to_string());
2780 }
2781 }
2782
2783 if field_name == binding_name {
2784 format!("ref {}", field_name)
2785 } else {
2786 format!("{}: ref {}", field_name, binding_name)
2787 }
2788 })
2789 .collect();
2790 writeln!(output, "{} {}{} {{ {} }} => {{", indent_str, enum_prefix, variant_name, bindings_str.join(", ")).unwrap();
2791 }
2792 } else {
2793 writeln!(output, "{} _ => {{", indent_str).unwrap();
2795 }
2796
2797 ctx.push_scope();
2798
2799 if let Some(variant_sym) = arm.variant {
2802 if let Some((_enum_name, variant_def)) = registry.find_variant(variant_sym) {
2803 for (field_sym, binding_sym) in &arm.bindings {
2804 if let Some(field_def) = variant_def.fields.iter().find(|f| f.name == *field_sym) {
2805 let rust_type = super::types::codegen_field_type(&field_def.ty, interner);
2806 ctx.register_variable_type(*binding_sym, rust_type);
2807 }
2808 }
2809 }
2810 }
2811
2812 for binding_name in &inner_boxed_binding_names {
2815 writeln!(output, "{} let {} = (**{}).clone();", indent_str, binding_name, binding_name).unwrap();
2816 }
2817
2818 if let Some(_) = arm.variant {
2820 for (_field, binding) in &arm.bindings {
2821 let binding_name = interner.resolve(*binding);
2822 if !inner_boxed_binding_names.contains(binding_name) {
2823 writeln!(output, "{} let {} = {}.clone();", indent_str, binding_name, binding_name).unwrap();
2824 }
2825 }
2826 }
2827
2828 for stmt in arm.body {
2829 let inner_stmt_code = if let Stmt::Inspect { target: inner_target, .. } = stmt {
2833 if let Expr::Identifier(sym) = inner_target {
2836 let target_name = interner.resolve(*sym);
2837 if inner_boxed_binding_names.contains(target_name) {
2838 let mut inner_output = String::new();
2840 writeln!(inner_output, "{}match {} {{", " ".repeat(indent + 2), target_name).unwrap();
2841
2842 if let Stmt::Inspect { arms: inner_arms, .. } = stmt {
2843 for inner_arm in inner_arms.iter() {
2844 if let Some(v) = inner_arm.variant {
2845 let v_name = interner.resolve(v);
2846 let inner_enum_prefix = inner_arm.enum_name
2847 .map(|e| format!("{}::", interner.resolve(e)))
2848 .unwrap_or_default();
2849
2850 if inner_arm.bindings.is_empty() {
2851 writeln!(inner_output, "{} {}{} => {{", " ".repeat(indent + 2), inner_enum_prefix, v_name).unwrap();
2852 } else {
2853 let bindings: Vec<String> = inner_arm.bindings.iter()
2854 .map(|(f, b)| {
2855 let fn_name = interner.resolve(*f);
2856 let bn_name = interner.resolve(*b);
2857 if fn_name == bn_name { format!("ref {}", fn_name) }
2858 else { format!("{}: ref {}", fn_name, bn_name) }
2859 })
2860 .collect();
2861 writeln!(inner_output, "{} {}{} {{ {} }} => {{", " ".repeat(indent + 2), inner_enum_prefix, v_name, bindings.join(", ")).unwrap();
2862 }
2863 } else {
2864 writeln!(inner_output, "{} _ => {{", " ".repeat(indent + 2)).unwrap();
2865 }
2866
2867 ctx.push_scope();
2868 for inner_stmt in inner_arm.body {
2869 inner_output.push_str(&codegen_stmt(inner_stmt, interner, indent + 4, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2870 }
2871 ctx.pop_scope();
2872 writeln!(inner_output, "{} }}", " ".repeat(indent + 2)).unwrap();
2873 }
2874 }
2875 writeln!(inner_output, "{}}}", " ".repeat(indent + 2)).unwrap();
2876 inner_output
2877 } else {
2878 codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2879 }
2880 } else {
2881 codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2882 }
2883 } else {
2884 codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2885 };
2886 output.push_str(&inner_stmt_code);
2887 }
2888 ctx.pop_scope();
2889 writeln!(output, "{} }}", indent_str).unwrap();
2890 }
2891
2892 writeln!(output, "{}}}", indent_str).unwrap();
2893 }
2894
2895 Stmt::Push { value, collection } => {
2896 if let Expr::Identifier(coll_sym) = collection {
2900 if let Some(cursor) = ctx.loop_fill_cursor(*coll_sym).map(|s| s.to_string()) {
2904 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2905 let coll_name = names.ident(*coll_sym);
2906 writeln!(output, "{}{}[{}] = {}; {} += 1;", indent_str, coll_name, cursor, val_str, cursor).unwrap();
2907 return output;
2908 }
2909 if ctx.affine_array(*coll_sym).is_some() {
2912 return output;
2913 }
2914 if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(coll_sym)) {
2917 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2918 let k = ctx.next_array_fill(*coll_sym);
2919 writeln!(output, "{}{}[{}][{}] = {};", indent_str, tag.backing, k, tag.col, val_str).unwrap();
2920 return output;
2921 }
2922 if ctx.is_scalarized_array(*coll_sym) {
2923 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2924 let k = ctx.next_array_fill(*coll_sym);
2925 let coll_name = names.ident(*coll_sym);
2926 writeln!(output, "{}{}[{}] = {};", indent_str, coll_name, k, val_str).unwrap();
2927 return output;
2928 }
2929 if let Some((buf, counter)) = ctx.fill_loop().map(|(b, c)| (b, c.to_string())) {
2933 if buf == *coll_sym {
2934 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2935 let coll_name = names.ident(*coll_sym);
2936 writeln!(output, "{}debug_assert!(({} as usize) < {}.len(), \"LOGOS fill-loop store out of range\");", indent_str, counter, coll_name).unwrap();
2946 writeln!(output, "{}unsafe {{ std::hint::assert_unchecked(({} as usize) < {}.len()); }}", indent_str, counter, coll_name).unwrap();
2947 writeln!(output, "{}{}[{} as usize] = {};", indent_str, coll_name, counter, val_str).unwrap();
2948 return output;
2949 }
2950 }
2951 if let Some(tail) = ctx.worklist(*coll_sym).map(|w| w.tail_var.clone()) {
2956 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2957 let coll_name = names.ident(*coll_sym);
2958 writeln!(output, "{}unsafe {{ std::hint::assert_unchecked({tail} < {coll_name}.len()); }}", indent_str).unwrap();
2959 writeln!(output, "{}{coll_name}[{tail}] = {val_str};", indent_str).unwrap();
2960 writeln!(output, "{}{tail} += 1;", indent_str).unwrap();
2961 return output;
2962 }
2963 }
2964 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2965 let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2966 emit_cow(collection, ctx, &names, &indent_str, &mut output);
2969 let narrowed_push = matches!(collection, Expr::Identifier(c) if ctx.is_narrowed(*c));
2972 if narrowed_push {
2973 writeln!(output, "{}{}.push(({}) as i32);", indent_str, coll_str, val_str).unwrap();
2974 } else {
2975 writeln!(output, "{}{}.push({});", indent_str, coll_str, val_str).unwrap();
2976 }
2977 }
2978
2979 Stmt::Pop { collection, into } => {
2980 let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2981 emit_cow(collection, ctx, &names, &indent_str, &mut output);
2983 match into {
2984 Some(var) => {
2985 let var_name = names.ident(*var);
2986 writeln!(output, "{}let {} = {}.pop().expect(\"Pop from empty collection\");", indent_str, var_name, coll_str).unwrap();
2988 }
2989 None => {
2990 writeln!(output, "{}{}.pop();", indent_str, coll_str).unwrap();
2991 }
2992 }
2993 }
2994
2995 Stmt::Add { value, collection } => {
2996 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2997 let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2998 emit_cow(collection, ctx, &names, &indent_str, &mut output);
3001 writeln!(output, "{}{}.insert({});", indent_str, coll_str, val_str).unwrap();
3002 }
3003
3004 Stmt::Remove { value, collection } => {
3005 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3006 let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
3007 emit_cow(collection, ctx, &names, &indent_str, &mut output);
3009 let is_set = matches!(collection, Expr::Identifier(sym)
3013 if ctx.get_variable_types().get(sym).is_some_and(|t| t.starts_with("Set<") || t.starts_with("FxHashSet<")));
3014 let method = if is_set { "shift_remove" } else { "remove" };
3015 writeln!(output, "{}{}.{}(&{});", indent_str, coll_str, method, val_str).unwrap();
3016 }
3017
3018 Stmt::SetIndex { collection, index, value } => {
3019 if let Expr::Index { collection: base, index: outer_idx } = collection {
3026 if let Expr::Identifier(base_sym) = base {
3027 let is_nested_seq = ctx.get_variable_types().get(base_sym).map_or(false, |t| {
3028 t.split("|__hl:").next().unwrap_or(t).starts_with("LogosSeq<LogosSeq")
3029 });
3030 if is_nested_seq {
3031 let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3032 let usize_index = |ix: &Expr| -> String {
3033 if let Expr::Identifier(s) = ix {
3034 if ctx.get_variable_types().get(s).map_or(false, |t| t == "__zero_based_i64") {
3035 return format!("{} as usize", codegen_expr_with_async(ix, interner, synced_vars, async_functions, ctx.get_variable_types()));
3036 }
3037 }
3038 simplify_1based_index(ix, interner, true, ctx.get_variable_types())
3039 };
3040 let k_idx = usize_index(outer_idx);
3041 let i_idx = usize_index(index);
3042 emit_cow(base, ctx, &names, &indent_str, &mut output);
3043 writeln!(output, "{}{}.set_nested({}, {}, {});", indent_str, names.ident(*base_sym), k_idx, i_idx, value_str).unwrap();
3044 return output;
3045 }
3046 }
3047 }
3048 if let Expr::Identifier(sym) = collection {
3050 if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(sym)) {
3051 let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3052 let is_zb = matches!(index, Expr::Identifier(s) if ctx.get_variable_types().get(s).map_or(false, |t| t == "__zero_based_i64"));
3053 let idx_part = if is_zb {
3054 format!("{} as usize", codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types()))
3055 } else {
3056 simplify_1based_index(index, interner, true, ctx.get_variable_types())
3057 };
3058 writeln!(output, "{}{}[{}][{}] = {};", indent_str, tag.backing, idx_part, tag.col, value_str).unwrap();
3059 return output;
3060 }
3061 }
3062 let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
3063 let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3064
3065 emit_cow(collection, ctx, &names, &indent_str, &mut output);
3069
3070 let known_type = if let Expr::Identifier(sym) = collection {
3073 ctx.get_variable_types().get(sym).map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
3074 } else {
3075 None
3076 };
3077
3078 match known_type {
3079 Some(t) if t.starts_with("LogosSeq") => {
3080 let is_zero_based_counter = if let Expr::Identifier(idx_sym) = index {
3082 ctx.get_variable_types().get(idx_sym).map_or(false, |t| t == "__zero_based_i64")
3083 } else {
3084 false
3085 };
3086 let index_part = if is_zero_based_counter {
3087 let idx_name = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3088 format!("{} as usize", idx_name)
3089 } else {
3090 simplify_1based_index(index, interner, true, ctx.get_variable_types())
3091 };
3092 let store_unchecked = crate::optimize::active_config()
3100 .is_on(crate::optimization::Opt::Unchecked)
3101 && ctx.oracle().map_or(false, |o| o.index_provably_in_bounds(collection, index));
3102 let needs_tmp = store_unchecked || expr_reads_any_collection(value);
3107 if store_unchecked {
3108 crate::optimize::mark_fired(crate::optimization::Opt::Unchecked);
3109 let i0 = if is_zero_based_counter {
3110 codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types())
3111 } else {
3112 simplify_1based_index(index, interner, false, ctx.get_variable_types())
3113 };
3114 writeln!(output, "{}debug_assert!(({}) >= 0 && ({}) < ({}.len() as i64), \"LOGOS oracle BCE: store out of range\");", indent_str, i0, i0, coll_str).unwrap();
3115 writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3116 writeln!(output, "{}unsafe {{ *{}.borrow_mut().get_unchecked_mut({}) = __set_val; }}", indent_str, coll_str, index_part).unwrap();
3117 } else if needs_tmp {
3118 writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3119 writeln!(output, "{}{}.borrow_mut()[{}] = __set_val;", indent_str, coll_str, index_part).unwrap();
3120 } else {
3121 writeln!(output, "{}{}.borrow_mut()[{}] = {};", indent_str, coll_str, index_part, value_str).unwrap();
3122 }
3123 }
3124 Some(t) if is_logos_map_type(t) => {
3125 let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3126 writeln!(output, "{}{}.insert({}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3127 }
3128 Some(t) if t.starts_with("Vec") || t.starts_with("&mut [") || t.starts_with("&[") || t.starts_with('[') => {
3129 let is_zero_based_counter = if let Expr::Identifier(idx_sym) = index {
3132 ctx.get_variable_types().get(idx_sym).map_or(false, |t| t == "__zero_based_i64")
3133 } else {
3134 false
3135 };
3136 let index_part = if is_zero_based_counter {
3137 let idx_name = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3138 format!("{} as usize", idx_name)
3139 } else {
3140 simplify_1based_index(index, interner, true, ctx.get_variable_types())
3141 };
3142 let narrowed = matches!(collection, Expr::Identifier(c) if ctx.is_narrowed(*c));
3145 let value_str = if narrowed { format!("(({}) as i32)", value_str) } else { value_str };
3146 let store_unchecked = crate::optimize::active_config().is_on(crate::optimization::Opt::Unchecked)
3151 && ctx.oracle().map_or(false, |o| o.index_provably_in_bounds(collection, index));
3152 if store_unchecked {
3153 crate::optimize::mark_fired(crate::optimization::Opt::Unchecked);
3154 let i0 = if is_zero_based_counter {
3155 codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types())
3156 } else {
3157 simplify_1based_index(index, interner, false, ctx.get_variable_types())
3158 };
3159 writeln!(output, "{}debug_assert!(({}) >= 0 && ({}) < ({}.len() as i64), \"LOGOS oracle BCE: store out of range\");", indent_str, i0, i0, coll_str).unwrap();
3160 writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3165 writeln!(output, "{}unsafe {{ *{}.get_unchecked_mut({}) = __set_val; }}", indent_str, coll_str, index_part).unwrap();
3166 } else {
3167 writeln!(output, "{}{}[{}] = {};", indent_str, coll_str, index_part, value_str).unwrap();
3168 }
3169 }
3170 Some(t) if t.starts_with("std::collections::HashMap") || t.starts_with("HashMap") || t.starts_with("rustc_hash::FxHashMap") || t.starts_with("FxHashMap") => {
3171 let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3172 writeln!(output, "{}{}.insert({}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3173 }
3174 _ => {
3175 let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3176 let needs_tmp = expr_reads_any_collection(value);
3182 if needs_tmp {
3183 writeln!(output, "{}let __set_tmp = {};", indent_str, value_str).unwrap();
3184 writeln!(output, "{}LogosIndexMut::logos_set(&mut {}, {}, __set_tmp);", indent_str, coll_str, index_str).unwrap();
3185 } else {
3186 writeln!(output, "{}LogosIndexMut::logos_set(&mut {}, {}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3187 }
3188 }
3189 }
3190 }
3191
3192 Stmt::Zone { name, capacity, source_file, body } => {
3194 let zone_name = interner.resolve(*name);
3195
3196 if let Some(src) = source_file {
3198 use crate::ast::stmt::ZoneSource;
3201 let path_expr = match src {
3202 ZoneSource::Literal(p) => format!("\"{}\"", interner.resolve(*p)),
3203 ZoneSource::Variable(v) => format!("&{}", interner.resolve(*v)),
3204 };
3205 writeln!(
3206 output,
3207 "{}let {} = logicaffeine_system::memory::Zone::new_mapped({}).expect(\"Failed to map file\");",
3208 indent_str, zone_name, path_expr
3209 ).unwrap();
3210 } else {
3211 let cap = capacity.unwrap_or(4096); writeln!(
3214 output,
3215 "{}let {} = logicaffeine_system::memory::Zone::new_heap({});",
3216 indent_str, zone_name, cap
3217 ).unwrap();
3218 }
3219
3220 writeln!(output, "{}{{", indent_str).unwrap();
3222 ctx.push_scope();
3223
3224 for stmt in *body {
3226 output.push_str(&codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
3227 }
3228
3229 ctx.pop_scope();
3230 writeln!(output, "{}}}", indent_str).unwrap();
3231 }
3232
3233 Stmt::Concurrent { tasks } => {
3237 let let_bindings: Vec<_> = tasks.iter().filter_map(|s| {
3239 if let Stmt::Let { var, .. } = s {
3240 Some(interner.resolve(*var).to_string())
3241 } else {
3242 None
3243 }
3244 }).collect();
3245
3246 let defined_vars: HashSet<Symbol> = tasks.iter().filter_map(|s| {
3248 if let Stmt::Let { var, .. } = s {
3249 Some(*var)
3250 } else {
3251 None
3252 }
3253 }).collect();
3254
3255 let mut has_intra_dependency = false;
3258 let mut seen_defs: HashSet<Symbol> = HashSet::new();
3259 for s in *tasks {
3260 let mut used_in_task: HashSet<Symbol> = HashSet::new();
3262 collect_stmt_identifiers(s, &mut used_in_task);
3263 for used_var in &used_in_task {
3264 if seen_defs.contains(used_var) {
3265 has_intra_dependency = true;
3266 break;
3267 }
3268 }
3269 if let Stmt::Let { var, .. } = s {
3271 seen_defs.insert(*var);
3272 }
3273 if has_intra_dependency {
3274 break;
3275 }
3276 }
3277
3278 let mut used_syms: HashSet<Symbol> = HashSet::new();
3281 for s in *tasks {
3282 collect_stmt_identifiers(s, &mut used_syms);
3283 }
3284 for def_var in &defined_vars {
3286 used_syms.remove(def_var);
3287 }
3288 let used_vars: HashSet<String> = used_syms.iter()
3289 .map(|sym| interner.resolve(*sym).to_string())
3290 .collect();
3291
3292 if has_intra_dependency {
3294 for stmt in *tasks {
3296 output.push_str(&codegen_stmt(stmt, interner, indent, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
3297 }
3298 } else {
3299 if !let_bindings.is_empty() {
3301 writeln!(output, "{}let ({}) = tokio::join!(", indent_str, let_bindings.join(", ")).unwrap();
3303 } else {
3304 writeln!(output, "{}tokio::join!(", indent_str).unwrap();
3305 }
3306
3307 for (i, stmt) in tasks.iter().enumerate() {
3308 let inner_code = match stmt {
3311 Stmt::Let { value, .. } => {
3312 codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3315 }
3316 Stmt::Call { function, args } => {
3317 let func_name = interner.resolve(*function);
3318 let args_str: Vec<String> = args.iter()
3319 .map(|a| codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types()))
3320 .collect();
3321 let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
3323 format!("{}({}){}", func_name, args_str.join(", "), await_suffix)
3324 }
3325 _ => {
3326 let inner = codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3328 inner.trim().to_string()
3329 }
3330 };
3331
3332 if !used_vars.is_empty() && i < tasks.len() - 1 {
3334 let clones: Vec<String> = used_vars.iter()
3336 .map(|v| format!("let {} = {}.clone();", v, v))
3337 .collect();
3338 write!(output, "{} {{ {} async move {{ {} }} }}",
3339 indent_str, clones.join(" "), inner_code).unwrap();
3340 } else {
3341 write!(output, "{} async {{ {} }}", indent_str, inner_code).unwrap();
3343 }
3344
3345 if i < tasks.len() - 1 {
3346 writeln!(output, ",").unwrap();
3347 } else {
3348 writeln!(output).unwrap();
3349 }
3350 }
3351
3352 writeln!(output, "{});", indent_str).unwrap();
3353 }
3354 }
3355
3356 Stmt::Parallel { tasks } => {
3359 let let_bindings: Vec<_> = tasks.iter().filter_map(|s| {
3361 if let Stmt::Let { var, .. } = s {
3362 Some(interner.resolve(*var).to_string())
3363 } else {
3364 None
3365 }
3366 }).collect();
3367
3368 if tasks.len() == 2 {
3369 if !let_bindings.is_empty() {
3371 writeln!(output, "{}let ({}) = rayon::join(", indent_str, let_bindings.join(", ")).unwrap();
3372 } else {
3373 writeln!(output, "{}rayon::join(", indent_str).unwrap();
3374 }
3375
3376 for (i, stmt) in tasks.iter().enumerate() {
3377 let inner_code = match stmt {
3379 Stmt::Let { value, .. } => {
3380 codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3382 }
3383 Stmt::Call { function, args } => {
3384 let func_name = interner.resolve(*function);
3385 let variable_types = ctx.get_variable_types();
3386 let callee_borrow_indices: HashSet<usize> =
3387 super::fn_role_indices(variable_types.get(function), super::FnRole::Borrow);
3388 let args_str: Vec<String> = args.iter().enumerate()
3389 .map(|(idx, a)| {
3390 let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
3391 if callee_borrow_indices.contains(&idx) {
3392 if let Expr::Identifier(sym) = a {
3393 if let Some(ty) = variable_types.get(sym) {
3394 if ty.starts_with("&[") {
3395 return s;
3396 }
3397 }
3398 }
3399 format!("&{}", s)
3400 } else { s }
3401 })
3402 .collect();
3403 format!("{}({})", func_name, args_str.join(", "))
3404 }
3405 _ => {
3406 let inner = codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3408 inner.trim().to_string()
3409 }
3410 };
3411 write!(output, "{} || {{ {} }}", indent_str, inner_code).unwrap();
3412 if i == 0 {
3413 writeln!(output, ",").unwrap();
3414 } else {
3415 writeln!(output).unwrap();
3416 }
3417 }
3418 writeln!(output, "{});", indent_str).unwrap();
3419 } else {
3420 writeln!(output, "{}{{", indent_str).unwrap();
3422 writeln!(output, "{} let handles: Vec<_> = vec![", indent_str).unwrap();
3423 for stmt in *tasks {
3424 let inner_code = match stmt {
3426 Stmt::Let { value, .. } => {
3427 codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3428 }
3429 Stmt::Call { function, args } => {
3430 let func_name = interner.resolve(*function);
3431 let variable_types = ctx.get_variable_types();
3432 let callee_borrow_indices: HashSet<usize> =
3433 super::fn_role_indices(variable_types.get(function), super::FnRole::Borrow);
3434 let args_str: Vec<String> = args.iter().enumerate()
3435 .map(|(idx, a)| {
3436 let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
3437 if callee_borrow_indices.contains(&idx) {
3438 if let Expr::Identifier(sym) = a {
3439 if let Some(ty) = variable_types.get(sym) {
3440 if ty.starts_with("&[") {
3441 return s;
3442 }
3443 }
3444 }
3445 format!("&{}", s)
3446 } else { s }
3447 })
3448 .collect();
3449 format!("{}({})", func_name, args_str.join(", "))
3450 }
3451 _ => {
3452 let inner = codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3453 inner.trim().to_string()
3454 }
3455 };
3456 writeln!(output, "{} std::thread::spawn(move || {{ {} }}),",
3457 indent_str, inner_code).unwrap();
3458 }
3459 writeln!(output, "{} ];", indent_str).unwrap();
3460 writeln!(output, "{} for h in handles {{ h.join().unwrap(); }}", indent_str).unwrap();
3461 writeln!(output, "{}}}", indent_str).unwrap();
3462 }
3463 }
3464
3465 Stmt::ReadFrom { var, source } => {
3468 let var_name = interner.resolve(*var);
3469 match source {
3470 ReadSource::Console => {
3471 writeln!(output, "{}let {} = logicaffeine_system::io::read_line();", indent_str, var_name).unwrap();
3472 }
3473 ReadSource::File(path_expr) => {
3474 let path_str = codegen_expr_with_async(path_expr, interner, synced_vars, async_functions, ctx.get_variable_types());
3475 writeln!(
3477 output,
3478 "{}let {} = vfs.read_to_string(&{}).await.expect(\"Failed to read file\");",
3479 indent_str, var_name, path_str
3480 ).unwrap();
3481 }
3482 }
3483 }
3484
3485 Stmt::WriteFile { content, path } => {
3488 let content_str = codegen_expr_with_async(content, interner, synced_vars, async_functions, ctx.get_variable_types());
3489 let path_str = codegen_expr_with_async(path, interner, synced_vars, async_functions, ctx.get_variable_types());
3490 writeln!(
3492 output,
3493 "{}vfs.write(&{}, {}.as_bytes()).await.expect(\"Failed to write file\");",
3494 indent_str, path_str, content_str
3495 ).unwrap();
3496 }
3497
3498 Stmt::Spawn { agent_type, name } => {
3500 let type_name = interner.resolve(*agent_type);
3501 let agent_name = interner.resolve(*name);
3502 writeln!(
3504 output,
3505 "{}let {} = tokio::spawn(async move {{ /* {} agent loop */ }});",
3506 indent_str, agent_name, type_name
3507 ).unwrap();
3508 }
3509
3510 Stmt::SendMessage { message, destination, .. } => {
3512 let msg_str = codegen_expr_with_async(message, interner, synced_vars, async_functions, ctx.get_variable_types());
3513 let dest_str = codegen_expr_with_async(destination, interner, synced_vars, async_functions, ctx.get_variable_types());
3514 writeln!(
3515 output,
3516 "{}{}.send({}).await.expect(\"Failed to send message\");",
3517 indent_str, dest_str, msg_str
3518 ).unwrap();
3519 }
3520
3521 Stmt::StreamMessage { .. } => {
3524 writeln!(output, "{}// Stream: interpreter-only (not yet lowered to AOT)", indent_str).unwrap();
3525 }
3526
3527 Stmt::AwaitMessage { source, into, view: _, stream: _ } => {
3530 let src_str = codegen_expr_with_async(source, interner, synced_vars, async_functions, ctx.get_variable_types());
3531 let var_name = interner.resolve(*into);
3532 writeln!(
3533 output,
3534 "{}let {} = {}.recv().await.expect(\"Failed to receive message\");",
3535 indent_str, var_name, src_str
3536 ).unwrap();
3537 }
3538
3539 Stmt::MergeCrdt { source, target } => {
3541 let src_str = codegen_expr_with_async(source, interner, synced_vars, async_functions, ctx.get_variable_types());
3542 let tgt_str = codegen_expr_with_async(target, interner, synced_vars, async_functions, ctx.get_variable_types());
3543 writeln!(
3544 output,
3545 "{}{}.merge(&{});",
3546 indent_str, tgt_str, src_str
3547 ).unwrap();
3548 }
3549
3550 Stmt::IncreaseCrdt { object, field, amount } => {
3553 let field_name = interner.resolve(*field);
3554 let amount_str = codegen_expr_with_async(amount, interner, synced_vars, async_functions, ctx.get_variable_types());
3555
3556 let root_sym = get_root_identifier(object);
3558 if let Some(sym) = root_sym {
3559 if synced_vars.contains(&sym) {
3560 let obj_name = interner.resolve(sym);
3562 writeln!(
3563 output,
3564 "{}{}.mutate(|inner| inner.{}.increment({} as u64)).await;",
3565 indent_str, obj_name, field_name, amount_str
3566 ).unwrap();
3567 return output;
3568 }
3569 }
3570
3571 let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3573 writeln!(
3574 output,
3575 "{}{}.{}.increment({} as u64);",
3576 indent_str, obj_str, field_name, amount_str
3577 ).unwrap();
3578 }
3579
3580 Stmt::DecreaseCrdt { object, field, amount } => {
3582 let field_name = interner.resolve(*field);
3583 let amount_str = codegen_expr_with_async(amount, interner, synced_vars, async_functions, ctx.get_variable_types());
3584
3585 let root_sym = get_root_identifier(object);
3587 if let Some(sym) = root_sym {
3588 if synced_vars.contains(&sym) {
3589 let obj_name = interner.resolve(sym);
3591 writeln!(
3592 output,
3593 "{}{}.mutate(|inner| inner.{}.decrement({} as u64)).await;",
3594 indent_str, obj_name, field_name, amount_str
3595 ).unwrap();
3596 return output;
3597 }
3598 }
3599
3600 let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3602 writeln!(
3603 output,
3604 "{}{}.{}.decrement({} as u64);",
3605 indent_str, obj_str, field_name, amount_str
3606 ).unwrap();
3607 }
3608
3609 Stmt::AppendToSequence { sequence, value } => {
3611 let seq_str = codegen_expr_with_async(sequence, interner, synced_vars, async_functions, ctx.get_variable_types());
3612 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3613 writeln!(
3614 output,
3615 "{}{}.append({});",
3616 indent_str, seq_str, val_str
3617 ).unwrap();
3618 }
3619
3620 Stmt::ResolveConflict { object, field, value } => {
3622 let field_name = interner.resolve(*field);
3623 let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3624 let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3625 writeln!(
3626 output,
3627 "{}{}.{}.resolve({});",
3628 indent_str, obj_str, field_name, val_str
3629 ).unwrap();
3630 }
3631
3632 Stmt::Escape { code, .. } => {
3634 let raw_code = interner.resolve(*code);
3635 write!(output, "{}{{\n", indent_str).unwrap();
3636 for line in raw_code.lines() {
3637 write!(output, "{} {}\n", indent_str, line).unwrap();
3638 }
3639 write!(output, "{}}}\n", indent_str).unwrap();
3640 }
3641
3642 Stmt::Require { .. } => {}
3644
3645 Stmt::Theorem(_) | Stmt::Definition(_) | Stmt::Axiom(_) | Stmt::Theory(_) => {}
3649 }
3650
3651 output
3652}
3653
3654fn try_emit_sentinel_break<'a>(
3662 stmt: &Stmt<'a>,
3663 counter_sym: Symbol,
3664 limit_expr: &Expr<'a>,
3665 interner: &Interner,
3666 indent: usize,
3667 mutable_vars: &HashSet<Symbol>,
3668 ctx: &mut RefinementContext<'a>,
3669 lww_fields: &HashSet<(String, String)>,
3670 mv_fields: &HashSet<(String, String)>,
3671 synced_vars: &mut HashSet<Symbol>,
3672 var_caps: &HashMap<Symbol, VariableCapabilities>,
3673 async_functions: &HashSet<Symbol>,
3674 pipe_vars: &HashSet<Symbol>,
3675 boxed_fields: &HashSet<(String, String, String)>,
3676 registry: &TypeRegistry,
3677 type_env: &crate::analysis::types::TypeEnv,
3678) -> Option<String> {
3679 let (if_cond, then_block, else_block) = match stmt {
3681 Stmt::If { cond, then_block, else_block } => (cond, then_block, else_block),
3682 _ => return None,
3683 };
3684
3685 if else_block.is_some() {
3686 return None;
3687 }
3688
3689 if then_block.is_empty() {
3690 return None;
3691 }
3692
3693 let last = &then_block[then_block.len() - 1];
3695 match last {
3696 Stmt::Set { target, value, .. } => {
3697 if *target != counter_sym || !exprs_equal(value, limit_expr) {
3698 return None;
3699 }
3700 }
3701 _ => return None,
3702 }
3703
3704 let indent_str = " ".repeat(indent);
3706 let var_types = ctx.get_variable_types();
3707 let cond_str = codegen_expr_with_async(if_cond, interner, synced_vars, async_functions, var_types);
3708 let mut output = String::new();
3709 writeln!(output, "{}if {} {{", indent_str, cond_str).unwrap();
3710
3711 for s in &then_block[..then_block.len() - 1] {
3713 output.push_str(&codegen_stmt(
3714 s, interner, indent + 1, mutable_vars, ctx,
3715 lww_fields, mv_fields, synced_vars, var_caps,
3716 async_functions, pipe_vars, boxed_fields, registry, type_env,
3717 ));
3718 }
3719
3720 writeln!(output, "{} break;", indent_str).unwrap();
3722 writeln!(output, "{}}}", indent_str).unwrap();
3723
3724 Some(output)
3725}
3726
3727pub(crate) fn get_root_identifier(expr: &Expr) -> Option<Symbol> {
3730 match expr {
3731 Expr::Identifier(sym) => Some(*sym),
3732 Expr::FieldAccess { object, .. } => get_root_identifier(object),
3733 _ => None,
3734 }
3735}
3736
3737pub(crate) fn extract_length_expr_syms(expr: &Expr) -> Vec<Symbol> {
3740 let mut out = Vec::new();
3741 collect_length_syms_from_expr(expr, &mut out);
3742 out
3743}
3744
3745fn collect_length_syms_from_expr(expr: &Expr, out: &mut Vec<Symbol>) {
3746 match expr {
3747 Expr::Length { collection } => {
3748 if let Expr::Identifier(sym) = collection {
3749 out.push(*sym);
3750 }
3751 }
3752 Expr::BinaryOp { left, right, .. } => {
3753 collect_length_syms_from_expr(left, out);
3754 collect_length_syms_from_expr(right, out);
3755 }
3756 Expr::Not { operand } => collect_length_syms_from_expr(operand, out),
3757 Expr::Index { collection, index } => {
3758 collect_length_syms_from_expr(collection, out);
3759 collect_length_syms_from_expr(index, out);
3760 }
3761 Expr::Call { args, .. } => {
3762 for arg in args.iter() {
3763 collect_length_syms_from_expr(arg, out);
3764 }
3765 }
3766 _ => {}
3767 }
3768}
3769
3770pub(crate) fn collect_length_syms_from_stmts(stmts: &[Stmt], out: &mut Vec<Symbol>) {
3772 for stmt in stmts {
3773 collect_length_syms_from_stmt(stmt, out);
3774 }
3775}
3776
3777fn collect_length_syms_from_stmt(stmt: &Stmt, out: &mut Vec<Symbol>) {
3778 match stmt {
3779 Stmt::Let { value, .. } => collect_length_syms_from_expr(value, out),
3780 Stmt::Set { value, .. } => collect_length_syms_from_expr(value, out),
3781 Stmt::Show { object, .. } => collect_length_syms_from_expr(object, out),
3782 Stmt::Push { value, collection } => {
3783 collect_length_syms_from_expr(value, out);
3784 collect_length_syms_from_expr(collection, out);
3785 }
3786 Stmt::SetIndex { collection, index, value } => {
3787 collect_length_syms_from_expr(collection, out);
3788 collect_length_syms_from_expr(index, out);
3789 collect_length_syms_from_expr(value, out);
3790 }
3791 Stmt::If { cond, then_block, else_block } => {
3792 collect_length_syms_from_expr(cond, out);
3793 collect_length_syms_from_stmts(then_block, out);
3794 if let Some(else_stmts) = else_block {
3795 collect_length_syms_from_stmts(else_stmts, out);
3796 }
3797 }
3798 Stmt::While { cond, body, .. } => {
3799 collect_length_syms_from_expr(cond, out);
3800 collect_length_syms_from_stmts(body, out);
3801 }
3802 Stmt::Repeat { body, .. } => {
3803 collect_length_syms_from_stmts(body, out);
3804 }
3805 Stmt::Return { value } => {
3806 if let Some(v) = value {
3807 collect_length_syms_from_expr(v, out);
3808 }
3809 }
3810 Stmt::Call { args, .. } => {
3811 for arg in args.iter() {
3812 collect_length_syms_from_expr(arg, out);
3813 }
3814 }
3815 _ => {}
3816 }
3817}
3818
3819pub(crate) fn is_copy_type(ty: &str) -> bool {
3822 crate::analysis::types::LogosType::from_rust_type_str(ty).is_copy()
3823}
3824
3825fn truthy_cond_wrap(
3830 cond: &Expr,
3831 cond_str: String,
3832 interner: &Interner,
3833 variable_types: &HashMap<Symbol, String>,
3834) -> String {
3835 if matches!(
3836 super::types::infer_logos_type(cond, interner, variable_types),
3837 crate::analysis::types::LogosType::Bool
3838 ) {
3839 cond_str
3840 } else {
3841 format!("logos_truthy(&({}))", cond_str)
3842 }
3843}
3844
3845pub(crate) fn has_copy_element_type(vec_type: &str) -> bool {
3848 crate::analysis::types::LogosType::from_rust_type_str(vec_type)
3849 .element_type()
3850 .map_or(false, |e| e.is_copy())
3851}
3852
3853pub(crate) fn has_copy_value_type(map_type: &str) -> bool {
3856 crate::analysis::types::LogosType::from_rust_type_str(map_type)
3857 .value_type()
3858 .map_or(false, |v| v.is_copy())
3859}
3860
3861fn try_emit_parallel_reduction<'a>(
3873 var_sym: Symbol,
3874 pattern_str: &str,
3875 iter_str: &str,
3876 iterable: &'a Expr<'a>,
3877 body: &'a [Stmt<'a>],
3878 interner: &Interner,
3879 indent: usize,
3880 ctx: &RefinementContext<'a>,
3881 synced_vars: &HashSet<Symbol>,
3882 async_functions: &HashSet<Symbol>,
3883) -> Option<String> {
3884 if body.len() != 1 { return None; }
3886
3887 let (acc_sym, op, increment_expr) = match &body[0] {
3888 Stmt::Set { target, value } => {
3889 if let Expr::BinaryOp { op, left, right } = value {
3890 match op {
3891 BinaryOpKind::Add => {
3892 if let Expr::Identifier(lhs) = left {
3894 if *lhs == *target {
3895 Some((*target, BinaryOpKind::Add, *right))
3896 } else {
3897 None
3898 }
3899 } else if let Expr::Identifier(rhs) = right {
3900 if *rhs == *target {
3901 Some((*target, BinaryOpKind::Add, *left))
3902 } else {
3903 None
3904 }
3905 } else {
3906 None
3907 }
3908 }
3909 _ => None,
3910 }
3911 } else {
3912 None
3913 }
3914 }
3915 _ => None,
3916 }?;
3917
3918 if !expr_is_pure_of(increment_expr, var_sym) {
3920 return None;
3921 }
3922
3923 let is_vec_i64 = if let Expr::Identifier(coll_sym) = iterable {
3925 ctx.get_variable_types().get(coll_sym)
3926 .map(|t| {
3927 let t = t.split("|__hl:").next().unwrap_or(t.as_str());
3928 (t.starts_with("LogosSeq<") || t.starts_with("Vec<") || t.starts_with("&[")) && has_copy_element_type(t)
3929 })
3930 .unwrap_or(false)
3931 } else {
3932 false
3933 };
3934
3935 if !is_vec_i64 { return None; }
3936
3937 let indent_str = " ".repeat(indent);
3938 let acc_name = interner.resolve(acc_sym);
3939
3940 let acc_ty = ctx
3945 .get_variable_types()
3946 .get(&acc_sym)
3947 .map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
3948 .unwrap_or("i64");
3949 let sum_ty = match acc_ty {
3950 "i64" | "f64" | "u64" | "i32" | "u32" | "usize" | "isize" => acc_ty,
3951 _ => return None,
3952 };
3953
3954 let incr_code = codegen_expr_with_async(
3956 increment_expr, interner, synced_vars, async_functions,
3957 ctx.get_variable_types(),
3958 );
3959
3960 let needs_map = !matches!(increment_expr, Expr::Identifier(s) if *s == var_sym);
3962
3963 let mut out = String::new();
3964
3965 let (borrow_expr, len_expr) = if let Expr::Identifier(coll_sym) = iterable {
3969 let ty = ctx.get_variable_types().get(coll_sym).map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()));
3970 if matches!(ty, Some(t) if t.starts_with("LogosSeq")) {
3971 (format!("{}.borrow()", iter_str), format!("{}.len()", iter_str))
3972 } else {
3973 (iter_str.to_string(), format!("{}.len()", iter_str))
3974 }
3975 } else {
3976 (format!("{}.borrow()", iter_str), format!("{}.len()", iter_str))
3977 };
3978 writeln!(out, "{}if {} >= 10000 {{", indent_str, len_expr).unwrap();
3979 writeln!(out, "{} use rayon::prelude::*;", indent_str).unwrap();
3980 writeln!(out, "{} let __par_ref = {};", indent_str, borrow_expr).unwrap();
3981 if needs_map {
3982 writeln!(out, "{} {} += __par_ref.par_iter().copied().map(|{}| {}).sum::<{}>();",
3983 indent_str, acc_name, pattern_str, incr_code, sum_ty).unwrap();
3984 } else {
3985 writeln!(out, "{} {} += __par_ref.par_iter().copied().sum::<{}>();",
3986 indent_str, acc_name, sum_ty).unwrap();
3987 }
3988 writeln!(out, "{}}} else {{", indent_str).unwrap();
3989 writeln!(out, "{} for {} in {}.to_vec() {{", indent_str, pattern_str, iter_str).unwrap();
3990
3991 match op {
3992 BinaryOpKind::Add => {
3993 writeln!(out, "{} {} += {};", indent_str, acc_name, incr_code).unwrap();
3994 }
3995 _ => {
3996 writeln!(out, "{} {} = {} {:?} {};", indent_str, acc_name, acc_name, op, incr_code).unwrap();
3997 }
3998 }
3999 writeln!(out, "{} }}", indent_str).unwrap();
4000 writeln!(out, "{}}}", indent_str).unwrap();
4001
4002 Some(out)
4003}
4004
4005fn expr_is_pure_of(expr: &Expr, allowed_sym: Symbol) -> bool {
4007 match expr {
4008 Expr::Identifier(s) => *s == allowed_sym,
4009 Expr::Literal(_) => true,
4010 Expr::BinaryOp { left, right, .. } => {
4011 expr_is_pure_of(left, allowed_sym) && expr_is_pure_of(right, allowed_sym)
4012 }
4013 Expr::Not { operand } => expr_is_pure_of(operand, allowed_sym),
4014 _ => false,
4015 }
4016}
4017