use std::collections::HashMap;
use crate::ast::{Expr, Spanned};
use crate::codegen::CodegenContext;
use crate::types::Type;
use super::super::types::{WasmType, aver_type_to_wasm};
use super::ExprEmitter;
#[derive(Debug, Clone)]
pub(in crate::codegen::wasm) struct VariantInfo {
pub tag: u32,
pub field_types: Vec<String>, }
pub(in crate::codegen::wasm) fn build_variant_registry(
ctx: &CodegenContext,
) -> HashMap<(String, String), VariantInfo> {
let mut registry = HashMap::new();
let mut process_td = |td: &crate::ast::TypeDef, prefix: Option<&str>| {
if let crate::ast::TypeDef::Sum { name, variants, .. } = td {
for (tag, variant) in variants.iter().enumerate() {
let qualified_type = match prefix {
Some(p) => format!("{}.{}", p, name),
None => name.clone(),
};
registry.insert(
(qualified_type.clone(), variant.name.clone()),
VariantInfo {
tag: tag as u32,
field_types: variant.fields.clone(),
},
);
if prefix.is_some() {
registry.insert(
(name.clone(), variant.name.clone()),
VariantInfo {
tag: tag as u32,
field_types: variant.fields.clone(),
},
);
}
}
}
};
for td in &ctx.type_defs {
process_td(td, None);
}
for module in &ctx.modules {
for td in &module.type_defs {
process_td(td, Some(&module.prefix));
}
}
registry
}
impl<'a> ExprEmitter<'a> {
#[track_caller]
pub(super) fn aver_type_of<'b>(&self, expr: &'b Spanned<Expr>) -> &'b Type {
expr.ty().unwrap_or_else(|| {
panic!(
"legacy WASM codegen: missing Spanned::ty() for {:?} \
(typecheck must run before codegen; synthesised nodes \
must call Spanned::set_ty)",
expr.node
)
})
}
#[track_caller]
pub(super) fn wasm_type_of(&self, expr: &Spanned<Expr>) -> WasmType {
aver_type_to_wasm(self.aver_type_of(expr))
}
pub(super) fn expr_is_heap_ptr_spanned(&self, expr: &Spanned<Expr>) -> bool {
self.is_heap_type(self.aver_type_of(expr))
}
pub(super) fn type_str_to_wasm(&self, type_str: &str) -> WasmType {
match type_str {
"Float" => WasmType::F64,
"Bool" => WasmType::I32,
"String" | "Str" => WasmType::I32,
"Int" => WasmType::I64,
"Unit" => WasmType::I32,
_ => WasmType::I32,
}
}
pub(super) fn record_fields(&self, type_name: &str) -> Option<&[(String, String)]> {
for td in &self.ctx.type_defs {
if let crate::ast::TypeDef::Product { name, fields, .. } = td
&& name == type_name
{
return Some(fields.as_slice());
}
}
for module in &self.ctx.modules {
for td in &module.type_defs {
if let crate::ast::TypeDef::Product { name, fields, .. } = td
&& (name == type_name || format!("{}.{}", module.prefix, name) == type_name)
{
return Some(fields.as_slice());
}
}
}
None
}
}