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