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