pepl_codegen/
test_codegen.rs1use std::collections::HashMap;
13use wasm_encoder::{Function, Instruction};
14
15use crate::compiler::FuncContext;
16use crate::error::CodegenResult;
17use crate::runtime::memarg;
18use crate::types::*;
19
20use pepl_types::ast::*;
21
22pub fn emit_test_body(
28 body: &Block,
29 actions: &HashMap<String, u32>,
30 dispatch_func_idx: u32,
31 init_func_idx: u32,
32 ctx: &mut FuncContext,
33 f: &mut Function,
34) -> CodegenResult<()> {
35 f.instruction(&Instruction::Call(init_func_idx));
37
38 for stmt in &body.stmts {
40 emit_test_stmt(stmt, actions, dispatch_func_idx, ctx, f)?;
41 }
42 Ok(())
43}
44
45fn emit_test_stmt(
47 stmt: &Stmt,
48 actions: &HashMap<String, u32>,
49 dispatch_func_idx: u32,
50 ctx: &mut FuncContext,
51 f: &mut Function,
52) -> CodegenResult<()> {
53 match stmt {
54 Stmt::Expr(expr_stmt) => {
55 if is_action_call(&expr_stmt.expr, actions) {
56 emit_action_dispatch(&expr_stmt.expr, actions, dispatch_func_idx, f)
57 } else {
58 crate::expr::emit_expr(&expr_stmt.expr, ctx, f)?;
59 f.instruction(&Instruction::Drop);
60 Ok(())
61 }
62 }
63 Stmt::Assert(assert_stmt) => emit_test_assert(assert_stmt, ctx, f),
64 Stmt::Let(binding) => {
65 crate::expr::emit_expr(&binding.value, ctx, f)?;
66 if let Some(name) = &binding.name {
67 let local = ctx.alloc_local(wasm_encoder::ValType::I32);
68 f.instruction(&Instruction::LocalSet(local));
69 ctx.push_local(&name.name, local);
70 } else {
71 f.instruction(&Instruction::Drop);
72 }
73 Ok(())
74 }
75 _ => crate::stmt::emit_stmt(stmt, ctx, f),
76 }
77}
78
79fn is_action_call(expr: &Expr, actions: &HashMap<String, u32>) -> bool {
81 matches!(&expr.kind, ExprKind::Call { name, .. } if actions.contains_key(&name.name))
82}
83
84fn emit_action_dispatch(
86 expr: &Expr,
87 actions: &HashMap<String, u32>,
88 dispatch_func_idx: u32,
89 f: &mut Function,
90) -> CodegenResult<()> {
91 if let ExprKind::Call { name, .. } = &expr.kind {
92 let action_id = actions[&name.name];
93 f.instruction(&Instruction::I32Const(action_id as i32));
94 f.instruction(&Instruction::I32Const(0)); f.instruction(&Instruction::I32Const(0)); f.instruction(&Instruction::Call(dispatch_func_idx));
97 }
98 Ok(())
99}
100
101fn emit_test_assert(
103 assert: &AssertStmt,
104 ctx: &mut FuncContext,
105 f: &mut Function,
106) -> CodegenResult<()> {
107 crate::expr::emit_expr(&assert.condition, ctx, f)?;
108
109 let val_local = ctx.alloc_local(wasm_encoder::ValType::I32);
110 f.instruction(&Instruction::LocalSet(val_local));
111 f.instruction(&Instruction::LocalGet(val_local));
112 f.instruction(&Instruction::I32Load(memarg(4, 2))); f.instruction(&Instruction::I32Eqz); f.instruction(&Instruction::If(wasm_encoder::BlockType::Empty));
116 let msg = assert
117 .message
118 .clone()
119 .unwrap_or_else(|| "assertion failed".to_string());
120 let (msg_ptr, msg_len) = ctx.intern_string(&msg);
121 f.instruction(&Instruction::I32Const(msg_ptr as i32));
122 f.instruction(&Instruction::I32Const(msg_len as i32));
123 f.instruction(&Instruction::Call(IMPORT_TRAP));
124 f.instruction(&Instruction::End);
125
126 Ok(())
127}
128
129pub fn emit_test_count(count: usize) -> Function {
131 let mut f = Function::new(vec![]);
132 f.instruction(&Instruction::I32Const(count as i32));
133 f.instruction(&Instruction::End);
134 f
135}