claw_codegen/
lib.rs

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            // Alias module instance export into component
83            let core_func_idx = component.alias_core_func(code_instance, name);
84            // Alias the post return
85            let post_return_idx =
86                component.alias_core_func(code_instance, format!("{}_post_return", name).as_str());
87
88            // Encode component func type
89            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            // Lift aliased function to component function
108            let func_idx =
109                component.lift_func(core_func_idx, type_idx, memory, realloc, post_return_idx);
110            // Export component function
111            component.export_func(name, func_idx, type_idx);
112        }
113    }
114    Ok(())
115}
116
117// ValType
118
119pub fn gen_allocator() -> Vec<u8> {
120    let wat = include_str!("../allocator.wat");
121    wat::parse_str(wat).unwrap()
122}