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