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