1use crate::op::*;
4use crate::program::*;
5use indexmap::IndexMap;
6use lex_ast as a;
7
8#[derive(Default)]
9struct ConstPool {
10 pool: Vec<Const>,
11 fields: IndexMap<String, u32>,
12 variants: IndexMap<String, u32>,
13 node_ids: IndexMap<String, u32>,
14 ints: IndexMap<i64, u32>,
15 bools: IndexMap<u8, u32>,
16 strs: IndexMap<String, u32>,
17}
18
19impl ConstPool {
20 fn field(&mut self, name: &str) -> u32 {
21 if let Some(i) = self.fields.get(name) { return *i; }
22 let i = self.pool.len() as u32;
23 self.pool.push(Const::FieldName(name.into()));
24 self.fields.insert(name.into(), i);
25 i
26 }
27 fn variant(&mut self, name: &str) -> u32 {
28 if let Some(i) = self.variants.get(name) { return *i; }
29 let i = self.pool.len() as u32;
30 self.pool.push(Const::VariantName(name.into()));
31 self.variants.insert(name.into(), i);
32 i
33 }
34 fn node_id(&mut self, name: &str) -> u32 {
35 if let Some(i) = self.node_ids.get(name) { return *i; }
36 let i = self.pool.len() as u32;
37 self.pool.push(Const::NodeId(name.into()));
38 self.node_ids.insert(name.into(), i);
39 i
40 }
41 fn int(&mut self, n: i64) -> u32 {
42 if let Some(i) = self.ints.get(&n) { return *i; }
43 let i = self.pool.len() as u32;
44 self.pool.push(Const::Int(n));
45 self.ints.insert(n, i);
46 i
47 }
48 fn bool(&mut self, b: bool) -> u32 {
49 let key = b as u8;
50 if let Some(i) = self.bools.get(&key) { return *i; }
51 let i = self.pool.len() as u32;
52 self.pool.push(Const::Bool(b));
53 self.bools.insert(key, i);
54 i
55 }
56 fn str(&mut self, s: &str) -> u32 {
57 if let Some(i) = self.strs.get(s) { return *i; }
58 let i = self.pool.len() as u32;
59 self.pool.push(Const::Str(s.into()));
60 self.strs.insert(s.into(), i);
61 i
62 }
63 fn float(&mut self, f: f64) -> u32 {
64 let i = self.pool.len() as u32;
66 self.pool.push(Const::Float(f));
67 i
68 }
69 fn unit(&mut self) -> u32 {
70 let i = self.pool.len() as u32;
71 self.pool.push(Const::Unit);
72 i
73 }
74}
75
76pub fn compile_program(stages: &[a::Stage]) -> Program {
77 let mut p = Program {
78 constants: Vec::new(),
79 functions: Vec::new(),
80 function_names: IndexMap::new(),
81 module_aliases: IndexMap::new(),
82 entry: None,
83 };
84
85 for s in stages {
88 if let a::Stage::Import(i) = s {
89 let module = i.reference.strip_prefix("std.").unwrap_or(&i.reference).to_string();
90 p.module_aliases.insert(i.alias.clone(), module);
91 }
92 }
93
94 for s in stages {
95 if let a::Stage::FnDecl(fd) = s {
96 let idx = p.functions.len() as u32;
97 p.function_names.insert(fd.name.clone(), idx);
98 p.functions.push(Function {
99 name: fd.name.clone(),
100 arity: fd.params.len() as u16,
101 locals_count: 0,
102 code: Vec::new(),
103 effects: fd.effects.iter().map(|e| DeclaredEffect {
104 kind: e.name.clone(),
105 arg: e.arg.as_ref().map(|a| match a {
106 a::EffectArg::Str { value } => EffectArg::Str(value.clone()),
107 a::EffectArg::Int { value } => EffectArg::Int(*value),
108 a::EffectArg::Ident { value } => EffectArg::Ident(value.clone()),
109 }),
110 }).collect(),
111 body_hash: crate::program::ZERO_BODY_HASH,
114 refinements: fd.params.iter().map(|p| match &p.ty {
118 a::TypeExpr::Refined { binding, predicate, .. } =>
119 Some(crate::program::Refinement {
120 binding: binding.clone(),
121 predicate: (**predicate).clone(),
122 }),
123 _ => None,
124 }).collect(),
125 });
126 }
127 }
128
129 let mut pool = ConstPool::default();
130 let function_names = p.function_names.clone();
131 let module_aliases = p.module_aliases.clone();
132 let mut pending_lambdas: Vec<PendingLambda> = Vec::new();
133
134 for s in stages {
135 if let a::Stage::FnDecl(_) = s {
136 let id_map = lex_ast::expr_ids(s);
139 let fd = match s { a::Stage::FnDecl(fd) => fd, _ => unreachable!() };
140 let mut fc = FnCompiler {
141 code: Vec::new(),
142 locals: IndexMap::new(),
143 next_local: 0,
144 peak_local: 0,
145 pool: &mut pool,
146 function_names: &function_names,
147 module_aliases: &module_aliases,
148 id_map: &id_map,
149 pending_lambdas: &mut pending_lambdas,
150 next_fn_id: &mut p.functions,
151 };
152 for param in &fd.params {
153 let i = fc.next_local;
154 fc.locals.insert(param.name.clone(), i);
155 fc.next_local += 1;
156 fc.peak_local = fc.next_local;
157 }
158 fc.compile_expr(&fd.body, true);
159 fc.code.push(Op::Return);
160 let code = std::mem::take(&mut fc.code);
161 let peak = fc.peak_local;
162 drop(fc);
163 let idx = function_names[&fd.name];
164 p.functions[idx as usize].code = code;
165 p.functions[idx as usize].locals_count = peak;
166 }
167 }
168
169 while let Some(pl) = pending_lambdas.pop() {
172 let id_map = std::collections::HashMap::new();
173 let mut fc = FnCompiler {
174 code: Vec::new(),
175 locals: IndexMap::new(),
176 next_local: 0,
177 peak_local: 0,
178 pool: &mut pool,
179 function_names: &function_names,
180 module_aliases: &module_aliases,
181 id_map: &id_map,
182 pending_lambdas: &mut pending_lambdas,
183 next_fn_id: &mut p.functions,
184 };
185 for name in &pl.capture_names {
186 let i = fc.next_local;
187 fc.locals.insert(name.clone(), i);
188 fc.next_local += 1;
189 fc.peak_local = fc.next_local;
190 }
191 for p in &pl.params {
192 let i = fc.next_local;
193 fc.locals.insert(p.name.clone(), i);
194 fc.next_local += 1;
195 fc.peak_local = fc.next_local;
196 }
197 fc.compile_expr(&pl.body, true);
198 fc.code.push(Op::Return);
199 let code = std::mem::take(&mut fc.code);
200 let peak = fc.peak_local;
201 drop(fc);
202 p.functions[pl.fn_id as usize].code = code;
203 p.functions[pl.fn_id as usize].locals_count = peak;
204 }
205
206 for f in p.functions.iter_mut() {
211 if f.body_hash == crate::program::ZERO_BODY_HASH {
212 f.body_hash = crate::program::compute_body_hash(
213 f.arity, f.locals_count, &f.code);
214 }
215 }
216
217 p.constants = pool.pool;
218 p
219}
220
221#[derive(Debug, Clone)]
222struct PendingLambda {
223 fn_id: u32,
224 capture_names: Vec<String>,
226 params: Vec<a::Param>,
227 body: a::CExpr,
228}
229
230struct FnCompiler<'a> {
231 code: Vec<Op>,
232 locals: IndexMap<String, u16>,
233 next_local: u16,
234 peak_local: u16,
236 pool: &'a mut ConstPool,
237 function_names: &'a IndexMap<String, u32>,
238 module_aliases: &'a IndexMap<String, String>,
239 id_map: &'a std::collections::HashMap<*const a::CExpr, lex_ast::NodeId>,
241 pending_lambdas: &'a mut Vec<PendingLambda>,
244 next_fn_id: &'a mut Vec<Function>,
247}
248
249impl<'a> FnCompiler<'a> {
250 fn alloc_local(&mut self, name: &str) -> u16 {
251 let i = self.next_local;
252 self.locals.insert(name.into(), i);
253 self.next_local += 1;
254 if self.next_local > self.peak_local { self.peak_local = self.next_local; }
255 i
256 }
257 fn emit(&mut self, op: Op) { self.code.push(op); }
258
259 fn compile_expr(&mut self, e: &a::CExpr, tail: bool) {
260 match e {
261 a::CExpr::Literal { value } => self.compile_lit(value),
262 a::CExpr::Var { name } => {
263 if let Some(slot) = self.locals.get(name) {
264 self.emit(Op::LoadLocal(*slot));
265 } else if let Some(&fn_id) = self.function_names.get(name) {
266 self.emit(Op::MakeClosure { fn_id, capture_count: 0 });
272 } else {
273 panic!("unknown var in compiler: {name}");
277 }
278 }
279 a::CExpr::Let { name, ty: _, value, body } => {
280 self.compile_expr(value, false);
281 let slot = self.alloc_local(name);
282 self.emit(Op::StoreLocal(slot));
283 self.compile_expr(body, tail);
284 }
285 a::CExpr::Block { statements, result } => {
286 for s in statements {
287 self.compile_expr(s, false);
288 self.emit(Op::Pop);
289 }
290 self.compile_expr(result, tail);
291 }
292 a::CExpr::Call { callee, args } => self.compile_call(e, callee, args, tail),
293 a::CExpr::Constructor { name, args } => {
294 for a in args { self.compile_expr(a, false); }
295 let name_idx = self.pool.variant(name);
296 self.emit(Op::MakeVariant { name_idx, arity: args.len() as u16 });
297 }
298 a::CExpr::Match { scrutinee, arms } => self.compile_match(scrutinee, arms, tail),
299 a::CExpr::RecordLit { fields } => {
300 let mut idxs = Vec::with_capacity(fields.len());
301 for f in fields {
302 self.compile_expr(&f.value, false);
303 idxs.push(self.pool.field(&f.name));
304 }
305 self.emit(Op::MakeRecord { field_name_indices: idxs });
306 }
307 a::CExpr::TupleLit { items } => {
308 for it in items { self.compile_expr(it, false); }
309 self.emit(Op::MakeTuple(items.len() as u16));
310 }
311 a::CExpr::ListLit { items } => {
312 for it in items { self.compile_expr(it, false); }
313 self.emit(Op::MakeList(items.len() as u32));
314 }
315 a::CExpr::FieldAccess { value, field } => {
316 self.compile_expr(value, false);
317 let idx = self.pool.field(field);
318 self.emit(Op::GetField(idx));
319 }
320 a::CExpr::BinOp { op, lhs, rhs } => self.compile_binop(op, lhs, rhs),
321 a::CExpr::UnaryOp { op, expr } => {
322 self.compile_expr(expr, false);
323 match op.as_str() {
324 "-" => self.emit(Op::NumNeg),
325 "not" => self.emit(Op::BoolNot),
326 other => panic!("unknown unary: {other}"),
327 }
328 }
329 a::CExpr::Lambda { params, body, .. } => self.compile_lambda(params, body),
330 a::CExpr::Return { value } => {
331 self.compile_expr(value, true);
332 self.emit(Op::Return);
333 }
334 }
335 }
336
337 fn compile_lit(&mut self, l: &a::CLit) {
338 let i = match l {
339 a::CLit::Int { value } => self.pool.int(*value),
340 a::CLit::Bool { value } => self.pool.bool(*value),
341 a::CLit::Float { value } => {
342 let f: f64 = value.parse().unwrap_or(0.0);
343 self.pool.float(f)
344 }
345 a::CLit::Str { value } => self.pool.str(value),
346 a::CLit::Bytes { value: _ } => {
347 let i = self.pool.pool.len() as u32;
349 self.pool.pool.push(Const::Bytes(Vec::new()));
350 i
351 }
352 a::CLit::Unit => self.pool.unit(),
353 };
354 self.emit(Op::PushConst(i));
355 }
356
357 fn compile_call(&mut self, call_expr: &a::CExpr, callee: &a::CExpr, args: &[a::CExpr], tail: bool) {
358 let node_id = self
359 .id_map
360 .get(&(call_expr as *const a::CExpr))
361 .map(|n| n.as_str().to_string())
362 .unwrap_or_else(|| "n_?".into());
363 let node_id_idx = self.pool.node_id(&node_id);
364
365 if let a::CExpr::FieldAccess { value, field } = callee {
370 if let a::CExpr::Var { name } = value.as_ref() {
371 if let Some(module) = self.module_aliases.get(name) {
372 if self.try_emit_higher_order(module, field, args, node_id_idx) {
373 let _ = tail;
374 return;
375 }
376 for a in args { self.compile_expr(a, false); }
377 let kind_idx = self.pool.str(module);
378 let op_idx = self.pool.str(field);
379 self.emit(Op::EffectCall {
380 kind_idx,
381 op_idx,
382 arity: args.len() as u16,
383 node_id_idx,
384 });
385 let _ = tail;
386 return;
387 }
388 }
389 }
390 match callee {
391 a::CExpr::Var { name } if self.function_names.contains_key(name) => {
392 for a in args { self.compile_expr(a, false); }
393 let fn_id = self.function_names[name];
394 if tail {
395 self.emit(Op::TailCall { fn_id, arity: args.len() as u16, node_id_idx });
396 } else {
397 self.emit(Op::Call { fn_id, arity: args.len() as u16, node_id_idx });
398 }
399 }
400 a::CExpr::Var { name } if self.locals.contains_key(name) => {
401 let slot = self.locals[name];
404 self.emit(Op::LoadLocal(slot));
405 for a in args { self.compile_expr(a, false); }
406 self.emit(Op::CallClosure { arity: args.len() as u16, node_id_idx });
407 }
408 other => {
410 self.compile_expr(other, false);
411 for a in args { self.compile_expr(a, false); }
412 self.emit(Op::CallClosure { arity: args.len() as u16, node_id_idx });
413 }
414 }
415 }
416
417 fn compile_binop(&mut self, op: &str, lhs: &a::CExpr, rhs: &a::CExpr) {
418 self.compile_expr(lhs, false);
419 self.compile_expr(rhs, false);
420 match op {
421 "+" => self.emit(Op::NumAdd),
422 "-" => self.emit(Op::NumSub),
423 "*" => self.emit(Op::NumMul),
424 "/" => self.emit(Op::NumDiv),
425 "%" => self.emit(Op::NumMod),
426 "==" => self.emit(Op::NumEq),
427 "!=" => { self.emit(Op::NumEq); self.emit(Op::BoolNot); }
428 "<" => self.emit(Op::NumLt),
429 "<=" => self.emit(Op::NumLe),
430 ">" => { self.emit_swap_top2(); self.emit(Op::NumLt); }
431 ">=" => { self.emit_swap_top2(); self.emit(Op::NumLe); }
432 "and" => self.emit(Op::BoolAnd),
433 "or" => self.emit(Op::BoolOr),
434 other => panic!("unknown binop: {other:?}"),
435 }
436 }
437
438 fn emit_swap_top2(&mut self) {
439 let a = self.alloc_local("__swap_a");
440 let b = self.alloc_local("__swap_b");
441 self.emit(Op::StoreLocal(b));
442 self.emit(Op::StoreLocal(a));
443 self.emit(Op::LoadLocal(b));
444 self.emit(Op::LoadLocal(a));
445 }
446
447 fn compile_match(&mut self, scrutinee: &a::CExpr, arms: &[a::Arm], tail: bool) {
448 self.compile_expr(scrutinee, false);
449 let scrut_slot = self.alloc_local("__scrut");
450 self.emit(Op::StoreLocal(scrut_slot));
451
452 let mut end_jumps: Vec<usize> = Vec::new();
453 for arm in arms {
454 let arm_start_locals = self.next_local;
455 let arm_start_locals_map = self.locals.clone();
456
457 self.emit(Op::LoadLocal(scrut_slot));
458 let mut bindings: Vec<(String, u16)> = Vec::new();
459 let fail_jumps: Vec<usize> = self.compile_pattern_test(&arm.pattern, &mut bindings);
460
461 self.compile_expr(&arm.body, tail);
462 let j_end = self.code.len();
463 self.emit(Op::Jump(0));
464 end_jumps.push(j_end);
465
466 let fail_target = self.code.len() as i32;
467 for j in fail_jumps {
468 match &mut self.code[j] {
474 Op::JumpIfNot(off) => *off = fail_target - (j as i32 + 1),
475 Op::Jump(off) => *off = fail_target - (j as i32 + 1),
476 _ => {}
477 }
478 }
479 self.next_local = arm_start_locals;
480 self.locals = arm_start_locals_map;
481 }
482 let panic_msg_idx = self.pool.str("non-exhaustive match");
483 self.emit(Op::Panic(panic_msg_idx));
484
485 let end_target = self.code.len() as i32;
486 for j in end_jumps {
487 if let Op::Jump(off) = &mut self.code[j] {
488 *off = end_target - (j as i32 + 1);
489 }
490 }
491 }
492
493 fn compile_pattern_test(&mut self, p: &a::Pattern, bindings: &mut Vec<(String, u16)>) -> Vec<usize> {
494 let mut fails = Vec::new();
495 match p {
496 a::Pattern::PWild => { self.emit(Op::Pop); }
497 a::Pattern::PVar { name } => {
498 let slot = self.alloc_local(name);
499 self.emit(Op::StoreLocal(slot));
500 bindings.push((name.clone(), slot));
501 }
502 a::Pattern::PLiteral { value } => {
503 self.compile_lit(value);
504 match value {
505 a::CLit::Str { .. } => self.emit(Op::StrEq),
506 a::CLit::Bytes { .. } => self.emit(Op::BytesEq),
507 _ => self.emit(Op::NumEq),
508 }
509 let j = self.code.len();
510 self.emit(Op::JumpIfNot(0));
511 fails.push(j);
512 }
513 a::Pattern::PConstructor { name, args } => {
514 let name_idx = self.pool.variant(name);
515 self.emit(Op::Dup); self.emit(Op::TestVariant(name_idx)); let j_success = self.code.len();
532 self.emit(Op::JumpIf(0)); self.emit(Op::Pop); let j_fail = self.code.len();
535 self.emit(Op::Jump(0)); fails.push(j_fail);
537 let success_target = self.code.len() as i32;
538 if let Op::JumpIf(off) = &mut self.code[j_success] {
539 *off = success_target - (j_success as i32 + 1);
540 }
541 if args.is_empty() {
542 self.emit(Op::Pop);
543 } else if args.len() == 1 {
544 self.emit(Op::GetVariantArg(0));
545 let sub_fails = self.compile_pattern_test(&args[0], bindings);
546 fails.extend(sub_fails);
547 } else {
548 let slot = self.alloc_local("__variant");
549 self.emit(Op::StoreLocal(slot));
550 for (i, arg) in args.iter().enumerate() {
551 self.emit(Op::LoadLocal(slot));
552 self.emit(Op::GetVariantArg(i as u16));
553 let sub_fails = self.compile_pattern_test(arg, bindings);
554 fails.extend(sub_fails);
555 }
556 }
557 }
558 a::Pattern::PRecord { fields } => {
559 let slot = self.alloc_local("__record");
560 self.emit(Op::StoreLocal(slot));
561 for f in fields {
562 self.emit(Op::LoadLocal(slot));
563 let fi = self.pool.field(&f.name);
564 self.emit(Op::GetField(fi));
565 let sub_fails = self.compile_pattern_test(&f.pattern, bindings);
566 fails.extend(sub_fails);
567 }
568 }
569 a::Pattern::PTuple { items } => {
570 let slot = self.alloc_local("__tuple");
571 self.emit(Op::StoreLocal(slot));
572 for (i, item) in items.iter().enumerate() {
573 self.emit(Op::LoadLocal(slot));
574 self.emit(Op::GetElem(i as u16));
575 let sub_fails = self.compile_pattern_test(item, bindings);
576 fails.extend(sub_fails);
577 }
578 }
579 }
580 fails
581 }
582
583 fn compile_lambda(&mut self, params: &[a::Param], body: &a::CExpr) {
587 let mut bound: std::collections::HashSet<String> = params.iter().map(|p| p.name.clone()).collect();
589 let mut frees: Vec<String> = Vec::new();
590 free_vars(body, &mut bound, &mut frees);
591
592 let captures: Vec<String> = frees.into_iter()
601 .filter(|n| self.locals.contains_key(n))
602 .collect();
603
604 let fn_id = self.next_fn_id.len() as u32;
606 self.next_fn_id.push(Function {
607 name: format!("__lambda_{fn_id}"),
608 arity: (captures.len() + params.len()) as u16,
609 locals_count: 0,
610 code: Vec::new(),
611 effects: Vec::new(),
612 body_hash: crate::program::ZERO_BODY_HASH,
614 refinements: Vec::new(),
619 });
620
621 for c in &captures {
623 let slot = *self.locals.get(c).expect("free var must be in scope");
624 self.emit(Op::LoadLocal(slot));
625 }
626 self.emit(Op::MakeClosure { fn_id, capture_count: captures.len() as u16 });
627
628 self.pending_lambdas.push(PendingLambda {
630 fn_id,
631 capture_names: captures,
632 params: params.to_vec(),
633 body: body.clone(),
634 });
635 }
636
637 fn try_emit_higher_order(
641 &mut self,
642 module: &str,
643 op: &str,
644 args: &[a::CExpr],
645 node_id_idx: u32,
646 ) -> bool {
647 match (module, op) {
648 ("result", "map") => self.emit_variant_map(args, "Ok", true),
649 ("result", "and_then") => self.emit_variant_map(args, "Ok", false),
650 ("result", "map_err") => self.emit_variant_map(args, "Err", true),
651 ("result", "or_else") => self.emit_variant_or_else(args, "Err", 1),
652 ("option", "map") => self.emit_variant_map(args, "Some", true),
653 ("option", "and_then") => self.emit_variant_map(args, "Some", false),
654 ("option", "or_else") => self.emit_variant_or_else(args, "None", 0),
655 ("option", "unwrap_or_else") => self.emit_option_unwrap_or_else(args),
656 ("list", "map") => self.emit_list_map(args),
657 ("list", "par_map") => self.emit_list_par_map(args),
658 ("list", "sort_by") => self.emit_list_sort_by(args),
659 ("list", "filter") => self.emit_list_filter(args),
660 ("list", "fold") => self.emit_list_fold(args),
661 ("iter", "from_list") => self.emit_iter_from_list(args),
662 ("iter", "next") => self.emit_iter_next(args),
663 ("iter", "is_empty") => self.emit_iter_is_empty(args),
664 ("iter", "count") => self.emit_iter_count(args),
665 ("iter", "take") => self.emit_iter_take(args),
666 ("iter", "skip") => self.emit_iter_skip(args),
667 ("iter", "to_list") => self.emit_iter_to_list(args),
668 ("iter", "map") => self.emit_iter_map(args),
669 ("iter", "filter") => self.emit_iter_filter(args),
670 ("iter", "fold") => self.emit_iter_fold(args),
671 ("map", "fold") => self.emit_map_fold(args, node_id_idx),
672 ("flow", "sequential") => self.emit_flow_sequential(args),
673 ("flow", "branch") => self.emit_flow_branch(args),
674 ("flow", "retry") => self.emit_flow_retry(args),
675 ("flow", "retry_with_backoff") => self.emit_flow_retry_with_backoff(args),
676 ("flow", "parallel") => self.emit_flow_parallel(args),
677 ("flow", "parallel_list") => self.emit_flow_parallel_list(args),
678 _ => return false,
679 }
680 true
681 }
682
683 fn emit_list_map(&mut self, args: &[a::CExpr]) {
686 self.compile_expr(&args[0], false);
688 let xs = self.alloc_local("__lm_xs");
689 self.emit(Op::StoreLocal(xs));
690 self.compile_expr(&args[1], false);
691 let f = self.alloc_local("__lm_f");
692 self.emit(Op::StoreLocal(f));
693
694 self.emit(Op::MakeList(0));
696 let out = self.alloc_local("__lm_out");
697 self.emit(Op::StoreLocal(out));
698
699 let zero = self.pool.int(0);
701 self.emit(Op::PushConst(zero));
702 let i = self.alloc_local("__lm_i");
703 self.emit(Op::StoreLocal(i));
704
705 let loop_top = self.code.len();
707 self.emit(Op::LoadLocal(i));
708 self.emit(Op::LoadLocal(xs));
709 self.emit(Op::GetListLen);
710 self.emit(Op::NumLt);
711 let j_exit = self.code.len();
712 self.emit(Op::JumpIfNot(0));
713
714 let nid = self.pool.node_id("n_list_map");
716 self.emit(Op::LoadLocal(out));
717 self.emit(Op::LoadLocal(f));
718 self.emit(Op::LoadLocal(xs));
719 self.emit(Op::LoadLocal(i));
720 self.emit(Op::GetListElemDyn);
721 self.emit(Op::CallClosure { arity: 1, node_id_idx: nid });
722 self.emit(Op::ListAppend);
723 self.emit(Op::StoreLocal(out));
724
725 self.emit(Op::LoadLocal(i));
727 let one = self.pool.int(1);
728 self.emit(Op::PushConst(one));
729 self.emit(Op::NumAdd);
730 self.emit(Op::StoreLocal(i));
731
732 let jump_back = self.code.len();
734 let back = (loop_top as i32) - (jump_back as i32 + 1);
735 self.emit(Op::Jump(back));
736
737 let exit_target = self.code.len() as i32;
739 if let Op::JumpIfNot(off) = &mut self.code[j_exit] {
740 *off = exit_target - (j_exit as i32 + 1);
741 }
742 self.emit(Op::LoadLocal(out));
743 }
744
745 fn emit_list_par_map(&mut self, args: &[a::CExpr]) {
751 self.compile_expr(&args[0], false);
752 self.compile_expr(&args[1], false);
753 let nid = self.pool.node_id("n_list_par_map");
754 self.emit(Op::ParallelMap { node_id_idx: nid });
755 }
756
757 fn emit_list_sort_by(&mut self, args: &[a::CExpr]) {
765 self.compile_expr(&args[0], false);
766 self.compile_expr(&args[1], false);
767 let nid = self.pool.node_id("n_list_sort_by");
768 self.emit(Op::SortByKey { node_id_idx: nid });
769 }
770
771 fn emit_list_filter(&mut self, args: &[a::CExpr]) {
773 self.compile_expr(&args[0], false);
774 let xs = self.alloc_local("__lf_xs");
775 self.emit(Op::StoreLocal(xs));
776 self.compile_expr(&args[1], false);
777 let f = self.alloc_local("__lf_f");
778 self.emit(Op::StoreLocal(f));
779
780 self.emit(Op::MakeList(0));
781 let out = self.alloc_local("__lf_out");
782 self.emit(Op::StoreLocal(out));
783
784 let zero = self.pool.int(0);
785 self.emit(Op::PushConst(zero));
786 let i = self.alloc_local("__lf_i");
787 self.emit(Op::StoreLocal(i));
788
789 let loop_top = self.code.len();
790 self.emit(Op::LoadLocal(i));
791 self.emit(Op::LoadLocal(xs));
792 self.emit(Op::GetListLen);
793 self.emit(Op::NumLt);
794 let j_exit = self.code.len();
795 self.emit(Op::JumpIfNot(0));
796
797 self.emit(Op::LoadLocal(xs));
799 self.emit(Op::LoadLocal(i));
800 self.emit(Op::GetListElemDyn);
801 let x = self.alloc_local("__lf_x");
802 self.emit(Op::StoreLocal(x));
803
804 let nid = self.pool.node_id("n_list_filter");
806 self.emit(Op::LoadLocal(f));
807 self.emit(Op::LoadLocal(x));
808 self.emit(Op::CallClosure { arity: 1, node_id_idx: nid });
809 let j_skip = self.code.len();
810 self.emit(Op::JumpIfNot(0));
811
812 self.emit(Op::LoadLocal(out));
813 self.emit(Op::LoadLocal(x));
814 self.emit(Op::ListAppend);
815 self.emit(Op::StoreLocal(out));
816
817 let skip_target = self.code.len() as i32;
818 if let Op::JumpIfNot(off) = &mut self.code[j_skip] {
819 *off = skip_target - (j_skip as i32 + 1);
820 }
821
822 self.emit(Op::LoadLocal(i));
824 let one = self.pool.int(1);
825 self.emit(Op::PushConst(one));
826 self.emit(Op::NumAdd);
827 self.emit(Op::StoreLocal(i));
828
829 let jump_back = self.code.len();
830 let back = (loop_top as i32) - (jump_back as i32 + 1);
831 self.emit(Op::Jump(back));
832
833 let exit_target = self.code.len() as i32;
834 if let Op::JumpIfNot(off) = &mut self.code[j_exit] {
835 *off = exit_target - (j_exit as i32 + 1);
836 }
837 self.emit(Op::LoadLocal(out));
838 }
839
840 fn emit_list_fold(&mut self, args: &[a::CExpr]) {
842 self.compile_expr(&args[0], false);
844 let xs = self.alloc_local("__lo_xs");
845 self.emit(Op::StoreLocal(xs));
846 self.compile_expr(&args[1], false);
847 let acc = self.alloc_local("__lo_acc");
848 self.emit(Op::StoreLocal(acc));
849 self.compile_expr(&args[2], false);
850 let f = self.alloc_local("__lo_f");
851 self.emit(Op::StoreLocal(f));
852
853 let zero = self.pool.int(0);
854 self.emit(Op::PushConst(zero));
855 let i = self.alloc_local("__lo_i");
856 self.emit(Op::StoreLocal(i));
857
858 let loop_top = self.code.len();
859 self.emit(Op::LoadLocal(i));
860 self.emit(Op::LoadLocal(xs));
861 self.emit(Op::GetListLen);
862 self.emit(Op::NumLt);
863 let j_exit = self.code.len();
864 self.emit(Op::JumpIfNot(0));
865
866 let nid = self.pool.node_id("n_list_fold");
868 self.emit(Op::LoadLocal(f));
869 self.emit(Op::LoadLocal(acc));
870 self.emit(Op::LoadLocal(xs));
871 self.emit(Op::LoadLocal(i));
872 self.emit(Op::GetListElemDyn);
873 self.emit(Op::CallClosure { arity: 2, node_id_idx: nid });
874 self.emit(Op::StoreLocal(acc));
875
876 self.emit(Op::LoadLocal(i));
878 let one = self.pool.int(1);
879 self.emit(Op::PushConst(one));
880 self.emit(Op::NumAdd);
881 self.emit(Op::StoreLocal(i));
882
883 let jump_back = self.code.len();
884 let back = (loop_top as i32) - (jump_back as i32 + 1);
885 self.emit(Op::Jump(back));
886
887 let exit_target = self.code.len() as i32;
888 if let Op::JumpIfNot(off) = &mut self.code[j_exit] {
889 *off = exit_target - (j_exit as i32 + 1);
890 }
891 self.emit(Op::LoadLocal(acc));
892 }
893
894 fn emit_iter_from_list(&mut self, args: &[a::CExpr]) {
901 self.compile_expr(&args[0], false);
902 let zero = self.pool.int(0);
903 self.emit(Op::PushConst(zero));
904 self.emit(Op::MakeTuple(2));
905 }
906
907 fn emit_iter_next(&mut self, args: &[a::CExpr]) {
909 self.compile_expr(&args[0], false);
910 let it = self.alloc_local("__in_it");
911 self.emit(Op::StoreLocal(it));
912
913 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
914 let list = self.alloc_local("__in_list");
915 self.emit(Op::StoreLocal(list));
916
917 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
918 let idx = self.alloc_local("__in_idx");
919 self.emit(Op::StoreLocal(idx));
920
921 self.emit(Op::LoadLocal(idx));
923 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
924 self.emit(Op::NumLt);
925 let j_else = self.code.len();
926 self.emit(Op::JumpIfNot(0));
927
928 self.emit(Op::LoadLocal(list));
930 self.emit(Op::LoadLocal(idx));
931 self.emit(Op::GetListElemDyn); self.emit(Op::LoadLocal(list));
934 self.emit(Op::LoadLocal(idx));
935 let one = self.pool.int(1);
936 self.emit(Op::PushConst(one));
937 self.emit(Op::NumAdd);
938 self.emit(Op::MakeTuple(2)); self.emit(Op::MakeTuple(2)); let some_idx = self.pool.variant("Some");
942 self.emit(Op::MakeVariant { name_idx: some_idx, arity: 1 });
943 let j_end = self.code.len();
944 self.emit(Op::Jump(0));
945
946 let else_t = self.code.len() as i32;
948 if let Op::JumpIfNot(off) = &mut self.code[j_else] {
949 *off = else_t - (j_else as i32 + 1);
950 }
951 let none_idx = self.pool.variant("None");
952 self.emit(Op::MakeVariant { name_idx: none_idx, arity: 0 });
953
954 let end_t = self.code.len() as i32;
955 if let Op::Jump(off) = &mut self.code[j_end] {
956 *off = end_t - (j_end as i32 + 1);
957 }
958 }
959
960 fn emit_iter_is_empty(&mut self, args: &[a::CExpr]) {
962 self.compile_expr(&args[0], false);
963 let it = self.alloc_local("__ie_it");
964 self.emit(Op::StoreLocal(it));
965
966 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1)); self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0)); self.emit(Op::GetListLen); self.emit(Op::NumLt); self.emit(Op::BoolNot); }
972
973 fn emit_iter_count(&mut self, args: &[a::CExpr]) {
975 self.compile_expr(&args[0], false);
976 let it = self.alloc_local("__ic_it");
977 self.emit(Op::StoreLocal(it));
978
979 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
980 self.emit(Op::GetListLen); self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1)); self.emit(Op::NumSub); }
984
985 fn emit_iter_take(&mut self, args: &[a::CExpr]) {
987 self.compile_expr(&args[0], false);
988 let it = self.alloc_local("__itk_it");
989 self.emit(Op::StoreLocal(it));
990
991 self.compile_expr(&args[1], false);
992 let n = self.alloc_local("__itk_n");
993 self.emit(Op::StoreLocal(n));
994
995 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
996 let list = self.alloc_local("__itk_list");
997 self.emit(Op::StoreLocal(list));
998
999 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1000 let i = self.alloc_local("__itk_i");
1001 self.emit(Op::StoreLocal(i));
1002
1003 self.emit(Op::MakeList(0));
1004 let out = self.alloc_local("__itk_out");
1005 self.emit(Op::StoreLocal(out));
1006
1007 let zero = self.pool.int(0);
1008 self.emit(Op::PushConst(zero));
1009 let cnt = self.alloc_local("__itk_cnt");
1010 self.emit(Op::StoreLocal(cnt));
1011
1012 let loop_top = self.code.len();
1013
1014 self.emit(Op::LoadLocal(cnt));
1016 self.emit(Op::LoadLocal(n));
1017 self.emit(Op::NumLt);
1018 let j_exit_n = self.code.len();
1019 self.emit(Op::JumpIfNot(0));
1020
1021 self.emit(Op::LoadLocal(i));
1023 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1024 self.emit(Op::NumLt);
1025 let j_exit_l = self.code.len();
1026 self.emit(Op::JumpIfNot(0));
1027
1028 self.emit(Op::LoadLocal(out));
1030 self.emit(Op::LoadLocal(list));
1031 self.emit(Op::LoadLocal(i));
1032 self.emit(Op::GetListElemDyn);
1033 self.emit(Op::ListAppend);
1034 self.emit(Op::StoreLocal(out));
1035
1036 let one = self.pool.int(1);
1037 self.emit(Op::LoadLocal(i));
1039 self.emit(Op::PushConst(one));
1040 self.emit(Op::NumAdd);
1041 self.emit(Op::StoreLocal(i));
1042 self.emit(Op::LoadLocal(cnt));
1044 self.emit(Op::PushConst(one));
1045 self.emit(Op::NumAdd);
1046 self.emit(Op::StoreLocal(cnt));
1047
1048 let jback = self.code.len();
1049 self.emit(Op::Jump((loop_top as i32) - (jback as i32 + 1)));
1050
1051 let exit_t = self.code.len() as i32;
1052 if let Op::JumpIfNot(off) = &mut self.code[j_exit_n] { *off = exit_t - (j_exit_n as i32 + 1); }
1053 if let Op::JumpIfNot(off) = &mut self.code[j_exit_l] { *off = exit_t - (j_exit_l as i32 + 1); }
1054
1055 self.emit(Op::LoadLocal(out));
1057 self.emit(Op::PushConst(zero));
1058 self.emit(Op::MakeTuple(2));
1059 }
1060
1061 fn emit_iter_skip(&mut self, args: &[a::CExpr]) {
1063 self.compile_expr(&args[0], false);
1064 let it = self.alloc_local("__isk_it");
1065 self.emit(Op::StoreLocal(it));
1066
1067 self.compile_expr(&args[1], false);
1068 let n = self.alloc_local("__isk_n");
1069 self.emit(Op::StoreLocal(n));
1070
1071 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
1072 let list = self.alloc_local("__isk_list");
1073 self.emit(Op::StoreLocal(list));
1074
1075 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1076 let idx = self.alloc_local("__isk_idx");
1077 self.emit(Op::StoreLocal(idx));
1078
1079 self.emit(Op::LoadLocal(idx));
1081 self.emit(Op::LoadLocal(n));
1082 self.emit(Op::NumAdd);
1083 let raw = self.alloc_local("__isk_raw");
1084 self.emit(Op::StoreLocal(raw));
1085
1086 self.emit(Op::LoadLocal(raw));
1088 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1089 self.emit(Op::NumLt);
1090 let j_use_raw = self.code.len();
1091 self.emit(Op::JumpIf(0));
1092
1093 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1095 let j_end = self.code.len();
1096 self.emit(Op::Jump(0));
1097
1098 let raw_t = self.code.len() as i32;
1100 if let Op::JumpIf(off) = &mut self.code[j_use_raw] { *off = raw_t - (j_use_raw as i32 + 1); }
1101 self.emit(Op::LoadLocal(raw));
1102
1103 let end_t = self.code.len() as i32;
1104 if let Op::Jump(off) = &mut self.code[j_end] { *off = end_t - (j_end as i32 + 1); }
1105
1106 let new_idx = self.alloc_local("__isk_ni");
1108 self.emit(Op::StoreLocal(new_idx));
1109 self.emit(Op::LoadLocal(list));
1110 self.emit(Op::LoadLocal(new_idx));
1111 self.emit(Op::MakeTuple(2));
1112 }
1113
1114 fn emit_iter_to_list(&mut self, args: &[a::CExpr]) {
1116 self.compile_expr(&args[0], false);
1117 let it = self.alloc_local("__itl_it");
1118 self.emit(Op::StoreLocal(it));
1119
1120 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
1121 let list = self.alloc_local("__itl_list");
1122 self.emit(Op::StoreLocal(list));
1123
1124 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1125 let i = self.alloc_local("__itl_i");
1126 self.emit(Op::StoreLocal(i));
1127
1128 self.emit(Op::MakeList(0));
1129 let out = self.alloc_local("__itl_out");
1130 self.emit(Op::StoreLocal(out));
1131
1132 let loop_top = self.code.len();
1133 self.emit(Op::LoadLocal(i));
1134 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1135 self.emit(Op::NumLt);
1136 let j_exit = self.code.len();
1137 self.emit(Op::JumpIfNot(0));
1138
1139 self.emit(Op::LoadLocal(out));
1140 self.emit(Op::LoadLocal(list));
1141 self.emit(Op::LoadLocal(i));
1142 self.emit(Op::GetListElemDyn);
1143 self.emit(Op::ListAppend);
1144 self.emit(Op::StoreLocal(out));
1145
1146 self.emit(Op::LoadLocal(i));
1147 let one = self.pool.int(1);
1148 self.emit(Op::PushConst(one));
1149 self.emit(Op::NumAdd);
1150 self.emit(Op::StoreLocal(i));
1151
1152 let jback = self.code.len();
1153 self.emit(Op::Jump((loop_top as i32) - (jback as i32 + 1)));
1154
1155 let exit_t = self.code.len() as i32;
1156 if let Op::JumpIfNot(off) = &mut self.code[j_exit] { *off = exit_t - (j_exit as i32 + 1); }
1157 self.emit(Op::LoadLocal(out));
1158 }
1159
1160 fn emit_iter_map(&mut self, args: &[a::CExpr]) {
1162 self.compile_expr(&args[0], false);
1163 let it = self.alloc_local("__im_it");
1164 self.emit(Op::StoreLocal(it));
1165
1166 self.compile_expr(&args[1], false);
1167 let f = self.alloc_local("__im_f");
1168 self.emit(Op::StoreLocal(f));
1169
1170 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
1171 let list = self.alloc_local("__im_list");
1172 self.emit(Op::StoreLocal(list));
1173
1174 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1175 let i = self.alloc_local("__im_i");
1176 self.emit(Op::StoreLocal(i));
1177
1178 self.emit(Op::MakeList(0));
1179 let out = self.alloc_local("__im_out");
1180 self.emit(Op::StoreLocal(out));
1181
1182 let loop_top = self.code.len();
1183 self.emit(Op::LoadLocal(i));
1184 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1185 self.emit(Op::NumLt);
1186 let j_exit = self.code.len();
1187 self.emit(Op::JumpIfNot(0));
1188
1189 let nid = self.pool.node_id("n_iter_map");
1190 self.emit(Op::LoadLocal(out));
1191 self.emit(Op::LoadLocal(f));
1192 self.emit(Op::LoadLocal(list));
1193 self.emit(Op::LoadLocal(i));
1194 self.emit(Op::GetListElemDyn);
1195 self.emit(Op::CallClosure { arity: 1, node_id_idx: nid });
1196 self.emit(Op::ListAppend);
1197 self.emit(Op::StoreLocal(out));
1198
1199 self.emit(Op::LoadLocal(i));
1200 let one = self.pool.int(1);
1201 self.emit(Op::PushConst(one));
1202 self.emit(Op::NumAdd);
1203 self.emit(Op::StoreLocal(i));
1204
1205 let jback = self.code.len();
1206 self.emit(Op::Jump((loop_top as i32) - (jback as i32 + 1)));
1207
1208 let exit_t = self.code.len() as i32;
1209 if let Op::JumpIfNot(off) = &mut self.code[j_exit] { *off = exit_t - (j_exit as i32 + 1); }
1210
1211 let zero = self.pool.int(0);
1212 self.emit(Op::LoadLocal(out));
1213 self.emit(Op::PushConst(zero));
1214 self.emit(Op::MakeTuple(2));
1215 }
1216
1217 fn emit_iter_filter(&mut self, args: &[a::CExpr]) {
1219 self.compile_expr(&args[0], false);
1220 let it = self.alloc_local("__if_it");
1221 self.emit(Op::StoreLocal(it));
1222
1223 self.compile_expr(&args[1], false);
1224 let f = self.alloc_local("__if_f");
1225 self.emit(Op::StoreLocal(f));
1226
1227 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
1228 let list = self.alloc_local("__if_list");
1229 self.emit(Op::StoreLocal(list));
1230
1231 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1232 let i = self.alloc_local("__if_i");
1233 self.emit(Op::StoreLocal(i));
1234
1235 self.emit(Op::MakeList(0));
1236 let out = self.alloc_local("__if_out");
1237 self.emit(Op::StoreLocal(out));
1238
1239 let loop_top = self.code.len();
1240 self.emit(Op::LoadLocal(i));
1241 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1242 self.emit(Op::NumLt);
1243 let j_exit = self.code.len();
1244 self.emit(Op::JumpIfNot(0));
1245
1246 self.emit(Op::LoadLocal(list));
1248 self.emit(Op::LoadLocal(i));
1249 self.emit(Op::GetListElemDyn);
1250 let x = self.alloc_local("__if_x");
1251 self.emit(Op::StoreLocal(x));
1252
1253 let nid = self.pool.node_id("n_iter_filter");
1254 self.emit(Op::LoadLocal(f));
1255 self.emit(Op::LoadLocal(x));
1256 self.emit(Op::CallClosure { arity: 1, node_id_idx: nid });
1257 let j_skip = self.code.len();
1258 self.emit(Op::JumpIfNot(0));
1259
1260 self.emit(Op::LoadLocal(out));
1261 self.emit(Op::LoadLocal(x));
1262 self.emit(Op::ListAppend);
1263 self.emit(Op::StoreLocal(out));
1264
1265 let skip_t = self.code.len() as i32;
1266 if let Op::JumpIfNot(off) = &mut self.code[j_skip] { *off = skip_t - (j_skip as i32 + 1); }
1267
1268 self.emit(Op::LoadLocal(i));
1269 let one = self.pool.int(1);
1270 self.emit(Op::PushConst(one));
1271 self.emit(Op::NumAdd);
1272 self.emit(Op::StoreLocal(i));
1273
1274 let jback = self.code.len();
1275 self.emit(Op::Jump((loop_top as i32) - (jback as i32 + 1)));
1276
1277 let exit_t = self.code.len() as i32;
1278 if let Op::JumpIfNot(off) = &mut self.code[j_exit] { *off = exit_t - (j_exit as i32 + 1); }
1279
1280 let zero = self.pool.int(0);
1281 self.emit(Op::LoadLocal(out));
1282 self.emit(Op::PushConst(zero));
1283 self.emit(Op::MakeTuple(2));
1284 }
1285
1286 fn emit_iter_fold(&mut self, args: &[a::CExpr]) {
1288 self.compile_expr(&args[0], false);
1289 let it = self.alloc_local("__ifo_it");
1290 self.emit(Op::StoreLocal(it));
1291
1292 self.compile_expr(&args[1], false);
1293 let acc = self.alloc_local("__ifo_acc");
1294 self.emit(Op::StoreLocal(acc));
1295
1296 self.compile_expr(&args[2], false);
1297 let f = self.alloc_local("__ifo_f");
1298 self.emit(Op::StoreLocal(f));
1299
1300 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(0));
1301 let list = self.alloc_local("__ifo_list");
1302 self.emit(Op::StoreLocal(list));
1303
1304 self.emit(Op::LoadLocal(it)); self.emit(Op::GetElem(1));
1305 let i = self.alloc_local("__ifo_i");
1306 self.emit(Op::StoreLocal(i));
1307
1308 let loop_top = self.code.len();
1309 self.emit(Op::LoadLocal(i));
1310 self.emit(Op::LoadLocal(list)); self.emit(Op::GetListLen);
1311 self.emit(Op::NumLt);
1312 let j_exit = self.code.len();
1313 self.emit(Op::JumpIfNot(0));
1314
1315 let nid = self.pool.node_id("n_iter_fold");
1316 self.emit(Op::LoadLocal(f));
1317 self.emit(Op::LoadLocal(acc));
1318 self.emit(Op::LoadLocal(list));
1319 self.emit(Op::LoadLocal(i));
1320 self.emit(Op::GetListElemDyn);
1321 self.emit(Op::CallClosure { arity: 2, node_id_idx: nid });
1322 self.emit(Op::StoreLocal(acc));
1323
1324 self.emit(Op::LoadLocal(i));
1325 let one = self.pool.int(1);
1326 self.emit(Op::PushConst(one));
1327 self.emit(Op::NumAdd);
1328 self.emit(Op::StoreLocal(i));
1329
1330 let jback = self.code.len();
1331 self.emit(Op::Jump((loop_top as i32) - (jback as i32 + 1)));
1332
1333 let exit_t = self.code.len() as i32;
1334 if let Op::JumpIfNot(off) = &mut self.code[j_exit] { *off = exit_t - (j_exit as i32 + 1); }
1335 self.emit(Op::LoadLocal(acc));
1336 }
1337
1338 fn emit_map_fold(&mut self, args: &[a::CExpr], node_id_idx: u32) {
1344 self.compile_expr(&args[0], false);
1346 let map_kind = self.pool.str("map");
1347 let entries_op = self.pool.str("entries");
1348 self.emit(Op::EffectCall {
1349 kind_idx: map_kind,
1350 op_idx: entries_op,
1351 arity: 1,
1352 node_id_idx,
1353 });
1354 let xs = self.alloc_local("__mf_xs");
1355 self.emit(Op::StoreLocal(xs));
1356
1357 self.compile_expr(&args[1], false);
1359 let acc = self.alloc_local("__mf_acc");
1360 self.emit(Op::StoreLocal(acc));
1361
1362 self.compile_expr(&args[2], false);
1364 let f = self.alloc_local("__mf_f");
1365 self.emit(Op::StoreLocal(f));
1366
1367 let zero = self.pool.int(0);
1369 self.emit(Op::PushConst(zero));
1370 let i = self.alloc_local("__mf_i");
1371 self.emit(Op::StoreLocal(i));
1372
1373 let loop_top = self.code.len();
1375 self.emit(Op::LoadLocal(i));
1376 self.emit(Op::LoadLocal(xs));
1377 self.emit(Op::GetListLen);
1378 self.emit(Op::NumLt);
1379 let j_exit = self.code.len();
1380 self.emit(Op::JumpIfNot(0));
1381
1382 self.emit(Op::LoadLocal(xs));
1384 self.emit(Op::LoadLocal(i));
1385 self.emit(Op::GetListElemDyn);
1386 let pair = self.alloc_local("__mf_pair");
1387 self.emit(Op::StoreLocal(pair));
1388
1389 let nid = self.pool.node_id("n_map_fold");
1391 self.emit(Op::LoadLocal(f));
1392 self.emit(Op::LoadLocal(acc));
1393 self.emit(Op::LoadLocal(pair));
1394 self.emit(Op::GetElem(0));
1395 self.emit(Op::LoadLocal(pair));
1396 self.emit(Op::GetElem(1));
1397 self.emit(Op::CallClosure { arity: 3, node_id_idx: nid });
1398 self.emit(Op::StoreLocal(acc));
1399
1400 self.emit(Op::LoadLocal(i));
1402 let one = self.pool.int(1);
1403 self.emit(Op::PushConst(one));
1404 self.emit(Op::NumAdd);
1405 self.emit(Op::StoreLocal(i));
1406
1407 let jump_back = self.code.len();
1408 let back = (loop_top as i32) - (jump_back as i32 + 1);
1409 self.emit(Op::Jump(back));
1410
1411 let exit_target = self.code.len() as i32;
1412 if let Op::JumpIfNot(off) = &mut self.code[j_exit] {
1413 *off = exit_target - (j_exit as i32 + 1);
1414 }
1415 self.emit(Op::LoadLocal(acc));
1416 }
1417
1418 fn emit_variant_map(
1424 &mut self,
1425 args: &[a::CExpr],
1426 wrap_with: &str,
1427 wrap_result: bool,
1428 ) {
1429 let wrap_idx = self.pool.variant(wrap_with);
1431
1432 self.compile_expr(&args[0], false);
1434 let val_slot = self.alloc_local("__hov");
1435 self.emit(Op::StoreLocal(val_slot));
1436
1437 self.compile_expr(&args[1], false);
1438 let f_slot = self.alloc_local("__hof");
1439 self.emit(Op::StoreLocal(f_slot));
1440
1441 self.emit(Op::LoadLocal(val_slot));
1448 self.emit(Op::Dup);
1449 self.emit(Op::TestVariant(wrap_idx));
1450 let j_skip = self.code.len();
1451 self.emit(Op::JumpIfNot(0));
1452
1453 self.emit(Op::GetVariantArg(0));
1455 let arg_slot = self.alloc_local("__hov_arg");
1456 self.emit(Op::StoreLocal(arg_slot));
1457 self.emit(Op::LoadLocal(f_slot));
1458 self.emit(Op::LoadLocal(arg_slot));
1459 let nid = self.pool.node_id("n_hov");
1460 self.emit(Op::CallClosure { arity: 1, node_id_idx: nid });
1461 if wrap_result {
1462 self.emit(Op::MakeVariant { name_idx: wrap_idx, arity: 1 });
1463 }
1464 let j_end = self.code.len();
1465 self.emit(Op::Jump(0));
1466
1467 let skip_target = self.code.len() as i32;
1469 if let Op::JumpIfNot(off) = &mut self.code[j_skip] {
1470 *off = skip_target - (j_skip as i32 + 1);
1471 }
1472
1473 let end_target = self.code.len() as i32;
1474 if let Op::Jump(off) = &mut self.code[j_end] {
1475 *off = end_target - (j_end as i32 + 1);
1476 }
1477 }
1478
1479 fn emit_variant_or_else(
1488 &mut self,
1489 args: &[a::CExpr],
1490 match_on: &str,
1491 closure_arity: u16,
1492 ) {
1493 let match_idx = self.pool.variant(match_on);
1494
1495 self.compile_expr(&args[0], false);
1496 let val_slot = self.alloc_local("__hoe");
1497 self.emit(Op::StoreLocal(val_slot));
1498
1499 self.compile_expr(&args[1], false);
1500 let f_slot = self.alloc_local("__hoe_f");
1501 self.emit(Op::StoreLocal(f_slot));
1502
1503 self.emit(Op::LoadLocal(val_slot));
1511 self.emit(Op::Dup);
1512 self.emit(Op::TestVariant(match_idx));
1513 let j_skip = self.code.len();
1514 self.emit(Op::JumpIfNot(0));
1515
1516 self.emit(Op::Pop);
1519 self.emit(Op::LoadLocal(f_slot));
1520 if closure_arity == 1 {
1521 self.emit(Op::LoadLocal(val_slot));
1522 self.emit(Op::GetVariantArg(0));
1523 }
1524 let nid = self.pool.node_id("n_hoe");
1525 self.emit(Op::CallClosure { arity: closure_arity, node_id_idx: nid });
1526
1527 let j_end = self.code.len();
1528 self.emit(Op::Jump(0));
1529
1530 let skip_target = self.code.len() as i32;
1532 if let Op::JumpIfNot(off) = &mut self.code[j_skip] {
1533 *off = skip_target - (j_skip as i32 + 1);
1534 }
1535
1536 let end_target = self.code.len() as i32;
1537 if let Op::Jump(off) = &mut self.code[j_end] {
1538 *off = end_target - (j_end as i32 + 1);
1539 }
1540 }
1541
1542 fn emit_option_unwrap_or_else(&mut self, args: &[a::CExpr]) {
1546 let some_idx = self.pool.variant("Some");
1547
1548 self.compile_expr(&args[0], false);
1550 let val_slot = self.alloc_local("__uoe_val");
1551 self.emit(Op::StoreLocal(val_slot));
1552
1553 self.compile_expr(&args[1], false);
1554 let f_slot = self.alloc_local("__uoe_f");
1555 self.emit(Op::StoreLocal(f_slot));
1556
1557 self.emit(Op::LoadLocal(val_slot));
1563 self.emit(Op::Dup);
1564 self.emit(Op::TestVariant(some_idx));
1565 let j_none = self.code.len();
1566 self.emit(Op::JumpIfNot(0));
1567
1568 self.emit(Op::GetVariantArg(0));
1570 let j_end = self.code.len();
1571 self.emit(Op::Jump(0));
1572
1573 let none_target = self.code.len() as i32;
1575 if let Op::JumpIfNot(off) = &mut self.code[j_none] {
1576 *off = none_target - (j_none as i32 + 1);
1577 }
1578 self.emit(Op::Pop);
1579 self.emit(Op::LoadLocal(f_slot));
1580 let nid = self.pool.node_id("n_uoe");
1581 self.emit(Op::CallClosure { arity: 0, node_id_idx: nid });
1582
1583 let end_target = self.code.len() as i32;
1585 if let Op::Jump(off) = &mut self.code[j_end] {
1586 *off = end_target - (j_end as i32 + 1);
1587 }
1588 }
1589
1590 fn install_trampoline(&mut self, name: &str, arity: u16, locals_count: u16, code: Vec<Op>) -> u32 {
1607 let fn_id = self.next_fn_id.len() as u32;
1608 let body_hash = crate::program::compute_body_hash(arity, locals_count, &code);
1609 self.next_fn_id.push(Function {
1610 name: name.into(),
1611 arity,
1612 locals_count,
1613 code,
1614 effects: Vec::new(),
1615 body_hash,
1616 refinements: Vec::new(),
1619 });
1620 fn_id
1621 }
1622
1623 fn emit_flow_sequential(&mut self, args: &[a::CExpr]) {
1625 self.compile_expr(&args[0], false);
1627 self.compile_expr(&args[1], false);
1628 let nid = self.pool.node_id("n_flow_sequential");
1629 let code = vec![
1630 Op::LoadLocal(0), Op::LoadLocal(2), Op::CallClosure { arity: 1, node_id_idx: nid }, Op::StoreLocal(3), Op::LoadLocal(1), Op::LoadLocal(3), Op::CallClosure { arity: 1, node_id_idx: nid }, Op::Return,
1640 ];
1641 let fn_id = self.install_trampoline("__flow_sequential", 3, 4, code);
1642 self.emit(Op::MakeClosure { fn_id, capture_count: 2 });
1643 }
1644
1645 fn emit_flow_parallel(&mut self, args: &[a::CExpr]) {
1653 self.compile_expr(&args[0], false);
1655 self.compile_expr(&args[1], false);
1656 let nid = self.pool.node_id("n_flow_parallel");
1657 let code = vec![
1658 Op::LoadLocal(0), Op::CallClosure { arity: 0, node_id_idx: nid }, Op::LoadLocal(1), Op::CallClosure { arity: 0, node_id_idx: nid }, Op::MakeTuple(2), Op::Return,
1665 ];
1666 let fn_id = self.install_trampoline("__flow_parallel", 2, 2, code);
1667 self.emit(Op::MakeClosure { fn_id, capture_count: 2 });
1668 }
1669
1670 fn emit_flow_parallel_list(&mut self, args: &[a::CExpr]) {
1677 self.compile_expr(&args[0], false);
1679 let xs = self.alloc_local("__fpl_xs");
1680 self.emit(Op::StoreLocal(xs));
1681
1682 self.emit(Op::MakeList(0));
1684 let out = self.alloc_local("__fpl_out");
1685 self.emit(Op::StoreLocal(out));
1686
1687 let zero = self.pool.int(0);
1689 self.emit(Op::PushConst(zero));
1690 let i = self.alloc_local("__fpl_i");
1691 self.emit(Op::StoreLocal(i));
1692
1693 let loop_top = self.code.len();
1695 self.emit(Op::LoadLocal(i));
1696 self.emit(Op::LoadLocal(xs));
1697 self.emit(Op::GetListLen);
1698 self.emit(Op::NumLt);
1699 let j_exit = self.code.len();
1700 self.emit(Op::JumpIfNot(0));
1701
1702 let nid = self.pool.node_id("n_flow_parallel_list");
1704 self.emit(Op::LoadLocal(out));
1705 self.emit(Op::LoadLocal(xs));
1706 self.emit(Op::LoadLocal(i));
1707 self.emit(Op::GetListElemDyn);
1708 self.emit(Op::CallClosure { arity: 0, node_id_idx: nid });
1709 self.emit(Op::ListAppend);
1710 self.emit(Op::StoreLocal(out));
1711
1712 self.emit(Op::LoadLocal(i));
1714 let one = self.pool.int(1);
1715 self.emit(Op::PushConst(one));
1716 self.emit(Op::NumAdd);
1717 self.emit(Op::StoreLocal(i));
1718
1719 let jump_back = self.code.len();
1721 let back = (loop_top as i32) - (jump_back as i32 + 1);
1722 self.emit(Op::Jump(back));
1723
1724 let exit_target = self.code.len() as i32;
1726 if let Op::JumpIfNot(off) = &mut self.code[j_exit] {
1727 *off = exit_target - (j_exit as i32 + 1);
1728 }
1729 self.emit(Op::LoadLocal(out));
1730 }
1731
1732 fn emit_flow_branch(&mut self, args: &[a::CExpr]) {
1734 self.compile_expr(&args[0], false);
1735 self.compile_expr(&args[1], false);
1736 self.compile_expr(&args[2], false);
1737 let nid = self.pool.node_id("n_flow_branch");
1738 let mut code = vec![
1739 Op::LoadLocal(0), Op::LoadLocal(3), Op::CallClosure { arity: 1, node_id_idx: nid }, ];
1744 let j_false = code.len();
1745 code.push(Op::JumpIfNot(0)); code.push(Op::LoadLocal(1));
1748 code.push(Op::LoadLocal(3));
1749 code.push(Op::CallClosure { arity: 1, node_id_idx: nid });
1750 code.push(Op::Return);
1751 let false_target = code.len() as i32;
1753 if let Op::JumpIfNot(off) = &mut code[j_false] {
1754 *off = false_target - (j_false as i32 + 1);
1755 }
1756 code.push(Op::LoadLocal(2));
1757 code.push(Op::LoadLocal(3));
1758 code.push(Op::CallClosure { arity: 1, node_id_idx: nid });
1759 code.push(Op::Return);
1760
1761 let fn_id = self.install_trampoline("__flow_branch", 4, 4, code);
1762 self.emit(Op::MakeClosure { fn_id, capture_count: 3 });
1763 }
1764
1765 fn emit_flow_retry(&mut self, args: &[a::CExpr]) {
1769 self.compile_expr(&args[0], false);
1770 self.compile_expr(&args[1], false);
1771 let call_nid = self.pool.node_id("n_flow_retry");
1772 let ok_idx = self.pool.variant("Ok");
1773 let zero_const = self.pool.int(0);
1774 let one_const = self.pool.int(1);
1775 let mut code = vec![
1777 Op::PushConst(zero_const),
1779 Op::StoreLocal(3),
1780 ];
1781 let loop_top = code.len() as i32;
1783 code.push(Op::LoadLocal(3));
1784 code.push(Op::LoadLocal(1));
1785 code.push(Op::NumLt);
1786 let j_done = code.len();
1787 code.push(Op::JumpIfNot(0)); code.push(Op::LoadLocal(0));
1791 code.push(Op::LoadLocal(2));
1792 code.push(Op::CallClosure { arity: 1, node_id_idx: call_nid });
1793 code.push(Op::StoreLocal(4));
1794
1795 code.push(Op::LoadLocal(4));
1797 code.push(Op::TestVariant(ok_idx));
1798 let j_was_err = code.len();
1799 code.push(Op::JumpIfNot(0)); code.push(Op::LoadLocal(4));
1801 code.push(Op::Return);
1802
1803 let was_err_target = code.len() as i32;
1805 if let Op::JumpIfNot(off) = &mut code[j_was_err] {
1806 *off = was_err_target - (j_was_err as i32 + 1);
1807 }
1808 code.push(Op::LoadLocal(3));
1809 code.push(Op::PushConst(one_const));
1810 code.push(Op::NumAdd);
1811 code.push(Op::StoreLocal(3));
1812 let pc_after_jump = code.len() as i32 + 1;
1813 code.push(Op::Jump(loop_top - pc_after_jump));
1814
1815 let done_target = code.len() as i32;
1817 if let Op::JumpIfNot(off) = &mut code[j_done] {
1818 *off = done_target - (j_done as i32 + 1);
1819 }
1820 code.push(Op::LoadLocal(4));
1821 code.push(Op::Return);
1822
1823 let fn_id = self.install_trampoline("__flow_retry", 3, 5, code);
1824 self.emit(Op::MakeClosure { fn_id, capture_count: 2 });
1825 }
1826
1827 fn emit_flow_retry_with_backoff(&mut self, args: &[a::CExpr]) {
1835 self.compile_expr(&args[0], false);
1838 self.compile_expr(&args[1], false);
1839 self.compile_expr(&args[2], false);
1840 let call_nid = self.pool.node_id("n_flow_retry_backoff");
1841 let sleep_nid = self.pool.node_id("n_flow_retry_backoff_sleep");
1842 let kind_idx = self.pool.str("time");
1843 let op_idx = self.pool.str("sleep_ms");
1844 let ok_idx = self.pool.variant("Ok");
1845 let zero_const = self.pool.int(0);
1846 let one_const = self.pool.int(1);
1847 let two_const = self.pool.int(2);
1848 let mut code = vec![
1853 Op::LoadLocal(2),
1855 Op::StoreLocal(6),
1856 Op::PushConst(zero_const),
1858 Op::StoreLocal(4),
1859 ];
1860
1861 let loop_top = code.len() as i32;
1862 code.push(Op::LoadLocal(4));
1864 code.push(Op::LoadLocal(1));
1865 code.push(Op::NumLt);
1866 let j_done = code.len();
1867 code.push(Op::JumpIfNot(0)); code.push(Op::PushConst(zero_const));
1871 code.push(Op::LoadLocal(4));
1872 code.push(Op::NumLt); let j_no_sleep = code.len();
1874 code.push(Op::JumpIfNot(0)); code.push(Op::LoadLocal(6)); code.push(Op::EffectCall {
1878 kind_idx, op_idx, arity: 1, node_id_idx: sleep_nid,
1879 });
1880 code.push(Op::Pop); code.push(Op::LoadLocal(6));
1883 code.push(Op::PushConst(two_const));
1884 code.push(Op::NumMul);
1885 code.push(Op::StoreLocal(6));
1886 let after_sleep = code.len() as i32;
1888 if let Op::JumpIfNot(off) = &mut code[j_no_sleep] {
1889 *off = after_sleep - (j_no_sleep as i32 + 1);
1890 }
1891
1892 code.push(Op::LoadLocal(0));
1894 code.push(Op::LoadLocal(3));
1895 code.push(Op::CallClosure { arity: 1, node_id_idx: call_nid });
1896 code.push(Op::StoreLocal(5));
1897
1898 code.push(Op::LoadLocal(5));
1900 code.push(Op::TestVariant(ok_idx));
1901 let j_was_err = code.len();
1902 code.push(Op::JumpIfNot(0)); code.push(Op::LoadLocal(5));
1904 code.push(Op::Return);
1905
1906 let was_err_target = code.len() as i32;
1908 if let Op::JumpIfNot(off) = &mut code[j_was_err] {
1909 *off = was_err_target - (j_was_err as i32 + 1);
1910 }
1911 code.push(Op::LoadLocal(4));
1912 code.push(Op::PushConst(one_const));
1913 code.push(Op::NumAdd);
1914 code.push(Op::StoreLocal(4));
1915 let pc_after_jump = code.len() as i32 + 1;
1916 code.push(Op::Jump(loop_top - pc_after_jump));
1917
1918 let done_target = code.len() as i32;
1920 if let Op::JumpIfNot(off) = &mut code[j_done] {
1921 *off = done_target - (j_done as i32 + 1);
1922 }
1923 code.push(Op::LoadLocal(5));
1924 code.push(Op::Return);
1925
1926 let fn_id = self.install_trampoline("__flow_retry_backoff", 4, 7, code);
1927 self.emit(Op::MakeClosure { fn_id, capture_count: 3 });
1928 }
1929}
1930
1931fn free_vars(e: &a::CExpr, bound: &mut std::collections::HashSet<String>, out: &mut Vec<String>) {
1936 match e {
1937 a::CExpr::Literal { .. } => {}
1938 a::CExpr::Var { name } => {
1939 if !bound.contains(name) && !out.contains(name) {
1940 out.push(name.clone());
1941 }
1942 }
1943 a::CExpr::Call { callee, args } => {
1944 free_vars(callee, bound, out);
1945 for a in args { free_vars(a, bound, out); }
1946 }
1947 a::CExpr::Let { name, value, body, .. } => {
1948 free_vars(value, bound, out);
1949 let was_bound = bound.contains(name);
1950 bound.insert(name.clone());
1951 free_vars(body, bound, out);
1952 if !was_bound { bound.remove(name); }
1953 }
1954 a::CExpr::Match { scrutinee, arms } => {
1955 free_vars(scrutinee, bound, out);
1956 for arm in arms {
1957 let mut local_bound = bound.clone();
1958 pattern_binders(&arm.pattern, &mut local_bound);
1959 free_vars(&arm.body, &mut local_bound, out);
1960 }
1961 }
1962 a::CExpr::Block { statements, result } => {
1963 let mut local_bound = bound.clone();
1964 for s in statements { free_vars(s, &mut local_bound, out); }
1965 free_vars(result, &mut local_bound, out);
1966 }
1967 a::CExpr::Constructor { args, .. } => {
1968 for a in args { free_vars(a, bound, out); }
1969 }
1970 a::CExpr::RecordLit { fields } => {
1971 for f in fields { free_vars(&f.value, bound, out); }
1972 }
1973 a::CExpr::TupleLit { items } | a::CExpr::ListLit { items } => {
1974 for it in items { free_vars(it, bound, out); }
1975 }
1976 a::CExpr::FieldAccess { value, .. } => free_vars(value, bound, out),
1977 a::CExpr::Lambda { params, body, .. } => {
1978 let mut inner = bound.clone();
1979 for p in params { inner.insert(p.name.clone()); }
1980 free_vars(body, &mut inner, out);
1981 }
1982 a::CExpr::BinOp { lhs, rhs, .. } => {
1983 free_vars(lhs, bound, out);
1984 free_vars(rhs, bound, out);
1985 }
1986 a::CExpr::UnaryOp { expr, .. } => free_vars(expr, bound, out),
1987 a::CExpr::Return { value } => free_vars(value, bound, out),
1988 }
1989}
1990
1991fn pattern_binders(p: &a::Pattern, bound: &mut std::collections::HashSet<String>) {
1992 match p {
1993 a::Pattern::PWild | a::Pattern::PLiteral { .. } => {}
1994 a::Pattern::PVar { name } => { bound.insert(name.clone()); }
1995 a::Pattern::PConstructor { args, .. } => {
1996 for a in args { pattern_binders(a, bound); }
1997 }
1998 a::Pattern::PRecord { fields } => {
1999 for f in fields { pattern_binders(&f.pattern, bound); }
2000 }
2001 a::Pattern::PTuple { items } => {
2002 for it in items { pattern_binders(it, bound); }
2003 }
2004 }
2005}