componentize_qjs/
codegen.rs1use std::collections::HashSet;
4use wit_parser::{Resolve, Type, TypeDefKind, TypeId, WorldId, WorldItem};
5
6pub fn generate_shim(resolve: &Resolve, world_id: WorldId) -> String {
8 let mut ctx = EmitContext::new(resolve, world_id);
9 ctx.emit();
10 ctx.output()
11}
12
13struct EmitContext<'a> {
14 resolve: &'a Resolve,
15 world_id: WorldId,
16 lines: Vec<String>,
17 streams: HashSet<Option<Type>>,
18 futures: HashSet<Option<Type>>,
19}
20
21impl<'a> EmitContext<'a> {
22 fn new(resolve: &'a Resolve, world_id: WorldId) -> Self {
23 Self {
24 resolve,
25 world_id,
26 lines: Vec::new(),
27 streams: HashSet::new(),
28 futures: HashSet::new(),
29 }
30 }
31
32 fn line(&mut self, s: &str) {
33 self.lines.push(s.to_string());
34 }
35
36 fn output(self) -> String {
37 self.lines.join("\n") + "\n"
38 }
39
40 fn emit(&mut self) {
41 let world = &self.resolve.worlds[self.world_id];
42
43 for item in world.imports.values().chain(world.exports.values()) {
44 match item {
45 WorldItem::Function(f) => {
46 self.collect_from_function(f);
47 }
48 WorldItem::Interface { id, .. } => {
49 for f in self.resolve.interfaces[*id].functions.values() {
50 self.collect_from_function(f);
51 }
52 }
53 WorldItem::Type(id) => {
54 self.collect_from_type_id(*id);
55 }
56 }
57 }
58
59 self.line("globalThis.wit = {};");
60
61 let streams: Vec<_> = self.streams.iter().copied().collect();
62 if !streams.is_empty() {
63 self.emit_constructor("Stream", "__cqjs.makeStream", &streams);
64 }
65
66 let futures: Vec<_> = self.futures.iter().copied().collect();
67 if !futures.is_empty() {
68 self.emit_constructor("Future", "__cqjs.makeFuture", &futures);
69 }
70 }
71
72 fn emit_constructor(&mut self, name: &str, native_fn: &str, types: &[Option<Type>]) {
73 if types.len() == 1 {
74 self.line(&format!(
75 "wit.{name} = function(type) {{ return {native_fn}(type ?? 0); }};"
76 ));
77 } else {
78 self.line(&format!("wit.{name} = function(type) {{"));
79 self.line(&format!(
80 " if (type === undefined) throw new Error('{name} type required, use wit.{name}.<TYPE>');"
81 ));
82 self.line(&format!(" return {native_fn}(type);"));
83 self.line("};");
84 }
85
86 self.line(&format!("wit.{name}.types = {{}};"));
87 for (index, elem_ty) in types.iter().enumerate() {
88 let const_name = type_const_name(self.resolve, elem_ty.as_ref());
89 self.line(&format!(
90 "wit.{name}.{const_name} = {index}; wit.{name}.types.{const_name} = {index};"
91 ));
92 }
93 }
94
95 fn collect_from_function(&mut self, func: &wit_parser::Function) {
96 for (_, ty) in &func.params {
97 self.collect_from_type(ty);
98 }
99 if let Some(result) = &func.result {
100 self.collect_from_type(result);
101 }
102 }
103
104 fn collect_from_type(&mut self, ty: &Type) {
105 if let Type::Id(id) = ty {
106 self.collect_from_type_id(*id);
107 }
108 }
109
110 fn collect_from_type_id(&mut self, id: TypeId) {
111 let typedef = &self.resolve.types[id];
112 match &typedef.kind {
113 TypeDefKind::Stream(elem) => {
114 self.streams.insert(*elem);
115 if let Some(elem) = elem {
116 self.collect_from_type(elem);
117 }
118 }
119 TypeDefKind::Future(elem) => {
120 self.futures.insert(*elem);
121 if let Some(elem) = elem {
122 self.collect_from_type(elem);
123 }
124 }
125 TypeDefKind::Record(r) => {
126 let tys: Vec<_> = r.fields.iter().map(|f| f.ty).collect();
127 for ty in &tys {
128 self.collect_from_type(ty);
129 }
130 }
131 TypeDefKind::Tuple(t) => {
132 let tys = t.types.clone();
133 for ty in &tys {
134 self.collect_from_type(ty);
135 }
136 }
137 TypeDefKind::Variant(v) => {
138 let tys: Vec<_> = v.cases.iter().filter_map(|c| c.ty).collect();
139 for ty in &tys {
140 self.collect_from_type(ty);
141 }
142 }
143 TypeDefKind::Option(ty) => {
144 let ty = *ty;
145 self.collect_from_type(&ty);
146 }
147 TypeDefKind::Result(r) => {
148 let ok = r.ok;
149 let err = r.err;
150 if let Some(ty) = &ok {
151 self.collect_from_type(ty);
152 }
153 if let Some(ty) = &err {
154 self.collect_from_type(ty);
155 }
156 }
157 TypeDefKind::List(ty) => {
158 let ty = *ty;
159 self.collect_from_type(&ty);
160 }
161 TypeDefKind::Type(ty) => {
162 let ty = *ty;
163 self.collect_from_type(&ty);
164 }
165 _ => {}
166 }
167 }
168}
169
170fn type_const_name(resolve: &Resolve, ty: Option<&Type>) -> String {
171 match ty {
172 None => "UNIT".to_string(),
173 Some(Type::Bool) => "BOOL".to_string(),
174 Some(Type::U8) => "U8".to_string(),
175 Some(Type::S8) => "S8".to_string(),
176 Some(Type::U16) => "U16".to_string(),
177 Some(Type::S16) => "S16".to_string(),
178 Some(Type::U32) => "U32".to_string(),
179 Some(Type::S32) => "S32".to_string(),
180 Some(Type::U64) => "U64".to_string(),
181 Some(Type::S64) => "S64".to_string(),
182 Some(Type::F32) => "F32".to_string(),
183 Some(Type::F64) => "F64".to_string(),
184 Some(Type::Char) => "CHAR".to_string(),
185 Some(Type::String) => "STRING".to_string(),
186 Some(Type::ErrorContext) => "ERROR_CONTEXT".to_string(),
187 Some(Type::Id(id)) => typedef_const_name(resolve, *id),
188 }
189}
190
191fn typedef_const_name(resolve: &Resolve, id: TypeId) -> String {
192 let typedef = &resolve.types[id];
193
194 if let Some(name) = &typedef.name {
195 return name.to_uppercase().replace('-', "_");
196 }
197
198 match &typedef.kind {
200 TypeDefKind::Option(inner) => {
201 format!("OPTION_{}", type_const_name(resolve, Some(inner)))
202 }
203 TypeDefKind::Tuple(t) => {
204 let inner: Vec<String> = t
205 .types
206 .iter()
207 .map(|t| type_const_name(resolve, Some(t)))
208 .collect();
209 format!("TUPLE_{}", inner.join("_"))
210 }
211 TypeDefKind::Result(r) => {
212 let ok =
213 r.ok.as_ref()
214 .map(|t| type_const_name(resolve, Some(t)))
215 .unwrap_or("VOID".to_string());
216 let err = r
217 .err
218 .as_ref()
219 .map(|t| type_const_name(resolve, Some(t)))
220 .unwrap_or("VOID".to_string());
221 format!("RESULT_{ok}_{err}")
222 }
223 TypeDefKind::List(inner) => {
224 format!("LIST_{}", type_const_name(resolve, Some(inner)))
225 }
226 TypeDefKind::Type(inner) => type_const_name(resolve, Some(inner)),
227 _ => "OTHER".to_string(),
228 }
229}