wit_bindgen_moonbit/
lib.rs

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