1use std::collections::HashMap;
12
13use pepl_types::ast::*;
14use wasm_encoder::{
15 CodeSection, ConstExpr, CustomSection, DataSection, ElementSection, Elements,
16 EntityType, ExportKind, ExportSection, Function, FunctionSection, GlobalSection,
17 GlobalType, ImportSection, Instruction, MemorySection, MemoryType, Module,
18 RefType, TableSection, TableType, TypeSection, ValType,
19};
20
21use crate::error::{CodegenError, CodegenResult};
22use crate::runtime::{
23 self, memarg, rt_func_idx, DataSegmentTracker, RT_FUNC_COUNT, RT_VAL_LIST_GET,
24 RT_VAL_RECORD_GET,
25};
26use crate::source_map::{FuncKind, SourceMap};
27use crate::types::*;
28
29pub fn compile(program: &Program) -> CodegenResult<Vec<u8>> {
38 let mut compiler = Compiler::new(program);
39 let (wasm, _source_map) = compiler.compile()?;
40 Ok(wasm)
41}
42
43pub fn compile_with_source_map(program: &Program) -> CodegenResult<(Vec<u8>, SourceMap)> {
46 let mut compiler = Compiler::new(program);
47 compiler.compile()
48}
49
50struct Compiler<'a> {
56 program: &'a Program,
57 data: DataSegmentTracker,
59 user_data: Vec<u8>,
61
62 state_field_names: Vec<String>,
65 action_names: Vec<String>,
67 view_names: Vec<String>,
69 variant_ids: HashMap<String, u32>,
71 function_table: HashMap<String, u32>,
73 lambda_bodies: Vec<LambdaBody>,
76 num_space_funcs: u32,
78 num_test_funcs: u32,
80 source_map: SourceMap,
82}
83
84#[derive(Clone)]
86pub struct LambdaBody {
87 pub params: Vec<pepl_types::ast::Param>,
88 pub body: pepl_types::ast::Block,
89 pub captured: Vec<String>,
90}
91
92impl<'a> Compiler<'a> {
93 fn new(program: &'a Program) -> Self {
94 Self {
95 program,
96 data: DataSegmentTracker::new(),
97 user_data: Vec::new(),
98 state_field_names: Vec::new(),
99 action_names: Vec::new(),
100 view_names: Vec::new(),
101 variant_ids: HashMap::new(),
102 function_table: HashMap::new(),
103 lambda_bodies: Vec::new(),
104 num_space_funcs: 0,
105 num_test_funcs: 0,
106 source_map: SourceMap::new(),
107 }
108 }
109
110 fn compile(&mut self) -> CodegenResult<(Vec<u8>, SourceMap)> {
112 self.collect_metadata();
113
114 let mut module = Module::new();
115
116 let types = self.emit_types();
118 module.section(&types);
119
120 let imports = self.emit_imports();
122 module.section(&imports);
123
124 let (func_section, code_section) = self.emit_functions()?;
126 module.section(&func_section);
127
128 let table = self.emit_table();
130 module.section(&table);
131
132 let memory = self.emit_memory();
134 module.section(&memory);
135
136 let globals = self.emit_globals();
138 module.section(&globals);
139
140 let exports = self.emit_exports();
142 module.section(&exports);
143
144 let elements = self.emit_elements();
146 module.section(&elements);
147
148 module.section(&code_section);
150
151 let data_sec = self.emit_data();
153 module.section(&data_sec);
154
155 let custom = self.emit_custom();
157 module.section(&custom);
158
159 let sm_bytes = self.source_map.to_json();
161 let sm_custom = CustomSection {
162 name: std::borrow::Cow::Borrowed("pepl_source_map"),
163 data: std::borrow::Cow::Owned(sm_bytes),
164 };
165 module.section(&sm_custom);
166
167 let wasm_bytes = module.finish();
168
169 wasmparser::validate(&wasm_bytes).map_err(|e| {
171 CodegenError::ValidationFailed(format!("{e}"))
172 })?;
173
174 Ok((wasm_bytes, self.source_map.clone()))
175 }
176
177 fn collect_metadata(&mut self) {
180 let body = &self.program.space.body;
181
182 for field in &body.state.fields {
184 self.state_field_names.push(field.name.name.clone());
185 }
186
187 if let Some(derived) = &body.derived {
189 for field in &derived.fields {
190 self.state_field_names.push(field.name.name.clone());
191 }
192 }
193
194 for action in &body.actions {
196 self.action_names.push(action.name.name.clone());
197 }
198
199 for view in &body.views {
201 self.view_names.push(view.name.name.clone());
202 }
203
204 let mut vid = 0u32;
206 for type_decl in &body.types {
207 if let TypeDeclBody::SumType(variants) = &type_decl.body {
208 for variant in variants {
209 self.variant_ids.insert(variant.name.name.clone(), vid);
210 vid += 1;
211 }
212 }
213 }
214 }
215
216 fn emit_types(&self) -> TypeSection {
219 let mut types = TypeSection::new();
220
221 types.ty().function(vec![], vec![]);
223 types.ty().function(vec![], vec![ValType::I32]);
225 types.ty().function(vec![ValType::I32], vec![]);
227 types.ty().function(vec![ValType::I32], vec![ValType::I32]);
229 types.ty().function(vec![ValType::I32, ValType::I32], vec![]);
231 types
233 .ty()
234 .function(vec![ValType::I32, ValType::I32], vec![ValType::I32]);
235 types.ty().function(
237 vec![ValType::I32, ValType::I32, ValType::I32],
238 vec![ValType::I32],
239 );
240 types.ty().function(vec![ValType::F64], vec![ValType::I32]);
242 types
244 .ty()
245 .function(vec![ValType::I32, ValType::F64], vec![]);
246 types.ty().function(vec![], vec![ValType::I64]);
248 types.ty().function(
250 vec![ValType::I32, ValType::I32, ValType::I32],
251 vec![],
252 );
253
254 types
255 }
256
257 fn emit_imports(&self) -> ImportSection {
260 let mut imports = ImportSection::new();
261
262 imports.import("env", "host_call", EntityType::Function(TYPE_I32X3_I32));
264 imports.import("env", "log", EntityType::Function(TYPE_I32X2_VOID));
266 imports.import("env", "trap", EntityType::Function(TYPE_I32X2_VOID));
268 imports.import("env", "get_timestamp", EntityType::Function(TYPE_VOID_I64));
270
271 imports
272 }
273
274 fn emit_memory(&self) -> MemorySection {
277 let mut memory = MemorySection::new();
278 memory.memory(MemoryType {
279 minimum: INITIAL_MEMORY_PAGES,
280 maximum: Some(MAX_MEMORY_PAGES),
281 memory64: false,
282 shared: false,
283 page_size_log2: None,
284 });
285 memory
286 }
287
288 fn emit_globals(&self) -> GlobalSection {
291 let mut globals = GlobalSection::new();
292
293 globals.global(
295 GlobalType {
296 val_type: ValType::I32,
297 mutable: true,
298 shared: false,
299 },
300 &ConstExpr::i32_const(HEAP_START as i32),
301 );
302
303 globals.global(
305 GlobalType {
306 val_type: ValType::I32,
307 mutable: true,
308 shared: false,
309 },
310 &ConstExpr::i32_const(0),
311 );
312
313 globals.global(
315 GlobalType {
316 val_type: ValType::I32,
317 mutable: true,
318 shared: false,
319 },
320 &ConstExpr::i32_const(1_000_000),
321 );
322
323 globals.global(
325 GlobalType {
326 val_type: ValType::I32,
327 mutable: true,
328 shared: false,
329 },
330 &ConstExpr::i32_const(0),
331 );
332
333 globals
334 }
335
336 fn emit_functions(&mut self) -> CodegenResult<(FunctionSection, CodeSection)> {
339 let mut func_section = FunctionSection::new();
340 let mut code_section = CodeSection::new();
341
342 func_section.function(TYPE_I32_I32);
347 code_section.function(&runtime::emit_alloc(
348 self.data.oom_ptr,
349 self.data.oom_len,
350 ));
351
352 func_section.function(TYPE_VOID_I32);
354 code_section.function(&runtime::emit_val_nil());
355
356 func_section.function(TYPE_I32X2_I32);
358 code_section.function(&runtime::emit_val_number());
359
360 func_section.function(TYPE_I32_I32);
362 code_section.function(&runtime::emit_val_bool());
363
364 func_section.function(TYPE_I32X2_I32);
366 code_section.function(&runtime::emit_val_string());
367
368 func_section.function(TYPE_I32X2_I32);
370 code_section.function(&runtime::emit_val_list());
371
372 func_section.function(TYPE_I32X2_I32);
374 code_section.function(&runtime::emit_val_record());
375
376 func_section.function(TYPE_I32X2_I32);
378 code_section.function(&runtime::emit_val_variant());
379
380 func_section.function(TYPE_I32_I32);
382 code_section.function(&runtime::emit_val_action_ref());
383
384 func_section.function(TYPE_I32_I32);
386 code_section.function(&runtime::emit_val_tag());
387
388 func_section.function(TYPE_I32_I32);
390 code_section.function(&runtime::emit_val_get_number());
391
392 func_section.function(TYPE_I32_I32);
394 code_section.function(&runtime::emit_val_get_w1());
395
396 func_section.function(TYPE_I32_I32);
398 code_section.function(&runtime::emit_val_get_w2());
399
400 func_section.function(TYPE_I32X2_I32);
402 code_section.function(&runtime::emit_val_eq());
403
404 func_section.function(TYPE_I32_I32);
406 code_section.function(&runtime::emit_val_to_string(&self.data));
407
408 func_section.function(TYPE_I32X2_I32);
410 code_section.function(&runtime::emit_val_string_concat());
411
412 func_section.function(TYPE_I32X2_I32);
414 code_section.function(&runtime::emit_val_add());
415 func_section.function(TYPE_I32X2_I32);
416 code_section.function(&runtime::emit_val_sub());
417 func_section.function(TYPE_I32X2_I32);
418 code_section.function(&runtime::emit_val_mul());
419 func_section.function(TYPE_I32X2_I32);
420 code_section.function(&runtime::emit_val_div(
421 self.data.div_by_zero_ptr,
422 self.data.div_by_zero_len,
423 ));
424 func_section.function(TYPE_I32X2_I32);
425 code_section.function(&runtime::emit_val_mod());
426
427 func_section.function(TYPE_I32_I32);
429 code_section.function(&runtime::emit_val_neg());
430
431 func_section.function(TYPE_I32_I32);
433 code_section.function(&runtime::emit_val_not());
434
435 func_section.function(TYPE_I32X2_I32);
437 code_section.function(&runtime::emit_val_lt());
438 func_section.function(TYPE_I32X2_I32);
439 code_section.function(&runtime::emit_val_le());
440 func_section.function(TYPE_I32X2_I32);
441 code_section.function(&runtime::emit_val_gt());
442 func_section.function(TYPE_I32X2_I32);
443 code_section.function(&runtime::emit_val_ge());
444
445 func_section.function(TYPE_I32X3_I32);
447 code_section.function(&runtime::emit_val_record_get());
448
449 func_section.function(TYPE_I32X2_I32);
451 code_section.function(&runtime::emit_val_list_get());
452
453 func_section.function(TYPE_I32_I32);
455 code_section.function(&runtime::emit_check_nan(
456 self.data.nan_ptr,
457 self.data.nan_len,
458 ));
459
460 func_section.function(TYPE_I32X3_I32);
462 code_section.function(&runtime::emit_memcmp());
463
464 let body = &self.program.space.body;
466
467 let init_idx = IMPORT_COUNT + RT_FUNC_COUNT;
469 func_section.function(TYPE_VOID_VOID);
470 let mut init_scratch = Function::new(vec![]);
471 let mut init_ctx = self.make_func_context(0); crate::space::emit_init(
473 &body.state,
474 body.derived.as_ref(),
475 &mut init_ctx,
476 &mut init_scratch,
477 )?;
478 self.merge_user_data(&init_ctx);
479 code_section.function(&Self::finalize_function(init_scratch, &init_ctx));
480 self.source_map.push(init_idx, "init", FuncKind::SpaceInfra, body.state.span);
481
482 let dispatch_idx = init_idx + 1;
484 func_section.function(TYPE_I32X3_VOID);
485 let mut dispatch_scratch = Function::new(vec![]);
486 let mut dispatch_ctx = self.make_func_context(3); crate::space::emit_dispatch_action(
488 &body.actions,
489 &body.invariants,
490 body.derived.as_ref(),
491 &mut dispatch_ctx,
492 &mut dispatch_scratch,
493 )?;
494 self.merge_user_data(&dispatch_ctx);
495 code_section.function(&Self::finalize_function(dispatch_scratch, &dispatch_ctx));
496 self.source_map.push(dispatch_idx, "dispatch_action", FuncKind::SpaceInfra, body.span);
497 for (ai, action) in body.actions.iter().enumerate() {
499 self.source_map.push(dispatch_idx, &action.name.name, FuncKind::Action, action.span);
500 let _ = ai; }
502
503 let render_idx = dispatch_idx + 1;
505 func_section.function(TYPE_I32_I32);
506 let mut render_scratch = Function::new(vec![]);
507 let mut render_ctx = self.make_func_context(1);
508 crate::space::emit_render(&body.views, &mut render_ctx, &mut render_scratch)?;
509 self.merge_user_data(&render_ctx);
510 code_section.function(&Self::finalize_function(render_scratch, &render_ctx));
511 self.source_map.push(render_idx, "render", FuncKind::SpaceInfra, body.span);
512 for view in &body.views {
513 self.source_map.push(render_idx, &view.name.name, FuncKind::View, view.span);
514 }
515
516 let get_state_idx = render_idx + 1;
518 func_section.function(TYPE_VOID_I32);
519 let mut get_state_func = Function::new(vec![]);
520 crate::space::emit_get_state(&mut get_state_func);
521 code_section.function(&get_state_func);
523
524 let dealloc_idx = get_state_idx + 1;
529 func_section.function(TYPE_I32X2_VOID);
530 let mut dealloc_func = Function::new(vec![]);
531 dealloc_func.instruction(&Instruction::End);
534 code_section.function(&dealloc_func);
535
536 let mut next_idx = dealloc_idx + 1;
538 if let Some(update_decl) = &body.update {
539 self.function_table
540 .insert("update".to_string(), next_idx);
541 func_section.function(TYPE_I32_VOID);
542 let mut update_scratch = Function::new(vec![]);
543 let mut update_ctx = self.make_func_context(1);
544 crate::space::emit_update(
545 update_decl,
546 body.derived.as_ref(),
547 &mut update_ctx,
548 &mut update_scratch,
549 )?;
550 self.merge_user_data(&update_ctx);
551 code_section.function(&Self::finalize_function(update_scratch, &update_ctx));
552 self.source_map.push(next_idx, "update", FuncKind::Update, update_decl.span);
553 next_idx += 1;
554 }
555
556 if let Some(handle_event_decl) = &body.handle_event {
558 self.function_table
559 .insert("handle_event".to_string(), next_idx);
560 func_section.function(TYPE_I32_VOID);
561 let mut he_scratch = Function::new(vec![]);
562 let mut he_ctx = self.make_func_context(1);
563 crate::space::emit_handle_event(
564 handle_event_decl,
565 body.derived.as_ref(),
566 &mut he_ctx,
567 &mut he_scratch,
568 )?;
569 self.merge_user_data(&he_ctx);
570 code_section.function(&Self::finalize_function(he_scratch, &he_ctx));
571 self.source_map.push(next_idx, "handle_event", FuncKind::HandleEvent, handle_event_decl.span);
572 next_idx += 1;
573 }
574
575 self.num_space_funcs = next_idx - (IMPORT_COUNT + RT_FUNC_COUNT);
577
578 let invoke_lambda_idx = next_idx;
582 func_section.function(TYPE_I32X2_I32);
583 let mut invoke_func = Function::new(vec![
584 (1, ValType::I32), (1, ValType::I32), ]);
587 invoke_func.instruction(&Instruction::LocalGet(0));
589 invoke_func.instruction(&Instruction::I32Load(memarg(4, 2)));
590 invoke_func.instruction(&Instruction::LocalSet(2));
591 invoke_func.instruction(&Instruction::LocalGet(0));
593 invoke_func.instruction(&Instruction::I32Load(memarg(8, 2)));
594 invoke_func.instruction(&Instruction::LocalSet(3));
595 invoke_func.instruction(&Instruction::LocalGet(3)); invoke_func.instruction(&Instruction::LocalGet(1)); invoke_func.instruction(&Instruction::LocalGet(2)); invoke_func.instruction(&Instruction::CallIndirect { type_index: TYPE_I32X2_I32, table_index: 0 });
601 invoke_func.instruction(&Instruction::End);
602 code_section.function(&invoke_func);
603 self.function_table
604 .insert("invoke_lambda".to_string(), invoke_lambda_idx);
605 self.source_map.push(invoke_lambda_idx, "invoke_lambda", FuncKind::InvokeLambda, self.program.space.body.span);
606 let mut _next_idx = next_idx + 1;
607
608 let lambda_bodies = self.lambda_bodies.clone();
611 for lb in &lambda_bodies {
612 func_section.function(TYPE_I32X2_I32);
613 let mut lam_scratch = Function::new(vec![]);
614 let mut lam_ctx = self.make_func_context(2);
616
617 for cap_name in &lb.captured {
619 let cap_local = lam_ctx.alloc_local(ValType::I32);
620 let (cap_key_ptr, cap_key_len) = lam_ctx.intern_string(cap_name);
621 lam_scratch.instruction(&Instruction::LocalGet(0)); lam_scratch.instruction(&Instruction::I32Const(cap_key_ptr as i32));
623 lam_scratch.instruction(&Instruction::I32Const(cap_key_len as i32));
624 lam_scratch.instruction(&Instruction::Call(rt_func_idx(RT_VAL_RECORD_GET)));
625 lam_scratch.instruction(&Instruction::LocalSet(cap_local));
626 lam_ctx.push_local(cap_name, cap_local);
627 }
628
629 if lb.params.len() == 1 {
633 let param_local = lam_ctx.alloc_local(ValType::I32);
634 lam_scratch.instruction(&Instruction::LocalGet(1)); lam_scratch.instruction(&Instruction::LocalSet(param_local));
636 lam_ctx.push_local(&lb.params[0].name.name, param_local);
637 } else {
638 for (pi, param) in lb.params.iter().enumerate() {
639 let param_local = lam_ctx.alloc_local(ValType::I32);
640 lam_scratch.instruction(&Instruction::LocalGet(1)); lam_scratch.instruction(&Instruction::I32Const(pi as i32));
642 lam_scratch.instruction(&Instruction::Call(rt_func_idx(RT_VAL_LIST_GET)));
643 lam_scratch.instruction(&Instruction::LocalSet(param_local));
644 lam_ctx.push_local(¶m.name.name, param_local);
645 }
646 }
647
648 crate::expr::emit_block_as_expr(&lb.body, &mut lam_ctx, &mut lam_scratch)?;
650 lam_scratch.instruction(&Instruction::End);
651
652 self.merge_user_data(&lam_ctx);
653 code_section.function(&Self::finalize_function(lam_scratch, &lam_ctx));
654 _next_idx += 1;
655 }
656
657 let all_cases: Vec<&TestCase> = self
660 .program
661 .tests
662 .iter()
663 .flat_map(|tb| &tb.cases)
664 .collect();
665
666 if !all_cases.is_empty() {
667 let actions_map: std::collections::HashMap<String, u32> = self
669 .action_names
670 .iter()
671 .enumerate()
672 .map(|(i, name)| (name.clone(), i as u32))
673 .collect();
674
675 let init_func_idx = IMPORT_COUNT + RT_FUNC_COUNT; let dispatch_func_idx = init_func_idx + 1;
677
678 for (ti, tc) in all_cases.iter().enumerate() {
679 let test_func_idx = _next_idx;
680 func_section.function(TYPE_VOID_VOID);
681 let mut test_scratch = Function::new(vec![]);
682 let mut test_ctx = self.make_func_context(0);
683 crate::test_codegen::emit_test_body(
684 &tc.body,
685 &actions_map,
686 dispatch_func_idx,
687 init_func_idx,
688 &mut test_ctx,
689 &mut test_scratch,
690 )?;
691 test_scratch.instruction(&Instruction::End);
692 self.merge_user_data(&test_ctx);
693 code_section.function(&Self::finalize_function(test_scratch, &test_ctx));
694 self.source_map.push(test_func_idx, format!("__test_{ti}"), FuncKind::Test, tc.span);
695 _next_idx += 1;
696 }
697
698 func_section.function(TYPE_VOID_I32);
700 code_section.function(&crate::test_codegen::emit_test_count(all_cases.len()));
701 self.source_map.push(_next_idx, "__test_count", FuncKind::TestCount, self.program.space.span);
702 _next_idx += 1;
703
704 self.num_test_funcs = all_cases.len() as u32 + 1; }
706
707 Ok((func_section, code_section))
708 }
709
710 fn emit_exports(&self) -> ExportSection {
713 let mut exports = ExportSection::new();
714 let base = IMPORT_COUNT + RT_FUNC_COUNT;
715
716 exports.export("init", ExportKind::Func, base);
717 exports.export("dispatch_action", ExportKind::Func, base + 1);
718 exports.export("render", ExportKind::Func, base + 2);
719 exports.export("get_state", ExportKind::Func, base + 3);
720 exports.export("dealloc", ExportKind::Func, base + 4);
721 exports.export("alloc", ExportKind::Func, IMPORT_COUNT + runtime::RT_ALLOC);
722 exports.export("memory", ExportKind::Memory, 0);
723
724 if self.function_table.contains_key("update") {
726 exports.export(
727 "update",
728 ExportKind::Func,
729 *self.function_table.get("update").unwrap(),
730 );
731 }
732 if self.function_table.contains_key("handle_event") {
733 exports.export(
734 "handle_event",
735 ExportKind::Func,
736 *self.function_table.get("handle_event").unwrap(),
737 );
738 }
739
740 if self.function_table.contains_key("invoke_lambda") {
742 exports.export(
743 "invoke_lambda",
744 ExportKind::Func,
745 *self.function_table.get("invoke_lambda").unwrap(),
746 );
747 }
748 if !self.lambda_bodies.is_empty() {
750 exports.export("__indirect_function_table", ExportKind::Table, 0);
751 }
752
753 if self.num_test_funcs > 0 {
755 let test_base = IMPORT_COUNT
756 + RT_FUNC_COUNT
757 + self.num_space_funcs
758 + 1 + self.lambda_bodies.len() as u32;
760 let num_cases = self.num_test_funcs - 1; for i in 0..num_cases {
762 exports.export(
763 &format!("__test_{i}"),
764 ExportKind::Func,
765 test_base + i,
766 );
767 }
768 exports.export(
769 "__test_count",
770 ExportKind::Func,
771 test_base + num_cases,
772 );
773 }
774
775 exports
776 }
777
778 fn emit_data(&self) -> DataSection {
781 let mut data_sec = DataSection::new();
782 let mut all_data = self.data.data_bytes();
783 all_data.extend_from_slice(&self.user_data);
784 data_sec.active(0, &ConstExpr::i32_const(0), all_data);
785 data_sec
786 }
787
788 fn emit_table(&self) -> TableSection {
791 let mut table_sec = TableSection::new();
792 let table_size = std::cmp::max(1, self.lambda_bodies.len() as u64);
795 table_sec.table(TableType {
796 element_type: RefType::FUNCREF,
797 minimum: table_size,
798 maximum: Some(table_size),
799 table64: false,
800 shared: false,
801 });
802 table_sec
803 }
804
805 fn emit_elements(&self) -> ElementSection {
808 let mut elem_sec = ElementSection::new();
809 if !self.lambda_bodies.is_empty() {
810 let lambda_base =
812 IMPORT_COUNT + RT_FUNC_COUNT + self.num_space_funcs + 1; let func_indices: Vec<u32> = (0..self.lambda_bodies.len() as u32)
814 .map(|i| lambda_base + i)
815 .collect();
816 elem_sec.active(
817 Some(0),
818 &ConstExpr::i32_const(0),
819 Elements::Functions(std::borrow::Cow::Owned(func_indices)),
820 );
821 }
822 elem_sec
823 }
824
825 fn emit_custom(&self) -> CustomSection<'_> {
828 CustomSection {
829 name: std::borrow::Cow::Borrowed(CUSTOM_SECTION_NAME),
830 data: std::borrow::Cow::Borrowed(COMPILER_VERSION.as_bytes()),
831 }
832 }
833
834 fn make_func_context(&self, param_count: u32) -> FuncContext {
838 FuncContext {
839 locals: Vec::new(),
840 local_names: HashMap::new(),
841 next_local: param_count,
842 state_field_names: self.state_field_names.clone(),
843 action_names: self.action_names.clone(),
844 variant_ids: self.variant_ids.clone(),
845 function_table: self.function_table.clone(),
846 data: self.data.clone_tracker(),
847 user_data: Vec::new(),
848 string_cache: HashMap::new(),
849 lambda_bodies: Vec::new(),
850 lambda_base_idx: IMPORT_COUNT + RT_FUNC_COUNT + self.num_space_funcs
851 + 1 + self.lambda_bodies.len() as u32,
853 }
854 }
855
856 fn merge_user_data(&mut self, ctx: &FuncContext) {
858 self.user_data.extend_from_slice(&ctx.user_data);
859 self.data.next_offset = ctx.data.next_offset;
861 self.lambda_bodies.extend(ctx.lambda_bodies.clone());
863 }
864
865 fn finalize_function(scratch: Function, ctx: &FuncContext) -> Function {
871 let raw = scratch.into_raw_body();
872 let instr_bytes = &raw[1..];
875 let mut f = Function::new(ctx.locals.clone());
876 f.raw(instr_bytes.iter().copied());
877 f
878 }
879}
880
881pub struct FuncContext {
887 pub locals: Vec<(u32, ValType)>,
889 pub local_names: HashMap<String, Vec<u32>>,
891 pub next_local: u32,
893 pub state_field_names: Vec<String>,
895 pub action_names: Vec<String>,
897 pub variant_ids: HashMap<String, u32>,
899 pub function_table: HashMap<String, u32>,
901 pub data: DataSegmentTrackerClone,
903 pub user_data: Vec<u8>,
905 pub string_cache: HashMap<String, (u32, u32)>,
907 pub lambda_bodies: Vec<LambdaBody>,
909 pub lambda_base_idx: u32,
911}
912
913impl FuncContext {
914 pub fn alloc_local(&mut self, ty: ValType) -> u32 {
916 let idx = self.next_local;
917 self.next_local += 1;
918 self.locals.push((1, ty));
919 idx
920 }
921
922 pub fn push_local(&mut self, name: &str, idx: u32) {
924 self.local_names
925 .entry(name.to_string())
926 .or_default()
927 .push(idx);
928 }
929
930 pub fn pop_local(&mut self, name: &str) {
932 if let Some(stack) = self.local_names.get_mut(name) {
933 stack.pop();
934 }
935 }
936
937 pub fn get_local(&self, name: &str) -> Option<u32> {
939 self.local_names
940 .get(name)
941 .and_then(|stack| stack.last().copied())
942 }
943
944 pub fn is_state_field(&self, name: &str) -> bool {
946 self.state_field_names.iter().any(|s| s == name)
947 }
948
949 pub fn get_action_id(&self, name: &str) -> Option<usize> {
951 self.action_names.iter().position(|a| a == name)
952 }
953
954 pub fn get_function(&self, name: &str) -> Option<u32> {
956 self.function_table.get(name).copied()
957 }
958
959 pub fn get_variant_id(&self, name: &str) -> u32 {
961 *self.variant_ids.get(name).unwrap_or(&0)
962 }
963
964 pub fn intern_string(&mut self, s: &str) -> (u32, u32) {
967 if let Some(&cached) = self.string_cache.get(s) {
968 return cached;
969 }
970 let (ptr, len) = self.data.intern_string(s);
971 self.user_data.extend_from_slice(s.as_bytes());
972 self.string_cache.insert(s.to_string(), (ptr, len));
973 (ptr, len)
974 }
975
976 pub fn register_lambda(
979 &mut self,
980 params: Vec<pepl_types::ast::Param>,
981 body: pepl_types::ast::Block,
982 captured: Vec<String>,
983 ) -> u32 {
984 let lambda_idx = self.lambda_bodies.len() as u32;
985 self.lambda_bodies.push(LambdaBody {
986 params,
987 body,
988 captured,
989 });
990 self.lambda_base_idx + lambda_idx
992 }
993
994 pub fn resolve_qualified_call(&self, module: &str, function: &str) -> (u32, u32) {
999 match module {
1000 "http" => {
1001 let fn_id = match function {
1002 "get" => 1,
1003 "post" => 2,
1004 "put" => 3,
1005 "patch" => 4,
1006 "delete" => 5,
1007 _ => 0,
1008 };
1009 (1, fn_id)
1010 }
1011 "storage" => {
1012 let fn_id = match function {
1013 "get" => 1,
1014 "set" => 2,
1015 "delete" => 3,
1016 "keys" => 4,
1017 _ => 0,
1018 };
1019 (2, fn_id)
1020 }
1021 "location" => (3, if function == "current" { 1 } else { 0 }),
1022 "notifications" => (4, if function == "send" { 1 } else { 0 }),
1023 "credential" => (5, if function == "get" { 1 } else { 0 }),
1024 "math" => (100, self.stdlib_fn_id(function)),
1026 "string" => (101, self.stdlib_fn_id(function)),
1027 "list" => (102, self.stdlib_fn_id(function)),
1028 "record" => (103, self.stdlib_fn_id(function)),
1029 "json" => (104, self.stdlib_fn_id(function)),
1030 "convert" => (105, self.stdlib_fn_id(function)),
1031 "time" => (106, self.stdlib_fn_id(function)),
1032 "timer" => (107, self.stdlib_fn_id(function)),
1033 "core" => (108, self.stdlib_fn_id(function)),
1034 _ => (0, 0),
1035 }
1036 }
1037
1038 pub fn resolve_method_call(&self, method: &str) -> (u32, u32) {
1040 let fn_id = self.stdlib_fn_id(method);
1042 (0, fn_id)
1044 }
1045
1046 fn stdlib_fn_id(&self, function: &str) -> u32 {
1048 let mut hash: u32 = 5381;
1051 for b in function.bytes() {
1052 hash = hash.wrapping_mul(33).wrapping_add(b as u32);
1053 }
1054 hash & 0xFFFF
1055 }
1056}
1057
1058#[derive(Clone)]
1064pub struct DataSegmentTrackerClone {
1065 pub true_ptr: u32,
1066 pub true_len: u32,
1067 pub false_ptr: u32,
1068 pub false_len: u32,
1069 pub nil_ptr: u32,
1070 pub nil_len: u32,
1071 pub value_ptr: u32,
1072 pub value_len: u32,
1073 pub gas_exhausted_ptr: u32,
1074 pub gas_exhausted_len: u32,
1075 pub div_by_zero_ptr: u32,
1076 pub div_by_zero_len: u32,
1077 pub nan_ptr: u32,
1078 pub nan_len: u32,
1079 pub assert_failed_ptr: u32,
1080 pub assert_failed_len: u32,
1081 pub invariant_failed_ptr: u32,
1082 pub invariant_failed_len: u32,
1083 pub unwrap_failed_ptr: u32,
1084 pub unwrap_failed_len: u32,
1085 pub oom_ptr: u32,
1086 pub oom_len: u32,
1087 pub next_offset: u32,
1088}
1089
1090impl DataSegmentTrackerClone {
1091 pub fn intern_string(&mut self, s: &str) -> (u32, u32) {
1093 let ptr = self.next_offset;
1094 let len = s.len() as u32;
1095 self.next_offset += len;
1096 (ptr, len)
1097 }
1098}
1099
1100impl DataSegmentTracker {
1101 pub fn clone_tracker(&self) -> DataSegmentTrackerClone {
1103 DataSegmentTrackerClone {
1104 true_ptr: self.true_ptr,
1105 true_len: self.true_len,
1106 false_ptr: self.false_ptr,
1107 false_len: self.false_len,
1108 nil_ptr: self.nil_ptr,
1109 nil_len: self.nil_len,
1110 value_ptr: self.value_ptr,
1111 value_len: self.value_len,
1112 gas_exhausted_ptr: self.gas_exhausted_ptr,
1113 gas_exhausted_len: self.gas_exhausted_len,
1114 div_by_zero_ptr: self.div_by_zero_ptr,
1115 div_by_zero_len: self.div_by_zero_len,
1116 nan_ptr: self.nan_ptr,
1117 nan_len: self.nan_len,
1118 assert_failed_ptr: self.assert_failed_ptr,
1119 assert_failed_len: self.assert_failed_len,
1120 invariant_failed_ptr: self.invariant_failed_ptr,
1121 invariant_failed_len: self.invariant_failed_len,
1122 unwrap_failed_ptr: self.unwrap_failed_ptr,
1123 unwrap_failed_len: self.unwrap_failed_len,
1124 oom_ptr: self.oom_ptr,
1125 oom_len: self.oom_len,
1126 next_offset: self.next_offset,
1127 }
1128 }
1129}