wit_bindgen_moonbit/
lib.rs

1use anyhow::Result;
2use core::panic;
3use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
4use std::{collections::HashMap, fmt::Write, mem, ops::Deref};
5use wit_bindgen_core::{
6    abi::{self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType},
7    dealias, uwrite, uwriteln,
8    wit_parser::{
9        Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle,
10        Int, InterfaceId, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind,
11        TypeId, TypeOwner, Variant, WorldId, WorldKey,
12    },
13    Direction, Files, InterfaceGenerator as _, Ns, Source, WorldGenerator,
14};
15
16// Assumptions:
17// - Data: u8 -> Byte, s8 | s16 | s32 -> Int, u16 | u32 -> UInt, s64 -> Int64, u64 -> UInt64, f32 | f64 -> Double, address -> Int
18// - Encoding: UTF16
19// - Lift/Lower list<T>: T == Int/UInt/Int64/UInt64/Float/Double -> FixedArray[T], T == Byte -> Bytes, T == Char -> String
20// Organization:
21// - one package per interface (export and import are treated as different interfaces)
22// - ffi utils are under `./ffi`, and the project entrance (package as link target) is under `./gen`
23// TODO: Export will share the type signatures with the import by using a newtype alias
24
25const FFI_DIR: &str = "ffi";
26
27const FFI: &str = r#"
28pub extern "wasm" fn extend16(value : Int) -> Int =
29  #|(func (param i32) (result i32) local.get 0 i32.extend16_s)
30
31pub extern "wasm" fn extend8(value : Int) -> Int =
32  #|(func (param i32) (result i32) local.get 0 i32.extend8_s)
33
34pub extern "wasm" fn store8(offset : Int, value : Int) =
35  #|(func (param i32) (param i32) local.get 0 local.get 1 i32.store8)
36
37pub extern "wasm" fn load8_u(offset : Int) -> Int =
38  #|(func (param i32) (result i32) local.get 0 i32.load8_u)
39
40pub extern "wasm" fn load8(offset : Int) -> Int =
41  #|(func (param i32) (result i32) local.get 0 i32.load8_s)
42
43pub extern "wasm" fn store16(offset : Int, value : Int) =
44  #|(func (param i32) (param i32) local.get 0 local.get 1 i32.store16)
45
46pub extern "wasm" fn load16(offset : Int) -> Int =
47  #|(func (param i32) (result i32) local.get 0 i32.load16_s)
48
49pub extern "wasm" fn load16_u(offset : Int) -> Int =
50  #|(func (param i32) (result i32) local.get 0 i32.load16_u)
51
52pub extern "wasm" fn store32(offset : Int, value : Int) =
53  #|(func (param i32) (param i32) local.get 0 local.get 1 i32.store)
54
55pub extern "wasm" fn load32(offset : Int) -> Int =
56  #|(func (param i32) (result i32) local.get 0 i32.load)
57
58pub extern "wasm" fn store64(offset : Int, value : Int64) =
59  #|(func (param i32) (param i64) local.get 0 local.get 1 i64.store)
60
61pub extern "wasm" fn load64(offset : Int) -> Int64 =
62  #|(func (param i32) (result i64) local.get 0 i64.load)
63
64pub extern "wasm" fn storef32(offset : Int, value : Float) =
65  #|(func (param i32) (param f32) local.get 0 local.get 1 f32.store)
66
67pub extern "wasm" fn loadf32(offset : Int) -> Float =
68  #|(func (param i32) (result f32) local.get 0 f32.load)
69
70pub extern "wasm" fn storef64(offset : Int, value : Double) =
71  #|(func (param i32) (param f64) local.get 0 local.get 1 f64.store)
72
73pub extern "wasm" fn loadf64(offset : Int) -> Double =
74  #|(func (param i32) (result f64) local.get 0 f64.load)
75
76pub extern "wasm" fn f32_to_i32(value : Float) -> Int =
77  #|(func (param f32) (result i32) local.get 0 f32.convert_i32_s)
78
79pub extern "wasm" fn f32_to_i64(value : Float) -> Int64 =
80  #|(func (param f32) (result i64) local.get 0 f32.convert_i64_s)
81
82// set pseudo header; allocate extra bytes for string
83pub extern "wasm" fn malloc(size : Int) -> Int =
84  #|(func (param i32) (result i32) (local i32)
85  #| local.get 0 i32.const 4 i32.add call $moonbit.gc.malloc
86  #| local.tee 1 i32.const 0 call $moonbit.init_array8
87  #| local.get 1 i32.const 8 i32.add)
88
89pub extern "wasm" fn free(position : Int) =
90  #|(func (param i32) local.get 0 i32.const 8 i32.sub call $moonbit.decref)
91
92extern "wasm" fn copy(dest : Int, src : Int, len : Int) =
93  #|(func (param i32) (param i32) (param i32) local.get 0 local.get 1 local.get 2 memory.copy)
94
95pub extern "wasm" fn str2ptr(str : String) -> Int =
96  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
97
98pub extern "wasm" fn ptr2str(ptr : Int, len : Int) -> String =
99  #|(func (param i32) (param i32) (result i32) (local i32)
100  #| local.get 0 i32.const 8 i32.sub local.tee 2
101  #| local.get 1 call $moonbit.init_array16
102  #| local.get 2)
103
104pub extern "wasm" fn bytes2ptr(bytes : FixedArray[Byte]) -> Int =
105  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
106
107pub extern "wasm" fn ptr2bytes(ptr : Int, len : Int) -> FixedArray[Byte] =
108  #|(func (param i32) (param i32) (result i32) (local i32)
109  #| local.get 0 i32.const 8 i32.sub local.tee 2
110  #| local.get 1 call $moonbit.init_array8
111  #| local.get 2)
112
113pub extern "wasm" fn uint_array2ptr(array : FixedArray[UInt]) -> Int =
114  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
115
116pub extern "wasm" fn uint64_array2ptr(array : FixedArray[UInt64]) -> Int =
117  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
118
119pub extern "wasm" fn int_array2ptr(array : FixedArray[Int]) -> Int =
120  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
121
122pub extern "wasm" fn int64_array2ptr(array : FixedArray[Int64]) -> Int =
123  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
124
125pub extern "wasm" fn float_array2ptr(array : FixedArray[Float]) -> Int =
126  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
127
128pub extern "wasm" fn double_array2ptr(array : FixedArray[Double]) -> Int =
129  #|(func (param i32) (result i32) local.get 0 i32.const 8 i32.add)
130
131pub extern "wasm" fn ptr2uint_array(ptr : Int, len : Int) -> FixedArray[UInt] =
132  #|(func (param i32) (param i32) (result i32) (local i32)
133  #| local.get 0 i32.const 8 i32.sub local.tee 2
134  #| local.get 1 call $moonbit.init_array32
135  #| local.get 2)
136
137pub extern "wasm" fn ptr2int_array(ptr : Int, len : Int) -> FixedArray[Int] =
138  #|(func (param i32) (param i32) (result i32) (local i32)
139  #| local.get 0 i32.const 8 i32.sub local.tee 2
140  #| local.get 1 call $moonbit.init_array32
141  #| local.get 2)
142
143pub extern "wasm" fn ptr2float_array(ptr : Int, len : Int) -> FixedArray[Float] =
144  #|(func (param i32) (param i32) (result i32) (local i32)
145  #| local.get 0 i32.const 8 i32.sub local.tee 2
146  #| local.get 1 call $moonbit.init_array32
147  #| local.get 2)
148
149pub extern "wasm" fn ptr2uint64_array(ptr : Int, len : Int) -> FixedArray[UInt64] =
150  #|(func (param i32) (param i32) (result i32) (local i32)
151  #| local.get 0 i32.const 8 i32.sub local.tee 2
152  #| local.get 1 call $moonbit.init_array64
153  #| local.get 2)
154
155pub extern "wasm" fn ptr2int64_array(ptr : Int, len : Int) -> FixedArray[Int64] =
156  #|(func (param i32) (param i32) (result i32) (local i32)
157  #| local.get 0 i32.const 8 i32.sub local.tee 2
158  #| local.get 1 call $moonbit.init_array64
159  #| local.get 2)
160
161pub extern "wasm" fn ptr2double_array(ptr : Int, len : Int) -> FixedArray[Double] =
162  #|(func (param i32) (param i32) (result i32) (local i32)
163  #| local.get 0 i32.const 8 i32.sub local.tee 2
164  #| local.get 1 call $moonbit.init_array64
165  #| local.get 2)
166
167pub fn cabi_realloc(
168    src_offset : Int,
169    src_size : Int,
170    _dst_alignment : Int,
171    dst_size : Int
172) -> Int {{
173    // malloc
174    if src_offset == 0 && src_size == 0 {{
175        return malloc(dst_size)
176    }}
177    // free
178    if dst_size == 0 {{
179        free(src_offset)
180        return 0
181    }}
182    // realloc
183    let dst = malloc(dst_size)
184    copy(dst, src_offset, if src_size < dst_size { src_size } else { dst_size })
185    free(src_offset)
186    dst
187}}
188
189pub(open) trait Any {}
190pub(all) struct Cleanup {
191    address : Int
192    size : Int
193    align : Int
194}
195"#;
196
197#[derive(Default, Debug, Clone)]
198#[cfg_attr(feature = "clap", derive(clap::Args))]
199pub struct Opts {
200    /// Whether or not to derive Show for all types
201    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
202    pub derive_show: bool,
203    /// Whether or not to derive Eq for all types
204    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
205    pub derive_eq: bool,
206    /// Whether or not to declare as Error type for types ".*error"
207    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
208    pub derive_error: bool,
209    /// Whether or not to generate stub files ; useful for update after WIT change
210    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
211    pub ignore_stub: bool,
212    /// Whether or not to generate moon.mod.json ; useful if the project is part of a larger project
213    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
214    pub ignore_module_file: bool,
215    /// The package/dir to generate the program entrance
216    #[cfg_attr(feature = "clap", arg(long, default_value = "gen"))]
217    pub gen_dir: String,
218    /// The project name ; or the package path prefix if the project is part of a larger project
219    #[cfg_attr(feature = "clap", arg(long, default_value = None))]
220    pub project_name: Option<String>,
221}
222
223impl Opts {
224    pub fn build(&self) -> Box<dyn WorldGenerator> {
225        Box::new(MoonBit {
226            opts: self.clone(),
227            ..MoonBit::default()
228        })
229    }
230}
231
232struct InterfaceFragment {
233    src: String,
234    ffi: String,
235    stub: String,
236}
237
238#[derive(Default)]
239struct Imports {
240    packages: HashMap<String, String>,
241    ns: Ns,
242}
243
244#[derive(Default)]
245pub struct MoonBit {
246    opts: Opts,
247    name: String,
248    needs_cleanup: bool,
249    import_interface_fragments: HashMap<String, Vec<InterfaceFragment>>,
250    export_interface_fragments: HashMap<String, Vec<InterfaceFragment>>,
251    import_world_fragments: Vec<InterfaceFragment>,
252    export_world_fragments: Vec<InterfaceFragment>,
253    sizes: SizeAlign,
254    import_interface_names: HashMap<InterfaceId, String>,
255    export_interface_names: HashMap<InterfaceId, String>,
256    interface_ns: Ns,
257    // dependencies between packages
258    package_import: HashMap<String, Imports>,
259    export: HashMap<String, String>,
260    export_ns: Ns,
261    // return area allocation
262    return_area_size: ArchitectureSize,
263    return_area_align: Alignment,
264}
265
266impl MoonBit {
267    fn interface<'a>(
268        &'a mut self,
269        resolve: &'a Resolve,
270        name: &'a str,
271        module: &'a str,
272        direction: Direction,
273    ) -> InterfaceGenerator<'a> {
274        InterfaceGenerator {
275            src: String::new(),
276            stub: String::new(),
277            ffi: String::new(),
278            gen: self,
279            resolve,
280            name,
281            module,
282            direction,
283        }
284    }
285}
286
287impl WorldGenerator for MoonBit {
288    fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
289        self.name = world_name(resolve, world);
290        self.sizes.fill(resolve);
291    }
292
293    fn import_interface(
294        &mut self,
295        resolve: &Resolve,
296        key: &WorldKey,
297        id: InterfaceId,
298        files: &mut Files,
299    ) -> Result<()> {
300        let name = interface_name(resolve, key);
301        let name = self.interface_ns.tmp(&name);
302        self.import_interface_names.insert(id, name.clone());
303
304        if let Some(content) = &resolve.interfaces[id].docs.contents {
305            if !content.is_empty() {
306                files.push(
307                    &format!("{}/README.md", name.replace(".", "/")),
308                    content.as_bytes(),
309                );
310            }
311        }
312
313        let module = &resolve.name_world_key(key);
314        let mut gen = self.interface(resolve, &name, module, Direction::Import);
315        gen.types(id);
316
317        for (_, func) in resolve.interfaces[id].functions.iter() {
318            gen.import(module, func);
319        }
320
321        gen.add_interface_fragment();
322
323        Ok(())
324    }
325
326    fn import_funcs(
327        &mut self,
328        resolve: &Resolve,
329        world: WorldId,
330        funcs: &[(&str, &Function)],
331        _files: &mut Files,
332    ) {
333        let name = world_name(resolve, world);
334        let mut gen = self.interface(resolve, &name, "$root", Direction::Import);
335
336        for (_, func) in funcs {
337            gen.import("$root", func);
338        }
339
340        gen.add_world_fragment();
341    }
342
343    fn export_interface(
344        &mut self,
345        resolve: &Resolve,
346        key: &WorldKey,
347        id: InterfaceId,
348        files: &mut Files,
349    ) -> Result<()> {
350        let name = format!("{}.{}", self.opts.gen_dir, interface_name(resolve, key));
351        let name = self.interface_ns.tmp(&name);
352        self.export_interface_names.insert(id, name.clone());
353
354        if let Some(content) = &resolve.interfaces[id].docs.contents {
355            if !content.is_empty() {
356                files.push(
357                    &format!("{}/README.md", name.replace(".", "/")),
358                    content.as_bytes(),
359                );
360            }
361        }
362
363        let module = &resolve.name_world_key(key);
364        let mut gen = self.interface(resolve, &name, module, Direction::Export);
365        gen.types(id);
366
367        for (_, func) in resolve.interfaces[id].functions.iter() {
368            gen.export(Some(module), func);
369        }
370
371        gen.add_interface_fragment();
372        Ok(())
373    }
374
375    fn export_funcs(
376        &mut self,
377        resolve: &Resolve,
378        world: WorldId,
379        funcs: &[(&str, &Function)],
380        _files: &mut Files,
381    ) -> Result<()> {
382        let name = format!("{}.{}", self.opts.gen_dir, world_name(resolve, world));
383        let mut gen = self.interface(resolve, &name, "$root", Direction::Export);
384
385        for (_, func) in funcs {
386            gen.export(None, func);
387        }
388
389        gen.add_world_fragment();
390        Ok(())
391    }
392
393    fn import_types(
394        &mut self,
395        resolve: &Resolve,
396        world: WorldId,
397        types: &[(&str, TypeId)],
398        _files: &mut Files,
399    ) {
400        let name = world_name(resolve, world);
401        let mut gen = self.interface(resolve, &name, "$root", Direction::Import);
402
403        for (ty_name, ty) in types {
404            gen.define_type(ty_name, *ty);
405        }
406
407        gen.add_world_fragment();
408    }
409
410    fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
411        let project_name = self
412            .opts
413            .project_name
414            .clone()
415            .or(resolve.worlds[id].package.map(|id| {
416                let package = &resolve.packages[id].name;
417                format!("{}/{}", package.namespace, package.name)
418            }))
419            .unwrap_or("generated".into());
420        let name = world_name(resolve, id);
421
422        if let Some(content) = &resolve.worlds[id].docs.contents {
423            if !content.is_empty() {
424                files.push(
425                    &format!("{}/README.md", name.replace(".", "/")),
426                    content.as_bytes(),
427                );
428            }
429        }
430
431        let version = env!("CARGO_PKG_VERSION");
432
433        let generate_pkg_definition = |name: &String, files: &mut Files| {
434            let directory = name.replace('.', "/");
435            let imports: Option<&Imports> = self.package_import.get(name);
436            if let Some(imports) = imports {
437                let mut deps = imports
438                    .packages
439                    .iter()
440                    .map(|(k, v)| {
441                        format!(
442                            "{{ \"path\" : \"{project_name}/{}\", \"alias\" : \"{}\" }}",
443                            k.replace(".", "/"),
444                            v
445                        )
446                    })
447                    .collect::<Vec<_>>();
448                deps.sort();
449
450                files.push(
451                    &format!("{directory}/moon.pkg.json"),
452                    format!("{{ \"import\": [{}] }}", deps.join(", ")).as_bytes(),
453                );
454            } else {
455                files.push(
456                    &format!("{directory}/moon.pkg.json"),
457                    format!("{{ }}").as_bytes(),
458                );
459            }
460        };
461
462        // Import world fragments
463        let mut src = Source::default();
464        let mut ffi = Source::default();
465        wit_bindgen_core::generated_preamble(&mut src, version);
466        wit_bindgen_core::generated_preamble(&mut ffi, version);
467        self.import_world_fragments.iter().for_each(|f| {
468            uwriteln!(src, "{}", f.src);
469            uwriteln!(ffi, "{}", f.ffi);
470            assert!(f.stub.is_empty());
471        });
472
473        let directory = name.replace('.', "/");
474        files.push(&format!("{directory}/import.mbt"), indent(&src).as_bytes());
475        files.push(
476            &format!("{directory}/ffi_import.mbt"),
477            indent(&ffi).as_bytes(),
478        );
479        generate_pkg_definition(&name, files);
480
481        // Export world fragments
482        let mut src = Source::default();
483        let mut stub = Source::default();
484        wit_bindgen_core::generated_preamble(&mut src, version);
485        generated_preamble(&mut stub, version);
486        self.export_world_fragments.iter().for_each(|f| {
487            uwriteln!(src, "{}", f.src);
488            uwriteln!(stub, "{}", f.stub);
489        });
490
491        files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
492        if !self.opts.ignore_stub {
493            files.push(
494                &format!("{}/{directory}/stub.mbt", self.opts.gen_dir),
495                indent(&stub).as_bytes(),
496            );
497            generate_pkg_definition(&format!("{}.{}", self.opts.gen_dir, name), files);
498        }
499
500        let generate_ffi =
501            |directory: String, fragments: &[InterfaceFragment], files: &mut Files| {
502                let b = fragments
503                    .iter()
504                    .map(|f| f.ffi.deref())
505                    .collect::<Vec<_>>()
506                    .join("\n");
507
508                let mut body = Source::default();
509                wit_bindgen_core::generated_preamble(&mut body, version);
510                uwriteln!(&mut body, "{b}");
511
512                files.push(
513                    &format!(
514                        "{}/{}_export.mbt",
515                        self.opts.gen_dir,
516                        directory.to_snake_case()
517                    ),
518                    indent(&body).as_bytes(),
519                );
520            };
521
522        generate_ffi(directory, &self.export_world_fragments, files);
523
524        // Import interface fragments
525        for (name, fragments) in &self.import_interface_fragments {
526            let mut src = Source::default();
527            let mut ffi = Source::default();
528            wit_bindgen_core::generated_preamble(&mut src, version);
529            wit_bindgen_core::generated_preamble(&mut ffi, version);
530            fragments.iter().for_each(|f| {
531                uwriteln!(src, "{}", f.src);
532                uwriteln!(ffi, "{}", f.ffi);
533                assert!(f.stub.is_empty());
534            });
535
536            let directory = name.replace('.', "/");
537            files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
538            files.push(&format!("{directory}/ffi.mbt"), indent(&ffi).as_bytes());
539            generate_pkg_definition(&name, files);
540        }
541
542        // Export interface fragments
543        for (name, fragments) in &self.export_interface_fragments {
544            let mut src = Source::default();
545            let mut stub = Source::default();
546            wit_bindgen_core::generated_preamble(&mut src, version);
547            generated_preamble(&mut stub, version);
548            fragments.iter().for_each(|f| {
549                uwriteln!(src, "{}", f.src);
550                uwriteln!(stub, "{}", f.stub);
551            });
552
553            let directory = name.replace('.', "/");
554            files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
555            if !self.opts.ignore_stub {
556                files.push(&format!("{directory}/stub.mbt"), indent(&stub).as_bytes());
557                generate_pkg_definition(&name, files);
558            }
559            generate_ffi(directory, fragments, files);
560        }
561
562        // Export FFI Utils
563        let mut body = Source::default();
564        wit_bindgen_core::generated_preamble(&mut body, version);
565        body.push_str(FFI);
566        files.push(&format!("{FFI_DIR}/top.mbt"), indent(&body).as_bytes());
567        files.push(
568            &format!("{FFI_DIR}/moon.pkg.json"),
569            "{ \"warn-list\": \"-44\", \"supported-targets\": [\"wasm\"] }".as_bytes(),
570        );
571
572        // Export project files
573        if !self.opts.ignore_stub && !self.opts.ignore_module_file {
574            let mut body = Source::default();
575            uwriteln!(
576                &mut body,
577                "{{ \"name\": \"{project_name}\", \"preferred-target\": \"wasm\" }}"
578            );
579            files.push(&format!("moon.mod.json"), body.as_bytes());
580        }
581
582        let export_dir = self.opts.gen_dir.clone();
583
584        // Export project entry point
585        let mut gen = self.interface(resolve, &export_dir.as_str(), "", Direction::Export);
586        let ffi_qualifier = gen.qualify_package(FFI_DIR);
587
588        let mut body = Source::default();
589        wit_bindgen_core::generated_preamble(&mut body, version);
590        uwriteln!(
591            &mut body,
592            "
593            pub fn cabi_realloc(
594                src_offset : Int,
595                src_size : Int,
596                dst_alignment : Int,
597                dst_size : Int
598            ) -> Int {{
599                {ffi_qualifier}cabi_realloc(src_offset, src_size, dst_alignment, dst_size)
600            }}
601            "
602        );
603        if !self.return_area_size.is_empty() {
604            uwriteln!(
605                &mut body,
606                "
607                let return_area : Int = {ffi_qualifier}malloc({})
608                ",
609                self.return_area_size.size_wasm32(),
610            );
611        }
612        files.push(
613            &format!("{}/ffi.mbt", self.opts.gen_dir),
614            indent(&body).as_bytes(),
615        );
616        self.export
617            .insert("cabi_realloc".into(), "cabi_realloc".into());
618
619        let mut body = Source::default();
620        let mut exports = self
621            .export
622            .iter()
623            .map(|(k, v)| format!("\"{k}:{v}\""))
624            .collect::<Vec<_>>();
625        exports.sort();
626
627        uwrite!(
628            &mut body,
629            r#"
630            {{
631                "link": {{
632                    "wasm": {{
633                        "exports": [{}],
634                        "export-memory-name": "memory",
635                        "heap-start-address": 16
636                    }}
637                }}
638            "#,
639            exports.join(", ")
640        );
641        if let Some(imports) = self.package_import.get(&self.opts.gen_dir) {
642            let mut deps = imports
643                .packages
644                .iter()
645                .map(|(k, v)| {
646                    format!(
647                        "{{ \"path\" : \"{project_name}/{}\", \"alias\" : \"{}\" }}",
648                        k.replace(".", "/"),
649                        v
650                    )
651                })
652                .collect::<Vec<_>>();
653            deps.sort();
654
655            uwrite!(&mut body, "    ,\"import\": [{}]", deps.join(", "));
656        }
657        uwrite!(
658            &mut body,
659            "
660            }}
661            ",
662        );
663        files.push(
664            &format!("{}/moon.pkg.json", self.opts.gen_dir,),
665            indent(&body).as_bytes(),
666        );
667
668        Ok(())
669    }
670}
671
672struct InterfaceGenerator<'a> {
673    src: String,
674    stub: String,
675    ffi: String,
676    gen: &'a mut MoonBit,
677    resolve: &'a Resolve,
678    // The current interface getting generated
679    name: &'a str,
680    module: &'a str,
681    direction: Direction,
682}
683
684impl InterfaceGenerator<'_> {
685    fn qualify_package(&mut self, name: &str) -> String {
686        if name != self.name {
687            let imports = self
688                .gen
689                .package_import
690                .entry(
691                    // This is a hack: the exported ffi calls are actually under the gen directory
692                    if self.direction == Direction::Export && name == FFI_DIR {
693                        self.gen.opts.gen_dir.clone()
694                    } else {
695                        self.name.to_string()
696                    },
697                )
698                .or_default();
699            if let Some(alias) = imports.packages.get(name) {
700                return format!("@{}.", alias);
701            } else {
702                let alias = imports
703                    .ns
704                    .tmp(&name.split(".").last().unwrap().to_lower_camel_case());
705                imports
706                    .packages
707                    .entry(name.to_string())
708                    .or_insert(alias.clone());
709                return format!("@{}.", alias);
710            }
711        } else {
712            "".into()
713        }
714    }
715    fn qualifier(&mut self, ty: &TypeDef) -> String {
716        if let TypeOwner::Interface(id) = &ty.owner {
717            if let Some(name) = self.gen.export_interface_names.get(id) {
718                if name != self.name {
719                    return self.qualify_package(&name.clone());
720                }
721            } else if let Some(name) = self.gen.import_interface_names.get(id) {
722                if name != self.name {
723                    return self.qualify_package(&name.clone());
724                }
725            }
726        } else if let TypeOwner::World(id) = &ty.owner {
727            let name = world_name(self.resolve, *id);
728            if name != self.name {
729                return self.qualify_package(&name.clone());
730            }
731        }
732
733        String::new()
734    }
735
736    fn add_interface_fragment(self) {
737        match self.direction {
738            Direction::Import => {
739                self.gen
740                    .import_interface_fragments
741                    .entry(self.name.to_owned())
742                    .or_default()
743                    .push(InterfaceFragment {
744                        src: self.src,
745                        stub: self.stub,
746                        ffi: self.ffi,
747                    });
748            }
749            Direction::Export => {
750                self.gen
751                    .export_interface_fragments
752                    .entry(self.name.to_owned())
753                    .or_default()
754                    .push(InterfaceFragment {
755                        src: self.src,
756                        stub: self.stub,
757                        ffi: self.ffi,
758                    });
759            }
760        }
761    }
762
763    fn add_world_fragment(self) {
764        match self.direction {
765            Direction::Import => {
766                self.gen.import_world_fragments.push(InterfaceFragment {
767                    src: self.src,
768                    stub: self.stub,
769                    ffi: self.ffi,
770                });
771            }
772            Direction::Export => {
773                self.gen.export_world_fragments.push(InterfaceFragment {
774                    src: self.src,
775                    stub: self.stub,
776                    ffi: self.ffi,
777                });
778            }
779        }
780    }
781
782    fn import(&mut self, module: &str, func: &Function) {
783        let mut bindgen = FunctionBindgen::new(
784            self,
785            &func.name,
786            self.name,
787            func.params
788                .iter()
789                .map(|(name, _)| name.to_moonbit_ident())
790                .collect(),
791        );
792
793        abi::call(
794            bindgen.gen.resolve,
795            AbiVariant::GuestImport,
796            LiftLower::LowerArgsLiftResults,
797            func,
798            &mut bindgen,
799            false,
800        );
801
802        let src = bindgen.src;
803
804        let cleanup_list = if bindgen.needs_cleanup_list {
805            self.gen.needs_cleanup = true;
806
807            let ffi_qualifier = self.qualify_package(FFI_DIR);
808
809            format!(
810                r#"let cleanupList : Array[{ffi_qualifier}Cleanup] = []
811                   let ignoreList : Array[&{ffi_qualifier}Any] = []"#
812            )
813        } else {
814            String::new()
815        };
816
817        let name = &func.name;
818
819        let sig = self.resolve.wasm_signature(AbiVariant::GuestImport, func);
820
821        let result_type = match &sig.results[..] {
822            [] => "".into(),
823            [result] => format!("-> {}", wasm_type(*result)),
824            _ => unreachable!(),
825        };
826
827        let camel_name = func.name.to_upper_camel_case();
828
829        let params = sig
830            .params
831            .iter()
832            .enumerate()
833            .map(|(i, param)| {
834                let ty = wasm_type(*param);
835                format!("p{i} : {ty}")
836            })
837            .collect::<Vec<_>>()
838            .join(", ");
839
840        let sig = self.sig_string(func, false);
841
842        uwriteln!(
843            self.ffi,
844            r#"fn wasmImport{camel_name}({params}) {result_type} = "{module}" "{name}""#
845        );
846
847        print_docs(&mut self.src, &func.docs);
848
849        uwrite!(
850            self.src,
851            r#"
852            {sig} {{
853              {cleanup_list}
854              {src}
855            }}
856            "#
857        );
858    }
859
860    fn export(&mut self, interface_name: Option<&str>, func: &Function) {
861        let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);
862
863        let func_sig = self.sig_string(func, true);
864
865        let export_name = func.legacy_core_export_name(interface_name);
866
867        let export_dir = self.gen.opts.gen_dir.clone();
868
869        let mut toplevel_generator = self.gen.interface(
870            self.resolve,
871            export_dir.as_str(),
872            self.module,
873            Direction::Export,
874        );
875
876        let mut bindgen = FunctionBindgen::new(
877            &mut toplevel_generator,
878            &func.name,
879            self.name,
880            (0..sig.params.len()).map(|i| format!("p{i}")).collect(),
881        );
882
883        abi::call(
884            bindgen.gen.resolve,
885            AbiVariant::GuestExport,
886            LiftLower::LiftArgsLowerResults,
887            func,
888            &mut bindgen,
889            false,
890        );
891
892        assert!(!bindgen.needs_cleanup_list);
893
894        let src = bindgen.src;
895
896        assert!(toplevel_generator.src.is_empty());
897        assert!(toplevel_generator.ffi.is_empty());
898
899        let result_type = match &sig.results[..] {
900            [] => "Unit",
901            [result] => wasm_type(*result),
902            _ => unreachable!(),
903        };
904
905        let camel_name = func.name.to_upper_camel_case();
906
907        let func_name = self.gen.export_ns.tmp(&format!("wasmExport{camel_name}"));
908
909        let params = sig
910            .params
911            .iter()
912            .enumerate()
913            .map(|(i, param)| {
914                let ty = wasm_type(*param);
915                format!("p{i} : {ty}")
916            })
917            .collect::<Vec<_>>()
918            .join(", ");
919
920        uwrite!(
921            self.ffi,
922            r#"
923            pub fn {func_name}({params}) -> {result_type} {{
924                {src}
925            }}
926            "#,
927        );
928        self.gen.export.insert(func_name, format!("{export_name}"));
929
930        if abi::guest_export_needs_post_return(self.resolve, func) {
931            let params = sig
932                .results
933                .iter()
934                .enumerate()
935                .map(|(i, param)| {
936                    let ty = wasm_type(*param);
937                    format!("p{i} : {ty}")
938                })
939                .collect::<Vec<_>>()
940                .join(", ");
941
942            let mut bindgen = FunctionBindgen::new(
943                self,
944                "INVALID",
945                self.name,
946                (0..sig.results.len()).map(|i| format!("p{i}")).collect(),
947            );
948
949            abi::post_return(bindgen.gen.resolve, func, &mut bindgen);
950
951            let src = bindgen.src;
952
953            let func_name = self
954                .gen
955                .export_ns
956                .tmp(&format!("wasmExport{camel_name}PostReturn"));
957
958            uwrite!(
959                self.ffi,
960                r#"
961                pub fn {func_name}({params}) -> Unit {{
962                    {src}
963                }}
964                "#
965            );
966            self.gen
967                .export
968                .insert(func_name, format!("cabi_post_{export_name}"));
969        }
970
971        print_docs(&mut self.stub, &func.docs);
972        uwrite!(
973            self.stub,
974            r#"
975            {func_sig} {{
976                ...
977            }}
978            "#
979        );
980    }
981
982    fn type_name(&mut self, ty: &Type, type_variable: bool) -> String {
983        match ty {
984            Type::Bool => "Bool".into(),
985            Type::U8 => "Byte".into(),
986            Type::S32 | Type::S8 | Type::S16 => "Int".into(),
987            Type::U16 | Type::U32 => "UInt".into(),
988            Type::Char => "Char".into(),
989            Type::U64 => "UInt64".into(),
990            Type::S64 => "Int64".into(),
991            Type::F32 => "Float".into(),
992            Type::F64 => "Double".into(),
993            Type::String => "String".into(),
994            Type::ErrorContext => todo!("moonbit error context type name"),
995            Type::Id(id) => {
996                let ty = &self.resolve.types[dealias(self.resolve, *id)];
997                match &ty.kind {
998                    TypeDefKind::Type(ty) => self.type_name(ty, type_variable),
999                    TypeDefKind::List(ty) => {
1000                        if type_variable {
1001                            match ty {
1002                                Type::U8
1003                                | Type::U32
1004                                | Type::U64
1005                                | Type::S32
1006                                | Type::S64
1007                                | Type::F32
1008                                | Type::F64 => {
1009                                    format!("FixedArray[{}]", self.type_name(ty, type_variable))
1010                                }
1011                                _ => format!("Array[{}]", self.type_name(ty, type_variable)),
1012                            }
1013                        } else {
1014                            "Array".into()
1015                        }
1016                    }
1017                    TypeDefKind::Tuple(tuple) => {
1018                        if type_variable {
1019                            format!(
1020                                "({})",
1021                                tuple
1022                                    .types
1023                                    .iter()
1024                                    .map(|ty| self.type_name(ty, type_variable))
1025                                    .collect::<Vec<_>>()
1026                                    .join(", ")
1027                            )
1028                        } else {
1029                            unreachable!()
1030                        }
1031                    }
1032                    TypeDefKind::Option(ty) => {
1033                        if type_variable {
1034                            format!("{}?", self.type_name(ty, type_variable))
1035                        } else {
1036                            "Option".into()
1037                        }
1038                    }
1039                    TypeDefKind::Result(result) => {
1040                        if type_variable {
1041                            let mut name = |ty: &Option<Type>| {
1042                                ty.as_ref()
1043                                    .map(|ty| self.type_name(ty, true))
1044                                    .unwrap_or_else(|| "Unit".into())
1045                            };
1046                            let ok = name(&result.ok);
1047                            let err = name(&result.err);
1048
1049                            format!("Result[{ok}, {err}]")
1050                        } else {
1051                            "Result".into()
1052                        }
1053                    }
1054                    TypeDefKind::Handle(handle) => {
1055                        let ty = match handle {
1056                            Handle::Own(ty) => ty,
1057                            Handle::Borrow(ty) => ty,
1058                        };
1059                        let ty = &self.resolve.types[dealias(self.resolve, *ty)];
1060                        if let Some(name) = &ty.name {
1061                            format!("{}{}", self.qualifier(ty), name.to_moonbit_type_ident())
1062                        } else {
1063                            unreachable!()
1064                        }
1065                    }
1066                    _ => {
1067                        if let Some(name) = &ty.name {
1068                            format!("{}{}", self.qualifier(ty), name.to_moonbit_type_ident())
1069                        } else {
1070                            unreachable!()
1071                        }
1072                    }
1073                }
1074            }
1075        }
1076    }
1077
1078    fn non_empty_type<'a>(&self, ty: Option<&'a Type>) -> Option<&'a Type> {
1079        if let Some(ty) = ty {
1080            let id = match ty {
1081                Type::Id(id) => *id,
1082                _ => return Some(ty),
1083            };
1084            match &self.resolve.types[id].kind {
1085                TypeDefKind::Type(t) => self.non_empty_type(Some(t)).map(|_| ty),
1086                TypeDefKind::Record(r) => (!r.fields.is_empty()).then_some(ty),
1087                TypeDefKind::Tuple(t) => (!t.types.is_empty()).then_some(ty),
1088                _ => Some(ty),
1089            }
1090        } else {
1091            None
1092        }
1093    }
1094
1095    fn sig_string(&mut self, func: &Function, ignore_param: bool) -> String {
1096        let name = match func.kind {
1097            FunctionKind::Freestanding => func.name.to_moonbit_ident(),
1098            FunctionKind::Constructor(_) => {
1099                func.name.replace("[constructor]", "").to_moonbit_ident()
1100            }
1101            _ => func.name.split(".").last().unwrap().to_moonbit_ident(),
1102        };
1103        let type_name = match func.kind.resource() {
1104            Some(ty) => {
1105                format!("{}::", self.type_name(&Type::Id(ty), true))
1106            }
1107            None => "".into(),
1108        };
1109
1110        let result_type = match &func.result {
1111            None => "Unit".into(),
1112            Some(ty) => self.type_name(ty, true),
1113        };
1114
1115        let params = func
1116            .params
1117            .iter()
1118            .map(|(name, ty)| {
1119                let ty = self.type_name(ty, true);
1120                let name = if ignore_param {
1121                    format!("_{}", name.to_moonbit_ident())
1122                } else {
1123                    name.to_moonbit_ident()
1124                };
1125                format!("{name} : {ty}")
1126            })
1127            .collect::<Vec<_>>()
1128            .join(", ");
1129
1130        format!("pub fn {type_name}{name}({params}) -> {result_type}")
1131    }
1132}
1133
1134impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
1135    fn resolve(&self) -> &'a Resolve {
1136        self.resolve
1137    }
1138
1139    fn type_record(&mut self, _id: TypeId, name: &str, record: &Record, docs: &Docs) {
1140        print_docs(&mut self.src, docs);
1141
1142        let name = name.to_moonbit_type_ident();
1143
1144        let parameters = record
1145            .fields
1146            .iter()
1147            .map(|field| {
1148                format!(
1149                    "{} : {}",
1150                    field.name.to_moonbit_ident(),
1151                    self.type_name(&field.ty, true),
1152                )
1153            })
1154            .collect::<Vec<_>>()
1155            .join("; ");
1156
1157        let mut deriviation: Vec<_> = Vec::new();
1158        if self.gen.opts.derive_show {
1159            deriviation.push("Show")
1160        }
1161        if self.gen.opts.derive_eq {
1162            deriviation.push("Eq")
1163        }
1164
1165        uwrite!(
1166            self.src,
1167            "
1168            pub(all) struct {name} {{
1169                {parameters}
1170            }} derive({})
1171            ",
1172            deriviation.join(", ")
1173        );
1174    }
1175
1176    fn type_resource(&mut self, _id: TypeId, name: &str, docs: &Docs) {
1177        print_docs(&mut self.src, docs);
1178        let type_name = name;
1179        let name = name.to_moonbit_type_ident();
1180
1181        let mut deriviation: Vec<_> = Vec::new();
1182        if self.gen.opts.derive_show {
1183            deriviation.push("Show")
1184        }
1185        if self.gen.opts.derive_eq {
1186            deriviation.push("Eq")
1187        }
1188        let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1189            "suberror"
1190        } else {
1191            "struct"
1192        };
1193
1194        uwrite!(
1195            self.src,
1196            r#"
1197            pub(all) {declaration} {name}(Int) derive({})
1198            "#,
1199            deriviation.join(", "),
1200        );
1201
1202        let module = self.module;
1203
1204        if self.direction == Direction::Import {
1205            uwrite!(
1206                &mut self.src,
1207                r#"
1208                /// Drops a resource handle.
1209                pub fn {name}::drop(self : {name}) -> Unit {{
1210                    let {name}(resource) = self
1211                    wasmImportResourceDrop{name}(resource)
1212                }}
1213                "#,
1214            );
1215
1216            uwrite!(
1217                &mut self.ffi,
1218                r#"
1219                fn wasmImportResourceDrop{name}(resource : Int) = "{module}" "[resource-drop]{type_name}"
1220                "#,
1221            )
1222        } else {
1223            uwrite!(
1224                &mut self.src,
1225                r#"
1226                /// Creates a new resource with the given `rep` as its representation and returning the handle to this resource.
1227                pub fn {name}::new(rep : Int) -> {name} {{
1228                    {name}::{name}(wasmExportResourceNew{name}(rep))
1229                }}
1230                fn wasmExportResourceNew{name}(rep : Int) -> Int = "[export]{module}" "[resource-new]{type_name}"
1231
1232                /// Drops a resource handle.
1233                pub fn {name}::drop(self : Self) -> Unit {{
1234                    let {name}(resource) = self
1235                    wasmExportResourceDrop{name}(resource)
1236                }}
1237                fn wasmExportResourceDrop{name}(resource : Int) = "[export]{module}" "[resource-drop]{type_name}"
1238
1239                /// Gets the `Int` representation of the resource pointed to the given handle.
1240                pub fn {name}::rep(self : Self) -> Int {{
1241                    let {name}(resource) = self
1242                    wasmExportResourceRep{name}(resource)
1243                }}
1244                fn wasmExportResourceRep{name}(resource : Int) -> Int = "[export]{module}" "[resource-rep]{type_name}"
1245                "#,
1246            );
1247
1248            uwrite!(
1249                &mut self.stub,
1250                r#"
1251                /// Destructor of the resource.
1252                pub fn {name}::dtor(_self : {name}) -> Unit {{
1253                  ...
1254                }}
1255                "#
1256            );
1257
1258            let func_name = self.gen.export_ns.tmp(&format!("wasmExport{name}Dtor"));
1259
1260            let export_dir = self.gen.opts.gen_dir.clone();
1261
1262            let mut gen =
1263                self.gen
1264                    .interface(self.resolve, export_dir.as_str(), "", Direction::Export);
1265
1266            uwrite!(
1267                self.ffi,
1268                r#"
1269                pub fn {func_name}(handle : Int) -> Unit {{
1270                    {}{name}::dtor(handle)
1271                }}
1272                "#,
1273                gen.qualify_package(&self.name.to_string())
1274            );
1275
1276            self.gen
1277                .export
1278                .insert(func_name, format!("{module}#[dtor]{type_name}"));
1279        }
1280    }
1281
1282    fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
1283        print_docs(&mut self.src, docs);
1284
1285        let name = name.to_moonbit_type_ident();
1286
1287        let ty = match flags.repr() {
1288            FlagsRepr::U8 => "Byte",
1289            FlagsRepr::U16 | FlagsRepr::U32(1) => "UInt",
1290            FlagsRepr::U32(2) => "UInt64",
1291            _ => unreachable!(), // https://github.com/WebAssembly/component-model/issues/370
1292        };
1293
1294        let cases = flags
1295            .flags
1296            .iter()
1297            .map(|flag| flag.name.to_shouty_snake_case())
1298            .collect::<Vec<_>>()
1299            .join("; ");
1300
1301        let map_to_int = flags
1302            .flags
1303            .iter()
1304            .enumerate()
1305            .map(|(i, flag)| {
1306                let flag_name = flag.name.to_shouty_snake_case();
1307                let suffix = if matches!(flags.repr(), FlagsRepr::U32(2)) {
1308                    "UL"
1309                } else {
1310                    "U"
1311                };
1312                let cast = if matches!(flags.repr(), FlagsRepr::U8) {
1313                    ".to_byte()"
1314                } else {
1315                    ""
1316                };
1317                format!("{flag_name} => ((1{suffix} << {i}){cast})")
1318            })
1319            .collect::<Vec<_>>()
1320            .join("\n    ");
1321
1322        let mut deriviation: Vec<_> = Vec::new();
1323        if self.gen.opts.derive_show {
1324            deriviation.push("Show")
1325        }
1326        if self.gen.opts.derive_eq {
1327            deriviation.push("Eq")
1328        }
1329        let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1330            "suberror"
1331        } else {
1332            "struct"
1333        };
1334
1335        uwrite!(
1336            self.src,
1337            "
1338            pub(all) {declaration} {name}({ty}) derive({})
1339            pub fn {name}::default() -> {name} {{
1340                {}
1341            }}
1342            pub(all) enum {name}Flag {{
1343                {cases}
1344            }}
1345            fn {name}Flag::value(self : {name}Flag) -> {ty} {{
1346              match self {{
1347                {map_to_int}
1348              }}
1349            }}
1350            pub fn {name}::set(self : Self, other: {name}Flag) -> {name} {{
1351              let {name}(flag) = self
1352              flag.lor(other.value())
1353            }}
1354            pub fn {name}::unset(self : Self, other: {name}Flag) -> {name} {{
1355              let {name}(flag) = self
1356              flag.land(other.value().lnot())
1357            }}
1358            pub fn {name}::is_set(self : Self, other: {name}Flag) -> Bool {{
1359              let {name}(flag) = self
1360              (flag.land(other.value()) == other.value())
1361            }}
1362            ",
1363            deriviation.join(", "),
1364            match ty {
1365                "Byte" => "b'\\x00'",
1366                "UInt" => "0U",
1367                "UInt64" => "0UL",
1368                _ => unreachable!(),
1369            }
1370        );
1371    }
1372
1373    fn type_tuple(&mut self, _id: TypeId, _name: &str, _tuple: &Tuple, _docs: &Docs) {
1374        // Not needed
1375    }
1376
1377    fn type_variant(&mut self, _id: TypeId, name: &str, variant: &Variant, docs: &Docs) {
1378        print_docs(&mut self.src, docs);
1379
1380        let name = name.to_moonbit_type_ident();
1381
1382        let cases = variant
1383            .cases
1384            .iter()
1385            .map(|case| {
1386                let name = case.name.to_upper_camel_case();
1387                if let Some(ty) = case.ty {
1388                    let ty = self.type_name(&ty, true);
1389                    format!("{name}({ty})")
1390                } else {
1391                    format!("{name}")
1392                }
1393            })
1394            .collect::<Vec<_>>()
1395            .join("\n  ");
1396
1397        let mut deriviation: Vec<_> = Vec::new();
1398        if self.gen.opts.derive_show {
1399            deriviation.push("Show")
1400        }
1401        if self.gen.opts.derive_eq {
1402            deriviation.push("Eq")
1403        }
1404        let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1405            "suberror"
1406        } else {
1407            "enum"
1408        };
1409
1410        uwrite!(
1411            self.src,
1412            "
1413            pub(all) {declaration} {name} {{
1414              {cases}
1415            }} derive({})
1416            ",
1417            deriviation.join(", ")
1418        );
1419    }
1420
1421    fn type_option(&mut self, _id: TypeId, _name: &str, _payload: &Type, _docs: &Docs) {
1422        // Not needed
1423    }
1424
1425    fn type_result(&mut self, _id: TypeId, _name: &str, _result: &Result_, _docs: &Docs) {
1426        // Not needed
1427    }
1428
1429    fn type_enum(&mut self, _id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
1430        print_docs(&mut self.src, docs);
1431
1432        let name = name.to_moonbit_type_ident();
1433
1434        // Type definition
1435        let cases = enum_
1436            .cases
1437            .iter()
1438            .map(|case| case.name.to_shouty_snake_case())
1439            .collect::<Vec<_>>()
1440            .join("; ");
1441
1442        let mut deriviation: Vec<_> = Vec::new();
1443        if self.gen.opts.derive_show {
1444            deriviation.push("Show")
1445        }
1446        if self.gen.opts.derive_eq {
1447            deriviation.push("Eq")
1448        }
1449        let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1450            "suberror"
1451        } else {
1452            "enum"
1453        };
1454
1455        uwrite!(
1456            self.src,
1457            "
1458            pub(all) {declaration} {name} {{
1459                {cases}
1460            }} derive({})
1461            ",
1462            deriviation.join(", ")
1463        );
1464
1465        // Case to integer
1466        let cases = enum_
1467            .cases
1468            .iter()
1469            .enumerate()
1470            .map(|(i, case)| format!("{} => {i}", case.name.to_shouty_snake_case()))
1471            .collect::<Vec<_>>()
1472            .join("\n  ");
1473
1474        uwrite!(
1475            self.src,
1476            "
1477            pub fn {name}::ordinal(self : {name}) -> Int {{
1478              match self {{
1479                {cases}
1480              }}
1481            }}
1482            "
1483        );
1484
1485        // Integer to case
1486        let cases = enum_
1487            .cases
1488            .iter()
1489            .enumerate()
1490            .map(|(i, case)| format!("{i} => {}", case.name.to_shouty_snake_case()))
1491            .collect::<Vec<_>>()
1492            .join("\n  ");
1493
1494        uwrite!(
1495            self.src,
1496            "
1497            pub fn {name}::from(self : Int) -> {name} {{
1498              match self {{
1499                {cases}
1500                _ => panic()
1501              }}
1502            }}
1503            "
1504        );
1505    }
1506
1507    fn type_alias(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1508        // TODO: Implement correct type aliasing
1509        // self.type_name(&Type::Id(id));
1510    }
1511
1512    fn type_list(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1513        // Not needed
1514    }
1515
1516    fn type_future(&mut self, id: TypeId, name: &str, ty: &Option<Type>, docs: &Docs) {
1517        _ = (id, name, ty, docs);
1518        todo!()
1519    }
1520
1521    fn type_stream(&mut self, id: TypeId, name: &str, ty: &Option<Type>, docs: &Docs) {
1522        _ = (id, name, ty, docs);
1523        todo!()
1524    }
1525
1526    fn type_builtin(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1527        unimplemented!();
1528    }
1529}
1530
1531struct Block {
1532    body: String,
1533    results: Vec<String>,
1534    element: String,
1535    base: String,
1536}
1537enum Cleanup {
1538    Memory {
1539        address: String,
1540        size: String,
1541        align: usize,
1542    },
1543    Object(String),
1544}
1545
1546struct BlockStorage {
1547    body: String,
1548    element: String,
1549    base: String,
1550    cleanup: Vec<Cleanup>,
1551}
1552
1553struct FunctionBindgen<'a, 'b> {
1554    gen: &'b mut InterfaceGenerator<'a>,
1555    func_name: &'b str,
1556    func_interface: &'b str,
1557    params: Box<[String]>,
1558    src: String,
1559    locals: Ns,
1560    block_storage: Vec<BlockStorage>,
1561    blocks: Vec<Block>,
1562    payloads: Vec<String>,
1563    cleanup: Vec<Cleanup>,
1564    needs_cleanup_list: bool,
1565}
1566
1567impl<'a, 'b> FunctionBindgen<'a, 'b> {
1568    fn new(
1569        gen: &'b mut InterfaceGenerator<'a>,
1570        func_name: &'b str,
1571        func_interface: &'b str,
1572        params: Box<[String]>,
1573    ) -> FunctionBindgen<'a, 'b> {
1574        let mut locals = Ns::default();
1575        params.iter().for_each(|str| {
1576            locals.tmp(str);
1577        });
1578        Self {
1579            gen,
1580            func_name,
1581            func_interface,
1582            params,
1583            src: String::new(),
1584            locals,
1585            block_storage: Vec::new(),
1586            blocks: Vec::new(),
1587            payloads: Vec::new(),
1588            cleanup: Vec::new(),
1589            needs_cleanup_list: false,
1590        }
1591    }
1592
1593    fn lower_variant(
1594        &mut self,
1595        cases: &[(&str, Option<Type>)],
1596        lowered_types: &[WasmType],
1597        op: &str,
1598        results: &mut Vec<String>,
1599        is_result: bool,
1600    ) {
1601        let blocks = self
1602            .blocks
1603            .drain(self.blocks.len() - cases.len()..)
1604            .collect::<Vec<_>>();
1605
1606        let payloads = self
1607            .payloads
1608            .drain(self.payloads.len() - cases.len()..)
1609            .collect::<Vec<_>>();
1610
1611        let lowered = lowered_types
1612            .iter()
1613            .map(|_| self.locals.tmp("lowered"))
1614            .collect::<Vec<_>>();
1615
1616        results.extend(lowered.iter().cloned());
1617
1618        let declarations = lowered.join(",");
1619
1620        let cases = cases
1621            .iter()
1622            .zip(blocks)
1623            .zip(payloads)
1624            .map(|(((name, ty), Block { body, results, .. }), payload)| {
1625                let name = name.to_upper_camel_case();
1626                let assignments = results
1627                    .iter()
1628                    .map(|result| format!("{result}"))
1629                    .collect::<Vec<_>>()
1630                    .join(", ");
1631
1632                let payload = if self.gen.non_empty_type(ty.as_ref()).is_some() {
1633                    payload
1634                } else if is_result {
1635                    format!("_{payload}")
1636                } else {
1637                    String::new()
1638                };
1639
1640                if payload.is_empty() {
1641                    format!(
1642                        "{name} => {{
1643                          {body}
1644                          ({assignments})
1645                        }}"
1646                    )
1647                } else {
1648                    format!(
1649                        "{name}({payload}) => {{
1650                          {body}
1651                          ({assignments})
1652                        }}",
1653                    )
1654                }
1655            })
1656            .collect::<Vec<_>>()
1657            .join("\n");
1658
1659        if declarations.is_empty() {
1660            uwrite!(
1661                self.src,
1662                r#"
1663                match {op} {{
1664                    {cases}
1665                }}
1666                "#
1667            );
1668        } else {
1669            uwrite!(
1670                self.src,
1671                r#"
1672                let ({declarations}) = match {op} {{
1673                    {cases}
1674                }}
1675                "#
1676            );
1677        }
1678    }
1679
1680    fn lift_variant(
1681        &mut self,
1682        ty: &Type,
1683        cases: &[(&str, Option<Type>)],
1684        op: &str,
1685        results: &mut Vec<String>,
1686        is_result: bool,
1687    ) {
1688        let blocks = self
1689            .blocks
1690            .drain(self.blocks.len() - cases.len()..)
1691            .collect::<Vec<_>>();
1692
1693        // Hacky way to get the type name without type parameter
1694        let ty = self.gen.type_name(ty, false);
1695        let lifted = self.locals.tmp("lifted");
1696
1697        let cases = cases
1698            .iter()
1699            .zip(blocks)
1700            .enumerate()
1701            .map(|(i, ((case_name, case_ty), Block { body, results, .. }))| {
1702                let payload = if self.gen.non_empty_type(case_ty.as_ref()).is_some() {
1703                    results.into_iter().next().unwrap()
1704                } else {
1705                    String::new()
1706                };
1707
1708                let constructor = format!("{ty}::{}", case_name.to_upper_camel_case());
1709
1710                if payload.is_empty() && !is_result {
1711                    format!(
1712                        "{i} => {{
1713                             {body}
1714                             {constructor}
1715                         }}"
1716                    )
1717                } else {
1718                    format!(
1719                        "{i} => {{
1720                             {body}
1721                             {constructor}({})
1722                         }}",
1723                        if payload.is_empty() {
1724                            "()".into()
1725                        } else {
1726                            payload
1727                        }
1728                    )
1729                }
1730            })
1731            .collect::<Vec<_>>()
1732            .join("\n");
1733
1734        uwrite!(
1735            self.src,
1736            r#"
1737            let {lifted} = match ({op}) {{
1738                {cases}
1739                _ => panic()
1740            }}
1741            "#
1742        );
1743
1744        results.push(lifted);
1745    }
1746}
1747
1748impl Bindgen for FunctionBindgen<'_, '_> {
1749    type Operand = String;
1750
1751    fn emit(
1752        &mut self,
1753        _resolve: &Resolve,
1754        inst: &Instruction<'_>,
1755        operands: &mut Vec<String>,
1756        results: &mut Vec<String>,
1757    ) {
1758        match inst {
1759            Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
1760            Instruction::I32Const { val } => results.push(format!("({})", val.to_string())),
1761            Instruction::ConstZero { tys } => results.extend(tys.iter().map(|ty| {
1762                match ty {
1763                    WasmType::I32 => "0",
1764                    WasmType::I64 => "0L",
1765                    WasmType::F32 => "(0.0 : Float)",
1766                    WasmType::F64 => "0.0",
1767                    WasmType::Pointer => "0",
1768                    WasmType::PointerOrI64 => "0L",
1769                    WasmType::Length => "0",
1770                }
1771                .to_owned()
1772            })),
1773
1774            Instruction::Bitcasts { casts } => results.extend(
1775                casts
1776                    .iter()
1777                    .zip(operands)
1778                    .map(|(cast, op)| perform_cast(op, cast)),
1779            ),
1780
1781            Instruction::I32FromS32
1782            | Instruction::I64FromS64
1783            | Instruction::S32FromI32
1784            | Instruction::S64FromI64
1785            | Instruction::CoreF64FromF64
1786            | Instruction::F64FromCoreF64 => results.push(operands[0].clone()),
1787
1788            Instruction::F32FromCoreF32 => results.push(operands[0].clone()),
1789            Instruction::CoreF32FromF32 => results.push(operands[0].clone()),
1790
1791            Instruction::CharFromI32 => {
1792                results.push(format!("Int::unsafe_to_char({})", operands[0]))
1793            }
1794            Instruction::I32FromChar => results.push(format!("({}).to_int()", operands[0])),
1795
1796            Instruction::I32FromU8 => results.push(format!("({}).to_int()", operands[0])),
1797            Instruction::I32FromU16 => {
1798                results.push(format!("({}).reinterpret_as_int()", operands[0]))
1799            }
1800            Instruction::U8FromI32 => results.push(format!("({}).to_byte()", operands[0])),
1801
1802            Instruction::I32FromS8 => results.push(format!(
1803                "{}extend8({})",
1804                self.gen.qualify_package(FFI_DIR),
1805                operands[0]
1806            )),
1807            Instruction::S8FromI32 => results.push(format!("({} - 0x100)", operands[0])),
1808            Instruction::S16FromI32 => results.push(format!("({} - 0x10000)", operands[0])),
1809            Instruction::I32FromS16 => results.push(format!(
1810                "{}extend16({})",
1811                self.gen.qualify_package(FFI_DIR),
1812                operands[0]
1813            )),
1814            Instruction::U16FromI32 => results.push(format!(
1815                "({}.land(0xFFFF).reinterpret_as_uint())",
1816                operands[0]
1817            )),
1818            Instruction::U32FromI32 => {
1819                results.push(format!("({}).reinterpret_as_uint()", operands[0]))
1820            }
1821            Instruction::I32FromU32 => {
1822                results.push(format!("({}).reinterpret_as_int()", operands[0]))
1823            }
1824
1825            Instruction::U64FromI64 => {
1826                results.push(format!("({}).reinterpret_as_uint64()", operands[0]))
1827            }
1828            Instruction::I64FromU64 => {
1829                results.push(format!("({}).reinterpret_as_int64()", operands[0]))
1830            }
1831
1832            Instruction::I32FromBool => {
1833                results.push(format!("(if {} {{ 1 }} else {{ 0 }})", operands[0]));
1834            }
1835            Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
1836
1837            Instruction::FlagsLower { flags, ty, .. } => match flags_repr(flags) {
1838                Int::U8 => {
1839                    let op = &operands[0];
1840                    let flag = self.locals.tmp("flag");
1841                    let ty = self.gen.type_name(&Type::Id(*ty), false);
1842                    uwriteln!(
1843                        self.src,
1844                        r#"
1845                        let {ty}({flag}) = {op}
1846                        "#
1847                    );
1848                    results.push(format!("{flag}.to_int()"));
1849                }
1850                Int::U16 | Int::U32 => {
1851                    let op = &operands[0];
1852                    let flag = self.locals.tmp("flag");
1853                    let ty = self.gen.type_name(&Type::Id(*ty), false);
1854                    uwriteln!(
1855                        self.src,
1856                        r#"
1857                        let {ty}({flag}) = {op}
1858                        "#
1859                    );
1860                    results.push(format!("{flag}.reinterpret_as_int()"));
1861                }
1862                Int::U64 => {
1863                    let op = &operands[0];
1864                    let flag = self.locals.tmp("flag");
1865                    let ty = self.gen.type_name(&Type::Id(*ty), false);
1866                    uwriteln!(
1867                        self.src,
1868                        r#"
1869                        let {ty}({flag}) = {op}
1870                        "#
1871                    );
1872                    results.push(format!("({flag}.to_int())"));
1873                    results.push(format!("({flag}.lsr(32)).to_int())"));
1874                }
1875            },
1876
1877            Instruction::FlagsLift { flags, ty, .. } => match flags_repr(flags) {
1878                Int::U8 => {
1879                    results.push(format!(
1880                        "{}({}.to_byte())",
1881                        self.gen.type_name(&Type::Id(*ty), true),
1882                        operands[0]
1883                    ));
1884                }
1885                Int::U16 | Int::U32 => {
1886                    results.push(format!(
1887                        "{}({}.reinterpret_as_uint())",
1888                        self.gen.type_name(&Type::Id(*ty), true),
1889                        operands[0]
1890                    ));
1891                }
1892                Int::U64 => {
1893                    results.push(format!(
1894                        "{}(({}).reinterpret_as_uint().to_uint64() | (({}).reinterpret_as_uint().to_uint64() << 32))",
1895                        self.gen.type_name(&Type::Id(*ty), true),
1896                        operands[0],
1897                        operands[1]
1898                    ));
1899                }
1900            },
1901
1902            Instruction::HandleLower { ty, .. } => {
1903                let op = &operands[0];
1904                let handle = self.locals.tmp("handle");
1905                let ty = self.gen.type_name(&Type::Id(*ty), false);
1906                uwrite!(
1907                    self.src,
1908                    r#"
1909                    let {ty}({handle}) = {op}
1910                    "#
1911                );
1912                results.push(handle);
1913            }
1914            Instruction::HandleLift { ty, .. } => {
1915                let op = &operands[0];
1916                let ty = self.gen.type_name(&Type::Id(*ty), false);
1917
1918                results.push(format!(
1919                    "{}::{}({})",
1920                    ty,
1921                    if ty.starts_with("@") {
1922                        ty.split('.').last().unwrap()
1923                    } else {
1924                        &ty
1925                    },
1926                    op
1927                ));
1928            }
1929
1930            Instruction::RecordLower { record, .. } => {
1931                let op = &operands[0];
1932                for field in record.fields.iter() {
1933                    results.push(format!("({op}).{}", field.name.to_moonbit_ident()));
1934                }
1935            }
1936            Instruction::RecordLift { ty, record, .. } => {
1937                let ops = operands
1938                    .iter()
1939                    .enumerate()
1940                    .map(|(i, op)| {
1941                        format!(
1942                            "{} : {}",
1943                            record.fields[i].name.to_moonbit_ident(),
1944                            op.to_string()
1945                        )
1946                    })
1947                    .collect::<Vec<_>>()
1948                    .join(", ");
1949
1950                results.push(format!(
1951                    "{}::{{{ops}}}",
1952                    self.gen.type_name(&Type::Id(*ty), true)
1953                ));
1954            }
1955
1956            Instruction::TupleLower { tuple, .. } => {
1957                let op = &operands[0];
1958                // Empty tuple is Unit
1959                // (T) is T
1960                if tuple.types.len() == 0 {
1961                    results.push("()".into());
1962                } else if tuple.types.len() == 1 {
1963                    results.push(format!("{}", operands[0]));
1964                } else {
1965                    for i in 0..tuple.types.len() {
1966                        results.push(format!("({op}).{i}"));
1967                    }
1968                }
1969            }
1970            Instruction::TupleLift { .. } => {
1971                let ops = operands
1972                    .iter()
1973                    .map(|op| op.to_string())
1974                    .collect::<Vec<_>>()
1975                    .join(", ");
1976                results.push(format!("({ops})"));
1977            }
1978
1979            Instruction::VariantPayloadName => {
1980                let payload = self.locals.tmp("payload");
1981                results.push(payload.clone());
1982                self.payloads.push(payload);
1983            }
1984
1985            Instruction::VariantLower {
1986                variant,
1987                results: lowered_types,
1988                ..
1989            } => self.lower_variant(
1990                &variant
1991                    .cases
1992                    .iter()
1993                    .map(|case| (case.name.deref(), case.ty))
1994                    .collect::<Vec<_>>(),
1995                lowered_types,
1996                &operands[0],
1997                results,
1998                false,
1999            ),
2000
2001            Instruction::VariantLift { variant, ty, .. } => self.lift_variant(
2002                &Type::Id(*ty),
2003                &variant
2004                    .cases
2005                    .iter()
2006                    .map(|case| (case.name.deref(), case.ty))
2007                    .collect::<Vec<_>>(),
2008                &operands[0],
2009                results,
2010                false,
2011            ),
2012
2013            Instruction::OptionLower {
2014                results: lowered_types,
2015                ..
2016            } => {
2017                let some = self.blocks.pop().unwrap();
2018                let none = self.blocks.pop().unwrap();
2019                let some_payload = self.payloads.pop().unwrap();
2020                let _none_payload = self.payloads.pop().unwrap();
2021
2022                let lowered = lowered_types
2023                    .iter()
2024                    .map(|_| self.locals.tmp("lowered"))
2025                    .collect::<Vec<_>>();
2026
2027                results.extend(lowered.iter().cloned());
2028
2029                let declarations = lowered
2030                    .iter()
2031                    .map(|lowered| format!("{lowered}"))
2032                    .collect::<Vec<_>>()
2033                    .join(", ");
2034
2035                let op = &operands[0];
2036
2037                let block = |Block { body, results, .. }| {
2038                    let assignments = results
2039                        .iter()
2040                        .map(|result| format!("{result}"))
2041                        .collect::<Vec<_>>()
2042                        .join(", ");
2043
2044                    format!(
2045                        "{body}
2046                         ({assignments})"
2047                    )
2048                };
2049
2050                let none = block(none);
2051                let some = block(some);
2052
2053                if declarations.is_empty() {
2054                    uwrite!(
2055                        self.src,
2056                        r#"
2057                        match (({op})) {{
2058                            None => {{
2059                                {none}
2060                            }}
2061                            Some({some_payload}) => {{
2062                                {some}
2063                            }}
2064                        }}
2065                        "#
2066                    );
2067                } else {
2068                    uwrite!(
2069                        self.src,
2070                        r#"
2071                        let ({declarations}) = match (({op})) {{
2072                            None => {{
2073                                {none}
2074                            }}
2075                            Some({some_payload}) => {{
2076                                {some}
2077                            }}
2078                        }}
2079                        "#
2080                    );
2081                }
2082            }
2083
2084            Instruction::OptionLift { payload, ty } => {
2085                let some = self.blocks.pop().unwrap();
2086                let _none = self.blocks.pop().unwrap();
2087
2088                let ty = self.gen.type_name(&Type::Id(*ty), true);
2089                let lifted = self.locals.tmp("lifted");
2090                let op = &operands[0];
2091
2092                let payload = if self.gen.non_empty_type(Some(*payload)).is_some() {
2093                    some.results.into_iter().next().unwrap()
2094                } else {
2095                    "None".into()
2096                };
2097
2098                let some = some.body;
2099
2100                uwrite!(
2101                    self.src,
2102                    r#"
2103                    let {lifted} : {ty} = match {op} {{
2104                        0 => Option::None
2105                        1 => {{
2106                            {some}
2107                            Option::Some({payload})
2108                        }}
2109                        _ => panic()
2110                    }}
2111                    "#
2112                );
2113
2114                results.push(lifted);
2115            }
2116
2117            Instruction::ResultLower {
2118                results: lowered_types,
2119                result,
2120                ..
2121            } => self.lower_variant(
2122                &[("Ok", result.ok), ("Err", result.err)],
2123                lowered_types,
2124                &operands[0],
2125                results,
2126                true,
2127            ),
2128
2129            Instruction::ResultLift { result, ty } => self.lift_variant(
2130                &Type::Id(*ty),
2131                &[("Ok", result.ok), ("Err", result.err)],
2132                &operands[0],
2133                results,
2134                true,
2135            ),
2136
2137            Instruction::EnumLower { .. } => results.push(format!("{}.ordinal()", operands[0])),
2138
2139            Instruction::EnumLift { ty, .. } => results.push(format!(
2140                "{}::from({})",
2141                self.gen.type_name(&Type::Id(*ty), true),
2142                operands[0]
2143            )),
2144
2145            Instruction::ListCanonLower { element, realloc } => match element {
2146                Type::U8 => {
2147                    let op = &operands[0];
2148
2149                    results.push(format!(
2150                        "{}bytes2ptr({op})",
2151                        self.gen.qualify_package(FFI_DIR)
2152                    ));
2153                    results.push(format!("{op}.length()"));
2154                    if realloc.is_none() {
2155                        self.cleanup.push(Cleanup::Object(op.clone()));
2156                    }
2157                }
2158                Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2159                    let op = &operands[0];
2160
2161                    let ty = match element {
2162                        Type::U32 => "uint",
2163                        Type::U64 => "uint64",
2164                        Type::S32 => "int",
2165                        Type::S64 => "int64",
2166                        Type::F32 => "float",
2167                        Type::F64 => "double",
2168                        _ => unreachable!(),
2169                    };
2170
2171                    results.push(format!(
2172                        "{}{ty}_array2ptr({op})",
2173                        self.gen.qualify_package(FFI_DIR)
2174                    ));
2175                    results.push(format!("{op}.length()"));
2176                    if realloc.is_none() {
2177                        self.cleanup.push(Cleanup::Object(op.clone()));
2178                    }
2179                }
2180                _ => unreachable!("unsupported list element type"),
2181            },
2182
2183            Instruction::ListCanonLift { element, .. } => match element {
2184                Type::U8 => {
2185                    let result = self.locals.tmp("result");
2186                    let address = &operands[0];
2187                    let length = &operands[1];
2188
2189                    uwrite!(
2190                        self.src,
2191                        "
2192                        let {result} = {}ptr2bytes({address}, {length})
2193                        ",
2194                        self.gen.qualify_package(FFI_DIR)
2195                    );
2196
2197                    results.push(result);
2198                }
2199                Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2200                    let ty = match element {
2201                        Type::U32 => "uint",
2202                        Type::U64 => "uint64",
2203                        Type::S32 => "int",
2204                        Type::S64 => "int64",
2205                        Type::F32 => "float",
2206                        Type::F64 => "double",
2207                        _ => unreachable!(),
2208                    };
2209
2210                    let result = self.locals.tmp("result");
2211                    let address = &operands[0];
2212                    let length = &operands[1];
2213
2214                    uwrite!(
2215                        self.src,
2216                        "
2217                        let {result} = {}ptr2{ty}_array({address}, {length})
2218                        ",
2219                        self.gen.qualify_package(FFI_DIR)
2220                    );
2221
2222                    results.push(result);
2223                }
2224                _ => unreachable!("unsupported list element type"),
2225            },
2226
2227            Instruction::StringLower { realloc } => {
2228                let op = &operands[0];
2229
2230                results.push(format!(
2231                    "{}str2ptr({op})",
2232                    self.gen.qualify_package(FFI_DIR)
2233                ));
2234                results.push(format!("{op}.length()"));
2235                if realloc.is_none() {
2236                    self.cleanup.push(Cleanup::Object(op.clone()));
2237                }
2238            }
2239
2240            Instruction::StringLift { .. } => {
2241                let result = self.locals.tmp("result");
2242                let address = &operands[0];
2243                let length = &operands[1];
2244
2245                uwrite!(
2246                    self.src,
2247                    "
2248                    let {result} = {}ptr2str({address}, {length})
2249                    ",
2250                    self.gen.qualify_package(FFI_DIR)
2251                );
2252
2253                results.push(result);
2254            }
2255
2256            Instruction::ListLower { element, realloc } => {
2257                let Block {
2258                    body,
2259                    results: block_results,
2260                    element: block_element,
2261                    base,
2262                } = self.blocks.pop().unwrap();
2263                assert!(block_results.is_empty());
2264
2265                let op = &operands[0];
2266                let size = self.gen.gen.sizes.size(element).size_wasm32();
2267                let align = self.gen.gen.sizes.align(element).align_wasm32();
2268                let address = self.locals.tmp("address");
2269                let ty = self.gen.type_name(element, true);
2270                let index = self.locals.tmp("index");
2271
2272                uwrite!(
2273                    self.src,
2274                    "
2275                    let {address} = {}malloc(({op}).length() * {size});
2276                    for {index} = 0; {index} < ({op}).length(); {index} = {index} + 1 {{
2277                        let {block_element} : {ty} = ({op})[({index})]
2278                        let {base} = {address} + ({index} * {size});
2279                        {body}
2280                    }}
2281                    ",
2282                    self.gen.qualify_package(FFI_DIR)
2283                );
2284
2285                if realloc.is_none() {
2286                    self.cleanup.push(Cleanup::Memory {
2287                        address: address.clone(),
2288                        size: format!("({op}).length() * {size}"),
2289                        align,
2290                    });
2291                }
2292
2293                results.push(address);
2294                results.push(format!("({op}).length()"));
2295            }
2296
2297            Instruction::ListLift { element, .. } => {
2298                let Block {
2299                    body,
2300                    results: block_results,
2301                    base,
2302                    ..
2303                } = self.blocks.pop().unwrap();
2304                let address = &operands[0];
2305                let length = &operands[1];
2306                let array = self.locals.tmp("array");
2307                let ty = self.gen.type_name(element, true);
2308                let size = self.gen.gen.sizes.size(element).size_wasm32();
2309                // let align = self.gen.gen.sizes.align(element);
2310                let index = self.locals.tmp("index");
2311
2312                let result = match &block_results[..] {
2313                    [result] => result,
2314                    _ => todo!("result count == {}", results.len()),
2315                };
2316
2317                uwrite!(
2318                    self.src,
2319                    "
2320                    let {array} : Array[{ty}] = [];
2321                    for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
2322                        let {base} = ({address}) + ({index} * {size})
2323                        {body}
2324                        {array}.push({result})
2325                    }}
2326                    {}free({address})
2327                    ",
2328                    self.gen.qualify_package(FFI_DIR)
2329                );
2330
2331                results.push(array);
2332            }
2333
2334            Instruction::IterElem { .. } => {
2335                results.push(self.block_storage.last().unwrap().element.clone())
2336            }
2337
2338            Instruction::IterBasePointer => {
2339                results.push(self.block_storage.last().unwrap().base.clone())
2340            }
2341
2342            Instruction::CallWasm { sig, .. } => {
2343                let assignment = match &sig.results[..] {
2344                    [result] => {
2345                        let ty = wasm_type(*result);
2346                        let result = self.locals.tmp("result");
2347                        let assignment = format!("let {result} : {ty} = ");
2348                        results.push(result);
2349                        assignment
2350                    }
2351
2352                    [] => String::new(),
2353
2354                    _ => unreachable!(),
2355                };
2356
2357                let func_name = self.func_name.to_upper_camel_case();
2358
2359                let operands = operands.join(", ");
2360
2361                uwriteln!(self.src, "{assignment} wasmImport{func_name}({operands});");
2362            }
2363
2364            Instruction::CallInterface { func, .. } => {
2365                let assignment = match func.result {
2366                    None => "let _ = ".into(),
2367                    Some(ty) => {
2368                        let ty = format!("({})", self.gen.type_name(&ty, true));
2369                        let result = self.locals.tmp("result");
2370                        results.push(result.clone());
2371                        let assignment = format!("let ({result}) : {ty} = ");
2372                        assignment
2373                    }
2374                };
2375
2376                let name = match func.kind {
2377                    FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
2378                        format!(
2379                            "{}{}",
2380                            self.r#gen.qualify_package(&self.func_interface.to_string()),
2381                            func.name.to_moonbit_ident()
2382                        )
2383                    }
2384                    FunctionKind::Constructor(ty) => {
2385                        let name = self.gen.type_name(&Type::Id(ty), false);
2386                        format!(
2387                            "{}::{}",
2388                            name,
2389                            func.name.replace("[constructor]", "").to_moonbit_ident()
2390                        )
2391                    }
2392                    FunctionKind::Method(ty)
2393                    | FunctionKind::Static(ty)
2394                    | FunctionKind::AsyncMethod(ty)
2395                    | FunctionKind::AsyncStatic(ty) => {
2396                        let name = self.gen.type_name(&Type::Id(ty), false);
2397                        format!(
2398                            "{}::{}",
2399                            name,
2400                            func.name.split(".").last().unwrap().to_moonbit_ident()
2401                        )
2402                    }
2403                };
2404
2405                let args = operands.join(", ");
2406
2407                uwrite!(
2408                    self.src,
2409                    "
2410                    {assignment}{name}({args});
2411                    ",
2412                );
2413            }
2414
2415            Instruction::Return { amt, .. } => {
2416                for clean in &self.cleanup {
2417                    match clean {
2418                        Cleanup::Memory {
2419                            address,
2420                            size: _,
2421                            align: _,
2422                        } => uwriteln!(
2423                            self.src,
2424                            "{}free({address})",
2425                            self.gen.qualify_package(FFI_DIR)
2426                        ),
2427                        Cleanup::Object(obj) => uwriteln!(self.src, "ignore({obj})"),
2428                    }
2429                }
2430
2431                if self.needs_cleanup_list {
2432                    uwrite!(
2433                        self.src,
2434                        "
2435                        cleanupList.each(fn(cleanup) {{
2436                            {}free(cleanup.address);
2437                        }})
2438                        ignore(ignoreList)
2439                        ",
2440                        self.gen.qualify_package(FFI_DIR)
2441                    );
2442                }
2443
2444                match *amt {
2445                    0 => (),
2446                    1 => uwriteln!(self.src, "return {}", operands[0]),
2447                    _ => {
2448                        let results = operands.join(", ");
2449                        uwriteln!(self.src, "return ({results})");
2450                    }
2451                }
2452            }
2453
2454            Instruction::I32Load { offset }
2455            | Instruction::PointerLoad { offset }
2456            | Instruction::LengthLoad { offset } => results.push(format!(
2457                "{}load32(({}) + {offset})",
2458                self.gen.qualify_package(FFI_DIR),
2459                operands[0],
2460                offset = offset.size_wasm32()
2461            )),
2462
2463            Instruction::I32Load8U { offset } => results.push(format!(
2464                "{}load8_u(({}) + {offset})",
2465                self.gen.qualify_package(FFI_DIR),
2466                operands[0],
2467                offset = offset.size_wasm32()
2468            )),
2469
2470            Instruction::I32Load8S { offset } => results.push(format!(
2471                "{}load8(({}) + {offset})",
2472                self.gen.qualify_package(FFI_DIR),
2473                operands[0],
2474                offset = offset.size_wasm32()
2475            )),
2476
2477            Instruction::I32Load16U { offset } => results.push(format!(
2478                "{}load16_u(({}) + {offset})",
2479                self.gen.qualify_package(FFI_DIR),
2480                operands[0],
2481                offset = offset.size_wasm32()
2482            )),
2483
2484            Instruction::I32Load16S { offset } => results.push(format!(
2485                "{}load16(({}) + {offset})",
2486                self.gen.qualify_package(FFI_DIR),
2487                operands[0],
2488                offset = offset.size_wasm32()
2489            )),
2490
2491            Instruction::I64Load { offset } => results.push(format!(
2492                "{}load64(({}) + {offset})",
2493                self.gen.qualify_package(FFI_DIR),
2494                operands[0],
2495                offset = offset.size_wasm32()
2496            )),
2497
2498            Instruction::F32Load { offset } => results.push(format!(
2499                "{}loadf32(({}) + {offset})",
2500                self.gen.qualify_package(FFI_DIR),
2501                operands[0],
2502                offset = offset.size_wasm32()
2503            )),
2504
2505            Instruction::F64Load { offset } => results.push(format!(
2506                "{}loadf64(({}) + {offset})",
2507                self.gen.qualify_package(FFI_DIR),
2508                operands[0],
2509                offset = offset.size_wasm32()
2510            )),
2511
2512            Instruction::I32Store { offset }
2513            | Instruction::PointerStore { offset }
2514            | Instruction::LengthStore { offset } => uwriteln!(
2515                self.src,
2516                "{}store32(({}) + {offset}, {})",
2517                self.gen.qualify_package(FFI_DIR),
2518                operands[1],
2519                operands[0],
2520                offset = offset.size_wasm32()
2521            ),
2522
2523            Instruction::I32Store8 { offset } => uwriteln!(
2524                self.src,
2525                "{}store8(({}) + {offset}, {})",
2526                self.gen.qualify_package(FFI_DIR),
2527                operands[1],
2528                operands[0],
2529                offset = offset.size_wasm32()
2530            ),
2531
2532            Instruction::I32Store16 { offset } => uwriteln!(
2533                self.src,
2534                "{}store16(({}) + {offset}, {})",
2535                self.gen.qualify_package(FFI_DIR),
2536                operands[1],
2537                operands[0],
2538                offset = offset.size_wasm32()
2539            ),
2540
2541            Instruction::I64Store { offset } => uwriteln!(
2542                self.src,
2543                "{}store64(({}) + {offset}, {})",
2544                self.gen.qualify_package(FFI_DIR),
2545                operands[1],
2546                operands[0],
2547                offset = offset.size_wasm32()
2548            ),
2549
2550            Instruction::F32Store { offset } => uwriteln!(
2551                self.src,
2552                "{}storef32(({}) + {offset}, {})",
2553                self.gen.qualify_package(FFI_DIR),
2554                operands[1],
2555                operands[0],
2556                offset = offset.size_wasm32()
2557            ),
2558
2559            Instruction::F64Store { offset } => uwriteln!(
2560                self.src,
2561                "{}storef64(({}) + {offset}, {})",
2562                self.gen.qualify_package(FFI_DIR),
2563                operands[1],
2564                operands[0],
2565                offset = offset.size_wasm32()
2566            ),
2567            // TODO: see what we can do with align
2568            Instruction::Malloc { size, .. } => {
2569                uwriteln!(
2570                    self.src,
2571                    "{}malloc({})",
2572                    self.gen.qualify_package(FFI_DIR),
2573                    size.size_wasm32()
2574                )
2575            }
2576
2577            Instruction::GuestDeallocate { .. } => {
2578                uwriteln!(
2579                    self.src,
2580                    "{}free({})",
2581                    self.gen.qualify_package(FFI_DIR),
2582                    operands[0]
2583                )
2584            }
2585
2586            Instruction::GuestDeallocateString => {
2587                uwriteln!(
2588                    self.src,
2589                    "{}free({})",
2590                    self.gen.qualify_package(FFI_DIR),
2591                    operands[0]
2592                )
2593            }
2594
2595            Instruction::GuestDeallocateVariant { blocks } => {
2596                let cases = self
2597                    .blocks
2598                    .drain(self.blocks.len() - blocks..)
2599                    .enumerate()
2600                    .map(|(i, Block { body, results, .. })| {
2601                        assert!(results.is_empty());
2602                        if body.is_empty() {
2603                            format!("{i} => ()")
2604                        } else {
2605                            format!(
2606                                "{i} => {{
2607                                   {body}
2608                                 }}"
2609                            )
2610                        }
2611                    })
2612                    .collect::<Vec<_>>()
2613                    .join("\n");
2614
2615                let op = &operands[0];
2616
2617                uwrite!(
2618                    self.src,
2619                    "
2620                    match ({op}) {{
2621                        {cases}
2622                        _ => panic()
2623                    }}
2624                    "
2625                );
2626            }
2627
2628            Instruction::GuestDeallocateList { element } => {
2629                let Block {
2630                    body,
2631                    results,
2632                    base,
2633                    ..
2634                } = self.blocks.pop().unwrap();
2635                assert!(results.is_empty());
2636
2637                let address = &operands[0];
2638                let length = &operands[1];
2639
2640                let size = self.gen.gen.sizes.size(element).size_wasm32();
2641                // let align = self.gen.gen.sizes.align(element);
2642
2643                if !body.trim().is_empty() {
2644                    let index = self.locals.tmp("index");
2645
2646                    uwrite!(
2647                        self.src,
2648                        "
2649                        for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
2650                            let {base} = ({address}) + ({index} * {size})
2651                            {body}
2652                        }}
2653                        "
2654                    );
2655                }
2656
2657                uwriteln!(
2658                    self.src,
2659                    "{}free({address})",
2660                    self.gen.qualify_package(FFI_DIR)
2661                );
2662            }
2663
2664            Instruction::Flush { amt } => {
2665                results.extend(operands.iter().take(*amt).map(|v| v.clone()));
2666            }
2667
2668            Instruction::AsyncTaskReturn { .. }
2669            | Instruction::FutureLower { .. }
2670            | Instruction::FutureLift { .. }
2671            | Instruction::StreamLower { .. }
2672            | Instruction::StreamLift { .. }
2673            | Instruction::ErrorContextLower { .. }
2674            | Instruction::ErrorContextLift { .. }
2675            | Instruction::DropHandle { .. } => todo!(),
2676        }
2677    }
2678
2679    fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
2680        if self.gen.direction == Direction::Import {
2681            let ffi_qualifier = self.gen.qualify_package(FFI_DIR);
2682            let address = self.locals.tmp("return_area");
2683            uwriteln!(
2684                self.src,
2685                "let {address} = {ffi_qualifier}malloc({})",
2686                size.size_wasm32(),
2687            );
2688            self.cleanup.push(Cleanup::Memory {
2689                address: address.clone(),
2690                size: size.size_wasm32().to_string(),
2691                align: align.align_wasm32(),
2692            });
2693            address
2694        } else {
2695            self.gen.gen.return_area_size = self.gen.gen.return_area_size.max(size);
2696            self.gen.gen.return_area_align = self.gen.gen.return_area_align.max(align);
2697            "return_area".into()
2698        }
2699    }
2700
2701    fn push_block(&mut self) {
2702        self.block_storage.push(BlockStorage {
2703            body: mem::take(&mut self.src),
2704            element: self.locals.tmp("element"),
2705            base: self.locals.tmp("base"),
2706            cleanup: mem::take(&mut self.cleanup),
2707        });
2708    }
2709
2710    fn finish_block(&mut self, operands: &mut Vec<String>) {
2711        let BlockStorage {
2712            body,
2713            element,
2714            base,
2715            cleanup,
2716        } = self.block_storage.pop().unwrap();
2717
2718        if !self.cleanup.is_empty() {
2719            self.needs_cleanup_list = true;
2720
2721            for cleanup in &self.cleanup {
2722                match cleanup {
2723                    Cleanup::Memory {
2724                        address,
2725                        size,
2726                        align,
2727                    } => uwriteln!(
2728                        self.src,
2729                        "cleanupList.push({{address: {address}, size: {size}, align: {align}}})",
2730                    ),
2731                    Cleanup::Object(obj) => uwriteln!(self.src, "ignoreList.push({obj})",),
2732                }
2733            }
2734        }
2735
2736        self.cleanup = cleanup;
2737
2738        self.blocks.push(Block {
2739            body: mem::replace(&mut self.src, body),
2740            results: mem::take(operands),
2741            element,
2742            base,
2743        });
2744    }
2745
2746    fn sizes(&self) -> &SizeAlign {
2747        &self.gen.gen.sizes
2748    }
2749
2750    fn is_list_canonical(&self, _resolve: &Resolve, element: &Type) -> bool {
2751        matches!(
2752            element,
2753            Type::U8 | Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64
2754        )
2755    }
2756}
2757
2758fn perform_cast(op: &str, cast: &Bitcast) -> String {
2759    match cast {
2760        Bitcast::I32ToF32 => {
2761            format!("({op}).reinterpret_as_float()")
2762        }
2763        Bitcast::I64ToF32 => format!("({op}).to_int().reinterpret_as_float()"),
2764        Bitcast::F32ToI32 => {
2765            format!("({op}).reinterpret_as_int()")
2766        }
2767        Bitcast::F32ToI64 => format!("({op}).reinterpret_as_int().to_int64()"),
2768        Bitcast::I64ToF64 => {
2769            format!("({op}).reinterpret_as_double()")
2770        }
2771        Bitcast::F64ToI64 => {
2772            format!("({op}).reinterpret_as_int64()")
2773        }
2774        Bitcast::LToI64 | Bitcast::PToP64 | Bitcast::I32ToI64 => format!("Int::to_int64({op})"),
2775        Bitcast::I64ToL | Bitcast::P64ToP | Bitcast::I64ToI32 => format!("Int64::to_int({op})"),
2776        Bitcast::I64ToP64
2777        | Bitcast::P64ToI64
2778        | Bitcast::I32ToP
2779        | Bitcast::PToI32
2780        | Bitcast::I32ToL
2781        | Bitcast::LToI32
2782        | Bitcast::LToP
2783        | Bitcast::PToL
2784        | Bitcast::None => op.to_owned(),
2785
2786        Bitcast::Sequence(sequence) => {
2787            let [first, second] = &**sequence;
2788            perform_cast(&perform_cast(op, first), second)
2789        }
2790    }
2791}
2792
2793fn wasm_type(ty: WasmType) -> &'static str {
2794    match ty {
2795        WasmType::I32 => "Int",
2796        WasmType::I64 => "Int64",
2797        WasmType::F32 => "Float",
2798        WasmType::F64 => "Double",
2799        WasmType::Pointer => "Int",
2800        WasmType::PointerOrI64 => "Int64",
2801        WasmType::Length => "Int",
2802    }
2803}
2804
2805fn flags_repr(flags: &Flags) -> Int {
2806    match flags.repr() {
2807        FlagsRepr::U8 => Int::U8,
2808        FlagsRepr::U16 => Int::U16,
2809        FlagsRepr::U32(1) => Int::U32,
2810        FlagsRepr::U32(2) => Int::U64,
2811        repr => panic!("unimplemented flags {repr:?}"),
2812    }
2813}
2814
2815fn indent(code: &str) -> Source {
2816    let mut indented = Source::default();
2817    let mut was_empty = false;
2818    for line in code.lines() {
2819        let trimmed = line.trim();
2820        if trimmed.is_empty() {
2821            if was_empty {
2822                continue;
2823            }
2824            was_empty = true;
2825        } else {
2826            was_empty = false;
2827        }
2828
2829        if trimmed.starts_with('}') {
2830            indented.deindent(2)
2831        }
2832        indented.push_str(trimmed);
2833        if trimmed.ends_with('{') && !trimmed.starts_with("///") {
2834            indented.indent(2)
2835        }
2836        indented.push_str("\n");
2837    }
2838    indented
2839}
2840
2841fn world_name(resolve: &Resolve, world: WorldId) -> String {
2842    format!("world.{}", resolve.worlds[world].name.to_lower_camel_case())
2843}
2844
2845fn interface_name(resolve: &Resolve, name: &WorldKey) -> String {
2846    let pkg = match name {
2847        WorldKey::Name(_) => None,
2848        WorldKey::Interface(id) => {
2849            let pkg = resolve.interfaces[*id].package.unwrap();
2850            Some(resolve.packages[pkg].name.clone())
2851        }
2852    };
2853
2854    let name = match name {
2855        WorldKey::Name(name) => name,
2856        WorldKey::Interface(id) => resolve.interfaces[*id].name.as_ref().unwrap(),
2857    }
2858    .to_lower_camel_case();
2859
2860    format!(
2861        "interface.{}{name}",
2862        if let Some(name) = &pkg {
2863            format!(
2864                "{}.{}.",
2865                name.namespace.to_moonbit_ident(),
2866                name.name.to_moonbit_ident()
2867            )
2868        } else {
2869            String::new()
2870        }
2871    )
2872}
2873
2874trait ToMoonBitIdent: ToOwned {
2875    fn to_moonbit_ident(&self) -> Self::Owned;
2876}
2877
2878impl ToMoonBitIdent for str {
2879    fn to_moonbit_ident(&self) -> String {
2880        // Escape MoonBit keywords and reserved keywords
2881        match self {
2882            // Keywords
2883            "as" | "else" | "extern" | "fn" | "fnalias" | "if" | "let" | "const" | "match" | "using"
2884            | "mut" | "type" | "typealias" | "struct" | "enum" | "trait" | "traitalias" | "derive"
2885            | "while" | "break" | "continue" | "import" | "return" | "throw" | "raise" | "try" | "catch"
2886            | "pub" | "priv" | "readonly" | "true" | "false" | "_" | "test" | "loop" | "for" | "in" | "impl"
2887            | "with" | "guard" | "async" | "is" | "suberror" | "and" | "letrec" | "enumview" | "noraise" 
2888            | "defer" | "init" | "main"
2889            // Reserved keywords
2890            | "module" | "move" | "ref" | "static" | "super" | "unsafe" | "use" | "where" | "await"
2891            | "dyn" | "abstract" | "do" | "final" | "macro" | "override" | "typeof" | "virtual" | "yield"
2892            | "local" | "method" | "alias" | "assert" | "package" | "recur" | "isnot" | "define" | "downcast"
2893            | "inherit" | "member" | "namespace" | "upcast" | "void" | "lazy" | "include" | "mixin"
2894            | "protected" | "sealed" | "constructor" | "atomic" | "volatile" | "anyframe" | "anytype"
2895            | "asm" | "comptime" | "errdefer" | "export" | "opaque" | "orelse" | "resume" | "threadlocal"
2896            | "unreachable" | "dynclass" | "dynobj" | "dynrec" | "var" | "finally" | "noasync" => {
2897                format!("{self}_")
2898            }
2899            _ => self.to_snake_case(),
2900        }
2901    }
2902}
2903
2904trait ToMoonBitTypeIdent: ToOwned {
2905    fn to_moonbit_type_ident(&self) -> Self::Owned;
2906}
2907
2908impl ToMoonBitTypeIdent for str {
2909    fn to_moonbit_type_ident(&self) -> String {
2910        // Escape MoonBit builtin types
2911        match self.to_upper_camel_case().as_str() {
2912            type_name @ ("Bool" | "Byte" | "Int" | "Int64" | "UInt" | "UInt64" | "Float"
2913            | "Double" | "Error" | "Buffer" | "Bytes" | "Array" | "FixedArray"
2914            | "Map" | "String" | "Option" | "Result" | "Char" | "Json") => {
2915                format!("{type_name}_")
2916            }
2917            type_name => type_name.to_owned(),
2918        }
2919    }
2920}
2921
2922fn generated_preamble(src: &mut Source, version: &str) {
2923    uwriteln!(src, "// Generated by `wit-bindgen` {version}.")
2924}
2925
2926fn print_docs(src: &mut String, docs: &Docs) {
2927    if let Some(docs) = &docs.contents {
2928        let lines = docs
2929            .trim()
2930            .lines()
2931            .map(|line| format!("/// {line}"))
2932            .collect::<Vec<_>>()
2933            .join("\n");
2934
2935        uwrite!(src, "{}", lines)
2936    }
2937}