wit_bindgen_moonbit/
lib.rs

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