submilli_engine/codegen/
field_name_strings.rs1use std::collections::BTreeSet;
7
8use wasm_encoder::{ConstExpr, GlobalSection, GlobalType, HeapType, Instruction, RefType, ValType};
9
10use crate::Type;
11use crate::codegen::intrinsics::IntrinsicTypeIndices;
12use crate::codegen::symbol_table::SymbolTable;
13use crate::codegen::{next_index, wasm_u32};
14use crate::compiler_error::CompilerFailure;
15
16pub fn collect(shapes: &[Type], extra_names: &[String]) -> Vec<String> {
20 let mut names: BTreeSet<String> = BTreeSet::new();
21 for shape in shapes {
22 if let Type::Object { fields, .. } = shape {
23 for k in fields.keys() {
24 names.insert(k.clone());
25 }
26 }
27 }
28 for name in extra_names {
29 names.insert(name.clone());
30 }
31 names.into_iter().collect()
32}
33
34pub fn emit(
35 names: &[String],
36 globals: &mut GlobalSection,
37 symbols: &mut SymbolTable,
38 next_global_idx: &mut u32,
39 intrinsics: IntrinsicTypeIndices,
40 string_vtable_global_idx: u32,
41) -> Result<(), CompilerFailure> {
42 let string_val_type = ValType::Ref(RefType {
43 nullable: false,
44 heap_type: HeapType::Concrete(intrinsics.string),
45 });
46 for name in names {
47 let init = build_init_expr(name, intrinsics, string_vtable_global_idx)?;
48 let global_idx = next_index(next_global_idx)?;
49 globals.global(
50 GlobalType {
51 val_type: string_val_type,
52 mutable: false,
53 shared: false,
54 },
55 &init,
56 );
57 symbols.record_field_name_string_global(name.clone(), global_idx);
58 }
59 Ok(())
60}
61
62fn build_init_expr(
63 name: &str,
64 intrinsics: IntrinsicTypeIndices,
65 string_vtable_global_idx: u32,
66) -> Result<ConstExpr, CompilerFailure> {
67 let mut instrs: Vec<Instruction<'_>> = Vec::new();
68 let code_units = crate::literal_units::literal_units(name);
69 instrs.push(Instruction::GlobalGet(string_vtable_global_idx));
70 for unit in &code_units {
71 instrs.push(Instruction::I32Const(i32::from(*unit)));
72 }
73 instrs.push(Instruction::ArrayNewFixed {
74 array_type_index: intrinsics.raw_string,
75 array_size: wasm_u32(code_units.len())?,
76 });
77 instrs.push(Instruction::I64Const(0));
78 instrs.push(Instruction::StructNew(intrinsics.string));
79 Ok(ConstExpr::extended(instrs))
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use std::collections::BTreeMap;
86
87 #[test]
88 fn collect_union_of_field_names_alphabetical() {
89 use crate::ObjectField;
90 let mut a = BTreeMap::new();
91 a.insert("kind".to_string(), ObjectField::required(Type::Number));
92 a.insert("radius".to_string(), ObjectField::required(Type::Number));
93 let mut b = BTreeMap::new();
94 b.insert("kind".to_string(), ObjectField::required(Type::Number));
95 b.insert("height".to_string(), ObjectField::required(Type::Number));
96 b.insert("width".to_string(), ObjectField::required(Type::Number));
97 let shapes = vec![
98 Type::Object {
99 index: None,
100 fields: a,
101 },
102 Type::Object {
103 index: None,
104 fields: b,
105 },
106 ];
107 let names = collect(&shapes, &[]);
108 assert_eq!(
109 names,
110 vec![
111 "height".to_string(),
112 "kind".to_string(),
113 "radius".to_string(),
114 "width".to_string(),
115 ]
116 );
117 }
118}