Skip to main content

wit_bindgen_moonbit/
lib.rs

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