1use anyhow::Result;
2use core::panic;
3use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
4use std::{
5 collections::{HashMap, HashSet},
6 fmt::Write,
7 mem,
8 ops::Deref,
9};
10use wit_bindgen_core::{
11 abi::{self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmSignature, WasmType},
12 dealias, uwrite, uwriteln,
13 wit_parser::{
14 Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle,
15 Int, InterfaceId, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind,
16 TypeId, TypeOwner, Variant, WorldId, WorldKey,
17 },
18 AsyncFilterSet, Direction, Files, InterfaceGenerator as CoreInterfaceGenerator, Ns, Source,
19 WorldGenerator,
20};
21
22pub(crate) const FFI_DIR: &str = "ffi";
31
32pub(crate) const FFI: &str = include_str!("./async-wasm/ffi.mbt");
33
34pub(crate) const ASYNC_PRIMITIVE: &str = include_str!("./async-wasm/async_primitive.mbt");
35pub(crate) const ASYNC_FUTURE: &str = include_str!("./async-wasm/future.mbt");
36pub(crate) const ASYNC_WASM_PRIMITIVE: &str = include_str!("./async-wasm/wasm_primitive.mbt");
37pub(crate) const ASYNC_WAITABLE_SET: &str = include_str!("./async-wasm/waitable_task.mbt");
38pub(crate) const ASYNC_SUBTASK: &str = include_str!("./async-wasm/subtask.mbt");
39pub(crate) const ASYNC_UTILS: [&str; 5] = [
40 ASYNC_PRIMITIVE,
41 ASYNC_FUTURE,
42 ASYNC_WASM_PRIMITIVE,
43 ASYNC_WAITABLE_SET,
44 ASYNC_SUBTASK,
45];
46
47#[derive(Default, Debug, Clone)]
48#[cfg_attr(feature = "clap", derive(clap::Parser))]
49pub struct Opts {
50 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
52 pub derive_show: bool,
53
54 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
56 pub derive_eq: bool,
57
58 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
60 pub derive_error: bool,
61
62 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
64 pub ignore_stub: bool,
65
66 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
68 pub ignore_module_file: bool,
69
70 #[cfg_attr(feature = "clap", arg(long, default_value = "gen"))]
72 pub gen_dir: String,
73
74 #[cfg_attr(feature = "clap", arg(long, default_value = None))]
76 pub project_name: Option<String>,
77
78 #[cfg_attr(feature = "clap", clap(flatten))]
79 pub async_: AsyncFilterSet,
80}
81
82impl Opts {
83 pub fn build(&self) -> Box<dyn WorldGenerator> {
84 Box::new(MoonBit {
85 opts: self.clone(),
86 ..MoonBit::default()
87 })
88 }
89}
90
91struct MoonbitSignature {
92 name: String,
93 params: Vec<(String, Type)>,
94 result_type: Option<Type>,
95}
96
97struct InterfaceFragment {
98 src: String,
99 ffi: String,
100 stub: String,
101}
102
103enum PayloadFor {
104 Future,
105 Stream,
106}
107
108#[derive(Default)]
109struct Imports {
110 packages: HashMap<String, String>,
111 ns: Ns,
112}
113
114#[derive(Default)]
115pub struct MoonBit {
116 opts: Opts,
117 name: String,
118 needs_cleanup: bool,
119 import_interface_fragments: HashMap<String, Vec<InterfaceFragment>>,
120 export_interface_fragments: HashMap<String, Vec<InterfaceFragment>>,
121 import_world_fragments: Vec<InterfaceFragment>,
122 export_world_fragments: Vec<InterfaceFragment>,
123 sizes: SizeAlign,
124 import_interface_names: HashMap<InterfaceId, String>,
125 export_interface_names: HashMap<InterfaceId, String>,
126 interface_ns: Ns,
127 package_import: HashMap<String, Imports>,
129 export: HashMap<String, String>,
130 export_ns: Ns,
131 return_area_size: ArchitectureSize,
133 return_area_align: Alignment,
134
135 futures: HashMap<String, HashSet<TypeId>>,
136 is_async: bool,
137}
138
139impl MoonBit {
140 fn interface<'a>(
141 &'a mut self,
142 resolve: &'a Resolve,
143 name: &'a str,
144 module: &'a str,
145 direction: Direction,
146 ) -> InterfaceGenerator<'a> {
147 InterfaceGenerator {
148 src: String::new(),
149 stub: String::new(),
150 ffi: String::new(),
151 gen: self,
152 resolve,
153 name,
154 module,
155 direction,
156 }
157 }
158}
159
160impl WorldGenerator for MoonBit {
161 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
162 self.name = world_name(resolve, world);
163 self.sizes.fill(resolve);
164 }
165
166 fn import_interface(
167 &mut self,
168 resolve: &Resolve,
169 key: &WorldKey,
170 id: InterfaceId,
171 files: &mut Files,
172 ) -> Result<()> {
173 let name = interface_name(resolve, key);
174 let name = self.interface_ns.tmp(&name);
175 self.import_interface_names.insert(id, name.clone());
176
177 if let Some(content) = &resolve.interfaces[id].docs.contents {
178 if !content.is_empty() {
179 files.push(
180 &format!("{}/README.md", name.replace(".", "/")),
181 content.as_bytes(),
182 );
183 }
184 }
185
186 let module = &resolve.name_world_key(key);
187 let mut gen = self.interface(resolve, &name, module, Direction::Import);
188 gen.types(id);
189
190 for (_, func) in resolve.interfaces[id].functions.iter() {
191 gen.import(Some(key), func);
192 }
193
194 gen.add_interface_fragment();
195
196 Ok(())
197 }
198
199 fn import_funcs(
200 &mut self,
201 resolve: &Resolve,
202 world: WorldId,
203 funcs: &[(&str, &Function)],
204 _files: &mut Files,
205 ) {
206 let name = world_name(resolve, world);
207 let mut gen = self.interface(resolve, &name, "$root", Direction::Import);
208
209 for (_, func) in funcs {
210 gen.import(None, func); }
212
213 gen.add_world_fragment();
214 }
215
216 fn export_interface(
217 &mut self,
218 resolve: &Resolve,
219 key: &WorldKey,
220 id: InterfaceId,
221 files: &mut Files,
222 ) -> Result<()> {
223 let name = format!("{}.{}", self.opts.gen_dir, interface_name(resolve, key));
224 let name = self.interface_ns.tmp(&name);
225 self.export_interface_names.insert(id, name.clone());
226
227 if let Some(content) = &resolve.interfaces[id].docs.contents {
228 if !content.is_empty() {
229 files.push(
230 &format!("{}/README.md", name.replace(".", "/")),
231 content.as_bytes(),
232 );
233 }
234 }
235
236 let module = &resolve.name_world_key(key);
237 let mut gen = self.interface(resolve, &name, module, Direction::Export);
238 gen.types(id);
239
240 for (_, func) in resolve.interfaces[id].functions.iter() {
241 gen.export(Some(key), func, Some(name.clone()));
242 }
243
244 gen.add_interface_fragment();
245 Ok(())
246 }
247
248 fn export_funcs(
249 &mut self,
250 resolve: &Resolve,
251 world: WorldId,
252 funcs: &[(&str, &Function)],
253 _files: &mut Files,
254 ) -> Result<()> {
255 let name = format!("{}.{}", self.opts.gen_dir, world_name(resolve, world));
256 let mut gen = self.interface(resolve, &name, "$root", Direction::Export);
257
258 for (_, func) in funcs {
259 gen.export(None, func, Some(name.clone()));
260 }
261
262 gen.add_world_fragment();
263 Ok(())
264 }
265
266 fn import_types(
267 &mut self,
268 resolve: &Resolve,
269 world: WorldId,
270 types: &[(&str, TypeId)],
271 _files: &mut Files,
272 ) {
273 let name = world_name(resolve, world);
274 let mut gen = self.interface(resolve, &name, "$root", Direction::Import);
275
276 for (ty_name, ty) in types {
277 gen.define_type(ty_name, *ty);
278 }
279
280 gen.add_world_fragment();
281 }
282
283 fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
284 let project_name = self
285 .opts
286 .project_name
287 .clone()
288 .or(resolve.worlds[id].package.map(|id| {
289 let package = &resolve.packages[id].name;
290 format!("{}/{}", package.namespace, package.name)
291 }))
292 .unwrap_or("generated".into());
293 let name = world_name(resolve, id);
294
295 if let Some(content) = &resolve.worlds[id].docs.contents {
296 if !content.is_empty() {
297 files.push(
298 &format!("{}/README.md", name.replace(".", "/")),
299 content.as_bytes(),
300 );
301 }
302 }
303
304 let version = env!("CARGO_PKG_VERSION");
305
306 let generate_pkg_definition = |name: &String, files: &mut Files| {
307 let directory = name.replace('.', "/");
308 let imports: Option<&Imports> = self.package_import.get(name);
309 if let Some(imports) = imports {
310 let mut deps = imports
311 .packages
312 .iter()
313 .map(|(k, v)| {
314 format!(
315 "{{ \"path\" : \"{project_name}/{}\", \"alias\" : \"{}\" }}",
316 k.replace(".", "/"),
317 v
318 )
319 })
320 .collect::<Vec<_>>();
321 deps.sort();
322
323 files.push(
324 &format!("{directory}/moon.pkg.json"),
325 format!("{{ \"import\": [{}] }}", deps.join(", ")).as_bytes(),
326 );
327 } else {
328 files.push(
329 &format!("{directory}/moon.pkg.json"),
330 "{ }".to_string().as_bytes(),
331 );
332 }
333 };
334
335 let mut src = Source::default();
337 let mut ffi = Source::default();
338 wit_bindgen_core::generated_preamble(&mut src, version);
339 wit_bindgen_core::generated_preamble(&mut ffi, version);
340 self.import_world_fragments.iter().for_each(|f| {
341 uwriteln!(src, "{}", f.src);
342 uwriteln!(ffi, "{}", f.ffi);
343 assert!(f.stub.is_empty());
344 });
345
346 let directory = name.replace('.', "/");
347 files.push(&format!("{directory}/import.mbt"), indent(&src).as_bytes());
348 files.push(
349 &format!("{directory}/ffi_import.mbt"),
350 indent(&ffi).as_bytes(),
351 );
352 generate_pkg_definition(&name, files);
353
354 let mut src = Source::default();
356 let mut stub = Source::default();
357 wit_bindgen_core::generated_preamble(&mut src, version);
358 generated_preamble(&mut stub, version);
359 self.export_world_fragments.iter().for_each(|f| {
360 uwriteln!(src, "{}", f.src);
361 uwriteln!(stub, "{}", f.stub);
362 });
363
364 files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
365 if !self.opts.ignore_stub {
366 files.push(
367 &format!("{}/{directory}/stub.mbt", self.opts.gen_dir),
368 indent(&stub).as_bytes(),
369 );
370 generate_pkg_definition(&format!("{}.{}", self.opts.gen_dir, name), files);
371 }
372
373 let generate_ffi =
374 |directory: String, fragments: &[InterfaceFragment], files: &mut Files| {
375 let b = fragments
376 .iter()
377 .map(|f| f.ffi.deref())
378 .collect::<Vec<_>>()
379 .join("\n");
380
381 let mut body = Source::default();
382 wit_bindgen_core::generated_preamble(&mut body, version);
383 uwriteln!(&mut body, "{b}");
384
385 files.push(
386 &format!(
387 "{}/{}_export.mbt",
388 self.opts.gen_dir,
389 directory.to_snake_case()
390 ),
391 indent(&body).as_bytes(),
392 );
393 };
394
395 generate_ffi(directory, &self.export_world_fragments, files);
396
397 for (name, fragments) in &self.import_interface_fragments {
399 let mut src = Source::default();
400 let mut ffi = Source::default();
401 wit_bindgen_core::generated_preamble(&mut src, version);
402 wit_bindgen_core::generated_preamble(&mut ffi, version);
403 fragments.iter().for_each(|f| {
404 uwriteln!(src, "{}", f.src);
405 uwriteln!(ffi, "{}", f.ffi);
406 assert!(f.stub.is_empty());
407 });
408
409 let directory = name.replace('.', "/");
410 files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
411 files.push(&format!("{directory}/ffi.mbt"), indent(&ffi).as_bytes());
412 generate_pkg_definition(name, files);
413 }
414
415 for (name, fragments) in &self.export_interface_fragments {
417 let mut src = Source::default();
418 let mut stub = Source::default();
419 wit_bindgen_core::generated_preamble(&mut src, version);
420 generated_preamble(&mut stub, version);
421 fragments.iter().for_each(|f| {
422 uwriteln!(src, "{}", f.src);
423 uwriteln!(stub, "{}", f.stub);
424 });
425
426 let directory = name.replace('.', "/");
427 files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
428 if !self.opts.ignore_stub {
429 files.push(&format!("{directory}/stub.mbt"), indent(&stub).as_bytes());
430 generate_pkg_definition(name, files);
431 }
432 generate_ffi(directory, fragments, files);
433 }
434
435 let mut body = Source::default();
437 wit_bindgen_core::generated_preamble(&mut body, version);
438 body.push_str(FFI);
439
440 if self.is_async || !self.futures.is_empty() {
443 ASYNC_UTILS.iter().for_each(|s| {
444 body.push_str("\n");
445 body.push_str(s);
446 });
447 }
448
449 files.push(&format!("{FFI_DIR}/top.mbt"), indent(&body).as_bytes());
450 files.push(
451 &format!("{FFI_DIR}/moon.pkg.json"),
452 "{ \"warn-list\": \"-44\", \"supported-targets\": [\"wasm\"] }".as_bytes(),
453 );
454
455 if !self.opts.ignore_stub && !self.opts.ignore_module_file {
457 let mut body = Source::default();
458 uwriteln!(
459 &mut body,
460 "{{ \"name\": \"{project_name}\", \"preferred-target\": \"wasm\" }}"
461 );
462 files.push("moon.mod.json", body.as_bytes());
463 }
464
465 let export_dir = self.opts.gen_dir.clone();
466
467 let mut gen = self.interface(resolve, export_dir.as_str(), "", Direction::Export);
469 let ffi_qualifier = gen.qualify_package(FFI_DIR);
470
471 let mut body = Source::default();
472 wit_bindgen_core::generated_preamble(&mut body, version);
473 uwriteln!(
474 &mut body,
475 "
476 pub fn cabi_realloc(
477 src_offset : Int,
478 src_size : Int,
479 dst_alignment : Int,
480 dst_size : Int
481 ) -> Int {{
482 {ffi_qualifier}cabi_realloc(src_offset, src_size, dst_alignment, dst_size)
483 }}
484 "
485 );
486 if !self.return_area_size.is_empty() {
487 uwriteln!(
488 &mut body,
489 "
490 let return_area : Int = {ffi_qualifier}malloc({})
491 ",
492 self.return_area_size.size_wasm32(),
493 );
494 }
495 files.push(
496 &format!("{}/ffi.mbt", self.opts.gen_dir),
497 indent(&body).as_bytes(),
498 );
499 self.export
500 .insert("cabi_realloc".into(), "cabi_realloc".into());
501
502 let mut body = Source::default();
503 let mut exports = self
504 .export
505 .iter()
506 .map(|(k, v)| format!("\"{k}:{v}\""))
507 .collect::<Vec<_>>();
508 exports.sort();
509
510 uwrite!(
511 &mut body,
512 r#"
513 {{
514 "link": {{
515 "wasm": {{
516 "exports": [{}],
517 "export-memory-name": "memory",
518 "heap-start-address": 16
519 }}
520 }}
521 "#,
522 exports.join(", ")
523 );
524 if let Some(imports) = self.package_import.get(&self.opts.gen_dir) {
525 let mut deps = imports
526 .packages
527 .iter()
528 .map(|(k, v)| {
529 format!(
530 "{{ \"path\" : \"{project_name}/{}\", \"alias\" : \"{}\" }}",
531 k.replace(".", "/"),
532 v
533 )
534 })
535 .collect::<Vec<_>>();
536 deps.sort();
537
538 uwrite!(&mut body, " ,\"import\": [{}]", deps.join(", "));
539 }
540 uwrite!(
541 &mut body,
542 "
543 }}
544 ",
545 );
546 files.push(
547 &format!("{}/moon.pkg.json", self.opts.gen_dir,),
548 indent(&body).as_bytes(),
549 );
550
551 Ok(())
552 }
553}
554
555struct InterfaceGenerator<'a> {
556 src: String,
557 stub: String,
558 ffi: String,
559 gen: &'a mut MoonBit,
560 resolve: &'a Resolve,
561 name: &'a str,
563 module: &'a str,
564 direction: Direction,
565}
566
567impl InterfaceGenerator<'_> {
568 fn qualify_package(&mut self, name: &str) -> String {
569 if name != self.name {
570 let imports = self
571 .gen
572 .package_import
573 .entry(self.name.to_string())
574 .or_default();
575 if let Some(alias) = imports.packages.get(name) {
576 format!("@{alias}.")
577 } else {
578 let alias = imports
579 .ns
580 .tmp(&name.split(".").last().unwrap().to_lower_camel_case());
581 imports
582 .packages
583 .entry(name.to_string())
584 .or_insert(alias.clone());
585 format!("@{alias}.")
586 }
587 } else {
588 "".into()
589 }
590 }
591 fn qualifier(&mut self, ty: &TypeDef) -> String {
592 if let TypeOwner::Interface(id) = &ty.owner {
593 if let Some(name) = self.gen.export_interface_names.get(id) {
594 if name != self.name {
595 return self.qualify_package(&name.clone());
596 }
597 } else if let Some(name) = self.gen.import_interface_names.get(id) {
598 if name != self.name {
599 return self.qualify_package(&name.clone());
600 }
601 }
602 } else if let TypeOwner::World(id) = &ty.owner {
603 let name = world_name(self.resolve, *id);
604 if name != self.name {
605 return self.qualify_package(&name.clone());
606 }
607 }
608
609 String::new()
610 }
611
612 fn add_interface_fragment(self) {
613 match self.direction {
614 Direction::Import => {
615 self.gen
616 .import_interface_fragments
617 .entry(self.name.to_owned())
618 .or_default()
619 .push(InterfaceFragment {
620 src: self.src,
621 stub: self.stub,
622 ffi: self.ffi,
623 });
624 }
625 Direction::Export => {
626 self.gen
627 .export_interface_fragments
628 .entry(self.name.to_owned())
629 .or_default()
630 .push(InterfaceFragment {
631 src: self.src,
632 stub: self.stub,
633 ffi: self.ffi,
634 });
635 }
636 }
637 }
638
639 fn add_world_fragment(self) {
640 match self.direction {
641 Direction::Import => {
642 self.gen.import_world_fragments.push(InterfaceFragment {
643 src: self.src,
644 stub: self.stub,
645 ffi: self.ffi,
646 });
647 }
648 Direction::Export => {
649 self.gen.export_world_fragments.push(InterfaceFragment {
650 src: self.src,
651 stub: self.stub,
652 ffi: self.ffi,
653 });
654 }
655 }
656 }
657
658 fn import(&mut self, module: Option<&WorldKey>, func: &Function) {
659 let async_ = self
660 .gen
661 .opts
662 .async_
663 .is_async(self.resolve, module, func, false);
664 if async_ {
665 self.gen.is_async = true;
666 }
667
668 let interface_name = match module {
669 Some(key) => &self.resolve.name_world_key(key),
670 None => "$root",
671 };
672 let mut bindgen = FunctionBindgen::new(
673 self,
674 &func.name,
675 self.name,
676 func.params
677 .iter()
678 .map(|(name, _)| name.to_moonbit_ident())
679 .collect(),
680 );
681
682 let (variant, async_prefix) = if async_ {
683 (AbiVariant::GuestImportAsync, "[async-lower]")
684 } else {
685 (AbiVariant::GuestImport, "")
686 };
687
688 abi::call(
689 bindgen.gen.resolve,
690 AbiVariant::GuestImport,
691 LiftLower::LowerArgsLiftResults,
692 func,
693 &mut bindgen,
694 false,
695 );
696
697 let mut src = bindgen.src.clone();
698
699 let cleanup_list = if bindgen.needs_cleanup_list {
700 self.gen.needs_cleanup = true;
701
702 let ffi_qualifier = self.qualify_package(FFI_DIR);
703
704 format!(
705 r#"let cleanupList : Array[{ffi_qualifier}Cleanup] = []
706 let ignoreList : Array[&{ffi_qualifier}Any] = []"#
707 )
708 } else {
709 String::new()
710 };
711
712 let name = &func.name;
713
714 let wasm_sig = self.resolve.wasm_signature(variant, func);
715
716 let result_type = match &wasm_sig.results[..] {
717 [] => "".into(),
718 [result] => format!("-> {}", wasm_type(*result)),
719 _ => unreachable!(),
720 };
721
722 let camel_name = func.name.to_upper_camel_case();
723
724 let params = wasm_sig
725 .params
726 .iter()
727 .enumerate()
728 .map(|(i, param)| {
729 let ty = wasm_type(*param);
730 format!("p{i} : {ty}")
731 })
732 .collect::<Vec<_>>()
733 .join(", ");
734
735 let mbt_sig = self.mbt_sig(func, false);
736 let sig = self.sig_string(&mbt_sig, async_);
737
738 let module = match module {
739 Some(key) => self.resolve.name_world_key(key),
740 None => "$root".into(),
741 };
742
743 self.generation_futures_and_streams_import("", func, interface_name);
744
745 uwriteln!(
746 self.ffi,
747 r#"fn wasmImport{camel_name}({params}) {result_type} = "{module}" "{async_prefix}{name}""#
748 );
749
750 print_docs(&mut self.src, &func.docs);
751
752 if async_ {
753 src = self.generate_async_import_function(func, mbt_sig, &wasm_sig);
754 }
755
756 uwrite!(
757 self.src,
758 r#"
759 {sig} {{
760 {cleanup_list}
761 {src}
762 }}
763 "#
764 );
765 }
766
767 fn generate_async_import_function(
768 &mut self,
769 func: &Function,
770 mbt_sig: MoonbitSignature,
771 sig: &WasmSignature,
772 ) -> String {
773 let mut body = String::default();
774 let mut lower_params = Vec::new();
775 let mut lower_results = Vec::new();
776
777 if sig.indirect_params {
778 match &func.params[..] {
779 [] => {}
780 [(_, _)] => {
781 lower_params.push("_lower_ptr".into());
782 }
783 multiple_params => {
784 let params = multiple_params.iter().map(|(_, ty)| ty);
785 let offsets = self.gen.sizes.field_offsets(params.clone());
786 let elem_info = self.gen.sizes.params(params);
787 body.push_str(&format!(
788 r#"
789 let _lower_ptr : Int = {ffi}malloc({})
790 "#,
791 elem_info.size.size_wasm32(),
792 ffi = self.qualify_package(FFI_DIR)
793 ));
794
795 for ((offset, ty), name) in offsets.iter().zip(
796 multiple_params
797 .iter()
798 .map(|(name, _)| name.to_moonbit_ident()),
799 ) {
800 let result = self.lower_to_memory(
801 &format!("_lower_ptr + {}", offset.size_wasm32()),
802 &name,
803 ty,
804 self.name,
805 );
806 body.push_str(&result);
807 }
808
809 lower_params.push("_lower_ptr".into());
810 }
811 }
812 } else {
813 let mut f = FunctionBindgen::new(self, "INVALID", self.name, Box::new([]));
814 for (name, ty) in mbt_sig.params.iter() {
815 lower_params.extend(abi::lower_flat(f.gen.resolve, &mut f, name.clone(), ty));
816 }
817 lower_results.push(f.src.clone());
818 }
819
820 let func_name = func.name.to_upper_camel_case();
821
822 let ffi = self.qualify_package(FFI_DIR);
823
824 let call_import = |params: &Vec<String>| {
825 format!(
826 r#"
827 let _subtask_code = wasmImport{func_name}({})
828 let _subtask_status = {ffi}SubtaskStatus::decode(_subtask_code)
829 let _subtask = @ffi.Subtask::from_handle(_subtask_status.handle(), code=_subtask_code)
830
831 let task = @ffi.current_task()
832 task.add_waitable(_subtask, @ffi.current_coroutine())
833 defer task.remove_waitable(_subtask)
834
835 for {{
836 if _subtask.done() || _subtask_status is Returned(_) {{
837 break
838 }} else {{
839 @ffi.suspend()
840 }}
841 }}
842
843 "#,
844 params.join(", ")
845 )
846 };
847 match &func.result {
848 Some(ty) => {
849 lower_params.push("_result_ptr".into());
850 let call_import = call_import(&lower_params);
851 let (lift, lift_result) = &self.lift_from_memory("_result_ptr", ty, self.name);
852 body.push_str(&format!(
853 r#"
854 {}
855 {}
856 {call_import}
857 {lift}
858 {lift_result}
859 "#,
860 lower_results.join("\n"),
861 &self.malloc_memory("_result_ptr", "1", ty)
862 ));
863 }
864 None => {
865 let call_import = call_import(&lower_params);
866 body.push_str(&call_import);
867 }
868 }
869
870 body.to_string()
871 }
872
873 fn export(&mut self, interface: Option<&WorldKey>, func: &Function, _: Option<String>) {
874 let async_ = self
875 .gen
876 .opts
877 .async_
878 .is_async(self.resolve, interface, func, false);
879 if async_ {
880 self.gen.is_async = true;
881 }
882
883 let variant = if async_ {
884 AbiVariant::GuestExportAsync
885 } else {
886 AbiVariant::GuestExport
887 };
888
889 let sig = self.resolve.wasm_signature(variant, func);
890 let mbt_sig = self.mbt_sig(func, false);
891
892 let func_sig = self.sig_string(&mbt_sig, async_);
893 let export_dir = self.gen.opts.gen_dir.clone();
894
895 let mut toplevel_generator = self.gen.interface(
896 self.resolve,
897 export_dir.as_str(),
898 self.module,
899 Direction::Export,
900 );
901
902 let mut bindgen = FunctionBindgen::new(
903 &mut toplevel_generator,
904 &func.name,
905 self.name,
906 (0..sig.params.len()).map(|i| format!("p{i}")).collect(),
907 );
908
909 abi::call(
910 bindgen.gen.resolve,
911 variant,
912 LiftLower::LiftArgsLowerResults,
913 func,
914 &mut bindgen,
915 async_,
916 );
917
918 assert!(!bindgen.needs_cleanup_list);
920
921 let deferred_task_return = bindgen.deferred_task_return.clone();
923
924 let src = bindgen.src;
925 assert!(toplevel_generator.src.is_empty());
926 assert!(toplevel_generator.ffi.is_empty());
927
928 let result_type = match &sig.results[..] {
929 [] => "Unit",
930 [result] => wasm_type(*result),
931 _ => unreachable!(),
932 };
933
934 let camel_name = func.name.to_upper_camel_case();
935
936 let func_name = self.gen.export_ns.tmp(&format!("wasmExport{camel_name}"));
937
938 let params = sig
939 .params
940 .iter()
941 .enumerate()
942 .map(|(i, param)| {
943 let ty = wasm_type(*param);
944 format!("p{i} : {ty}")
945 })
946 .collect::<Vec<_>>()
947 .join(", ");
948
949 let async_export_prefix = if async_ { "[async-lift]" } else { "" };
951 let interface_name = match interface {
953 Some(key) => Some(self.resolve.name_world_key(key)),
954 None => None,
955 };
956
957 let export_name = func.legacy_core_export_name(interface_name.as_deref());
958 let module_name = interface_name.as_deref().unwrap_or("$root");
959 self.generation_futures_and_streams_import("[export]", func, module_name);
960
961 uwrite!(
962 self.ffi,
963 r#"
964 pub fn {func_name}({params}) -> {result_type} {{
965 {src}
966 }}
967 "#,
968 );
969
970 self.gen
971 .export
972 .insert(func_name, format!("{async_export_prefix}{export_name}"));
973
974 if async_ {
975 let snake = self.gen.name.to_lower_camel_case();
976 let export_func_name = self
977 .gen
978 .export_ns
979 .tmp(&format!("wasmExport{snake}Async{camel_name}"));
980 let DeferredTaskReturn::Emitted {
981 body: task_return_body,
982 params: task_return_params,
983 return_param,
984 } = deferred_task_return
985 else {
986 unreachable!()
987 };
988 let func_name = func.name.clone();
989 let import_module = self.resolve.name_world_key(interface.unwrap());
990 self.gen.export.insert(
991 export_func_name.clone(),
992 format!("[callback]{async_export_prefix}{export_name}"),
993 );
994 let task_return_param_tys = task_return_params
995 .iter()
996 .enumerate()
997 .map(|(idx, (ty, _expr))| format!("p{}: {}", idx, wasm_type(*ty)))
998 .collect::<Vec<_>>()
999 .join(", ");
1000 let task_return_param_exprs = task_return_params
1001 .iter()
1002 .map(|(_ty, expr)| expr.as_str())
1003 .collect::<Vec<_>>()
1004 .join(", ");
1005 let return_ty = match &func.result {
1006 Some(result) => self.type_name(result, true).to_string(),
1007 None => "Unit".into(),
1008 };
1009 let return_expr = match return_ty.as_str() {
1010 "Unit" => "".into(),
1011 _ => format!("{return_param}: {return_ty}",),
1012 };
1013 let snake_func_name = func.name.to_moonbit_ident().to_string();
1014 let ffi = self.qualify_package(FFI_DIR);
1015
1016 uwriteln!(
1017 self.src,
1018 r#"
1019 fn {export_func_name}TaskReturn({task_return_param_tys}) = "[export]{import_module}" "[task-return]{func_name}"
1020
1021 pub fn {snake_func_name}_task_return({return_expr}) -> Unit {{
1022 {task_return_body}
1023 {export_func_name}TaskReturn({task_return_param_exprs})
1024 }}
1025 "#
1026 );
1027
1028 uwriteln!(
1029 self.ffi,
1030 r#"
1031 pub fn {export_func_name}(event_raw: Int, waitable: Int, code: Int) -> Int {{
1032 {ffi}callback(event_raw, waitable, code)
1033 }}
1034 "#
1035 );
1036 } else if abi::guest_export_needs_post_return(self.resolve, func) {
1037 let params = sig
1038 .results
1039 .iter()
1040 .enumerate()
1041 .map(|(i, param)| {
1042 let ty = wasm_type(*param);
1043 format!("p{i} : {ty}")
1044 })
1045 .collect::<Vec<_>>()
1046 .join(", ");
1047
1048 let mut bindgen = FunctionBindgen::new(
1049 self,
1050 "INVALID",
1051 self.name,
1052 (0..sig.results.len()).map(|i| format!("p{i}")).collect(),
1053 );
1054
1055 abi::post_return(bindgen.gen.resolve, func, &mut bindgen);
1056
1057 let src = bindgen.src;
1058
1059 let func_name = self
1060 .gen
1061 .export_ns
1062 .tmp(&format!("wasmExport{camel_name}PostReturn"));
1063
1064 uwrite!(
1065 self.ffi,
1066 r#"
1067 pub fn {func_name}({params}) -> Unit {{
1068 {src}
1069 }}
1070 "#
1071 );
1072 self.gen
1073 .export
1074 .insert(func_name, format!("cabi_post_{export_name}"));
1075 }
1076
1077 print_docs(&mut self.stub, &func.docs);
1078 uwrite!(
1079 self.stub,
1080 r#"
1081 {func_sig} {{
1082 ...
1083 }}
1084 "#
1085 );
1086 }
1087
1088 fn mbt_sig(&mut self, func: &Function, ignore_param: bool) -> MoonbitSignature {
1089 let name = match func.kind {
1090 FunctionKind::Freestanding => func.name.to_moonbit_ident(),
1091 FunctionKind::Constructor(_) => {
1092 func.name.replace("[constructor]", "").to_moonbit_ident()
1093 }
1094 _ => func.name.split(".").last().unwrap().to_moonbit_ident(),
1095 };
1096 let type_name = match func.kind.resource() {
1097 Some(ty) => {
1098 format!("{}::", self.type_name(&Type::Id(ty), true))
1099 }
1100 None => "".into(),
1101 };
1102
1103 let params = func
1104 .params
1105 .iter()
1106 .map(|(name, ty)| {
1107 let name = if ignore_param {
1108 format!("_{}", name.to_moonbit_ident())
1109 } else {
1110 name.to_moonbit_ident()
1111 };
1112 (name, *ty)
1113 })
1114 .collect::<Vec<_>>();
1115
1116 MoonbitSignature {
1117 name: format!("{type_name}{name}"),
1118 params,
1119 result_type: func.result,
1120 }
1121 }
1122
1123 fn type_name(&mut self, ty: &Type, type_variable: bool) -> String {
1124 match ty {
1125 Type::Bool => "Bool".into(),
1126 Type::U8 => "Byte".into(),
1127 Type::S32 | Type::S8 | Type::S16 => "Int".into(),
1128 Type::U16 | Type::U32 => "UInt".into(),
1129 Type::Char => "Char".into(),
1130 Type::U64 => "UInt64".into(),
1131 Type::S64 => "Int64".into(),
1132 Type::F32 => "Float".into(),
1133 Type::F64 => "Double".into(),
1134 Type::String => "String".into(),
1135 Type::ErrorContext => todo!("moonbit error context type name"),
1136 Type::Id(id) => {
1137 let ty = &self.resolve.types[dealias(self.resolve, *id)];
1138 match &ty.kind {
1139 TypeDefKind::Type(ty) => self.type_name(ty, type_variable),
1140 TypeDefKind::List(ty) => {
1141 if type_variable {
1142 match ty {
1143 Type::U8
1144 | Type::U32
1145 | Type::U64
1146 | Type::S32
1147 | Type::S64
1148 | Type::F32
1149 | Type::F64 => {
1150 format!("FixedArray[{}]", self.type_name(ty, type_variable))
1151 }
1152 _ => format!("Array[{}]", self.type_name(ty, type_variable)),
1153 }
1154 } else {
1155 "Array".into()
1156 }
1157 }
1158 TypeDefKind::Tuple(tuple) => {
1159 if type_variable {
1160 format!(
1161 "({})",
1162 tuple
1163 .types
1164 .iter()
1165 .map(|ty| self.type_name(ty, type_variable))
1166 .collect::<Vec<_>>()
1167 .join(", ")
1168 )
1169 } else {
1170 unreachable!()
1171 }
1172 }
1173 TypeDefKind::Option(ty) => {
1174 if type_variable {
1175 format!("{}?", self.type_name(ty, type_variable))
1176 } else {
1177 "Option".into()
1178 }
1179 }
1180 TypeDefKind::Result(result) => {
1181 if type_variable {
1182 let mut name = |ty: &Option<Type>| {
1183 ty.as_ref()
1184 .map(|ty| self.type_name(ty, true))
1185 .unwrap_or_else(|| "Unit".into())
1186 };
1187 let ok = name(&result.ok);
1188 let err = name(&result.err);
1189
1190 format!("Result[{ok}, {err}]")
1191 } else {
1192 "Result".into()
1193 }
1194 }
1195 TypeDefKind::Handle(handle) => {
1196 let ty = match handle {
1197 Handle::Own(ty) => ty,
1198 Handle::Borrow(ty) => ty,
1199 };
1200 let ty = &self.resolve.types[dealias(self.resolve, *ty)];
1201 if let Some(name) = &ty.name {
1202 format!("{}{}", self.qualifier(ty), name.to_moonbit_type_ident())
1203 } else {
1204 unreachable!()
1205 }
1206 }
1207
1208 TypeDefKind::Future(ty) => {
1209 let qualifier = self.qualify_package(FFI_DIR);
1210 format!(
1211 "{}FutureReader[{}]",
1212 qualifier,
1213 ty.as_ref()
1214 .map(|t| self.type_name(t, type_variable))
1215 .unwrap_or_else(|| "Unit".into())
1216 )
1217 }
1218
1219 TypeDefKind::Stream(ty) => {
1220 let qualifier = self.qualify_package(FFI_DIR);
1221 format!(
1222 "{}StreamReader[{}]",
1223 qualifier,
1224 ty.as_ref()
1225 .map(|t| self.type_name(t, type_variable))
1226 .unwrap_or_else(|| "Unit".into())
1227 )
1228 }
1229
1230 _ => {
1231 if let Some(name) = &ty.name {
1232 format!("{}{}", self.qualifier(ty), name.to_moonbit_type_ident())
1233 } else {
1234 unreachable!()
1235 }
1236 }
1237 }
1238 }
1239 }
1240 }
1241
1242 fn non_empty_type<'a>(&self, ty: Option<&'a Type>) -> Option<&'a Type> {
1243 if let Some(ty) = ty {
1244 let id = match ty {
1245 Type::Id(id) => *id,
1246 _ => return Some(ty),
1247 };
1248 match &self.resolve.types[id].kind {
1249 TypeDefKind::Type(t) => self.non_empty_type(Some(t)).map(|_| ty),
1250 TypeDefKind::Record(r) => (!r.fields.is_empty()).then_some(ty),
1251 TypeDefKind::Tuple(t) => (!t.types.is_empty()).then_some(ty),
1252 _ => Some(ty),
1253 }
1254 } else {
1255 None
1256 }
1257 }
1258
1259 fn deallocate_lists(
1260 &mut self,
1261 types: &[Type],
1262 operands: &[String],
1263 indirect: bool,
1264 module: &str,
1265 ) -> String {
1266 let mut f = FunctionBindgen::new(self, "INVALID", module, Box::new([]));
1267 abi::deallocate_lists_in_types(f.r#gen.resolve, types, operands, indirect, &mut f);
1268 f.src
1269 }
1270
1271 fn lift_from_memory(&mut self, address: &str, ty: &Type, module: &str) -> (String, String) {
1272 let mut f = FunctionBindgen::new(self, "INVALID", module, Box::new([]));
1273
1274 let result = abi::lift_from_memory(f.gen.resolve, &mut f, address.into(), ty);
1275 (f.src, result)
1276 }
1277
1278 fn lower_to_memory(&mut self, address: &str, value: &str, ty: &Type, module: &str) -> String {
1279 let mut f = FunctionBindgen::new(self, "INVALID", module, Box::new([]));
1280 abi::lower_to_memory(f.gen.resolve, &mut f, address.into(), value.into(), ty);
1281 f.src
1282 }
1283
1284 fn malloc_memory(&mut self, address: &str, length: &str, ty: &Type) -> String {
1285 let size = self.gen.sizes.size(ty).size_wasm32();
1286 let ffi = self.qualify_package(FFI_DIR);
1287 format!("let {address} = {ffi}malloc({size} * {length});")
1288 }
1289
1290 fn is_list_canonical(&self, _resolve: &Resolve, element: &Type) -> bool {
1291 matches!(
1292 element,
1293 Type::U8 | Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64
1294 )
1295 }
1296
1297 fn list_lift_from_memory(
1298 &mut self,
1299 address: &str,
1300 length: &str,
1301 lift_func: &str,
1302 ty: &Type,
1303 ) -> String {
1304 let ffi = self.qualify_package(FFI_DIR);
1305 if self.is_list_canonical(self.resolve, ty) {
1306 if ty == &Type::U8 {
1307 return format!("{ffi}ptr2bytes({address}, {length})");
1308 }
1309 let ty = match ty {
1310 Type::U32 => "uint",
1311 Type::U64 => "uint64",
1312 Type::S32 => "int",
1313 Type::S64 => "int64",
1314 Type::F32 => "float",
1315 Type::F64 => "double",
1316 _ => unreachable!(),
1317 };
1318
1319 return format!("{ffi}ptr2{ty}_array({address}, {length})");
1320 }
1321 let size = self.gen.sizes.size(ty).size_wasm32();
1322 format!(
1323 r#"
1324 FixedArray::makei(
1325 {length},
1326 (index) => {{
1327 let ptr = ({address}) + (index * {size});
1328 {lift_func}(ptr)
1329 }}
1330 )
1331 "#
1332 )
1333 }
1334
1335 fn list_lower_to_memory(&mut self, lower_func: &str, value: &str, ty: &Type) -> String {
1336 let ffi = self.qualify_package(FFI_DIR);
1338 if self.is_list_canonical(self.resolve, ty) {
1339 if ty == &Type::U8 {
1340 return format!("{ffi}bytes2ptr({value})");
1341 }
1342
1343 let ty = match ty {
1344 Type::U32 => "uint",
1345 Type::U64 => "uint64",
1346 Type::S32 => "int",
1347 Type::S64 => "int64",
1348 Type::F32 => "float",
1349 Type::F64 => "double",
1350 _ => unreachable!(),
1351 };
1352 return format!("{ffi}{ty}_array2ptr({value})");
1353 }
1354 let size = self.gen.sizes.size(ty).size_wasm32();
1355 format!(
1356 r#"
1357 let address = {ffi}malloc(({value}).length() * {size});
1358 for index = 0; index < ({value}).length(); index = index + 1 {{
1359 let ptr = (address) + (index * {size});
1360 let value = {value}[index];
1361 {lower_func}(value, ptr);
1362 }}
1363 address
1364 "#
1365 )
1366 }
1367
1368 fn generation_futures_and_streams_import(
1369 &mut self,
1370 prefix: &str,
1371 func: &Function,
1372 module: &str,
1373 ) {
1374 let module = format!("{prefix}{module}");
1375 for (index, ty) in func
1376 .find_futures_and_streams(self.resolve)
1377 .into_iter()
1378 .enumerate()
1379 {
1380 let func_name = &func.name;
1381
1382 match &self.resolve.types[ty].kind {
1383 TypeDefKind::Future(payload_type) => {
1384 self.generate_async_future_or_stream_import(
1385 PayloadFor::Future,
1386 &module,
1387 index,
1388 func_name,
1389 ty,
1390 payload_type.as_ref(),
1391 );
1392 }
1393 TypeDefKind::Stream(payload_type) => {
1394 self.generate_async_future_or_stream_import(
1395 PayloadFor::Stream,
1396 &module,
1397 index,
1398 func_name,
1399 ty,
1400 payload_type.as_ref(),
1401 );
1402 }
1403 _ => unreachable!(),
1404 }
1405 }
1406 }
1407
1408 fn generate_async_future_or_stream_import(
1409 &mut self,
1410 payload_for: PayloadFor,
1411 module: &str,
1412 index: usize,
1413 func_name: &str,
1414 ty: TypeId,
1415 result_type: Option<&Type>,
1416 ) {
1417 if let Some(set) = self.gen.futures.get(module) {
1418 if set.contains(&ty) {
1419 return;
1420 }
1421 }
1422
1423 self.gen
1424 .futures
1425 .entry(module.to_string())
1426 .or_default()
1427 .insert(ty);
1428 let result = match result_type {
1429 Some(ty) => self.type_name(ty, true),
1430 None => "Unit".into(),
1431 };
1432
1433 let type_name = self.type_name(&Type::Id(ty), true);
1434 let name = result.to_upper_camel_case();
1435 let kind = match payload_for {
1436 PayloadFor::Future => "future",
1437 PayloadFor::Stream => "stream",
1438 };
1439 let table_name = format!("{}_{}_table", type_name.to_snake_case(), kind);
1440 let camel_kind = kind.to_upper_camel_case();
1441 let payload_len_arg = match payload_for {
1442 PayloadFor::Future => "",
1443 PayloadFor::Stream => " ,length : Int",
1444 };
1445
1446 let payload_lift_func = match payload_for {
1447 PayloadFor::Future => "",
1448 PayloadFor::Stream => "List",
1449 };
1450 let ffi = self.qualify_package(FFI_DIR);
1451
1452 let mut dealloc_list;
1453 let malloc;
1454 let lift;
1455 let lower;
1456 let lift_result;
1457 let lift_list: String;
1458 let lower_list: String;
1459 if let Some(result_type) = result_type {
1460 (lift, lift_result) = self.lift_from_memory("ptr", result_type, module);
1461 lower = self.lower_to_memory("ptr", "value", result_type, module);
1462 dealloc_list = self.deallocate_lists(
1463 std::slice::from_ref(result_type),
1464 &[String::from("ptr")],
1465 true,
1466 module,
1467 );
1468 lift_list = self.list_lift_from_memory(
1469 "ptr",
1470 "length",
1471 &format!("wasm{name}{kind}Lift"),
1472 result_type,
1473 );
1474 lower_list =
1475 self.list_lower_to_memory(&format!("wasm{name}{kind}Lower"), "value", result_type);
1476
1477 malloc = self.malloc_memory("ptr", "length", result_type);
1478
1479 if dealloc_list.is_empty() {
1480 dealloc_list = "let _ = ptr".to_string();
1481 }
1482 } else {
1483 lift = "let _ = ptr".to_string();
1484 lower = "let _ = (ptr, value)".to_string();
1485 dealloc_list = "let _ = ptr".to_string();
1486 malloc = "let ptr = 0;".into();
1487 lift_result = "".into();
1488 lift_list = "FixedArray::make(length, Unit::default())".into();
1489 lower_list = "0".into();
1490 }
1491
1492 let (mut lift_func, mut lower_func) = if result_type
1493 .is_some_and(|ty| self.is_list_canonical(self.resolve, ty))
1494 && matches!(payload_for, PayloadFor::Stream)
1495 {
1496 ("".into(), "".into())
1497 } else {
1498 (
1499 format!(
1500 r#"
1501 fn wasm{name}{kind}Lift(ptr: Int) -> {result} {{
1502 {lift}
1503 {lift_result}
1504 }}
1505 "#
1506 ),
1507 format!(
1508 r#"
1509 fn wasm{name}{kind}Lower(value: {result}, ptr: Int) -> Unit {{
1510 {lower}
1511 }}
1512 "#
1513 ),
1514 )
1515 };
1516
1517 if matches!(payload_for, PayloadFor::Stream) {
1518 lift_func.push_str(&format!(
1519 r#"
1520 fn wasm{name}{kind}ListLift(ptr: Int, length: Int) -> FixedArray[{result}] {{
1521 {lift_list}
1522 }}
1523 "#
1524 ));
1525
1526 lower_func.push_str(&format!(
1527 r#"
1528 fn wasm{name}{kind}ListLower(value: FixedArray[{result}]) -> Int {{
1529 {lower_list}
1530 }}
1531 "#
1532 ));
1533 };
1534
1535 uwriteln!(
1536 self.ffi,
1537 r#"
1538fn wasmImport{name}{kind}New() -> UInt64 = "{module}" "[{kind}-new-{index}]{func_name}"
1539fn wasmImport{name}{kind}Read(handle : Int, buffer_ptr : Int{payload_len_arg}) -> Int = "{module}" "[async-lower][{kind}-read-{index}]{func_name}"
1540fn wasmImport{name}{kind}Write(handle : Int, buffer_ptr : Int{payload_len_arg}) -> Int = "{module}" "[async-lower][{kind}-write-{index}]{func_name}"
1541fn wasmImport{name}{kind}CancelRead(handle : Int) -> Int = "{module}" "[{kind}-cancel-read-{index}]{func_name}"
1542fn wasmImport{name}{kind}CancelWrite(handle : Int) -> Int = "{module}" "[{kind}-cancel-write-{index}]{func_name}"
1543fn wasmImport{name}{kind}DropReadable(handle : Int) = "{module}" "[{kind}-drop-readable-{index}]{func_name}"
1544fn wasmImport{name}{kind}DropWritable(handle : Int) = "{module}" "[{kind}-drop-writable-{index}]{func_name}"
1545fn wasm{name}{kind}Deallocate(ptr: Int) -> Unit {{
1546 {dealloc_list}
1547}}
1548fn wasm{name}{kind}Malloc(length: Int) -> Int {{
1549 {malloc}
1550 ptr
1551}}
1552
1553fn {table_name}() -> {ffi}{camel_kind}VTable[{result}] {{
1554 {ffi}{camel_kind}VTable::new(
1555 wasmImport{name}{kind}New,
1556 wasmImport{name}{kind}Read,
1557 wasmImport{name}{kind}Write,
1558 wasmImport{name}{kind}CancelRead,
1559 wasmImport{name}{kind}CancelWrite,
1560 wasmImport{name}{kind}DropReadable,
1561 wasmImport{name}{kind}DropWritable,
1562 wasm{name}{kind}Malloc,
1563 wasm{name}{kind}Deallocate,
1564 wasm{name}{kind}{payload_lift_func}Lift,
1565 wasm{name}{kind}{payload_lift_func}Lower,
1566 )
1567}}
1568{lift_func}
1569{lower_func}
1570pub let static_{table_name}: {ffi}{camel_kind}VTable[{result}] = {table_name}();
1571"#
1572 );
1573 }
1574
1575 fn sig_string(&mut self, sig: &MoonbitSignature, async_: bool) -> String {
1576 let params = sig
1577 .params
1578 .iter()
1579 .map(|(name, ty)| {
1580 let ty = self.type_name(ty, true);
1581 format!("{name} : {ty}")
1582 })
1583 .collect::<Vec<_>>();
1584
1585 let params = params.join(", ");
1586 let (async_prefix, async_suffix) = if async_ { ("async ", "") } else { ("", "") };
1587 let result_type = match &sig.result_type {
1588 None => "Unit".into(),
1589 Some(ty) => self.type_name(ty, true),
1590 };
1591 format!(
1592 "pub {async_prefix}fn {}({params}) -> {}{async_suffix}",
1593 sig.name, result_type
1594 )
1595 }
1596}
1597
1598impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
1599 fn resolve(&self) -> &'a Resolve {
1600 self.resolve
1601 }
1602
1603 fn type_record(&mut self, _id: TypeId, name: &str, record: &Record, docs: &Docs) {
1604 print_docs(&mut self.src, docs);
1605
1606 let name = name.to_moonbit_type_ident();
1607
1608 let parameters = record
1609 .fields
1610 .iter()
1611 .map(|field| {
1612 format!(
1613 "{} : {}",
1614 field.name.to_moonbit_ident(),
1615 self.type_name(&field.ty, true),
1616 )
1617 })
1618 .collect::<Vec<_>>()
1619 .join("; ");
1620
1621 let mut deriviation: Vec<_> = Vec::new();
1622 if self.gen.opts.derive_show {
1623 deriviation.push("Show")
1624 }
1625 if self.gen.opts.derive_eq {
1626 deriviation.push("Eq")
1627 }
1628
1629 uwrite!(
1630 self.src,
1631 "
1632 pub(all) struct {name} {{
1633 {parameters}
1634 }} derive({})
1635 ",
1636 deriviation.join(", ")
1637 );
1638 }
1639
1640 fn type_resource(&mut self, _id: TypeId, name: &str, docs: &Docs) {
1641 print_docs(&mut self.src, docs);
1642 let type_name = name;
1643 let name = name.to_moonbit_type_ident();
1644
1645 let mut deriviation: Vec<_> = Vec::new();
1646 if self.gen.opts.derive_show {
1647 deriviation.push("Show")
1648 }
1649 if self.gen.opts.derive_eq {
1650 deriviation.push("Eq")
1651 }
1652 let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1653 "suberror"
1654 } else {
1655 "struct"
1656 };
1657
1658 uwrite!(
1659 self.src,
1660 r#"
1661 pub(all) {declaration} {name}(Int) derive({})
1662 "#,
1663 deriviation.join(", "),
1664 );
1665
1666 let module = self.module;
1667
1668 if self.direction == Direction::Import {
1669 uwrite!(
1670 &mut self.src,
1671 r#"
1672 /// Drops a resource handle.
1673 pub fn {name}::drop(self : {name}) -> Unit {{
1674 let {name}(resource) = self
1675 wasmImportResourceDrop{name}(resource)
1676 }}
1677 "#,
1678 );
1679
1680 uwrite!(
1681 &mut self.ffi,
1682 r#"
1683 fn wasmImportResourceDrop{name}(resource : Int) = "{module}" "[resource-drop]{type_name}"
1684 "#,
1685 )
1686 } else {
1687 uwrite!(
1688 &mut self.src,
1689 r#"
1690 /// Creates a new resource with the given `rep` as its representation and returning the handle to this resource.
1691 pub fn {name}::new(rep : Int) -> {name} {{
1692 {name}::{name}(wasmExportResourceNew{name}(rep))
1693 }}
1694 fn wasmExportResourceNew{name}(rep : Int) -> Int = "[export]{module}" "[resource-new]{type_name}"
1695
1696 /// Drops a resource handle.
1697 pub fn {name}::drop(self : Self) -> Unit {{
1698 let {name}(resource) = self
1699 wasmExportResourceDrop{name}(resource)
1700 }}
1701 fn wasmExportResourceDrop{name}(resource : Int) = "[export]{module}" "[resource-drop]{type_name}"
1702
1703 /// Gets the `Int` representation of the resource pointed to the given handle.
1704 pub fn {name}::rep(self : Self) -> Int {{
1705 let {name}(resource) = self
1706 wasmExportResourceRep{name}(resource)
1707 }}
1708 fn wasmExportResourceRep{name}(resource : Int) -> Int = "[export]{module}" "[resource-rep]{type_name}"
1709 "#,
1710 );
1711
1712 uwrite!(
1713 &mut self.stub,
1714 r#"
1715 /// Destructor of the resource.
1716 pub fn {name}::dtor(_self : {name}) -> Unit {{
1717 ...
1718 }}
1719 "#
1720 );
1721
1722 let func_name = self.gen.export_ns.tmp(&format!("wasmExport{name}Dtor"));
1723
1724 let export_dir = self.gen.opts.gen_dir.clone();
1725
1726 let mut gen =
1727 self.gen
1728 .interface(self.resolve, export_dir.as_str(), "", Direction::Export);
1729
1730 uwrite!(
1731 self.ffi,
1732 r#"
1733 pub fn {func_name}(handle : Int) -> Unit {{
1734 {}{name}::dtor(handle)
1735 }}
1736 "#,
1737 gen.qualify_package(self.name)
1738 );
1739
1740 self.gen
1741 .export
1742 .insert(func_name, format!("{module}#[dtor]{type_name}"));
1743 }
1744 }
1745
1746 fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
1747 print_docs(&mut self.src, docs);
1748
1749 let name = name.to_moonbit_type_ident();
1750
1751 let ty = match flags.repr() {
1752 FlagsRepr::U8 => "Byte",
1753 FlagsRepr::U16 | FlagsRepr::U32(1) => "UInt",
1754 FlagsRepr::U32(2) => "UInt64",
1755 _ => unreachable!(), };
1757
1758 let cases = flags
1759 .flags
1760 .iter()
1761 .map(|flag| flag.name.to_shouty_snake_case())
1762 .collect::<Vec<_>>()
1763 .join("; ");
1764
1765 let map_to_int = flags
1766 .flags
1767 .iter()
1768 .enumerate()
1769 .map(|(i, flag)| {
1770 let flag_name = flag.name.to_shouty_snake_case();
1771 let suffix = if matches!(flags.repr(), FlagsRepr::U32(2)) {
1772 "UL"
1773 } else {
1774 "U"
1775 };
1776 let cast = if matches!(flags.repr(), FlagsRepr::U8) {
1777 ".to_byte()"
1778 } else {
1779 ""
1780 };
1781 format!("{flag_name} => ((1{suffix} << {i}){cast})")
1782 })
1783 .collect::<Vec<_>>()
1784 .join("\n ");
1785
1786 let mut deriviation: Vec<_> = Vec::new();
1787 if self.gen.opts.derive_show {
1788 deriviation.push("Show")
1789 }
1790 if self.gen.opts.derive_eq {
1791 deriviation.push("Eq")
1792 }
1793 let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1794 "suberror"
1795 } else {
1796 "struct"
1797 };
1798
1799 uwrite!(
1800 self.src,
1801 "
1802 pub(all) {declaration} {name}({ty}) derive({})
1803 pub fn {name}::default() -> {name} {{
1804 {}
1805 }}
1806 pub(all) enum {name}Flag {{
1807 {cases}
1808 }}
1809 fn {name}Flag::value(self : {name}Flag) -> {ty} {{
1810 match self {{
1811 {map_to_int}
1812 }}
1813 }}
1814 pub fn {name}::set(self : Self, other: {name}Flag) -> {name} {{
1815 let {name}(flag) = self
1816 flag.lor(other.value())
1817 }}
1818 pub fn {name}::unset(self : Self, other: {name}Flag) -> {name} {{
1819 let {name}(flag) = self
1820 flag.land(other.value().lnot())
1821 }}
1822 pub fn {name}::is_set(self : Self, other: {name}Flag) -> Bool {{
1823 let {name}(flag) = self
1824 (flag.land(other.value()) == other.value())
1825 }}
1826 ",
1827 deriviation.join(", "),
1828 match ty {
1829 "Byte" => "b'\\x00'",
1830 "UInt" => "0U",
1831 "UInt64" => "0UL",
1832 _ => unreachable!(),
1833 }
1834 );
1835 }
1836
1837 fn type_tuple(&mut self, _id: TypeId, _name: &str, _tuple: &Tuple, _docs: &Docs) {
1838 }
1840
1841 fn type_variant(&mut self, _id: TypeId, name: &str, variant: &Variant, docs: &Docs) {
1842 print_docs(&mut self.src, docs);
1843
1844 let name = name.to_moonbit_type_ident();
1845
1846 let cases = variant
1847 .cases
1848 .iter()
1849 .map(|case| {
1850 let name = case.name.to_upper_camel_case();
1851 if let Some(ty) = case.ty {
1852 let ty = self.type_name(&ty, true);
1853 format!("{name}({ty})")
1854 } else {
1855 name.to_string()
1856 }
1857 })
1858 .collect::<Vec<_>>()
1859 .join("\n ");
1860
1861 let mut deriviation: Vec<_> = Vec::new();
1862 if self.gen.opts.derive_show {
1863 deriviation.push("Show")
1864 }
1865 if self.gen.opts.derive_eq {
1866 deriviation.push("Eq")
1867 }
1868 let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1869 "suberror"
1870 } else {
1871 "enum"
1872 };
1873
1874 uwrite!(
1875 self.src,
1876 "
1877 pub(all) {declaration} {name} {{
1878 {cases}
1879 }} derive({})
1880 ",
1881 deriviation.join(", ")
1882 );
1883 }
1884
1885 fn type_option(&mut self, _id: TypeId, _name: &str, _payload: &Type, _docs: &Docs) {
1886 }
1888
1889 fn type_result(&mut self, _id: TypeId, _name: &str, _result: &Result_, _docs: &Docs) {
1890 }
1892
1893 fn type_enum(&mut self, _id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
1894 print_docs(&mut self.src, docs);
1895
1896 let name = name.to_moonbit_type_ident();
1897
1898 let cases = enum_
1900 .cases
1901 .iter()
1902 .map(|case| case.name.to_shouty_snake_case())
1903 .collect::<Vec<_>>()
1904 .join("; ");
1905
1906 let mut deriviation: Vec<_> = Vec::new();
1907 if self.gen.opts.derive_show {
1908 deriviation.push("Show")
1909 }
1910 if self.gen.opts.derive_eq {
1911 deriviation.push("Eq")
1912 }
1913 let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1914 "suberror"
1915 } else {
1916 "enum"
1917 };
1918
1919 uwrite!(
1920 self.src,
1921 "
1922 pub(all) {declaration} {name} {{
1923 {cases}
1924 }} derive({})
1925 ",
1926 deriviation.join(", ")
1927 );
1928
1929 let cases = enum_
1931 .cases
1932 .iter()
1933 .enumerate()
1934 .map(|(i, case)| format!("{} => {i}", case.name.to_shouty_snake_case()))
1935 .collect::<Vec<_>>()
1936 .join("\n ");
1937
1938 uwrite!(
1939 self.src,
1940 "
1941 pub fn {name}::ordinal(self : {name}) -> Int {{
1942 match self {{
1943 {cases}
1944 }}
1945 }}
1946 "
1947 );
1948
1949 let cases = enum_
1951 .cases
1952 .iter()
1953 .enumerate()
1954 .map(|(i, case)| format!("{i} => {}", case.name.to_shouty_snake_case()))
1955 .collect::<Vec<_>>()
1956 .join("\n ");
1957
1958 uwrite!(
1959 self.src,
1960 "
1961 pub fn {name}::from(self : Int) -> {name} {{
1962 match self {{
1963 {cases}
1964 _ => panic()
1965 }}
1966 }}
1967 "
1968 );
1969 }
1970
1971 fn type_alias(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {}
1972
1973 fn type_list(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1974 }
1976
1977 fn type_future(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
1978 unimplemented!() }
1980
1981 fn type_stream(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
1982 unimplemented!() }
1984
1985 fn type_builtin(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1986 unimplemented!();
1987 }
1988}
1989
1990struct Block {
1991 body: String,
1992 results: Vec<String>,
1993 element: String,
1994 base: String,
1995}
1996enum Cleanup {
1997 Memory {
1998 address: String,
1999 size: String,
2000 align: usize,
2001 },
2002 Object(String),
2003}
2004
2005struct BlockStorage {
2006 body: String,
2007 element: String,
2008 base: String,
2009 cleanup: Vec<Cleanup>,
2010}
2011
2012#[derive(Clone, Debug)]
2013enum DeferredTaskReturn {
2014 None,
2015 Generating {
2016 prev_src: String,
2017 return_param: String,
2018 },
2019 Emitted {
2020 params: Vec<(WasmType, String)>,
2021 body: String,
2022 return_param: String,
2023 },
2024}
2025
2026struct FunctionBindgen<'a, 'b> {
2027 gen: &'b mut InterfaceGenerator<'a>,
2028 func_name: &'b str,
2029 func_interface: &'b str,
2030 params: Box<[String]>,
2031 src: String,
2032 locals: Ns,
2033 block_storage: Vec<BlockStorage>,
2034 blocks: Vec<Block>,
2035 payloads: Vec<String>,
2036 cleanup: Vec<Cleanup>,
2037 needs_cleanup_list: bool,
2038 deferred_task_return: DeferredTaskReturn,
2039}
2040
2041impl<'a, 'b> FunctionBindgen<'a, 'b> {
2042 fn new(
2043 gen: &'b mut InterfaceGenerator<'a>,
2044 func_name: &'b str,
2045 func_interface: &'b str,
2046 params: Box<[String]>,
2047 ) -> FunctionBindgen<'a, 'b> {
2048 let mut locals = Ns::default();
2049 params.iter().for_each(|str| {
2050 locals.tmp(str);
2051 });
2052 Self {
2053 gen,
2054 func_name,
2055 func_interface,
2056 params,
2057 src: String::new(),
2058 locals,
2059 block_storage: Vec::new(),
2060 blocks: Vec::new(),
2061 payloads: Vec::new(),
2062 cleanup: Vec::new(),
2063 needs_cleanup_list: false,
2064 deferred_task_return: DeferredTaskReturn::None,
2065 }
2066 }
2067
2068 fn lower_variant(
2069 &mut self,
2070 cases: &[(&str, Option<Type>)],
2071 lowered_types: &[WasmType],
2072 op: &str,
2073 results: &mut Vec<String>,
2074 is_result: bool,
2075 ) {
2076 let blocks = self
2077 .blocks
2078 .drain(self.blocks.len() - cases.len()..)
2079 .collect::<Vec<_>>();
2080
2081 let payloads = self
2082 .payloads
2083 .drain(self.payloads.len() - cases.len()..)
2084 .collect::<Vec<_>>();
2085
2086 let lowered = lowered_types
2087 .iter()
2088 .map(|_| self.locals.tmp("lowered"))
2089 .collect::<Vec<_>>();
2090
2091 results.extend(lowered.iter().cloned());
2092
2093 let declarations = lowered.join(",");
2094
2095 let cases = cases
2096 .iter()
2097 .zip(blocks)
2098 .zip(payloads)
2099 .map(|(((name, ty), Block { body, results, .. }), payload)| {
2100 let name = name.to_upper_camel_case();
2101 let assignments = results
2102 .iter()
2103 .map(|result| result.to_string())
2104 .collect::<Vec<_>>()
2105 .join(", ");
2106
2107 let payload = if self.gen.non_empty_type(ty.as_ref()).is_some() {
2108 payload
2109 } else if is_result {
2110 format!("_{payload}")
2111 } else {
2112 String::new()
2113 };
2114
2115 if payload.is_empty() {
2116 format!(
2117 "{name} => {{
2118 {body}
2119 ({assignments})
2120 }}"
2121 )
2122 } else {
2123 format!(
2124 "{name}({payload}) => {{
2125 {body}
2126 ({assignments})
2127 }}",
2128 )
2129 }
2130 })
2131 .collect::<Vec<_>>()
2132 .join("\n");
2133
2134 if declarations.is_empty() {
2135 uwrite!(
2136 self.src,
2137 r#"
2138 match {op} {{
2139 {cases}
2140 }}
2141 "#
2142 );
2143 } else {
2144 uwrite!(
2145 self.src,
2146 r#"
2147 let ({declarations}) = match {op} {{
2148 {cases}
2149 }}
2150 "#
2151 );
2152 }
2153 }
2154
2155 fn lift_variant(
2156 &mut self,
2157 ty: &Type,
2158 cases: &[(&str, Option<Type>)],
2159 op: &str,
2160 results: &mut Vec<String>,
2161 is_result: bool,
2162 ) {
2163 let blocks = self
2164 .blocks
2165 .drain(self.blocks.len() - cases.len()..)
2166 .collect::<Vec<_>>();
2167
2168 let ty = self.gen.type_name(ty, false);
2170 let lifted = self.locals.tmp("lifted");
2171
2172 let cases = cases
2173 .iter()
2174 .zip(blocks)
2175 .enumerate()
2176 .map(|(i, ((case_name, case_ty), Block { body, results, .. }))| {
2177 let payload = if self.gen.non_empty_type(case_ty.as_ref()).is_some() {
2178 results.into_iter().next().unwrap()
2179 } else {
2180 String::new()
2181 };
2182
2183 let constructor = format!("{ty}::{}", case_name.to_upper_camel_case());
2184
2185 if payload.is_empty() && !is_result {
2186 format!(
2187 "{i} => {{
2188 {body}
2189 {constructor}
2190 }}"
2191 )
2192 } else {
2193 format!(
2194 "{i} => {{
2195 {body}
2196 {constructor}({})
2197 }}",
2198 if payload.is_empty() {
2199 "()".into()
2200 } else {
2201 payload
2202 }
2203 )
2204 }
2205 })
2206 .collect::<Vec<_>>()
2207 .join("\n");
2208
2209 uwrite!(
2210 self.src,
2211 r#"
2212 let {lifted} = match ({op}) {{
2213 {cases}
2214 _ => panic()
2215 }}
2216 "#
2217 );
2218
2219 results.push(lifted);
2220 }
2221}
2222
2223impl Bindgen for FunctionBindgen<'_, '_> {
2224 type Operand = String;
2225
2226 fn emit(
2227 &mut self,
2228 _resolve: &Resolve,
2229 inst: &Instruction<'_>,
2230 operands: &mut Vec<String>,
2231 results: &mut Vec<String>,
2232 ) {
2233 match inst {
2234 Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
2235 Instruction::I32Const { val } => results.push(format!("({val})")),
2236 Instruction::ConstZero { tys } => results.extend(tys.iter().map(|ty| {
2237 match ty {
2238 WasmType::I32 => "0",
2239 WasmType::I64 => "0L",
2240 WasmType::F32 => "(0.0 : Float)",
2241 WasmType::F64 => "0.0",
2242 WasmType::Pointer => "0",
2243 WasmType::PointerOrI64 => "0L",
2244 WasmType::Length => "0",
2245 }
2246 .to_owned()
2247 })),
2248
2249 Instruction::Bitcasts { casts } => results.extend(
2250 casts
2251 .iter()
2252 .zip(operands)
2253 .map(|(cast, op)| perform_cast(op, cast)),
2254 ),
2255
2256 Instruction::I32FromS32
2257 | Instruction::I64FromS64
2258 | Instruction::S32FromI32
2259 | Instruction::S64FromI64
2260 | Instruction::CoreF64FromF64
2261 | Instruction::F64FromCoreF64 => results.push(operands[0].clone()),
2262
2263 Instruction::F32FromCoreF32 => results.push(operands[0].clone()),
2264 Instruction::CoreF32FromF32 => results.push(operands[0].clone()),
2265
2266 Instruction::CharFromI32 => {
2267 results.push(format!("Int::unsafe_to_char({})", operands[0]))
2268 }
2269 Instruction::I32FromChar => results.push(format!("({}).to_int()", operands[0])),
2270
2271 Instruction::I32FromU8 => results.push(format!("({}).to_int()", operands[0])),
2272 Instruction::I32FromU16 => {
2273 results.push(format!("({}).reinterpret_as_int()", operands[0]))
2274 }
2275 Instruction::U8FromI32 => results.push(format!("({}).to_byte()", operands[0])),
2276
2277 Instruction::I32FromS8 => results.push(format!(
2278 "{}extend8({})",
2279 self.gen.qualify_package(FFI_DIR),
2280 operands[0]
2281 )),
2282 Instruction::S8FromI32 => results.push(format!("({} - 0x100)", operands[0])),
2283 Instruction::S16FromI32 => results.push(format!("({} - 0x10000)", operands[0])),
2284 Instruction::I32FromS16 => results.push(format!(
2285 "{}extend16({})",
2286 self.gen.qualify_package(FFI_DIR),
2287 operands[0]
2288 )),
2289 Instruction::U16FromI32 => results.push(format!(
2290 "({}.land(0xFFFF).reinterpret_as_uint())",
2291 operands[0]
2292 )),
2293 Instruction::U32FromI32 => {
2294 results.push(format!("({}).reinterpret_as_uint()", operands[0]))
2295 }
2296 Instruction::I32FromU32 => {
2297 results.push(format!("({}).reinterpret_as_int()", operands[0]))
2298 }
2299
2300 Instruction::U64FromI64 => {
2301 results.push(format!("({}).reinterpret_as_uint64()", operands[0]))
2302 }
2303 Instruction::I64FromU64 => {
2304 results.push(format!("({}).reinterpret_as_int64()", operands[0]))
2305 }
2306
2307 Instruction::I32FromBool => {
2308 results.push(format!("(if {} {{ 1 }} else {{ 0 }})", operands[0]));
2309 }
2310 Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
2311
2312 Instruction::FlagsLower { flags, ty, .. } => match flags_repr(flags) {
2313 Int::U8 => {
2314 let op = &operands[0];
2315 let flag = self.locals.tmp("flag");
2316 let ty = self.gen.type_name(&Type::Id(*ty), false);
2317 uwriteln!(
2318 self.src,
2319 r#"
2320 let {ty}({flag}) = {op}
2321 "#
2322 );
2323 results.push(format!("{flag}.to_int()"));
2324 }
2325 Int::U16 | Int::U32 => {
2326 let op = &operands[0];
2327 let flag = self.locals.tmp("flag");
2328 let ty = self.gen.type_name(&Type::Id(*ty), false);
2329 uwriteln!(
2330 self.src,
2331 r#"
2332 let {ty}({flag}) = {op}
2333 "#
2334 );
2335 results.push(format!("{flag}.reinterpret_as_int()"));
2336 }
2337 Int::U64 => {
2338 let op = &operands[0];
2339 let flag = self.locals.tmp("flag");
2340 let ty = self.gen.type_name(&Type::Id(*ty), false);
2341 uwriteln!(
2342 self.src,
2343 r#"
2344 let {ty}({flag}) = {op}
2345 "#
2346 );
2347 results.push(format!("({flag}.to_int())"));
2348 results.push(format!("({flag}.lsr(32)).to_int())"));
2349 }
2350 },
2351
2352 Instruction::FlagsLift { flags, ty, .. } => match flags_repr(flags) {
2353 Int::U8 => {
2354 results.push(format!(
2355 "{}({}.to_byte())",
2356 self.gen.type_name(&Type::Id(*ty), true),
2357 operands[0]
2358 ));
2359 }
2360 Int::U16 | Int::U32 => {
2361 results.push(format!(
2362 "{}({}.reinterpret_as_uint())",
2363 self.gen.type_name(&Type::Id(*ty), true),
2364 operands[0]
2365 ));
2366 }
2367 Int::U64 => {
2368 results.push(format!(
2369 "{}(({}).reinterpret_as_uint().to_uint64() | (({}).reinterpret_as_uint().to_uint64() << 32))",
2370 self.gen.type_name(&Type::Id(*ty), true),
2371 operands[0],
2372 operands[1]
2373 ));
2374 }
2375 },
2376
2377 Instruction::HandleLower { ty, .. } => {
2378 let op = &operands[0];
2379 let handle = self.locals.tmp("handle");
2380 let ty = self.gen.type_name(&Type::Id(*ty), false);
2381 uwrite!(
2382 self.src,
2383 r#"
2384 let {ty}({handle}) = {op}
2385 "#
2386 );
2387 results.push(handle);
2388 }
2389 Instruction::HandleLift { ty, .. } => {
2390 let op = &operands[0];
2391 let ty = self.gen.type_name(&Type::Id(*ty), false);
2392
2393 results.push(format!(
2394 "{}::{}({})",
2395 ty,
2396 if ty.starts_with("@") {
2397 ty.split('.').next_back().unwrap()
2398 } else {
2399 &ty
2400 },
2401 op
2402 ));
2403 }
2404
2405 Instruction::RecordLower { record, .. } => {
2406 let op = &operands[0];
2407 for field in record.fields.iter() {
2408 results.push(format!("({op}).{}", field.name.to_moonbit_ident()));
2409 }
2410 }
2411 Instruction::RecordLift { ty, record, .. } => {
2412 let ops = operands
2413 .iter()
2414 .enumerate()
2415 .map(|(i, op)| format!("{} : {}", record.fields[i].name.to_moonbit_ident(), op))
2416 .collect::<Vec<_>>()
2417 .join(", ");
2418
2419 results.push(format!(
2420 "{}::{{{ops}}}",
2421 self.gen.type_name(&Type::Id(*ty), true)
2422 ));
2423 }
2424
2425 Instruction::TupleLower { tuple, .. } => {
2426 let op = &operands[0];
2427 if tuple.types.is_empty() {
2430 results.push("()".into());
2431 } else if tuple.types.len() == 1 {
2432 results.push(operands[0].to_string());
2433 } else {
2434 for i in 0..tuple.types.len() {
2435 results.push(format!("({op}).{i}"));
2436 }
2437 }
2438 }
2439 Instruction::TupleLift { .. } => {
2440 let ops = operands
2441 .iter()
2442 .map(|op| op.to_string())
2443 .collect::<Vec<_>>()
2444 .join(", ");
2445 results.push(format!("({ops})"));
2446 }
2447
2448 Instruction::VariantPayloadName => {
2449 let payload = self.locals.tmp("payload");
2450 results.push(payload.clone());
2451 self.payloads.push(payload);
2452 }
2453
2454 Instruction::VariantLower {
2455 variant,
2456 results: lowered_types,
2457 ..
2458 } => self.lower_variant(
2459 &variant
2460 .cases
2461 .iter()
2462 .map(|case| (case.name.deref(), case.ty))
2463 .collect::<Vec<_>>(),
2464 lowered_types,
2465 &operands[0],
2466 results,
2467 false,
2468 ),
2469
2470 Instruction::VariantLift { variant, ty, .. } => self.lift_variant(
2471 &Type::Id(*ty),
2472 &variant
2473 .cases
2474 .iter()
2475 .map(|case| (case.name.deref(), case.ty))
2476 .collect::<Vec<_>>(),
2477 &operands[0],
2478 results,
2479 false,
2480 ),
2481
2482 Instruction::OptionLower {
2483 results: lowered_types,
2484 ..
2485 } => {
2486 let some = self.blocks.pop().unwrap();
2487 let none = self.blocks.pop().unwrap();
2488 let some_payload = self.payloads.pop().unwrap();
2489 let _none_payload = self.payloads.pop().unwrap();
2490
2491 let lowered = lowered_types
2492 .iter()
2493 .map(|_| self.locals.tmp("lowered"))
2494 .collect::<Vec<_>>();
2495
2496 results.extend(lowered.iter().cloned());
2497
2498 let declarations = lowered
2499 .iter()
2500 .map(|lowered| lowered.to_string())
2501 .collect::<Vec<_>>()
2502 .join(", ");
2503
2504 let op = &operands[0];
2505
2506 let block = |Block { body, results, .. }| {
2507 let assignments = results
2508 .iter()
2509 .map(|result| result.to_string())
2510 .collect::<Vec<_>>()
2511 .join(", ");
2512
2513 format!(
2514 "{body}
2515 ({assignments})"
2516 )
2517 };
2518
2519 let none = block(none);
2520 let some = block(some);
2521
2522 if declarations.is_empty() {
2523 uwrite!(
2524 self.src,
2525 r#"
2526 match (({op})) {{
2527 None => {{
2528 {none}
2529 }}
2530 Some({some_payload}) => {{
2531 {some}
2532 }}
2533 }}
2534 "#
2535 );
2536 } else {
2537 uwrite!(
2538 self.src,
2539 r#"
2540 let ({declarations}) = match (({op})) {{
2541 None => {{
2542 {none}
2543 }}
2544 Some({some_payload}) => {{
2545 {some}
2546 }}
2547 }}
2548 "#
2549 );
2550 }
2551 }
2552
2553 Instruction::OptionLift { payload, ty } => {
2554 let some = self.blocks.pop().unwrap();
2555 let _none = self.blocks.pop().unwrap();
2556
2557 let ty = self.gen.type_name(&Type::Id(*ty), true);
2558 let lifted = self.locals.tmp("lifted");
2559 let op = &operands[0];
2560
2561 let payload = if self.gen.non_empty_type(Some(*payload)).is_some() {
2562 some.results.into_iter().next().unwrap()
2563 } else {
2564 "None".into()
2565 };
2566
2567 let some = some.body;
2568
2569 uwrite!(
2570 self.src,
2571 r#"
2572 let {lifted} : {ty} = match {op} {{
2573 0 => Option::None
2574 1 => {{
2575 {some}
2576 Option::Some({payload})
2577 }}
2578 _ => panic()
2579 }}
2580 "#
2581 );
2582
2583 results.push(lifted);
2584 }
2585
2586 Instruction::ResultLower {
2587 results: lowered_types,
2588 result,
2589 ..
2590 } => self.lower_variant(
2591 &[("Ok", result.ok), ("Err", result.err)],
2592 lowered_types,
2593 &operands[0],
2594 results,
2595 true,
2596 ),
2597
2598 Instruction::ResultLift { result, ty } => self.lift_variant(
2599 &Type::Id(*ty),
2600 &[("Ok", result.ok), ("Err", result.err)],
2601 &operands[0],
2602 results,
2603 true,
2604 ),
2605
2606 Instruction::EnumLower { .. } => results.push(format!("{}.ordinal()", operands[0])),
2607
2608 Instruction::EnumLift { ty, .. } => results.push(format!(
2609 "{}::from({})",
2610 self.gen.type_name(&Type::Id(*ty), true),
2611 operands[0]
2612 )),
2613
2614 Instruction::ListCanonLower { element, realloc } => match element {
2615 Type::U8 => {
2616 let op = &operands[0];
2617
2618 results.push(format!(
2619 "{}bytes2ptr({op})",
2620 self.gen.qualify_package(FFI_DIR)
2621 ));
2622 results.push(format!("{op}.length()"));
2623 if realloc.is_none() {
2624 self.cleanup.push(Cleanup::Object(op.clone()));
2625 }
2626 }
2627 Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2628 let op = &operands[0];
2629
2630 let ty = match element {
2631 Type::U32 => "uint",
2632 Type::U64 => "uint64",
2633 Type::S32 => "int",
2634 Type::S64 => "int64",
2635 Type::F32 => "float",
2636 Type::F64 => "double",
2637 _ => unreachable!(),
2638 };
2639
2640 results.push(format!(
2641 "{}{ty}_array2ptr({op})",
2642 self.gen.qualify_package(FFI_DIR)
2643 ));
2644 results.push(format!("{op}.length()"));
2645 if realloc.is_none() {
2646 self.cleanup.push(Cleanup::Object(op.clone()));
2647 }
2648 }
2649 _ => unreachable!("unsupported list element type"),
2650 },
2651
2652 Instruction::ListCanonLift { element, .. } => match element {
2653 Type::U8 => {
2654 let result = self.locals.tmp("result");
2655 let address = &operands[0];
2656 let length = &operands[1];
2657
2658 uwrite!(
2659 self.src,
2660 "
2661 let {result} = {}ptr2bytes({address}, {length})
2662 ",
2663 self.gen.qualify_package(FFI_DIR)
2664 );
2665
2666 results.push(result);
2667 }
2668 Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2669 let ty = match element {
2670 Type::U32 => "uint",
2671 Type::U64 => "uint64",
2672 Type::S32 => "int",
2673 Type::S64 => "int64",
2674 Type::F32 => "float",
2675 Type::F64 => "double",
2676 _ => unreachable!(),
2677 };
2678
2679 let result = self.locals.tmp("result");
2680 let address = &operands[0];
2681 let length = &operands[1];
2682
2683 uwrite!(
2684 self.src,
2685 "
2686 let {result} = {}ptr2{ty}_array({address}, {length})
2687 ",
2688 self.gen.qualify_package(FFI_DIR)
2689 );
2690
2691 results.push(result);
2692 }
2693 _ => unreachable!("unsupported list element type"),
2694 },
2695
2696 Instruction::StringLower { realloc } => {
2697 let op = &operands[0];
2698
2699 results.push(format!(
2700 "{}str2ptr({op})",
2701 self.gen.qualify_package(FFI_DIR)
2702 ));
2703 results.push(format!("{op}.length()"));
2704 if realloc.is_none() {
2705 self.cleanup.push(Cleanup::Object(op.clone()));
2706 }
2707 }
2708
2709 Instruction::StringLift { .. } => {
2710 let result = self.locals.tmp("result");
2711 let address = &operands[0];
2712 let length = &operands[1];
2713
2714 uwrite!(
2715 self.src,
2716 "
2717 let {result} = {}ptr2str({address}, {length})
2718 ",
2719 self.gen.qualify_package(FFI_DIR)
2720 );
2721
2722 results.push(result);
2723 }
2724
2725 Instruction::ListLower { element, realloc } => {
2726 let Block {
2727 body,
2728 results: block_results,
2729 element: block_element,
2730 base,
2731 } = self.blocks.pop().unwrap();
2732 assert!(block_results.is_empty());
2733
2734 let op = &operands[0];
2735 let size = self.gen.gen.sizes.size(element).size_wasm32();
2736 let align = self.gen.gen.sizes.align(element).align_wasm32();
2737 let address = self.locals.tmp("address");
2738 let ty = self.gen.type_name(element, true);
2739 let index = self.locals.tmp("index");
2740
2741 uwrite!(
2742 self.src,
2743 "
2744 let {address} = {}malloc(({op}).length() * {size});
2745 for {index} = 0; {index} < ({op}).length(); {index} = {index} + 1 {{
2746 let {block_element} : {ty} = ({op})[({index})]
2747 let {base} = {address} + ({index} * {size});
2748 {body}
2749 }}
2750 ",
2751 self.gen.qualify_package(FFI_DIR)
2752 );
2753
2754 if realloc.is_none() {
2755 self.cleanup.push(Cleanup::Memory {
2756 address: address.clone(),
2757 size: format!("({op}).length() * {size}"),
2758 align,
2759 });
2760 }
2761
2762 results.push(address);
2763 results.push(format!("({op}).length()"));
2764 }
2765
2766 Instruction::ListLift { element, .. } => {
2767 let Block {
2768 body,
2769 results: block_results,
2770 base,
2771 ..
2772 } = self.blocks.pop().unwrap();
2773 let address = &operands[0];
2774 let length = &operands[1];
2775 let array = self.locals.tmp("array");
2776 let ty = self.gen.type_name(element, true);
2777 let size = self.gen.gen.sizes.size(element).size_wasm32();
2778 let index = self.locals.tmp("index");
2780
2781 let result = match &block_results[..] {
2782 [result] => result,
2783 _ => todo!("result count == {}", results.len()),
2784 };
2785
2786 uwrite!(
2787 self.src,
2788 "
2789 let {array} : Array[{ty}] = [];
2790 for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
2791 let {base} = ({address}) + ({index} * {size})
2792 {body}
2793 {array}.push({result})
2794 }}
2795 {}free({address})
2796 ",
2797 self.gen.qualify_package(FFI_DIR)
2798 );
2799
2800 results.push(array);
2801 }
2802
2803 Instruction::IterElem { .. } => {
2804 results.push(self.block_storage.last().unwrap().element.clone())
2805 }
2806
2807 Instruction::IterBasePointer => {
2808 results.push(self.block_storage.last().unwrap().base.clone())
2809 }
2810
2811 Instruction::CallWasm { sig, .. } => {
2812 let assignment = match &sig.results[..] {
2813 [result] => {
2814 let ty = wasm_type(*result);
2815 let result = self.locals.tmp("result");
2816 let assignment = format!("let {result} : {ty} = ");
2817 results.push(result);
2818 assignment
2819 }
2820
2821 [] => String::new(),
2822
2823 _ => unreachable!(),
2824 };
2825
2826 let func_name = self.func_name.to_upper_camel_case();
2827
2828 let operands = operands.join(", ");
2829 uwriteln!(self.src, "{assignment} wasmImport{func_name}({operands});");
2831 }
2832
2833 Instruction::CallInterface { func, async_ } => {
2834 let name = match func.kind {
2835 FunctionKind::Freestanding => {
2836 format!(
2837 "{}{}",
2838 self.r#gen.qualify_package(self.func_interface),
2839 func.name.to_moonbit_ident()
2840 )
2841 }
2842 FunctionKind::AsyncFreestanding => {
2843 format!(
2844 "{}{}",
2845 self.r#gen.qualify_package(self.func_interface),
2846 func.name.to_moonbit_ident()
2847 )
2848 }
2849 FunctionKind::Constructor(ty) => {
2850 let name = self.gen.type_name(&Type::Id(ty), false);
2851 format!(
2852 "{}::{}",
2853 name,
2854 func.name.replace("[constructor]", "").to_moonbit_ident()
2855 )
2856 }
2857 FunctionKind::Method(ty)
2858 | FunctionKind::Static(ty)
2859 | FunctionKind::AsyncMethod(ty)
2860 | FunctionKind::AsyncStatic(ty) => {
2861 let name = self.gen.type_name(&Type::Id(ty), false);
2862 format!(
2863 "{}::{}",
2864 name,
2865 func.name.split(".").last().unwrap().to_moonbit_ident()
2866 )
2867 }
2868 };
2869
2870 let args = operands.join(", ");
2871
2872 if *async_ {
2873 let (async_func_result, task_return_result, task_return_type) =
2874 match func.result {
2875 Some(ty) => {
2876 let res = self.locals.tmp("return_result");
2877 (res.clone(), res, self.gen.type_name(&ty, true))
2878 }
2879 None => ("_ignore".into(), "".into(), "Unit".into()),
2880 };
2881
2882 if func.result.is_some() {
2883 results.push(async_func_result.clone());
2884 }
2885 let ffi = self.gen.qualify_package(FFI_DIR);
2886 uwrite!(
2887 self.src,
2888 r#"
2889 let task = {ffi}current_task();
2890 let _ = task.with_waitable_set(fn(task) {{
2891 let {async_func_result}: Ref[{task_return_type}?] = Ref::new(None)
2892 task.wait(fn() {{
2893 {async_func_result}.val = Some({name}({args}));
2894 }})
2895 for {{
2896 if task.no_wait() && {async_func_result}.val is Some({async_func_result}){{
2897 {name}_task_return({task_return_result});
2898 break;
2899 }} else {{
2900 {ffi}suspend() catch {{
2901 _ => {{
2902 {ffi}task_cancel();
2903 }}
2904 }}
2905 }}
2906 }}
2907 }})
2908 if task.is_fail() is Some({ffi}Cancelled::Cancelled) {{
2909 {ffi}task_cancel();
2910 return {ffi}CallbackCode::Exit.encode()
2911 }}
2912 if task.is_done() {{
2913 return {ffi}CallbackCode::Exit.encode()
2914 }}
2915 return {ffi}CallbackCode::Wait(task.handle()).encode()
2916 "#,
2917 );
2918 assert!(matches!(
2919 self.deferred_task_return,
2920 DeferredTaskReturn::None
2921 ));
2922 self.deferred_task_return = DeferredTaskReturn::Generating {
2923 prev_src: mem::take(&mut self.src),
2924 return_param: async_func_result.to_string(),
2925 };
2926 return;
2927 }
2928
2929 let assignment = match func.result {
2930 None => "let _ = ".into(),
2931 Some(ty) => {
2932 let ty = format!("({})", self.gen.type_name(&ty, true));
2933 let result = self.locals.tmp("result");
2934 if func.result.is_some() {
2935 results.push(result.clone());
2936 }
2937 let assignment = format!("let ({result}) : {ty} = ");
2938 assignment
2939 }
2940 };
2941
2942 uwrite!(
2943 self.src,
2944 "
2945 {assignment}{name}({args});
2946 ",
2947 );
2948 }
2949
2950 Instruction::Return { amt, .. } => {
2951 for clean in &self.cleanup {
2952 match clean {
2953 Cleanup::Memory {
2954 address,
2955 size: _,
2956 align: _,
2957 } => uwriteln!(
2958 self.src,
2959 "{}free({address})",
2960 self.gen.qualify_package(FFI_DIR)
2961 ),
2962 Cleanup::Object(obj) => uwriteln!(self.src, "ignore({obj})"),
2963 }
2964 }
2965
2966 if self.needs_cleanup_list {
2967 uwrite!(
2968 self.src,
2969 "
2970 cleanupList.each(fn(cleanup) {{
2971 {}free(cleanup.address);
2972 }})
2973 ignore(ignoreList)
2974 ",
2975 self.gen.qualify_package(FFI_DIR)
2976 );
2977 }
2978
2979 match *amt {
2980 0 => (),
2981 1 => uwriteln!(self.src, "return {}", operands[0]),
2982 _ => {
2983 let results = operands.join(", ");
2984 uwriteln!(self.src, "return ({results})");
2985 }
2986 }
2987 }
2988
2989 Instruction::I32Load { offset }
2990 | Instruction::PointerLoad { offset }
2991 | Instruction::LengthLoad { offset } => results.push(format!(
2992 "{}load32(({}) + {offset})",
2993 self.gen.qualify_package(FFI_DIR),
2994 operands[0],
2995 offset = offset.size_wasm32()
2996 )),
2997
2998 Instruction::I32Load8U { offset } => results.push(format!(
2999 "{}load8_u(({}) + {offset})",
3000 self.gen.qualify_package(FFI_DIR),
3001 operands[0],
3002 offset = offset.size_wasm32()
3003 )),
3004
3005 Instruction::I32Load8S { offset } => results.push(format!(
3006 "{}load8(({}) + {offset})",
3007 self.gen.qualify_package(FFI_DIR),
3008 operands[0],
3009 offset = offset.size_wasm32()
3010 )),
3011
3012 Instruction::I32Load16U { offset } => results.push(format!(
3013 "{}load16_u(({}) + {offset})",
3014 self.gen.qualify_package(FFI_DIR),
3015 operands[0],
3016 offset = offset.size_wasm32()
3017 )),
3018
3019 Instruction::I32Load16S { offset } => results.push(format!(
3020 "{}load16(({}) + {offset})",
3021 self.gen.qualify_package(FFI_DIR),
3022 operands[0],
3023 offset = offset.size_wasm32()
3024 )),
3025
3026 Instruction::I64Load { offset } => results.push(format!(
3027 "{}load64(({}) + {offset})",
3028 self.gen.qualify_package(FFI_DIR),
3029 operands[0],
3030 offset = offset.size_wasm32()
3031 )),
3032
3033 Instruction::F32Load { offset } => results.push(format!(
3034 "{}loadf32(({}) + {offset})",
3035 self.gen.qualify_package(FFI_DIR),
3036 operands[0],
3037 offset = offset.size_wasm32()
3038 )),
3039
3040 Instruction::F64Load { offset } => results.push(format!(
3041 "{}loadf64(({}) + {offset})",
3042 self.gen.qualify_package(FFI_DIR),
3043 operands[0],
3044 offset = offset.size_wasm32()
3045 )),
3046
3047 Instruction::I32Store { offset }
3048 | Instruction::PointerStore { offset }
3049 | Instruction::LengthStore { offset } => uwriteln!(
3050 self.src,
3051 "{}store32(({}) + {offset}, {})",
3052 self.gen.qualify_package(FFI_DIR),
3053 operands[1],
3054 operands[0],
3055 offset = offset.size_wasm32()
3056 ),
3057
3058 Instruction::I32Store8 { offset } => uwriteln!(
3059 self.src,
3060 "{}store8(({}) + {offset}, {})",
3061 self.gen.qualify_package(FFI_DIR),
3062 operands[1],
3063 operands[0],
3064 offset = offset.size_wasm32()
3065 ),
3066
3067 Instruction::I32Store16 { offset } => uwriteln!(
3068 self.src,
3069 "{}store16(({}) + {offset}, {})",
3070 self.gen.qualify_package(FFI_DIR),
3071 operands[1],
3072 operands[0],
3073 offset = offset.size_wasm32()
3074 ),
3075
3076 Instruction::I64Store { offset } => uwriteln!(
3077 self.src,
3078 "{}store64(({}) + {offset}, {})",
3079 self.gen.qualify_package(FFI_DIR),
3080 operands[1],
3081 operands[0],
3082 offset = offset.size_wasm32()
3083 ),
3084
3085 Instruction::F32Store { offset } => uwriteln!(
3086 self.src,
3087 "{}storef32(({}) + {offset}, {})",
3088 self.gen.qualify_package(FFI_DIR),
3089 operands[1],
3090 operands[0],
3091 offset = offset.size_wasm32()
3092 ),
3093
3094 Instruction::F64Store { offset } => uwriteln!(
3095 self.src,
3096 "{}storef64(({}) + {offset}, {})",
3097 self.gen.qualify_package(FFI_DIR),
3098 operands[1],
3099 operands[0],
3100 offset = offset.size_wasm32()
3101 ),
3102 Instruction::Malloc { size, .. } => {
3104 uwriteln!(
3105 self.src,
3106 "{}malloc({})",
3107 self.gen.qualify_package(FFI_DIR),
3108 size.size_wasm32()
3109 )
3110 }
3111
3112 Instruction::GuestDeallocate { .. } => {
3113 uwriteln!(
3114 self.src,
3115 "{}free({})",
3116 self.gen.qualify_package(FFI_DIR),
3117 operands[0]
3118 )
3119 }
3120
3121 Instruction::GuestDeallocateString => {
3122 uwriteln!(
3123 self.src,
3124 "{}free({})",
3125 self.gen.qualify_package(FFI_DIR),
3126 operands[0]
3127 )
3128 }
3129
3130 Instruction::GuestDeallocateVariant { blocks } => {
3131 let cases = self
3132 .blocks
3133 .drain(self.blocks.len() - blocks..)
3134 .enumerate()
3135 .map(|(i, Block { body, results, .. })| {
3136 assert!(results.is_empty());
3137 if body.is_empty() {
3138 format!("{i} => ()")
3139 } else {
3140 format!(
3141 "{i} => {{
3142 {body}
3143 }}"
3144 )
3145 }
3146 })
3147 .collect::<Vec<_>>()
3148 .join("\n");
3149
3150 let op = &operands[0];
3151
3152 uwrite!(
3153 self.src,
3154 "
3155 match ({op}) {{
3156 {cases}
3157 _ => panic()
3158 }}
3159 "
3160 );
3161 }
3162
3163 Instruction::GuestDeallocateList { element } => {
3164 let Block {
3165 body,
3166 results,
3167 base,
3168 ..
3169 } = self.blocks.pop().unwrap();
3170 assert!(results.is_empty());
3171
3172 let address = &operands[0];
3173 let length = &operands[1];
3174
3175 let size = self.gen.gen.sizes.size(element).size_wasm32();
3176 if !body.trim().is_empty() {
3179 let index = self.locals.tmp("index");
3180
3181 uwrite!(
3182 self.src,
3183 "
3184 for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
3185 let {base} = ({address}) + ({index} * {size})
3186 {body}
3187 }}
3188 "
3189 );
3190 }
3191
3192 uwriteln!(
3193 self.src,
3194 "{}free({address})",
3195 self.gen.qualify_package(FFI_DIR)
3196 );
3197 }
3198
3199 Instruction::Flush { amt } => {
3200 results.extend(operands.iter().take(*amt).cloned());
3201 }
3202
3203 Instruction::FutureLift { ty, .. } => {
3204 let result = self.locals.tmp("result");
3205 let op = &operands[0];
3206 let ty = self.gen.type_name(&Type::Id(*ty), true);
3208 let ffi = self.gen.qualify_package(FFI_DIR);
3209
3210 let snake_name = format!("static_{}_future_table", ty.to_snake_case(),);
3211
3212 uwriteln!(
3213 self.src,
3214 r#"let {result} = {ffi}FutureReader::new({op}, {snake_name});"#,
3215 );
3216
3217 results.push(result);
3218 }
3219
3220 Instruction::FutureLower { .. } => {
3221 let op = &operands[0];
3222 results.push(format!("{op}.handle"));
3223 }
3224
3225 Instruction::AsyncTaskReturn { params, .. } => {
3226 let (body, return_param) = match &mut self.deferred_task_return {
3227 DeferredTaskReturn::Generating {
3228 prev_src,
3229 return_param,
3230 } => {
3231 mem::swap(&mut self.src, prev_src);
3232 (mem::take(prev_src), return_param.clone())
3233 }
3234 _ => unreachable!(),
3235 };
3236 assert_eq!(params.len(), operands.len());
3237 self.deferred_task_return = DeferredTaskReturn::Emitted {
3238 body,
3239 params: params
3240 .iter()
3241 .zip(operands)
3242 .map(|(a, b)| (*a, b.clone()))
3243 .collect(),
3244 return_param,
3245 };
3246 }
3247
3248 Instruction::StreamLower { .. } => {
3249 let op = &operands[0];
3250 results.push(format!("{op}.handle"));
3251 }
3252
3253 Instruction::StreamLift { ty, .. } => {
3254 let result = self.locals.tmp("result");
3255 let op = &operands[0];
3256 let qualifier = self.r#gen.qualify_package(self.func_interface);
3257 let ty = self.gen.type_name(&Type::Id(*ty), true);
3258 let ffi = self.gen.qualify_package(FFI_DIR);
3259 let snake_name = format!(
3260 "static_{}_stream_table",
3261 ty.replace(&qualifier, "").to_snake_case(),
3262 );
3263
3264 uwriteln!(
3265 self.src,
3266 r#"let {result} = {ffi}StreamReader::new({op}, {snake_name});"#,
3267 );
3268
3269 results.push(result);
3270 }
3271 Instruction::ErrorContextLower { .. }
3272 | Instruction::ErrorContextLift { .. }
3273 | Instruction::DropHandle { .. } => todo!(),
3274 }
3275 }
3276
3277 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
3278 if self.gen.direction == Direction::Import {
3279 let ffi_qualifier = self.gen.qualify_package(FFI_DIR);
3280 let address = self.locals.tmp("return_area");
3281 uwriteln!(
3282 self.src,
3283 "let {address} = {ffi_qualifier}malloc({})",
3284 size.size_wasm32(),
3285 );
3286 self.cleanup.push(Cleanup::Memory {
3287 address: address.clone(),
3288 size: size.size_wasm32().to_string(),
3289 align: align.align_wasm32(),
3290 });
3291 address
3292 } else {
3293 self.gen.gen.return_area_size = self.gen.gen.return_area_size.max(size);
3294 self.gen.gen.return_area_align = self.gen.gen.return_area_align.max(align);
3295 "return_area".into()
3296 }
3297 }
3298
3299 fn push_block(&mut self) {
3300 self.block_storage.push(BlockStorage {
3301 body: mem::take(&mut self.src),
3302 element: self.locals.tmp("element"),
3303 base: self.locals.tmp("base"),
3304 cleanup: mem::take(&mut self.cleanup),
3305 });
3306 }
3307
3308 fn finish_block(&mut self, operands: &mut Vec<String>) {
3309 let BlockStorage {
3310 body,
3311 element,
3312 base,
3313 cleanup,
3314 } = self.block_storage.pop().unwrap();
3315
3316 if !self.cleanup.is_empty() {
3317 self.needs_cleanup_list = true;
3318
3319 for cleanup in &self.cleanup {
3320 match cleanup {
3321 Cleanup::Memory {
3322 address,
3323 size,
3324 align,
3325 } => uwriteln!(
3326 self.src,
3327 "cleanupList.push({{address: {address}, size: {size}, align: {align}}})",
3328 ),
3329 Cleanup::Object(obj) => uwriteln!(self.src, "ignoreList.push({obj})",),
3330 }
3331 }
3332 }
3333
3334 self.cleanup = cleanup;
3335
3336 self.blocks.push(Block {
3337 body: mem::replace(&mut self.src, body),
3338 results: mem::take(operands),
3339 element,
3340 base,
3341 });
3342 }
3343
3344 fn sizes(&self) -> &SizeAlign {
3345 &self.gen.gen.sizes
3346 }
3347
3348 fn is_list_canonical(&self, _resolve: &Resolve, element: &Type) -> bool {
3349 matches!(
3350 element,
3351 Type::U8 | Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64
3352 )
3353 }
3354}
3355
3356fn perform_cast(op: &str, cast: &Bitcast) -> String {
3357 match cast {
3358 Bitcast::I32ToF32 => {
3359 format!("({op}).reinterpret_as_float()")
3360 }
3361 Bitcast::I64ToF32 => format!("({op}).to_int().reinterpret_as_float()"),
3362 Bitcast::F32ToI32 => {
3363 format!("({op}).reinterpret_as_int()")
3364 }
3365 Bitcast::F32ToI64 => format!("({op}).reinterpret_as_int().to_int64()"),
3366 Bitcast::I64ToF64 => {
3367 format!("({op}).reinterpret_as_double()")
3368 }
3369 Bitcast::F64ToI64 => {
3370 format!("({op}).reinterpret_as_int64()")
3371 }
3372 Bitcast::LToI64 | Bitcast::PToP64 | Bitcast::I32ToI64 => format!("Int::to_int64({op})"),
3373 Bitcast::I64ToL | Bitcast::P64ToP | Bitcast::I64ToI32 => format!("Int64::to_int({op})"),
3374 Bitcast::I64ToP64
3375 | Bitcast::P64ToI64
3376 | Bitcast::I32ToP
3377 | Bitcast::PToI32
3378 | Bitcast::I32ToL
3379 | Bitcast::LToI32
3380 | Bitcast::LToP
3381 | Bitcast::PToL
3382 | Bitcast::None => op.to_owned(),
3383
3384 Bitcast::Sequence(sequence) => {
3385 let [first, second] = &**sequence;
3386 perform_cast(&perform_cast(op, first), second)
3387 }
3388 }
3389}
3390
3391fn wasm_type(ty: WasmType) -> &'static str {
3392 match ty {
3393 WasmType::I32 => "Int",
3394 WasmType::I64 => "Int64",
3395 WasmType::F32 => "Float",
3396 WasmType::F64 => "Double",
3397 WasmType::Pointer => "Int",
3398 WasmType::PointerOrI64 => "Int64",
3399 WasmType::Length => "Int",
3400 }
3401}
3402
3403fn flags_repr(flags: &Flags) -> Int {
3404 match flags.repr() {
3405 FlagsRepr::U8 => Int::U8,
3406 FlagsRepr::U16 => Int::U16,
3407 FlagsRepr::U32(1) => Int::U32,
3408 FlagsRepr::U32(2) => Int::U64,
3409 repr => panic!("unimplemented flags {repr:?}"),
3410 }
3411}
3412
3413fn indent(code: &str) -> Source {
3414 let mut indented = Source::default();
3415 let mut was_empty = false;
3416 for line in code.lines() {
3417 let trimmed = line.trim();
3418 if trimmed.is_empty() {
3419 if was_empty {
3420 continue;
3421 }
3422 was_empty = true;
3423 } else {
3424 was_empty = false;
3425 }
3426
3427 if trimmed.starts_with('}') {
3428 indented.deindent(2)
3429 }
3430 indented.push_str(trimmed);
3431 if trimmed.ends_with('{') && !trimmed.starts_with("///") {
3432 indented.indent(2)
3433 }
3434 indented.push_str("\n");
3435 }
3436 indented
3437}
3438
3439fn world_name(resolve: &Resolve, world: WorldId) -> String {
3440 format!("world.{}", resolve.worlds[world].name.to_lower_camel_case())
3441}
3442
3443fn interface_name(resolve: &Resolve, name: &WorldKey) -> String {
3444 let pkg = match name {
3445 WorldKey::Name(_) => None,
3446 WorldKey::Interface(id) => {
3447 let pkg = resolve.interfaces[*id].package.unwrap();
3448 Some(resolve.packages[pkg].name.clone())
3449 }
3450 };
3451
3452 let name = match name {
3453 WorldKey::Name(name) => name,
3454 WorldKey::Interface(id) => resolve.interfaces[*id].name.as_ref().unwrap(),
3455 }
3456 .to_lower_camel_case();
3457
3458 format!(
3459 "interface.{}{name}",
3460 if let Some(name) = &pkg {
3461 format!(
3462 "{}.{}.",
3463 name.namespace.to_moonbit_ident(),
3464 name.name.to_moonbit_ident()
3465 )
3466 } else {
3467 String::new()
3468 }
3469 )
3470}
3471
3472trait ToMoonBitIdent: ToOwned {
3473 fn to_moonbit_ident(&self) -> Self::Owned;
3474}
3475
3476impl ToMoonBitIdent for str {
3477 fn to_moonbit_ident(&self) -> String {
3478 match self {
3480 "as" | "else" | "extern" | "fn" | "fnalias" | "if" | "let" | "const" | "match" | "using"
3482 | "mut" | "type" | "typealias" | "struct" | "enum" | "trait" | "traitalias" | "derive"
3483 | "while" | "break" | "continue" | "import" | "return" | "throw" | "raise" | "try" | "catch"
3484 | "pub" | "priv" | "readonly" | "true" | "false" | "_" | "test" | "loop" | "for" | "in" | "impl"
3485 | "with" | "guard" | "async" | "is" | "suberror" | "and" | "letrec" | "enumview" | "noraise"
3486 | "defer" | "init" | "main"
3487 | "module" | "move" | "ref" | "static" | "super" | "unsafe" | "use" | "where" | "await"
3489 | "dyn" | "abstract" | "do" | "final" | "macro" | "override" | "typeof" | "virtual" | "yield"
3490 | "local" | "method" | "alias" | "assert" | "package" | "recur" | "isnot" | "define" | "downcast"
3491 | "inherit" | "member" | "namespace" | "upcast" | "void" | "lazy" | "include" | "mixin"
3492 | "protected" | "sealed" | "constructor" | "atomic" | "volatile" | "anyframe" | "anytype"
3493 | "asm" | "comptime" | "errdefer" | "export" | "opaque" | "orelse" | "resume" | "threadlocal"
3494 | "unreachable" | "dynclass" | "dynobj" | "dynrec" | "var" | "finally" | "noasync" => {
3495 format!("{self}_")
3496 }
3497 _ => self.strip_prefix("[async]").unwrap_or(self).to_snake_case(),
3498 }
3499 }
3500}
3501
3502trait ToMoonBitTypeIdent: ToOwned {
3503 fn to_moonbit_type_ident(&self) -> Self::Owned;
3504}
3505
3506impl ToMoonBitTypeIdent for str {
3507 fn to_moonbit_type_ident(&self) -> String {
3508 match self.to_upper_camel_case().as_str() {
3510 type_name @ ("Bool" | "Byte" | "Int" | "Int64" | "UInt" | "UInt64" | "Float"
3511 | "Double" | "Error" | "Buffer" | "Bytes" | "Array" | "FixedArray"
3512 | "Map" | "String" | "Option" | "Result" | "Char" | "Json") => {
3513 format!("{type_name}_")
3514 }
3515 type_name => type_name.to_owned(),
3516 }
3517 }
3518}
3519
3520fn generated_preamble(src: &mut Source, version: &str) {
3521 uwriteln!(src, "// Generated by `wit-bindgen` {version}.")
3522}
3523
3524fn print_docs(src: &mut String, docs: &Docs) {
3525 if let Some(docs) = &docs.contents {
3526 let lines = docs
3527 .trim()
3528 .lines()
3529 .map(|line| format!("/// {line}"))
3530 .collect::<Vec<_>>()
3531 .join("\n");
3532
3533 uwrite!(src, "{}", lines)
3534 }
3535}