Skip to main content

wit_bindgen_moonbit/
lib.rs

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