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