Skip to main content

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