1use pepl_types::ast::*;
8use wasm_encoder::{BlockType, Function, Instruction, ValType};
9
10use crate::compiler::FuncContext;
11use crate::error::CodegenResult;
12use crate::gas;
13use crate::runtime::*;
14use crate::stmt::emit_stmts;
15use crate::types::*;
16
17pub fn emit_expr(expr: &Expr, ctx: &mut FuncContext, f: &mut Function) -> CodegenResult<()> {
19 match &expr.kind {
20 ExprKind::NumberLit(n) => emit_number_lit(*n, ctx, f),
22 ExprKind::StringLit(s) => emit_string_lit(s, ctx, f),
23 ExprKind::BoolLit(b) => emit_bool_lit(*b, f),
24 ExprKind::NilLit => emit_nil_lit(f),
25 ExprKind::ListLit(elems) => emit_list_lit(elems, ctx, f),
26 ExprKind::RecordLit(entries) => emit_record_lit(entries, ctx, f),
27 ExprKind::StringInterpolation(parts) => emit_string_interpolation(parts, ctx, f),
28
29 ExprKind::Identifier(name) => emit_identifier(name, ctx, f),
31
32 ExprKind::Call { name, args } => emit_call(&name.name, args, ctx, f),
34 ExprKind::QualifiedCall {
35 module,
36 function,
37 args,
38 } => emit_qualified_call(&module.name, &function.name, args, ctx, f),
39 ExprKind::FieldAccess { object, field } => {
40 emit_field_access(object, &field.name, ctx, f)
41 }
42 ExprKind::MethodCall {
43 object,
44 method,
45 args,
46 } => emit_method_call(object, &method.name, args, ctx, f),
47
48 ExprKind::Binary { left, op, right } => emit_binary(left, *op, right, ctx, f),
50 ExprKind::Unary { op, operand } => emit_unary(*op, operand, ctx, f),
51 ExprKind::ResultUnwrap(inner) => emit_result_unwrap(inner, ctx, f),
52 ExprKind::NilCoalesce { left, right } => emit_nil_coalesce(left, right, ctx, f),
53
54 ExprKind::If(if_expr) => emit_if_expr(if_expr, ctx, f),
56 ExprKind::For(for_expr) => emit_for_expr(for_expr, ctx, f),
57 ExprKind::Match(match_expr) => emit_match_expr(match_expr, ctx, f),
58
59 ExprKind::Lambda(lambda) => {
61 emit_lambda(lambda, ctx, f)
62 }
63
64 ExprKind::Paren(inner) => emit_expr(inner, ctx, f),
66 }
67}
68
69fn emit_number_lit(n: f64, _ctx: &mut FuncContext, f: &mut Function) -> CodegenResult<()> {
74 f.instruction(&Instruction::I32Const(VALUE_SIZE as i32));
76 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
77 let local = _ctx.alloc_local(ValType::I32);
79 f.instruction(&Instruction::LocalTee(local));
80 f.instruction(&Instruction::I32Const(TAG_NUMBER));
81 f.instruction(&Instruction::I32Store(memarg(0, 2)));
82 f.instruction(&Instruction::LocalGet(local));
83 f.instruction(&Instruction::F64Const(n));
84 f.instruction(&Instruction::F64Store(memarg(4, 3)));
85 f.instruction(&Instruction::LocalGet(local));
86 Ok(())
87}
88
89fn emit_string_lit(s: &str, ctx: &mut FuncContext, f: &mut Function) -> CodegenResult<()> {
90 let (ptr, len) = ctx.intern_string(s);
91 f.instruction(&Instruction::I32Const(ptr as i32));
92 f.instruction(&Instruction::I32Const(len as i32));
93 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_STRING)));
94 Ok(())
95}
96
97fn emit_bool_lit(b: bool, f: &mut Function) -> CodegenResult<()> {
98 f.instruction(&Instruction::I32Const(if b { 1 } else { 0 }));
99 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_BOOL)));
100 Ok(())
101}
102
103fn emit_nil_lit(f: &mut Function) -> CodegenResult<()> {
104 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
105 Ok(())
106}
107
108fn emit_lambda(
109 lambda: &LambdaExpr,
110 ctx: &mut FuncContext,
111 f: &mut Function,
112) -> CodegenResult<()> {
113 let param_names: Vec<String> = lambda.params.iter().map(|p| p.name.name.clone()).collect();
116 let mut captured: Vec<String> = ctx
117 .local_names
118 .keys()
119 .filter(|name| !param_names.contains(name))
120 .cloned()
121 .collect();
122 captured.sort(); let env_local = ctx.alloc_local(ValType::I32);
126 if captured.is_empty() {
127 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
129 f.instruction(&Instruction::LocalSet(env_local));
130 } else {
131 let cap_entries = ctx.alloc_local(ValType::I32);
133 f.instruction(&Instruction::I32Const((captured.len() * 12) as i32));
134 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
135 f.instruction(&Instruction::LocalSet(cap_entries));
136
137 for (ci, cap_name) in captured.iter().enumerate() {
138 let (cap_key_ptr, cap_key_len) = ctx.intern_string(cap_name);
139 let cap_val_local = ctx.get_local(cap_name).unwrap_or(0);
140 let base = (ci * 12) as u64;
141 f.instruction(&Instruction::LocalGet(cap_entries));
143 f.instruction(&Instruction::I32Const(cap_key_ptr as i32));
144 f.instruction(&Instruction::I32Store(memarg(base, 2)));
145 f.instruction(&Instruction::LocalGet(cap_entries));
147 f.instruction(&Instruction::I32Const(cap_key_len as i32));
148 f.instruction(&Instruction::I32Store(memarg(base + 4, 2)));
149 f.instruction(&Instruction::LocalGet(cap_entries));
151 f.instruction(&Instruction::LocalGet(cap_val_local));
152 f.instruction(&Instruction::I32Store(memarg(base + 8, 2)));
153 }
154
155 f.instruction(&Instruction::LocalGet(cap_entries));
156 f.instruction(&Instruction::I32Const(captured.len() as i32));
157 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD)));
158 f.instruction(&Instruction::LocalSet(env_local));
159 }
160
161 let table_idx = ctx.register_lambda(
163 lambda.params.clone(),
164 lambda.body.clone(),
165 captured,
166 );
167
168 let lambda_val = ctx.alloc_local(ValType::I32);
170 f.instruction(&Instruction::I32Const(VALUE_SIZE as i32));
171 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
172 f.instruction(&Instruction::LocalSet(lambda_val));
173 f.instruction(&Instruction::LocalGet(lambda_val));
175 f.instruction(&Instruction::I32Const(TAG_LAMBDA));
176 f.instruction(&Instruction::I32Store(memarg(0, 2)));
177 f.instruction(&Instruction::LocalGet(lambda_val));
179 f.instruction(&Instruction::I32Const(table_idx as i32));
180 f.instruction(&Instruction::I32Store(memarg(4, 2)));
181 f.instruction(&Instruction::LocalGet(lambda_val));
183 f.instruction(&Instruction::LocalGet(env_local));
184 f.instruction(&Instruction::I32Store(memarg(8, 2)));
185 f.instruction(&Instruction::LocalGet(lambda_val));
187 Ok(())
188}
189
190fn emit_list_lit(
191 elems: &[Expr],
192 ctx: &mut FuncContext,
193 f: &mut Function,
194) -> CodegenResult<()> {
195 let count = elems.len() as i32;
196 if count == 0 {
197 f.instruction(&Instruction::I32Const(0));
199 f.instruction(&Instruction::I32Const(0));
200 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST)));
201 return Ok(());
202 }
203
204 let arr_local = ctx.alloc_local(ValType::I32);
206 f.instruction(&Instruction::I32Const(count * 4));
207 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
208 f.instruction(&Instruction::LocalSet(arr_local));
209
210 for (i, elem) in elems.iter().enumerate() {
212 let elem_local = ctx.alloc_local(ValType::I32);
213 emit_expr(elem, ctx, f)?;
214 f.instruction(&Instruction::LocalSet(elem_local));
215 f.instruction(&Instruction::LocalGet(arr_local));
217 f.instruction(&Instruction::LocalGet(elem_local));
218 f.instruction(&Instruction::I32Store(memarg(i as u64 * 4, 2)));
219 }
220
221 f.instruction(&Instruction::LocalGet(arr_local));
223 f.instruction(&Instruction::I32Const(count));
224 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST)));
225 Ok(())
226}
227
228fn emit_record_lit(
229 entries: &[RecordEntry],
230 ctx: &mut FuncContext,
231 f: &mut Function,
232) -> CodegenResult<()> {
233 let explicit_count = entries
234 .iter()
235 .filter(|e| matches!(e, RecordEntry::Field { .. }))
236 .count();
237
238 let has_spread = entries
239 .iter()
240 .any(|e| matches!(e, RecordEntry::Spread(_)));
241
242 if !has_spread {
243 if explicit_count == 0 {
245 f.instruction(&Instruction::I32Const(0));
246 f.instruction(&Instruction::I32Const(0));
247 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD)));
248 return Ok(());
249 }
250
251 let entries_local = ctx.alloc_local(ValType::I32);
252 f.instruction(&Instruction::I32Const((explicit_count * 12) as i32));
253 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
254 f.instruction(&Instruction::LocalSet(entries_local));
255
256 let mut idx = 0usize;
257 for entry in entries {
258 if let RecordEntry::Field { name, value } = entry {
259 let (key_ptr, key_len) = ctx.intern_string(&name.name);
260 let val_local = ctx.alloc_local(ValType::I32);
261 emit_expr(value, ctx, f)?;
262 f.instruction(&Instruction::LocalSet(val_local));
263
264 let base_offset = (idx * 12) as u64;
265 f.instruction(&Instruction::LocalGet(entries_local));
266 f.instruction(&Instruction::I32Const(key_ptr as i32));
267 f.instruction(&Instruction::I32Store(memarg(base_offset, 2)));
268 f.instruction(&Instruction::LocalGet(entries_local));
269 f.instruction(&Instruction::I32Const(key_len as i32));
270 f.instruction(&Instruction::I32Store(memarg(base_offset + 4, 2)));
271 f.instruction(&Instruction::LocalGet(entries_local));
272 f.instruction(&Instruction::LocalGet(val_local));
273 f.instruction(&Instruction::I32Store(memarg(base_offset + 8, 2)));
274 idx += 1;
275 }
276 }
277
278 f.instruction(&Instruction::LocalGet(entries_local));
279 f.instruction(&Instruction::I32Const(explicit_count as i32));
280 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD)));
281 return Ok(());
282 }
283
284 let new_entries = ctx.alloc_local(ValType::I32);
289 let final_count = ctx.alloc_local(ValType::I32);
290
291 let spread_expr = entries
293 .iter()
294 .find_map(|e| match e {
295 RecordEntry::Spread(expr) => Some(expr),
296 _ => None,
297 })
298 .unwrap();
299
300 let spread_local = ctx.alloc_local(ValType::I32);
301 emit_expr(spread_expr, ctx, f)?;
302 f.instruction(&Instruction::LocalSet(spread_local));
303
304 let spread_entries_ptr = ctx.alloc_local(ValType::I32);
306 let spread_count_local = ctx.alloc_local(ValType::I32);
307 f.instruction(&Instruction::LocalGet(spread_local));
308 f.instruction(&Instruction::I32Load(memarg(4, 2)));
309 f.instruction(&Instruction::LocalSet(spread_entries_ptr));
310 f.instruction(&Instruction::LocalGet(spread_local));
311 f.instruction(&Instruction::I32Load(memarg(8, 2)));
312 f.instruction(&Instruction::LocalSet(spread_count_local));
313
314 f.instruction(&Instruction::LocalGet(spread_count_local));
316 f.instruction(&Instruction::I32Const(explicit_count as i32));
317 f.instruction(&Instruction::I32Add);
318 f.instruction(&Instruction::I32Const(12));
319 f.instruction(&Instruction::I32Mul);
320 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
321 f.instruction(&Instruction::LocalSet(new_entries));
322
323 let copy_i = ctx.alloc_local(ValType::I32);
325 let src_entry = ctx.alloc_local(ValType::I32);
326 let dst_entry = ctx.alloc_local(ValType::I32);
327 f.instruction(&Instruction::I32Const(0));
328 f.instruction(&Instruction::LocalSet(copy_i));
329
330 f.instruction(&Instruction::Block(BlockType::Empty));
331 f.instruction(&Instruction::Loop(BlockType::Empty));
332 f.instruction(&Instruction::LocalGet(copy_i));
333 f.instruction(&Instruction::LocalGet(spread_count_local));
334 f.instruction(&Instruction::I32GeU);
335 f.instruction(&Instruction::BrIf(1));
336
337 f.instruction(&Instruction::LocalGet(spread_entries_ptr));
338 f.instruction(&Instruction::LocalGet(copy_i));
339 f.instruction(&Instruction::I32Const(12));
340 f.instruction(&Instruction::I32Mul);
341 f.instruction(&Instruction::I32Add);
342 f.instruction(&Instruction::LocalSet(src_entry));
343 f.instruction(&Instruction::LocalGet(new_entries));
344 f.instruction(&Instruction::LocalGet(copy_i));
345 f.instruction(&Instruction::I32Const(12));
346 f.instruction(&Instruction::I32Mul);
347 f.instruction(&Instruction::I32Add);
348 f.instruction(&Instruction::LocalSet(dst_entry));
349
350 f.instruction(&Instruction::LocalGet(dst_entry));
352 f.instruction(&Instruction::LocalGet(src_entry));
353 f.instruction(&Instruction::I32Load(memarg(0, 2)));
354 f.instruction(&Instruction::I32Store(memarg(0, 2)));
355 f.instruction(&Instruction::LocalGet(dst_entry));
356 f.instruction(&Instruction::LocalGet(src_entry));
357 f.instruction(&Instruction::I32Load(memarg(4, 2)));
358 f.instruction(&Instruction::I32Store(memarg(4, 2)));
359 f.instruction(&Instruction::LocalGet(dst_entry));
360 f.instruction(&Instruction::LocalGet(src_entry));
361 f.instruction(&Instruction::I32Load(memarg(8, 2)));
362 f.instruction(&Instruction::I32Store(memarg(8, 2)));
363
364 f.instruction(&Instruction::LocalGet(copy_i));
365 f.instruction(&Instruction::I32Const(1));
366 f.instruction(&Instruction::I32Add);
367 f.instruction(&Instruction::LocalSet(copy_i));
368 f.instruction(&Instruction::Br(0));
369 f.instruction(&Instruction::End); f.instruction(&Instruction::End); f.instruction(&Instruction::LocalGet(spread_count_local));
374 f.instruction(&Instruction::LocalSet(final_count));
375
376 for entry in entries {
378 if let RecordEntry::Field { name, value } = entry {
379 let (key_ptr, key_len) = ctx.intern_string(&name.name);
380 let val_local = ctx.alloc_local(ValType::I32);
381 emit_expr(value, ctx, f)?;
382 f.instruction(&Instruction::LocalSet(val_local));
383
384 let scan_i = ctx.alloc_local(ValType::I32);
385 let found = ctx.alloc_local(ValType::I32);
386 let scan_entry = ctx.alloc_local(ValType::I32);
387 f.instruction(&Instruction::I32Const(0));
388 f.instruction(&Instruction::LocalSet(scan_i));
389 f.instruction(&Instruction::I32Const(0));
390 f.instruction(&Instruction::LocalSet(found));
391
392 f.instruction(&Instruction::Block(BlockType::Empty));
393 f.instruction(&Instruction::Loop(BlockType::Empty));
394 f.instruction(&Instruction::LocalGet(scan_i));
395 f.instruction(&Instruction::LocalGet(final_count));
396 f.instruction(&Instruction::I32GeU);
397 f.instruction(&Instruction::BrIf(1));
398
399 f.instruction(&Instruction::LocalGet(new_entries));
400 f.instruction(&Instruction::LocalGet(scan_i));
401 f.instruction(&Instruction::I32Const(12));
402 f.instruction(&Instruction::I32Mul);
403 f.instruction(&Instruction::I32Add);
404 f.instruction(&Instruction::LocalSet(scan_entry));
405
406 f.instruction(&Instruction::LocalGet(scan_entry));
408 f.instruction(&Instruction::I32Load(memarg(4, 2)));
409 f.instruction(&Instruction::I32Const(key_len as i32));
410 f.instruction(&Instruction::I32Eq);
411 f.instruction(&Instruction::If(BlockType::Empty));
412 f.instruction(&Instruction::LocalGet(scan_entry));
413 f.instruction(&Instruction::I32Load(memarg(0, 2)));
414 f.instruction(&Instruction::I32Const(key_ptr as i32));
415 f.instruction(&Instruction::I32Const(key_len as i32));
416 f.instruction(&Instruction::Call(rt_func_idx(RT_MEMCMP)));
417 f.instruction(&Instruction::If(BlockType::Empty));
418 f.instruction(&Instruction::LocalGet(scan_entry));
420 f.instruction(&Instruction::LocalGet(val_local));
421 f.instruction(&Instruction::I32Store(memarg(8, 2)));
422 f.instruction(&Instruction::I32Const(1));
423 f.instruction(&Instruction::LocalSet(found));
424 f.instruction(&Instruction::Br(3)); f.instruction(&Instruction::End); f.instruction(&Instruction::End); f.instruction(&Instruction::LocalGet(scan_i));
429 f.instruction(&Instruction::I32Const(1));
430 f.instruction(&Instruction::I32Add);
431 f.instruction(&Instruction::LocalSet(scan_i));
432 f.instruction(&Instruction::Br(0));
433 f.instruction(&Instruction::End); f.instruction(&Instruction::End); f.instruction(&Instruction::LocalGet(found));
438 f.instruction(&Instruction::I32Eqz);
439 f.instruction(&Instruction::If(BlockType::Empty));
440 let append_entry = ctx.alloc_local(ValType::I32);
441 f.instruction(&Instruction::LocalGet(new_entries));
442 f.instruction(&Instruction::LocalGet(final_count));
443 f.instruction(&Instruction::I32Const(12));
444 f.instruction(&Instruction::I32Mul);
445 f.instruction(&Instruction::I32Add);
446 f.instruction(&Instruction::LocalSet(append_entry));
447 f.instruction(&Instruction::LocalGet(append_entry));
448 f.instruction(&Instruction::I32Const(key_ptr as i32));
449 f.instruction(&Instruction::I32Store(memarg(0, 2)));
450 f.instruction(&Instruction::LocalGet(append_entry));
451 f.instruction(&Instruction::I32Const(key_len as i32));
452 f.instruction(&Instruction::I32Store(memarg(4, 2)));
453 f.instruction(&Instruction::LocalGet(append_entry));
454 f.instruction(&Instruction::LocalGet(val_local));
455 f.instruction(&Instruction::I32Store(memarg(8, 2)));
456 f.instruction(&Instruction::LocalGet(final_count));
457 f.instruction(&Instruction::I32Const(1));
458 f.instruction(&Instruction::I32Add);
459 f.instruction(&Instruction::LocalSet(final_count));
460 f.instruction(&Instruction::End); }
462 }
463
464 f.instruction(&Instruction::LocalGet(new_entries));
466 f.instruction(&Instruction::LocalGet(final_count));
467 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD)));
468 Ok(())
469}
470
471fn emit_string_interpolation(
472 parts: &[StringPart],
473 ctx: &mut FuncContext,
474 f: &mut Function,
475) -> CodegenResult<()> {
476 let (empty_ptr, empty_len) = ctx.intern_string("");
479 f.instruction(&Instruction::I32Const(empty_ptr as i32));
480 f.instruction(&Instruction::I32Const(empty_len as i32));
481 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_STRING)));
482
483 for part in parts {
484 match part {
485 StringPart::Literal(s) => {
486 if !s.is_empty() {
487 emit_string_lit(s, ctx, f)?;
488 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_STRING_CONCAT)));
489 }
490 }
491 StringPart::Expr(expr) => {
492 emit_expr(expr, ctx, f)?;
493 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_TO_STRING)));
494 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_STRING_CONCAT)));
495 }
496 }
497 }
498 Ok(())
499}
500
501fn emit_identifier(name: &str, ctx: &mut FuncContext, f: &mut Function) -> CodegenResult<()> {
506 if let Some(local_idx) = ctx.get_local(name) {
508 f.instruction(&Instruction::LocalGet(local_idx));
509 return Ok(());
510 }
511
512 if ctx.is_state_field(name) {
514 let (key_ptr, key_len) = ctx.intern_string(name);
515 f.instruction(&Instruction::GlobalGet(GLOBAL_STATE_PTR));
516 f.instruction(&Instruction::I32Const(key_ptr as i32));
517 f.instruction(&Instruction::I32Const(key_len as i32));
518 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD_GET)));
519 return Ok(());
520 }
521
522 if let Some(action_id) = ctx.get_action_id(name) {
524 f.instruction(&Instruction::I32Const(action_id as i32));
525 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_ACTION_REF)));
526 return Ok(());
527 }
528
529 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
531 Ok(())
532}
533
534fn emit_call(
535 name: &str,
536 args: &[Expr],
537 ctx: &mut FuncContext,
538 f: &mut Function,
539) -> CodegenResult<()> {
540 gas::emit_gas_tick(f, ctx.data.gas_exhausted_ptr, ctx.data.gas_exhausted_len);
542
543 if let Some(func_idx) = ctx.get_function(name) {
545 for arg in args {
547 emit_expr(arg, ctx, f)?;
548 }
549 f.instruction(&Instruction::Call(func_idx));
550 return Ok(());
551 }
552
553 for arg in args {
555 emit_expr(arg, ctx, f)?;
556 f.instruction(&Instruction::Drop);
557 }
558 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
559 Ok(())
560}
561
562fn emit_qualified_call(
563 module: &str,
564 function: &str,
565 args: &[Expr],
566 ctx: &mut FuncContext,
567 f: &mut Function,
568) -> CodegenResult<()> {
569 gas::emit_gas_tick(f, ctx.data.gas_exhausted_ptr, ctx.data.gas_exhausted_len);
570
571 let args_local = ctx.alloc_local(ValType::I32);
577 if args.is_empty() {
578 f.instruction(&Instruction::I32Const(0));
579 f.instruction(&Instruction::I32Const(0));
580 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST)));
581 } else {
582 let arr_local = ctx.alloc_local(ValType::I32);
584 let count = args.len() as i32;
585 f.instruction(&Instruction::I32Const(count * 4));
586 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
587 f.instruction(&Instruction::LocalSet(arr_local));
588 for (i, arg) in args.iter().enumerate() {
589 let tmp = ctx.alloc_local(ValType::I32);
590 emit_expr(arg, ctx, f)?;
591 f.instruction(&Instruction::LocalSet(tmp));
592 f.instruction(&Instruction::LocalGet(arr_local));
593 f.instruction(&Instruction::LocalGet(tmp));
594 f.instruction(&Instruction::I32Store(memarg(i as u64 * 4, 2)));
595 }
596 f.instruction(&Instruction::LocalGet(arr_local));
597 f.instruction(&Instruction::I32Const(count));
598 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST)));
599 }
600 f.instruction(&Instruction::LocalSet(args_local));
601
602 let (mod_id, fn_id) = ctx.resolve_qualified_call(module, function);
604
605 f.instruction(&Instruction::I32Const(mod_id as i32));
607 f.instruction(&Instruction::I32Const(fn_id as i32));
608 f.instruction(&Instruction::LocalGet(args_local));
609 f.instruction(&Instruction::Call(IMPORT_HOST_CALL));
610
611 Ok(())
612}
613
614fn emit_field_access(
615 object: &Expr,
616 field: &str,
617 ctx: &mut FuncContext,
618 f: &mut Function,
619) -> CodegenResult<()> {
620 emit_expr(object, ctx, f)?;
621 let (key_ptr, key_len) = ctx.intern_string(field);
622 f.instruction(&Instruction::I32Const(key_ptr as i32));
623 f.instruction(&Instruction::I32Const(key_len as i32));
624 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD_GET)));
625 Ok(())
626}
627
628fn emit_method_call(
629 object: &Expr,
630 method: &str,
631 args: &[Expr],
632 ctx: &mut FuncContext,
633 f: &mut Function,
634) -> CodegenResult<()> {
635 gas::emit_gas_tick(f, ctx.data.gas_exhausted_ptr, ctx.data.gas_exhausted_len);
639
640 let total_args = 1 + args.len();
641 let arr_local = ctx.alloc_local(ValType::I32);
642 let count = total_args as i32;
643
644 f.instruction(&Instruction::I32Const(count * 4));
645 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
646 f.instruction(&Instruction::LocalSet(arr_local));
647
648 let recv_local = ctx.alloc_local(ValType::I32);
650 emit_expr(object, ctx, f)?;
651 f.instruction(&Instruction::LocalSet(recv_local));
652 f.instruction(&Instruction::LocalGet(arr_local));
653 f.instruction(&Instruction::LocalGet(recv_local));
654 f.instruction(&Instruction::I32Store(memarg(0, 2)));
655
656 for (i, arg) in args.iter().enumerate() {
658 let tmp = ctx.alloc_local(ValType::I32);
659 emit_expr(arg, ctx, f)?;
660 f.instruction(&Instruction::LocalSet(tmp));
661 f.instruction(&Instruction::LocalGet(arr_local));
662 f.instruction(&Instruction::LocalGet(tmp));
663 f.instruction(&Instruction::I32Store(memarg((i as u64 + 1) * 4, 2)));
664 }
665
666 let (mod_id, fn_id) = ctx.resolve_method_call(method);
669
670 f.instruction(&Instruction::I32Const(mod_id as i32));
671 f.instruction(&Instruction::I32Const(fn_id as i32));
672 f.instruction(&Instruction::LocalGet(arr_local));
673 f.instruction(&Instruction::I32Const(count));
674 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST)));
675 f.instruction(&Instruction::Call(IMPORT_HOST_CALL));
676
677 Ok(())
678}
679
680fn emit_binary(
685 left: &Expr,
686 op: BinOp,
687 right: &Expr,
688 ctx: &mut FuncContext,
689 f: &mut Function,
690) -> CodegenResult<()> {
691 match op {
692 BinOp::And => {
693 let left_local = ctx.alloc_local(ValType::I32);
695 emit_expr(left, ctx, f)?;
696 f.instruction(&Instruction::LocalTee(left_local));
697 f.instruction(&Instruction::I32Load(memarg(4, 2)));
699 f.instruction(&Instruction::If(BlockType::Result(ValType::I32)));
700 emit_expr(right, ctx, f)?;
701 f.instruction(&Instruction::Else);
702 f.instruction(&Instruction::LocalGet(left_local));
703 f.instruction(&Instruction::End);
704 return Ok(());
705 }
706 BinOp::Or => {
707 let left_local = ctx.alloc_local(ValType::I32);
709 emit_expr(left, ctx, f)?;
710 f.instruction(&Instruction::LocalTee(left_local));
711 f.instruction(&Instruction::I32Load(memarg(4, 2)));
712 f.instruction(&Instruction::If(BlockType::Result(ValType::I32)));
713 f.instruction(&Instruction::LocalGet(left_local));
714 f.instruction(&Instruction::Else);
715 emit_expr(right, ctx, f)?;
716 f.instruction(&Instruction::End);
717 return Ok(());
718 }
719 _ => {}
720 }
721
722 let a = ctx.alloc_local(ValType::I32);
724 let b = ctx.alloc_local(ValType::I32);
725 emit_expr(left, ctx, f)?;
726 f.instruction(&Instruction::LocalSet(a));
727 emit_expr(right, ctx, f)?;
728 f.instruction(&Instruction::LocalSet(b));
729
730 match op {
731 BinOp::Add => {
732 f.instruction(&Instruction::LocalGet(a));
736 f.instruction(&Instruction::LocalGet(b));
737 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_ADD)));
738 }
739 BinOp::Sub => {
740 f.instruction(&Instruction::LocalGet(a));
741 f.instruction(&Instruction::LocalGet(b));
742 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_SUB)));
743 }
744 BinOp::Mul => {
745 f.instruction(&Instruction::LocalGet(a));
746 f.instruction(&Instruction::LocalGet(b));
747 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_MUL)));
748 }
749 BinOp::Div => {
750 f.instruction(&Instruction::LocalGet(a));
751 f.instruction(&Instruction::LocalGet(b));
752 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_DIV)));
753 }
754 BinOp::Mod => {
755 f.instruction(&Instruction::LocalGet(a));
756 f.instruction(&Instruction::LocalGet(b));
757 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_MOD)));
758 }
759 BinOp::Eq => {
760 f.instruction(&Instruction::LocalGet(a));
761 f.instruction(&Instruction::LocalGet(b));
762 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_EQ)));
763 }
764 BinOp::NotEq => {
765 f.instruction(&Instruction::LocalGet(a));
767 f.instruction(&Instruction::LocalGet(b));
768 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_EQ)));
769 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NOT)));
770 }
771 BinOp::Less => {
772 f.instruction(&Instruction::LocalGet(a));
773 f.instruction(&Instruction::LocalGet(b));
774 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LT)));
775 }
776 BinOp::LessEq => {
777 f.instruction(&Instruction::LocalGet(a));
778 f.instruction(&Instruction::LocalGet(b));
779 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LE)));
780 }
781 BinOp::Greater => {
782 f.instruction(&Instruction::LocalGet(a));
783 f.instruction(&Instruction::LocalGet(b));
784 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_GT)));
785 }
786 BinOp::GreaterEq => {
787 f.instruction(&Instruction::LocalGet(a));
788 f.instruction(&Instruction::LocalGet(b));
789 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_GE)));
790 }
791 BinOp::And | BinOp::Or => unreachable!("handled above"),
792 }
793 Ok(())
794}
795
796fn emit_unary(
797 op: UnaryOp,
798 operand: &Expr,
799 ctx: &mut FuncContext,
800 f: &mut Function,
801) -> CodegenResult<()> {
802 emit_expr(operand, ctx, f)?;
803 match op {
804 UnaryOp::Neg => {
805 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NEG)));
806 }
807 UnaryOp::Not => {
808 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NOT)));
809 }
810 }
811 Ok(())
812}
813
814fn emit_result_unwrap(
815 inner: &Expr,
816 ctx: &mut FuncContext,
817 f: &mut Function,
818) -> CodegenResult<()> {
819 emit_expr(inner, ctx, f)?;
821 let result_local = ctx.alloc_local(ValType::I32);
822 f.instruction(&Instruction::LocalSet(result_local));
823
824 let err_id = ctx.get_variant_id("Err");
826
827 f.instruction(&Instruction::LocalGet(result_local));
829 f.instruction(&Instruction::I32Load(memarg(0, 2))); f.instruction(&Instruction::I32Const(TAG_VARIANT));
831 f.instruction(&Instruction::I32Eq);
832 f.instruction(&Instruction::If(BlockType::Empty));
833 f.instruction(&Instruction::LocalGet(result_local));
835 f.instruction(&Instruction::I32Load(memarg(4, 2))); f.instruction(&Instruction::I32Const(err_id as i32));
837 f.instruction(&Instruction::I32Eq);
838 f.instruction(&Instruction::If(BlockType::Empty));
839 f.instruction(&Instruction::I32Const(ctx.data.unwrap_failed_ptr as i32));
841 f.instruction(&Instruction::I32Const(ctx.data.unwrap_failed_len as i32));
842 f.instruction(&Instruction::Call(IMPORT_TRAP));
843 f.instruction(&Instruction::Unreachable);
844 f.instruction(&Instruction::End); f.instruction(&Instruction::End); f.instruction(&Instruction::LocalGet(result_local));
849 f.instruction(&Instruction::I32Load(memarg(8, 2))); Ok(())
851}
852
853fn emit_nil_coalesce(
854 left: &Expr,
855 right: &Expr,
856 ctx: &mut FuncContext,
857 f: &mut Function,
858) -> CodegenResult<()> {
859 let left_local = ctx.alloc_local(ValType::I32);
861 emit_expr(left, ctx, f)?;
862 f.instruction(&Instruction::LocalTee(left_local));
863 f.instruction(&Instruction::I32Load(memarg(0, 2)));
865 f.instruction(&Instruction::I32Const(TAG_NIL));
866 f.instruction(&Instruction::I32Eq);
867 f.instruction(&Instruction::If(BlockType::Result(ValType::I32)));
868 emit_expr(right, ctx, f)?;
869 f.instruction(&Instruction::Else);
870 f.instruction(&Instruction::LocalGet(left_local));
871 f.instruction(&Instruction::End);
872 Ok(())
873}
874
875fn emit_if_expr(
880 if_expr: &IfExpr,
881 ctx: &mut FuncContext,
882 f: &mut Function,
883) -> CodegenResult<()> {
884 emit_expr(&if_expr.condition, ctx, f)?;
886 f.instruction(&Instruction::I32Load(memarg(4, 2)));
888
889 f.instruction(&Instruction::If(BlockType::Result(ValType::I32)));
890
891 emit_block_as_expr(&if_expr.then_block, ctx, f)?;
893
894 f.instruction(&Instruction::Else);
895
896 match &if_expr.else_branch {
898 Some(ElseBranch::Block(block)) => {
899 emit_block_as_expr(block, ctx, f)?;
900 }
901 Some(ElseBranch::ElseIf(elif)) => {
902 emit_if_expr(elif, ctx, f)?;
903 }
904 None => {
905 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
907 }
908 }
909
910 f.instruction(&Instruction::End);
911 Ok(())
912}
913
914fn emit_for_expr(
915 for_expr: &ForExpr,
916 ctx: &mut FuncContext,
917 f: &mut Function,
918) -> CodegenResult<()> {
919 let list_local = ctx.alloc_local(ValType::I32);
921 let arr_local = ctx.alloc_local(ValType::I32);
922 let count_local = ctx.alloc_local(ValType::I32);
923 let i_local = ctx.alloc_local(ValType::I32);
924
925 emit_expr(&for_expr.iterable, ctx, f)?;
926 f.instruction(&Instruction::LocalSet(list_local));
927
928 f.instruction(&Instruction::LocalGet(list_local));
930 f.instruction(&Instruction::I32Load(memarg(4, 2)));
931 f.instruction(&Instruction::LocalSet(arr_local));
932
933 f.instruction(&Instruction::LocalGet(list_local));
935 f.instruction(&Instruction::I32Load(memarg(8, 2)));
936 f.instruction(&Instruction::LocalSet(count_local));
937
938 f.instruction(&Instruction::I32Const(0));
940 f.instruction(&Instruction::LocalSet(i_local));
941
942 let item_local = ctx.alloc_local(ValType::I32);
944 let index_local = if for_expr.index.is_some() {
945 Some(ctx.alloc_local(ValType::I32))
946 } else {
947 None
948 };
949
950 ctx.push_local(&for_expr.item.name, item_local);
952 if let (Some(idx_ident), Some(idx_local)) = (&for_expr.index, index_local) {
953 ctx.push_local(&idx_ident.name, idx_local);
954 }
955
956 f.instruction(&Instruction::Block(BlockType::Empty));
957 f.instruction(&Instruction::Loop(BlockType::Empty));
958
959 gas::emit_gas_tick(f, ctx.data.gas_exhausted_ptr, ctx.data.gas_exhausted_len);
961
962 f.instruction(&Instruction::LocalGet(i_local));
964 f.instruction(&Instruction::LocalGet(count_local));
965 f.instruction(&Instruction::I32GeU);
966 f.instruction(&Instruction::BrIf(1));
967
968 f.instruction(&Instruction::LocalGet(arr_local));
970 f.instruction(&Instruction::LocalGet(i_local));
971 f.instruction(&Instruction::I32Const(4));
972 f.instruction(&Instruction::I32Mul);
973 f.instruction(&Instruction::I32Add);
974 f.instruction(&Instruction::I32Load(memarg(0, 2)));
975 f.instruction(&Instruction::LocalSet(item_local));
976
977 if let Some(idx_local) = index_local {
979 f.instruction(&Instruction::I32Const(VALUE_SIZE as i32));
981 f.instruction(&Instruction::Call(rt_func_idx(RT_ALLOC)));
982 f.instruction(&Instruction::LocalTee(idx_local));
983 f.instruction(&Instruction::I32Const(TAG_NUMBER));
984 f.instruction(&Instruction::I32Store(memarg(0, 2)));
985 f.instruction(&Instruction::LocalGet(idx_local));
986 f.instruction(&Instruction::LocalGet(i_local));
987 f.instruction(&Instruction::F64ConvertI32U);
988 f.instruction(&Instruction::F64Store(memarg(4, 3)));
989 }
990
991 emit_stmts(&for_expr.body.stmts, ctx, f)?;
993
994 f.instruction(&Instruction::LocalGet(i_local));
996 f.instruction(&Instruction::I32Const(1));
997 f.instruction(&Instruction::I32Add);
998 f.instruction(&Instruction::LocalSet(i_local));
999 f.instruction(&Instruction::Br(0));
1000
1001 f.instruction(&Instruction::End); f.instruction(&Instruction::End); ctx.pop_local(&for_expr.item.name);
1006 if let Some(idx_ident) = &for_expr.index {
1007 ctx.pop_local(&idx_ident.name);
1008 }
1009
1010 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
1012 Ok(())
1013}
1014
1015fn emit_match_expr(
1016 match_expr: &MatchExpr,
1017 ctx: &mut FuncContext,
1018 f: &mut Function,
1019) -> CodegenResult<()> {
1020 let subj_local = ctx.alloc_local(ValType::I32);
1022 emit_expr(&match_expr.subject, ctx, f)?;
1023 f.instruction(&Instruction::LocalSet(subj_local));
1024
1025 let result_local = ctx.alloc_local(ValType::I32);
1030 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
1032 f.instruction(&Instruction::LocalSet(result_local));
1033
1034 f.instruction(&Instruction::Block(BlockType::Empty));
1036
1037 for arm in &match_expr.arms {
1038 match &arm.pattern {
1039 Pattern::Wildcard(_) => {
1040 match &arm.body {
1042 MatchArmBody::Expr(expr) => {
1043 emit_expr(expr, ctx, f)?;
1044 }
1045 MatchArmBody::Block(block) => {
1046 emit_block_as_expr(block, ctx, f)?;
1047 }
1048 }
1049 f.instruction(&Instruction::LocalSet(result_local));
1050 f.instruction(&Instruction::Br(0));
1051 }
1052 Pattern::Variant { name, bindings } => {
1053 let vid = ctx.get_variant_id(&name.name);
1055
1056 f.instruction(&Instruction::LocalGet(subj_local));
1058 f.instruction(&Instruction::I32Load(memarg(0, 2)));
1059 f.instruction(&Instruction::I32Const(TAG_VARIANT));
1060 f.instruction(&Instruction::I32Eq);
1061 f.instruction(&Instruction::If(BlockType::Empty));
1062
1063 f.instruction(&Instruction::LocalGet(subj_local));
1065 f.instruction(&Instruction::I32Load(memarg(4, 2)));
1066 f.instruction(&Instruction::I32Const(vid as i32));
1067 f.instruction(&Instruction::I32Eq);
1068 f.instruction(&Instruction::If(BlockType::Empty));
1069
1070 if !bindings.is_empty() {
1073 let data_local = ctx.alloc_local(ValType::I32);
1074 f.instruction(&Instruction::LocalGet(subj_local));
1075 f.instruction(&Instruction::I32Load(memarg(8, 2)));
1076 f.instruction(&Instruction::LocalSet(data_local));
1077
1078 for (bi, binding) in bindings.iter().enumerate() {
1079 let bind_local = ctx.alloc_local(ValType::I32);
1080 f.instruction(&Instruction::LocalGet(data_local));
1082 f.instruction(&Instruction::I32Const(bi as i32));
1083 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST_GET)));
1084 f.instruction(&Instruction::LocalSet(bind_local));
1085 ctx.push_local(&binding.name, bind_local);
1086 }
1087 }
1088
1089 match &arm.body {
1091 MatchArmBody::Expr(expr) => {
1092 emit_expr(expr, ctx, f)?;
1093 }
1094 MatchArmBody::Block(block) => {
1095 emit_block_as_expr(block, ctx, f)?;
1096 }
1097 }
1098 f.instruction(&Instruction::LocalSet(result_local));
1099
1100 for binding in bindings.iter().rev() {
1102 ctx.pop_local(&binding.name);
1103 }
1104
1105 f.instruction(&Instruction::Br(2)); f.instruction(&Instruction::End); f.instruction(&Instruction::End); }
1110 }
1111 }
1112
1113 f.instruction(&Instruction::End); f.instruction(&Instruction::LocalGet(result_local));
1116 Ok(())
1117}
1118
1119pub fn emit_block_as_expr(
1126 block: &Block,
1127 ctx: &mut FuncContext,
1128 f: &mut Function,
1129) -> CodegenResult<()> {
1130 if block.stmts.is_empty() {
1131 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
1132 return Ok(());
1133 }
1134
1135 let (last, rest) = block.stmts.split_last().unwrap();
1137 emit_stmts(rest, ctx, f)?;
1138
1139 match last {
1141 Stmt::Expr(expr_stmt) => {
1142 emit_expr(&expr_stmt.expr, ctx, f)?;
1143 }
1144 _ => {
1145 emit_stmts(std::slice::from_ref(last), ctx, f)?;
1147 f.instruction(&Instruction::Call(rt_func_idx(RT_VAL_NIL)));
1148 }
1149 }
1150 Ok(())
1151}
1152
1153fn memarg(offset: u64, align: u32) -> wasm_encoder::MemArg {
1155 wasm_encoder::MemArg {
1156 offset,
1157 align,
1158 memory_index: 0,
1159 }
1160}