1use alloc::collections::{BTreeMap, BTreeSet};
2use alloc::format;
3use alloc::string::String;
4use alloc::vec;
5use alloc::vec::Vec;
6use core::iter::once;
7use core::mem::{replace, take};
8
9use anyhow::Context;
10use pit_core::{Arg, ResTy};
11use portal_pc_waffle::{
12 util::new_sig, Block, BlockTarget, Export, ExportKind, Func, FuncDecl, FunctionBody, Import,
13 ImportKind, Module, Operator, SignatureData, Table, TableData, Type, Value, WithNullable,
14};
15pub fn add_op(f: &mut FunctionBody, args: &[Value], types: &[Type], op: Operator) -> Value{
16 let args = f.arg_pool.from_iter(args.iter().cloned());
17 let types = f.type_pool.from_iter(types.iter().cloned());
18 f.values.push(portal_pc_waffle::ValueDef::Operator(op, args, types))
19}
20use crate::get_interfaces;
23
24pub fn to_waffle_type(t: &pit_core::Arg, tpit: bool) -> portal_pc_waffle::Type {
29 match t {
30 pit_core::Arg::I32 => portal_pc_waffle::Type::I32,
31 pit_core::Arg::I64 => portal_pc_waffle::Type::I64,
32 pit_core::Arg::F32 => portal_pc_waffle::Type::F32,
33 pit_core::Arg::F64 => portal_pc_waffle::Type::F64,
34 pit_core::Arg::Resource {
35 ty,
36 nullable,
37 take,
38 ann,
39 } => {
40 if tpit {
41 portal_pc_waffle::Type::I32
42 } else {
43 portal_pc_waffle::Type::Heap(WithNullable {
44 nullable: true,
45 value: portal_pc_waffle::HeapType::ExternRef,
46 })
47 }
48 }
49 _ => todo!(),
50 }
51}
52pub fn to_waffle_type_in(
53 t: &pit_core::Arg,
54 tpit: bool,
55 module: &mut Module,
56) -> portal_pc_waffle::Type {
57 match t {
58 t => to_waffle_type(t, tpit),
59 }
60}
61pub fn to_waffle_sig(m: &mut Module, t: &pit_core::Sig, tpit: bool) -> portal_pc_waffle::Signature {
62 let s = portal_pc_waffle::SignatureData::Func {
63 params: once(if tpit {
64 Type::I32
65 } else {
66 portal_pc_waffle::Type::Heap(WithNullable {
67 nullable: true,
68 value: portal_pc_waffle::HeapType::ExternRef,
69 })
70 })
71 .chain(t.params.iter().map(|a| to_waffle_type_in(a, tpit, m)))
72 .collect(),
73 returns: t
74 .rets
75 .iter()
76 .map(|a| to_waffle_type_in(a, tpit, m))
77 .collect(),
78 shared: true,
79 };
80 return new_sig(m, s);
81}
82pub fn waffle_funcs(m: &mut Module, i: &pit_core::Interface, tpit: bool) -> BTreeMap<String, Func> {
83 return i
84 .methods
85 .iter()
86 .map(|(a, b)| {
87 let module = format!("{}pit/{}", i.rid_str(), if tpit { "t" } else { "" });
88 let name = a.clone();
89 if let Some(f) = m.imports.iter().find_map(|i| {
90 if i.module == module && i.name == name {
91 match &i.kind {
92 ImportKind::Func(f) => Some(*f),
93 _ => None,
94 }
95 } else {
96 None
97 }
98 }) {
99 return (a.clone(), f);
100 };
101 let s = to_waffle_sig(m, b, tpit);
102 let f = m.funcs.push(portal_pc_waffle::FuncDecl::Import(
103 s,
104 format!("{module}.{name}"),
105 ));
106 m.imports.push(Import {
107 module,
108 name,
109 kind: portal_pc_waffle::ImportKind::Func(f),
110 });
111 (a.clone(), f)
112 })
113 .collect();
114}
115pub fn canon(m: &mut Module, i: &pit_core::Interface, destruct: Option<Func>, name: &str) -> Func {
116 let tys = i
117 .methods
118 .iter()
119 .flat_map(|a| a.1.rets.iter())
120 .cloned()
121 .collect::<Vec<_>>();
122 let sig = new_sig(
123 m,
124 SignatureData::Func {
125 params: tys.iter().map(|a| to_waffle_type(a, false)).collect(),
126 returns: vec![portal_pc_waffle::Type::Heap(WithNullable {
127 nullable: true,
128 value: portal_pc_waffle::HeapType::ExternRef,
129 })],
130 shared: true,
131 },
132 );
133 let f = m
134 .funcs
135 .push(FuncDecl::Import(sig, format!("pit-canon/{}", i.rid_str())));
136 m.imports.push(Import {
137 module: format!("pit/{}", i.rid_str()),
138 name: format!("~{name}"),
139 kind: ImportKind::Func(f),
140 });
141 let mut j = 0;
142 for (s, meth) in i.methods.iter() {
143 let sig = SignatureData::Func {
144 params: tys.iter().map(|a| to_waffle_type_in(a, false, m)).collect(),
145 returns: meth
146 .rets
147 .iter()
148 .map(|a| to_waffle_type_in(a, false, m))
149 .collect(),
150 shared: true,
151 };
152 let sig = new_sig(m, sig);
153 let mut f = FunctionBody::new(&m, sig);
154 let args = f.blocks[f.entry]
155 .params
156 .iter()
157 .map(|a| a.1)
158 .collect::<Vec<_>>();
159 let r = meth
160 .rets
161 .iter()
162 .map(|_| {
163 let a = args[j];
164 j += 1;
165 a
166 })
167 .collect();
168 f.set_terminator(f.entry, portal_pc_waffle::Terminator::Return { values: r });
169 let f = m.funcs.push(FuncDecl::Body(
170 sig,
171 format!("pit-canon/{}/{s}", i.rid_str()),
172 f,
173 ));
174 m.exports.push(Export {
175 name: format!("pit/{}/~{name}/{s}", i.rid_str()),
176 kind: ExportKind::Func(f),
177 });
178 }
179 {
180 let sig = new_sig(
181 m,
182 SignatureData::Func {
183 params: vec![portal_pc_waffle::Type::Heap(WithNullable {
184 nullable: true,
185 value: portal_pc_waffle::HeapType::ExternRef,
186 })],
187 returns: vec![],
188 shared: true,
189 },
190 );
191 let dropper = m.funcs.push(FuncDecl::Import(
192 sig,
193 format!("pit-canon/{}--idrop", i.rid_str()),
194 ));
195 m.imports.push(Import {
196 module: format!("pit"),
197 name: format!("drop"),
198 kind: ImportKind::Func(dropper),
199 });
200 let sig = SignatureData::Func {
201 params: tys.iter().map(|a| to_waffle_type_in(a, false, m)).collect(),
202 returns: vec![],
203 shared: true,
204 };
205 let sig = new_sig(m, sig);
206 let f = match destruct {
207 None => {
208 let mut f = FunctionBody::new(&m, sig);
209 let args = f.blocks[f.entry]
210 .params
211 .iter()
212 .map(|a| a.1)
213 .collect::<Vec<_>>();
214 for (v, a) in args.iter().zip(tys.iter()) {
215 if let Arg::Resource {
216 ty,
217 nullable,
218 take,
219 ann,
220 } = a
221 {
222 f.add_op(
223 f.entry,
224 Operator::Call {
225 function_index: dropper,
226 },
227 &[*v],
228 &[],
229 );
230 }
231 }
232 f.set_terminator(
233 f.entry,
234 portal_pc_waffle::Terminator::Return { values: vec![] },
235 );
236 m.funcs.push(FuncDecl::Body(
237 sig,
238 format!("pit-canon/{}.drop", i.rid_str()),
239 f,
240 ))
241 }
242 Some(a) => a,
243 };
244 m.exports.push(Export {
245 name: format!("pit/{}/~{name}.drop", i.rid_str()),
246 kind: ExportKind::Func(f),
247 });
248 };
249 return f;
250}