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