1#![allow(clippy::single_match)]
2
3mod builders;
4mod code;
5mod expression;
6mod function;
7mod imports;
8mod module;
9mod statement;
10mod types;
11
12use builders::component::*;
13
14use claw_ast as ast;
15use claw_resolver::{ResolvedComponent, ResolverError};
16use miette::Diagnostic;
17use thiserror::Error;
18use types::EncodeType;
19
20#[derive(Error, Debug, Diagnostic)]
21pub enum GenerationError {
22 #[error(transparent)]
23 #[diagnostic(transparent)]
24 Resolver(#[from] ResolverError),
25}
26
27pub const MAX_FLAT_PARAMS: u8 = 16;
28pub const MAX_FLAT_RESULTS: u8 = 1;
29
30pub fn generate(resolved_comp: &ResolvedComponent) -> Result<Vec<u8>, GenerationError> {
31 let component = generate_component(resolved_comp)?;
32 Ok(component.finalize().finish())
33}
34
35fn generate_component(
36 resolved_comp: &ResolvedComponent,
37) -> Result<ComponentBuilder, GenerationError> {
38 let mut builder = ComponentBuilder::default();
39
40 let alloc_module = builder.module_bytes(gen_allocator());
41
42 let args: Vec<(&str, ModuleInstantiateArgs)> = vec![];
43 let alloc_instance = builder.instantiate(alloc_module, args);
44
45 let memory = builder.alias_memory(alloc_instance, "memory");
46 let realloc = builder.alias_core_func(alloc_instance, "realloc");
47
48 let import_encoder = imports::ImportEncoder::new(&mut builder, resolved_comp, memory, realloc);
49 let imports = import_encoder.encode()?;
50
51 let function_encoder = function::FunctionEncoder::new(resolved_comp);
52 let functions = function_encoder.encode()?;
53
54 let code_module = builder.module(module::generate(resolved_comp, &imports, &functions)?);
55
56 let args = vec![
57 ("alloc", ModuleInstantiateArgs::Instance(alloc_instance)),
58 (
59 "claw",
60 ModuleInstantiateArgs::Instance(imports.imports_instance),
61 ),
62 ];
63 let code_instance = builder.instantiate(code_module, args);
64
65 generate_exports(&mut builder, resolved_comp, code_instance, memory, realloc)?;
66
67 Ok(builder)
68}
69
70fn generate_exports(
71 component: &mut ComponentBuilder,
72 resolved_comp: &ResolvedComponent,
73 code_instance: ComponentModuleInstanceIndex,
74 memory: ComponentCoreMemoryIndex,
75 realloc: ComponentCoreFunctionIndex,
76) -> Result<(), GenerationError> {
77 let comp = &resolved_comp.component;
78
79 for function in resolved_comp.component.functions.values() {
80 if function.exported {
81 let name = comp.get_name(function.ident);
82 let core_func_idx = component.alias_core_func(code_instance, name);
84 let post_return_idx =
86 component.alias_core_func(code_instance, format!("{}_post_return", name).as_str());
87
88 let params = function.params.iter().map(|(param_name, param_type)| {
90 let param_name = resolved_comp.component.get_name(*param_name);
91 let param_type = comp.get_type(*param_type);
92 let param_type = match param_type {
93 ast::ValType::Result(_) => todo!(),
94 ast::ValType::Primitive(ptype) => ptype.to_comp_valtype(resolved_comp),
95 };
96 (param_name, param_type)
97 });
98 let results = function.results.map(|result_type| {
99 let result_type = comp.get_type(result_type);
100 match result_type {
101 ast::ValType::Result(_) => todo!(),
102 ast::ValType::Primitive(ptype) => ptype.to_comp_valtype(resolved_comp),
103 }
104 });
105 let type_idx = component.func_type(params, results);
106
107 let func_idx =
109 component.lift_func(core_func_idx, type_idx, memory, realloc, post_return_idx);
110 component.export_func(name, func_idx, type_idx);
112 }
113 }
114 Ok(())
115}
116
117pub fn gen_allocator() -> Vec<u8> {
120 let wat = include_str!("../allocator.wat");
121 wat::parse_str(wat).unwrap()
122}