pit_patch/
util.rs

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}
20// use waffle_ast::{add_op, results_ref_2, Builder, Expr};
21
22use crate::get_interfaces;
23
24// pub use waffle_ast::tutils::*;
25
26// use portal_pc_waffle::{util::new_sig, Module};
27
28pub 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}