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