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_future(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
1323 unimplemented!() }
1325
1326 fn type_stream(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
1327 unimplemented!() }
1329
1330 fn type_builtin(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
1331 unimplemented!();
1332 }
1333}
1334
1335struct Block {
1336 body: String,
1337 results: Vec<String>,
1338}
1339
1340struct Cleanup {
1341 address: String,
1342}
1343
1344struct BlockStorage {
1345 body: String,
1346 cleanup: Vec<Cleanup>,
1347}
1348
1349#[derive(Clone, Debug)]
1350enum DeferredTaskReturn {
1351 None,
1352 Generating {
1353 prev_src: String,
1354 return_param: String,
1355 },
1356 Emitted {
1357 params: Vec<(WasmType, String)>,
1358 body: String,
1359 return_param: String,
1360 },
1361}
1362
1363struct FunctionBindgen<'a, 'b> {
1364 r#gen: &'b mut InterfaceGenerator<'a>,
1365 func_name: &'b str,
1366 func_interface: &'b str,
1367 params: Box<[String]>,
1368 src: String,
1369 locals: Ns,
1370 block_storage: Vec<BlockStorage>,
1371 blocks: Vec<Block>,
1372 payloads: Vec<String>,
1373 cleanup: Vec<Cleanup>,
1374 needs_cleanup_list: bool,
1375 deferred_task_return: DeferredTaskReturn,
1376}
1377
1378impl<'a, 'b> FunctionBindgen<'a, 'b> {
1379 fn new(
1380 r#gen: &'b mut InterfaceGenerator<'a>,
1381 func_name: &'b str,
1382 func_interface: &'b str,
1383 params: Box<[String]>,
1384 ) -> FunctionBindgen<'a, 'b> {
1385 let mut locals = Ns::default();
1386 params.iter().for_each(|str| {
1387 locals.tmp(str);
1388 });
1389 Self {
1390 r#gen,
1391 func_name,
1392 func_interface,
1393 params,
1394 src: String::new(),
1395 locals,
1396 block_storage: Vec::new(),
1397 blocks: Vec::new(),
1398 payloads: Vec::new(),
1399 cleanup: Vec::new(),
1400 needs_cleanup_list: false,
1401 deferred_task_return: DeferredTaskReturn::None,
1402 }
1403 }
1404
1405 fn lower_variant(
1406 &mut self,
1407 cases: &[(&str, Option<Type>)],
1408 lowered_types: &[WasmType],
1409 op: &str,
1410 results: &mut Vec<String>,
1411 is_result: bool,
1412 ) {
1413 let blocks = self
1414 .blocks
1415 .drain(self.blocks.len() - cases.len()..)
1416 .collect::<Vec<_>>();
1417
1418 let payloads = self
1419 .payloads
1420 .drain(self.payloads.len() - cases.len()..)
1421 .collect::<Vec<_>>();
1422
1423 let lowered = lowered_types
1424 .iter()
1425 .map(|_| self.locals.tmp("lowered"))
1426 .collect::<Vec<_>>();
1427
1428 results.extend(lowered.iter().cloned());
1429
1430 let declarations = lowered.join(",");
1431
1432 let cases = cases
1433 .iter()
1434 .zip(blocks)
1435 .zip(payloads)
1436 .map(|(((name, ty), Block { body, results, .. }), payload)| {
1437 let name = name.to_upper_camel_case();
1438 let assignments = results
1439 .iter()
1440 .map(|result| result.to_string())
1441 .collect::<Vec<_>>()
1442 .join(", ");
1443
1444 let payload = if self
1445 .r#gen
1446 .r#gen
1447 .pkg_resolver
1448 .non_empty_type(ty.as_ref())
1449 .is_some()
1450 {
1451 payload
1452 } else if is_result {
1453 format!("_{payload}")
1454 } else {
1455 String::new()
1456 };
1457
1458 if payload.is_empty() {
1459 format!(
1460 "{name} => {{
1461 {body}
1462 ({assignments})
1463 }}"
1464 )
1465 } else {
1466 format!(
1467 "{name}({payload}) => {{
1468 {body}
1469 ({assignments})
1470 }}",
1471 )
1472 }
1473 })
1474 .collect::<Vec<_>>()
1475 .join("\n");
1476
1477 if declarations.is_empty() {
1478 uwrite!(
1479 self.src,
1480 r#"
1481 match {op} {{
1482 {cases}
1483 }}
1484 "#
1485 );
1486 } else {
1487 uwrite!(
1488 self.src,
1489 r#"
1490 let ({declarations}) = match {op} {{
1491 {cases}
1492 }}
1493 "#
1494 );
1495 }
1496 }
1497
1498 fn lift_variant(
1499 &mut self,
1500 ty: &Type,
1501 cases: &[(&str, Option<Type>)],
1502 op: &str,
1503 results: &mut Vec<String>,
1504 is_result: bool,
1505 ) {
1506 let blocks = self
1507 .blocks
1508 .drain(self.blocks.len() - cases.len()..)
1509 .collect::<Vec<_>>();
1510
1511 let ty = self
1513 .r#gen
1514 .r#gen
1515 .pkg_resolver
1516 .type_constructor(self.r#gen.name, ty);
1517 let lifted = self.locals.tmp("lifted");
1518
1519 let cases = cases
1520 .iter()
1521 .zip(blocks)
1522 .enumerate()
1523 .map(|(i, ((case_name, case_ty), Block { body, results, .. }))| {
1524 let payload = if self
1525 .r#gen
1526 .r#gen
1527 .pkg_resolver
1528 .non_empty_type(case_ty.as_ref())
1529 .is_some()
1530 {
1531 results.into_iter().next().unwrap()
1532 } else {
1533 String::new()
1534 };
1535
1536 let constructor = format!("{ty}::{}", case_name.to_upper_camel_case());
1537
1538 if payload.is_empty() && !is_result {
1539 format!(
1540 "{i} => {{
1541 {body}
1542 {constructor}
1543 }}"
1544 )
1545 } else {
1546 format!(
1547 "{i} => {{
1548 {body}
1549 {constructor}({})
1550 }}",
1551 if payload.is_empty() {
1552 "()".into()
1553 } else {
1554 payload
1555 }
1556 )
1557 }
1558 })
1559 .collect::<Vec<_>>()
1560 .join("\n");
1561
1562 uwrite!(
1563 self.src,
1564 r#"
1565 let {lifted} = match ({op}) {{
1566 {cases}
1567 _ => panic()
1568 }}
1569 "#
1570 );
1571
1572 results.push(lifted);
1573 }
1574}
1575
1576impl Bindgen for FunctionBindgen<'_, '_> {
1577 type Operand = String;
1578
1579 fn emit(
1580 &mut self,
1581 _resolve: &Resolve,
1582 inst: &Instruction<'_>,
1583 operands: &mut Vec<String>,
1584 results: &mut Vec<String>,
1585 ) {
1586 match inst {
1587 Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
1588 Instruction::I32Const { val } => results.push(format!("({val})")),
1589 Instruction::ConstZero { tys } => results.extend(tys.iter().map(|ty| {
1590 match ty {
1591 WasmType::I32 => "0",
1592 WasmType::I64 => "0L",
1593 WasmType::F32 => "(0.0 : Float)",
1594 WasmType::F64 => "0.0",
1595 WasmType::Pointer => "0",
1596 WasmType::PointerOrI64 => "0L",
1597 WasmType::Length => "0",
1598 }
1599 .to_owned()
1600 })),
1601
1602 Instruction::Bitcasts { casts } => results.extend(
1603 casts
1604 .iter()
1605 .zip(operands)
1606 .map(|(cast, op)| perform_cast(op, cast)),
1607 ),
1608
1609 Instruction::I32FromS32
1610 | Instruction::I64FromS64
1611 | Instruction::S32FromI32
1612 | Instruction::S64FromI64
1613 | Instruction::CoreF64FromF64
1614 | Instruction::F64FromCoreF64
1615 | Instruction::F32FromCoreF32
1616 | Instruction::CoreF32FromF32 => results.push(operands[0].clone()),
1617
1618 Instruction::CharFromI32 => {
1619 results.push(format!("Int::unsafe_to_char({})", operands[0]))
1620 }
1621 Instruction::I32FromChar => results.push(format!("({}).to_int()", operands[0])),
1622
1623 Instruction::I32FromU8 => results.push(format!("({}).to_int()", operands[0])),
1624 Instruction::I32FromU16 => {
1625 results.push(format!("({}).reinterpret_as_int()", operands[0]))
1626 }
1627 Instruction::U8FromI32 => results.push(format!("({}).to_byte()", operands[0])),
1628
1629 Instruction::I32FromS8 => {
1630 self.r#gen.ffi_imports.insert(ffi::EXTEND8);
1631 results.push(format!("mbt_ffi_extend8({})", operands[0]))
1632 }
1633 Instruction::S8FromI32 => results.push(format!("({} - 0x100)", operands[0])),
1634 Instruction::S16FromI32 => results.push(format!("({} - 0x10000)", operands[0])),
1635 Instruction::I32FromS16 => {
1636 self.r#gen.ffi_imports.insert(ffi::EXTEND16);
1637 results.push(format!("mbt_ffi_extend16({})", operands[0]))
1638 }
1639 Instruction::U16FromI32 => results.push(format!(
1640 "({}.land(0xFFFF).reinterpret_as_uint())",
1641 operands[0]
1642 )),
1643 Instruction::U32FromI32 => {
1644 results.push(format!("({}).reinterpret_as_uint()", operands[0]))
1645 }
1646 Instruction::I32FromU32 => {
1647 results.push(format!("({}).reinterpret_as_int()", operands[0]))
1648 }
1649
1650 Instruction::U64FromI64 => {
1651 results.push(format!("({}).reinterpret_as_uint64()", operands[0]))
1652 }
1653 Instruction::I64FromU64 => {
1654 results.push(format!("({}).reinterpret_as_int64()", operands[0]))
1655 }
1656
1657 Instruction::I32FromBool => {
1658 results.push(format!("(if {} {{ 1 }} else {{ 0 }})", operands[0]));
1659 }
1660 Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
1661
1662 Instruction::FlagsLower { flags, ty, .. } => match flags_repr(flags) {
1663 Int::U8 => {
1664 let op = &operands[0];
1665 let flag = self.locals.tmp("flag");
1666 let ty = self
1667 .r#gen
1668 .r#gen
1669 .pkg_resolver
1670 .type_constructor(self.r#gen.name, &Type::Id(*ty));
1671 uwriteln!(
1672 self.src,
1673 r#"
1674 let {ty}({flag}) = {op}
1675 "#
1676 );
1677 results.push(format!("{flag}.to_int()"));
1678 }
1679 Int::U16 | Int::U32 => {
1680 let op = &operands[0];
1681 let flag = self.locals.tmp("flag");
1682 let ty = self
1683 .r#gen
1684 .r#gen
1685 .pkg_resolver
1686 .type_constructor(self.r#gen.name, &Type::Id(*ty));
1687 uwriteln!(
1688 self.src,
1689 r#"
1690 let {ty}({flag}) = {op}
1691 "#
1692 );
1693 results.push(format!("{flag}.reinterpret_as_int()"));
1694 }
1695 Int::U64 => {
1696 let op = &operands[0];
1697 let flag = self.locals.tmp("flag");
1698 let ty = self
1699 .r#gen
1700 .r#gen
1701 .pkg_resolver
1702 .type_constructor(self.r#gen.name, &Type::Id(*ty));
1703 uwriteln!(
1704 self.src,
1705 r#"
1706 let {ty}({flag}) = {op}
1707 "#
1708 );
1709 results.push(format!("({flag}.to_int())"));
1710 results.push(format!("({flag} >> 32).to_int())"));
1711 }
1712 },
1713
1714 Instruction::FlagsLift { flags, ty, .. } => match flags_repr(flags) {
1715 Int::U8 => {
1716 results.push(format!(
1717 "{}({}.to_byte())",
1718 self.r#gen
1719 .r#gen
1720 .pkg_resolver
1721 .type_name(self.r#gen.name, &Type::Id(*ty)),
1722 operands[0]
1723 ));
1724 }
1725 Int::U16 | Int::U32 => {
1726 results.push(format!(
1727 "{}({}.reinterpret_as_uint())",
1728 self.r#gen
1729 .r#gen
1730 .pkg_resolver
1731 .type_name(self.r#gen.name, &Type::Id(*ty)),
1732 operands[0]
1733 ));
1734 }
1735 Int::U64 => {
1736 results.push(format!(
1737 "{}(({}).reinterpret_as_uint().to_uint64() | (({}).reinterpret_as_uint().to_uint64() << 32))",
1738 self.r#gen.r#gen.pkg_resolver.type_name(self.r#gen.name, &Type::Id(*ty)),
1739 operands[0],
1740 operands[1]
1741 ));
1742 }
1743 },
1744
1745 Instruction::HandleLower { ty, .. } => {
1746 let op = &operands[0];
1747 let handle = self.locals.tmp("handle");
1748 let ty = self
1749 .r#gen
1750 .r#gen
1751 .pkg_resolver
1752 .type_constructor(self.r#gen.name, &Type::Id(*ty));
1753 uwrite!(
1754 self.src,
1755 r#"
1756 let {ty}({handle}) = {op}
1757 "#
1758 );
1759 results.push(handle);
1760 }
1761 Instruction::HandleLift { ty, .. } => {
1762 let op = &operands[0];
1763 let ty = self
1764 .r#gen
1765 .r#gen
1766 .pkg_resolver
1767 .type_constructor(self.r#gen.name, &Type::Id(*ty));
1768
1769 results.push(format!(
1770 "{}::{}({})",
1771 ty,
1772 if ty.starts_with("@") {
1773 ty.split('.').next_back().unwrap()
1774 } else {
1775 &ty
1776 },
1777 op
1778 ));
1779 }
1780
1781 Instruction::RecordLower { record, .. } => {
1782 let op = &operands[0];
1783 for field in record.fields.iter() {
1784 results.push(format!("({op}).{}", field.name.to_moonbit_ident()));
1785 }
1786 }
1787 Instruction::RecordLift { ty, record, .. } => {
1788 let ops = operands
1789 .iter()
1790 .enumerate()
1791 .map(|(i, op)| format!("{} : {}", record.fields[i].name.to_moonbit_ident(), op))
1792 .collect::<Vec<_>>()
1793 .join(", ");
1794
1795 results.push(format!(
1796 "{}::{{{ops}}}",
1797 self.r#gen
1798 .r#gen
1799 .pkg_resolver
1800 .type_name(self.r#gen.name, &Type::Id(*ty))
1801 ));
1802 }
1803
1804 Instruction::TupleLower { tuple, .. } => {
1805 let op = &operands[0];
1806 if tuple.types.is_empty() {
1809 results.push("()".into());
1810 } else if tuple.types.len() == 1 {
1811 results.push(operands[0].to_string());
1812 } else {
1813 for i in 0..tuple.types.len() {
1814 results.push(format!("({op}).{i}"));
1815 }
1816 }
1817 }
1818 Instruction::TupleLift { .. } => {
1819 let ops = operands
1820 .iter()
1821 .map(|op| op.to_string())
1822 .collect::<Vec<_>>()
1823 .join(", ");
1824 results.push(format!("({ops})"));
1825 }
1826
1827 Instruction::VariantPayloadName => {
1828 let payload = self.locals.tmp("payload");
1829 results.push(payload.clone());
1830 self.payloads.push(payload);
1831 }
1832
1833 Instruction::VariantLower {
1834 variant,
1835 results: lowered_types,
1836 ..
1837 } => self.lower_variant(
1838 &variant
1839 .cases
1840 .iter()
1841 .map(|case| (case.name.deref(), case.ty))
1842 .collect::<Vec<_>>(),
1843 lowered_types,
1844 &operands[0],
1845 results,
1846 false,
1847 ),
1848
1849 Instruction::VariantLift { variant, ty, .. } => self.lift_variant(
1850 &Type::Id(*ty),
1851 &variant
1852 .cases
1853 .iter()
1854 .map(|case| (case.name.deref(), case.ty))
1855 .collect::<Vec<_>>(),
1856 &operands[0],
1857 results,
1858 false,
1859 ),
1860
1861 Instruction::OptionLower {
1862 results: lowered_types,
1863 ..
1864 } => {
1865 let some = self.blocks.pop().unwrap();
1866 let none = self.blocks.pop().unwrap();
1867 let some_payload = self.payloads.pop().unwrap();
1868 let _none_payload = self.payloads.pop().unwrap();
1869
1870 let lowered = lowered_types
1871 .iter()
1872 .map(|_| self.locals.tmp("lowered"))
1873 .collect::<Vec<_>>();
1874
1875 results.extend(lowered.iter().cloned());
1876
1877 let declarations = lowered
1878 .iter()
1879 .map(|lowered| lowered.to_string())
1880 .collect::<Vec<_>>()
1881 .join(", ");
1882
1883 let op = &operands[0];
1884
1885 let block = |Block { body, results, .. }| {
1886 let assignments = results
1887 .iter()
1888 .map(|result| result.to_string())
1889 .collect::<Vec<_>>()
1890 .join(", ");
1891
1892 format!(
1893 "{body}
1894 ({assignments})"
1895 )
1896 };
1897
1898 let none = block(none);
1899 let some = block(some);
1900 let assignment = if declarations.is_empty() {
1901 "".into()
1902 } else {
1903 format!("let ({declarations}) = ")
1904 };
1905 uwrite!(
1906 self.src,
1907 r#"
1908 {assignment}match ({op}) {{
1909 None => {{
1910 {none}
1911 }}
1912 Some({some_payload}) => {{
1913 {some}
1914 }}
1915 }}
1916 "#,
1917 );
1918 }
1919
1920 Instruction::OptionLift { payload, ty } => {
1921 let some = self.blocks.pop().unwrap();
1922 let _none = self.blocks.pop().unwrap();
1923
1924 let ty = self
1925 .r#gen
1926 .r#gen
1927 .pkg_resolver
1928 .type_name(self.r#gen.name, &Type::Id(*ty));
1929 let lifted = self.locals.tmp("lifted");
1930 let op = &operands[0];
1931
1932 let payload = if self
1933 .r#gen
1934 .r#gen
1935 .pkg_resolver
1936 .non_empty_type(Some(*payload))
1937 .is_some()
1938 {
1939 some.results.into_iter().next().unwrap()
1940 } else {
1941 "None".into()
1942 };
1943
1944 let some = some.body;
1945
1946 uwrite!(
1947 self.src,
1948 r#"
1949 let {lifted} : {ty} = match {op} {{
1950 0 => Option::None
1951 1 => {{
1952 {some}
1953 Option::Some({payload})
1954 }}
1955 _ => panic()
1956 }}
1957 "#
1958 );
1959
1960 results.push(lifted);
1961 }
1962
1963 Instruction::ResultLower {
1964 results: lowered_types,
1965 result,
1966 ..
1967 } => self.lower_variant(
1968 &[("Ok", result.ok), ("Err", result.err)],
1969 lowered_types,
1970 &operands[0],
1971 results,
1972 true,
1973 ),
1974
1975 Instruction::ResultLift { result, ty } => self.lift_variant(
1976 &Type::Id(*ty),
1977 &[("Ok", result.ok), ("Err", result.err)],
1978 &operands[0],
1979 results,
1980 true,
1981 ),
1982
1983 Instruction::EnumLower { .. } => results.push(format!("{}.ordinal()", operands[0])),
1984
1985 Instruction::EnumLift { ty, .. } => results.push(format!(
1986 "{}::from({})",
1987 self.r#gen
1988 .r#gen
1989 .pkg_resolver
1990 .type_name(self.r#gen.name, &Type::Id(*ty)),
1991 operands[0]
1992 )),
1993
1994 Instruction::ListCanonLower { element, realloc } => match element {
1995 Type::U8 => {
1996 let op = &operands[0];
1997 let ptr = self.locals.tmp("ptr");
1998 self.r#gen.ffi_imports.insert(ffi::BYTES2PTR);
1999 uwriteln!(
2000 self.src,
2001 "
2002 let {ptr} = mbt_ffi_bytes2ptr({op})
2003 ",
2004 );
2005 results.push(ptr.clone());
2006 results.push(format!("{op}.length()"));
2007 if realloc.is_none() {
2008 self.cleanup.push(Cleanup { address: ptr });
2009 }
2010 }
2011 Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2012 let op = &operands[0];
2013 let ptr = self.locals.tmp("ptr");
2014 let ty = match element {
2015 Type::U32 => {
2016 self.r#gen.ffi_imports.insert(ffi::UINT_ARRAY2PTR);
2017 "uint"
2018 }
2019 Type::U64 => {
2020 self.r#gen.ffi_imports.insert(ffi::UINT64_ARRAY2PTR);
2021 "uint64"
2022 }
2023 Type::S32 => {
2024 self.r#gen.ffi_imports.insert(ffi::INT_ARRAY2PTR);
2025 "int"
2026 }
2027 Type::S64 => {
2028 self.r#gen.ffi_imports.insert(ffi::INT64_ARRAY2PTR);
2029 "int64"
2030 }
2031 Type::F32 => {
2032 self.r#gen.ffi_imports.insert(ffi::FLOAT_ARRAY2PTR);
2033 "float"
2034 }
2035 Type::F64 => {
2036 self.r#gen.ffi_imports.insert(ffi::DOUBLE_ARRAY2PTR);
2037 "double"
2038 }
2039 _ => unreachable!(),
2040 };
2041
2042 uwriteln!(
2043 self.src,
2044 "
2045 let {ptr} = mbt_ffi_{ty}_array2ptr({op})
2046 ",
2047 );
2048 results.push(ptr.clone());
2049 results.push(format!("{op}.length()"));
2050 if realloc.is_none() {
2051 self.cleanup.push(Cleanup { address: ptr });
2052 }
2053 }
2054 _ => unreachable!("unsupported list element type"),
2055 },
2056
2057 Instruction::ListCanonLift { element, .. } => match element {
2058 Type::U8 => {
2059 let result = self.locals.tmp("result");
2060 let address = &operands[0];
2061 let length = &operands[1];
2062 self.r#gen.ffi_imports.insert(ffi::PTR2BYTES);
2063 uwrite!(
2064 self.src,
2065 "
2066 let {result} = mbt_ffi_ptr2bytes({address}, {length})
2067 ",
2068 );
2069
2070 results.push(result);
2071 }
2072 Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64 => {
2073 let ty = match element {
2074 Type::U32 => {
2075 self.r#gen.ffi_imports.insert(ffi::PTR2UINT_ARRAY);
2076 "uint"
2077 }
2078 Type::U64 => {
2079 self.r#gen.ffi_imports.insert(ffi::PTR2UINT64_ARRAY);
2080 "uint64"
2081 }
2082 Type::S32 => {
2083 self.r#gen.ffi_imports.insert(ffi::PTR2INT_ARRAY);
2084 "int"
2085 }
2086 Type::S64 => {
2087 self.r#gen.ffi_imports.insert(ffi::PTR2INT64_ARRAY);
2088 "int64"
2089 }
2090 Type::F32 => {
2091 self.r#gen.ffi_imports.insert(ffi::PTR2FLOAT_ARRAY);
2092 "float"
2093 }
2094 Type::F64 => {
2095 self.r#gen.ffi_imports.insert(ffi::PTR2DOUBLE_ARRAY);
2096 "double"
2097 }
2098 _ => unreachable!(),
2099 };
2100
2101 let result = self.locals.tmp("result");
2102 let address = &operands[0];
2103 let length = &operands[1];
2104
2105 uwrite!(
2106 self.src,
2107 "
2108 let {result} = mbt_ffi_ptr2{ty}_array({address}, {length})
2109 ",
2110 );
2111
2112 results.push(result);
2113 }
2114 _ => unreachable!("unsupported list element type"),
2115 },
2116
2117 Instruction::StringLower { realloc } => {
2118 let op = &operands[0];
2119 let ptr = self.locals.tmp("ptr");
2120
2121 self.r#gen.ffi_imports.insert(ffi::STR2PTR);
2122 uwrite!(
2123 self.src,
2124 "
2125 let {ptr} = mbt_ffi_str2ptr({op})
2126 ",
2127 );
2128
2129 results.push(ptr.clone());
2130 results.push(format!("{op}.length()"));
2131 if realloc.is_none() {
2132 self.cleanup.push(Cleanup { address: ptr });
2133 }
2134 }
2135
2136 Instruction::StringLift { .. } => {
2137 let result = self.locals.tmp("result");
2138 let address = &operands[0];
2139 let length = &operands[1];
2140
2141 self.r#gen.ffi_imports.insert(ffi::PTR2STR);
2142 uwrite!(
2143 self.src,
2144 "
2145 let {result} = mbt_ffi_ptr2str({address}, {length})
2146 ",
2147 );
2148
2149 results.push(result);
2150 }
2151
2152 Instruction::ListLower { element, realloc } => {
2153 let Block {
2154 body,
2155 results: block_results,
2156 } = self.blocks.pop().unwrap();
2157 assert!(block_results.is_empty());
2158
2159 let op = &operands[0];
2160 let size = self.r#gen.r#gen.sizes.size(element).size_wasm32();
2161 let _align = self.r#gen.r#gen.sizes.align(element).align_wasm32();
2162 let address = self.locals.tmp("address");
2163 let ty = self
2164 .r#gen
2165 .r#gen
2166 .pkg_resolver
2167 .type_name(self.r#gen.name, element);
2168 let index = self.locals.tmp("index");
2169
2170 self.r#gen.ffi_imports.insert(ffi::MALLOC);
2171 uwrite!(
2172 self.src,
2173 "
2174 let {address} = mbt_ffi_malloc(({op}).length() * {size});
2175 for {index} = 0; {index} < ({op}).length(); {index} = {index} + 1 {{
2176 let iter_elem : {ty} = ({op})[({index})]
2177 let iter_base = {address} + ({index} * {size});
2178 {body}
2179 }}
2180 ",
2181 );
2182
2183 results.push(address.clone());
2184 results.push(format!("({op}).length()"));
2185
2186 if realloc.is_none() {
2187 self.cleanup.push(Cleanup { address });
2188 }
2189 }
2190
2191 Instruction::ListLift { element, .. } => {
2192 let Block {
2193 body,
2194 results: block_results,
2195 } = self.blocks.pop().unwrap();
2196 let address = &operands[0];
2197 let length = &operands[1];
2198 let array = self.locals.tmp("array");
2199 let ty = self
2200 .r#gen
2201 .r#gen
2202 .pkg_resolver
2203 .type_name(self.r#gen.name, element);
2204 let size = self.r#gen.r#gen.sizes.size(element).size_wasm32();
2205 let index = self.locals.tmp("index");
2207
2208 let result = match &block_results[..] {
2209 [result] => result,
2210 _ => todo!("result count == {}", results.len()),
2211 };
2212
2213 self.r#gen.ffi_imports.insert(ffi::FREE);
2214 uwrite!(
2215 self.src,
2216 "
2217 let {array} : Array[{ty}] = [];
2218 for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
2219 let iter_base = ({address}) + ({index} * {size})
2220 {body}
2221 {array}.push({result})
2222 }}
2223 mbt_ffi_free({address})
2224 ",
2225 );
2226
2227 results.push(array);
2228 }
2229
2230 Instruction::IterElem { .. } => results.push("iter_elem".into()),
2231
2232 Instruction::IterBasePointer => results.push("iter_base".into()),
2233
2234 Instruction::CallWasm { sig, .. } => {
2235 let assignment = match &sig.results[..] {
2236 [result] => {
2237 let ty = wasm_type(*result);
2238 let result = self.locals.tmp("result");
2239 let assignment = format!("let {result} : {ty} = ");
2240 results.push(result);
2241 assignment
2242 }
2243
2244 [] => String::new(),
2245
2246 _ => unreachable!(),
2247 };
2248
2249 let func_name = self.func_name.to_upper_camel_case();
2250
2251 let operands = operands.join(", ");
2252 uwriteln!(self.src, "{assignment} wasmImport{func_name}({operands});");
2254 }
2255
2256 Instruction::CallInterface { func, async_ } => {
2257 let name = self.r#gen.r#gen.pkg_resolver.func_call(
2258 self.r#gen.name,
2259 func,
2260 self.func_interface,
2261 );
2262
2263 let args = operands.join(", ");
2264
2265 if *async_ {
2266 let (async_func_result, task_return_result, task_return_type) =
2267 match func.result {
2268 Some(ty) => {
2269 let res = self.locals.tmp("return_result");
2270 (
2271 res.clone(),
2272 res,
2273 self.r#gen
2274 .r#gen
2275 .pkg_resolver
2276 .type_name(self.r#gen.name, &ty),
2277 )
2278 }
2279 None => ("_ignore".into(), "".into(), "Unit".into()),
2280 };
2281
2282 if func.result.is_some() {
2283 results.push(async_func_result.clone());
2284 }
2285 let ffi = self
2286 .r#gen
2287 .r#gen
2288 .pkg_resolver
2289 .qualify_package(self.r#gen.name, FFI_DIR);
2290 uwrite!(
2291 self.src,
2292 r#"
2293 let task = {ffi}current_task();
2294 let _ = task.with_waitable_set(fn(task) {{
2295 let {async_func_result}: Ref[{task_return_type}?] = Ref::new(None)
2296 task.wait(fn() {{
2297 {async_func_result}.val = Some({name}({args}));
2298 }})
2299 for {{
2300 if task.no_wait() && {async_func_result}.val is Some({async_func_result}){{
2301 {name}_task_return({task_return_result});
2302 break;
2303 }} else {{
2304 {ffi}suspend() catch {{
2305 _ => {{
2306 {ffi}task_cancel();
2307 }}
2308 }}
2309 }}
2310 }}
2311 }})
2312 if task.is_fail() is Some({ffi}Cancelled::Cancelled) {{
2313 {ffi}task_cancel();
2314 return {ffi}CallbackCode::Exit.encode()
2315 }}
2316 if task.is_done() {{
2317 return {ffi}CallbackCode::Exit.encode()
2318 }}
2319 return {ffi}CallbackCode::Wait(task.handle()).encode()
2320 "#,
2321 );
2322 assert!(matches!(
2323 self.deferred_task_return,
2324 DeferredTaskReturn::None
2325 ));
2326 self.deferred_task_return = DeferredTaskReturn::Generating {
2327 prev_src: mem::take(&mut self.src),
2328 return_param: async_func_result.to_string(),
2329 };
2330 return;
2331 }
2332
2333 let assignment = match func.result {
2334 None => "let _ = ".into(),
2335 Some(ty) => {
2336 let ty = format!(
2337 "({})",
2338 self.r#gen
2339 .r#gen
2340 .pkg_resolver
2341 .type_name(self.r#gen.name, &ty)
2342 );
2343 let result = self.locals.tmp("result");
2344 if func.result.is_some() {
2345 results.push(result.clone());
2346 }
2347 let assignment = format!("let ({result}) : {ty} = ");
2348 assignment
2349 }
2350 };
2351
2352 uwrite!(
2353 self.src,
2354 "
2355 {assignment}{name}({args});
2356 ",
2357 );
2358 }
2359
2360 Instruction::Return { amt, .. } => {
2361 for clean in &self.cleanup {
2362 let address = &clean.address;
2363 self.r#gen.ffi_imports.insert(ffi::FREE);
2364 uwriteln!(self.src, "mbt_ffi_free({address})",);
2365 }
2366
2367 if self.needs_cleanup_list {
2368 self.r#gen.ffi_imports.insert(ffi::FREE);
2369 uwrite!(
2370 self.src,
2371 "
2372 cleanup_list.each(mbt_ffi_free)
2373 ",
2374 );
2375 }
2376
2377 match *amt {
2378 0 => (),
2379 1 => uwriteln!(self.src, "return {}", operands[0]),
2380 _ => {
2381 let results = operands.join(", ");
2382 uwriteln!(self.src, "return ({results})");
2383 }
2384 }
2385 }
2386
2387 Instruction::I32Load { offset }
2388 | Instruction::PointerLoad { offset }
2389 | Instruction::LengthLoad { offset } => {
2390 self.r#gen.ffi_imports.insert(ffi::LOAD32);
2391 results.push(format!(
2392 "mbt_ffi_load32(({}) + {offset})",
2393 operands[0],
2394 offset = offset.size_wasm32()
2395 ))
2396 }
2397
2398 Instruction::I32Load8U { offset } => {
2399 self.r#gen.ffi_imports.insert(ffi::LOAD8_U);
2400 results.push(format!(
2401 "mbt_ffi_load8_u(({}) + {offset})",
2402 operands[0],
2403 offset = offset.size_wasm32()
2404 ))
2405 }
2406
2407 Instruction::I32Load8S { offset } => {
2408 self.r#gen.ffi_imports.insert(ffi::LOAD8);
2409 results.push(format!(
2410 "mbt_ffi_load8(({}) + {offset})",
2411 operands[0],
2412 offset = offset.size_wasm32()
2413 ))
2414 }
2415
2416 Instruction::I32Load16U { offset } => {
2417 self.r#gen.ffi_imports.insert(ffi::LOAD16_U);
2418 results.push(format!(
2419 "mbt_ffi_load16_u(({}) + {offset})",
2420 operands[0],
2421 offset = offset.size_wasm32()
2422 ))
2423 }
2424
2425 Instruction::I32Load16S { offset } => {
2426 self.r#gen.ffi_imports.insert(ffi::LOAD16);
2427 results.push(format!(
2428 "mbt_ffi_load16(({}) + {offset})",
2429 operands[0],
2430 offset = offset.size_wasm32()
2431 ))
2432 }
2433
2434 Instruction::I64Load { offset } => {
2435 self.r#gen.ffi_imports.insert(ffi::LOAD64);
2436 results.push(format!(
2437 "mbt_ffi_load64(({}) + {offset})",
2438 operands[0],
2439 offset = offset.size_wasm32()
2440 ))
2441 }
2442
2443 Instruction::F32Load { offset } => {
2444 self.r#gen.ffi_imports.insert(ffi::LOADF32);
2445 results.push(format!(
2446 "mbt_ffi_loadf32(({}) + {offset})",
2447 operands[0],
2448 offset = offset.size_wasm32()
2449 ))
2450 }
2451
2452 Instruction::F64Load { offset } => {
2453 self.r#gen.ffi_imports.insert(ffi::LOADF64);
2454 results.push(format!(
2455 "mbt_ffi_loadf64(({}) + {offset})",
2456 operands[0],
2457 offset = offset.size_wasm32()
2458 ))
2459 }
2460
2461 Instruction::I32Store { offset }
2462 | Instruction::PointerStore { offset }
2463 | Instruction::LengthStore { offset } => {
2464 self.r#gen.ffi_imports.insert(ffi::STORE32);
2465 uwriteln!(
2466 self.src,
2467 "mbt_ffi_store32(({}) + {offset}, {})",
2468 operands[1],
2469 operands[0],
2470 offset = offset.size_wasm32()
2471 )
2472 }
2473
2474 Instruction::I32Store8 { offset } => {
2475 self.r#gen.ffi_imports.insert(ffi::STORE8);
2476 uwriteln!(
2477 self.src,
2478 "mbt_ffi_store8(({}) + {offset}, {})",
2479 operands[1],
2480 operands[0],
2481 offset = offset.size_wasm32()
2482 )
2483 }
2484
2485 Instruction::I32Store16 { offset } => {
2486 self.r#gen.ffi_imports.insert(ffi::STORE16);
2487 uwriteln!(
2488 self.src,
2489 "mbt_ffi_store16(({}) + {offset}, {})",
2490 operands[1],
2491 operands[0],
2492 offset = offset.size_wasm32()
2493 )
2494 }
2495
2496 Instruction::I64Store { offset } => {
2497 self.r#gen.ffi_imports.insert(ffi::STORE64);
2498 uwriteln!(
2499 self.src,
2500 "mbt_ffi_store64(({}) + {offset}, {})",
2501 operands[1],
2502 operands[0],
2503 offset = offset.size_wasm32()
2504 )
2505 }
2506
2507 Instruction::F32Store { offset } => {
2508 self.r#gen.ffi_imports.insert(ffi::STOREF32);
2509 uwriteln!(
2510 self.src,
2511 "mbt_ffi_storef32(({}) + {offset}, {})",
2512 operands[1],
2513 operands[0],
2514 offset = offset.size_wasm32()
2515 )
2516 }
2517
2518 Instruction::F64Store { offset } => {
2519 self.r#gen.ffi_imports.insert(ffi::STOREF64);
2520 uwriteln!(
2521 self.src,
2522 "mbt_ffi_storef64(({}) + {offset}, {})",
2523 operands[1],
2524 operands[0],
2525 offset = offset.size_wasm32()
2526 )
2527 }
2528 Instruction::Malloc { size, .. } => {
2530 self.r#gen.ffi_imports.insert(ffi::MALLOC);
2531 uwriteln!(self.src, "mbt_ffi_malloc({})", size.size_wasm32())
2532 }
2533
2534 Instruction::GuestDeallocate { .. } => {
2535 self.r#gen.ffi_imports.insert(ffi::FREE);
2536 uwriteln!(self.src, "mbt_ffi_free({})", operands[0])
2537 }
2538
2539 Instruction::GuestDeallocateString => {
2540 self.r#gen.ffi_imports.insert(ffi::FREE);
2541 uwriteln!(self.src, "mbt_ffi_free({})", operands[0])
2542 }
2543
2544 Instruction::GuestDeallocateVariant { blocks } => {
2545 let cases = self
2546 .blocks
2547 .drain(self.blocks.len() - blocks..)
2548 .enumerate()
2549 .map(|(i, Block { body, results, .. })| {
2550 assert!(results.is_empty());
2551 if body.is_empty() {
2552 format!("{i} => ()")
2553 } else {
2554 format!(
2555 "{i} => {{
2556 {body}
2557 }}"
2558 )
2559 }
2560 })
2561 .collect::<Vec<_>>()
2562 .join("\n");
2563
2564 let op = &operands[0];
2565
2566 uwrite!(
2567 self.src,
2568 "
2569 match ({op}) {{
2570 {cases}
2571 _ => panic()
2572 }}
2573 "
2574 );
2575 }
2576
2577 Instruction::GuestDeallocateList { element } => {
2578 let Block { body, results, .. } = self.blocks.pop().unwrap();
2579 assert!(results.is_empty());
2580
2581 let address = &operands[0];
2582 let length = &operands[1];
2583
2584 let size = self.r#gen.r#gen.sizes.size(element).size_wasm32();
2585 if !body.trim().is_empty() {
2588 let index = self.locals.tmp("index");
2589
2590 uwrite!(
2591 self.src,
2592 "
2593 for {index} = 0; {index} < ({length}); {index} = {index} + 1 {{
2594 let iter_base = ({address}) + ({index} * {size})
2595 {body}
2596 }}
2597 "
2598 );
2599 }
2600
2601 self.r#gen.ffi_imports.insert(ffi::FREE);
2602 uwriteln!(self.src, "mbt_ffi_free({address})",);
2603 }
2604
2605 Instruction::Flush { amt } => {
2606 results.extend(operands.iter().take(*amt).cloned());
2607 }
2608
2609 Instruction::FutureLift { ty, .. } => {
2610 let result = self.locals.tmp("result");
2611 let op = &operands[0];
2612 let ty = self
2614 .r#gen
2615 .r#gen
2616 .pkg_resolver
2617 .type_name(self.r#gen.name, &Type::Id(*ty));
2618 let ffi = self
2619 .r#gen
2620 .r#gen
2621 .pkg_resolver
2622 .qualify_package(self.r#gen.name, FFI_DIR);
2623
2624 let snake_name = format!("static_{}_future_table", ty.to_snake_case(),);
2625
2626 uwriteln!(
2627 self.src,
2628 r#"let {result} = {ffi}FutureReader::new({op}, {snake_name});"#,
2629 );
2630
2631 results.push(result);
2632 }
2633
2634 Instruction::FutureLower { .. } => {
2635 let op = &operands[0];
2636 results.push(format!("{op}.handle"));
2637 }
2638
2639 Instruction::AsyncTaskReturn { params, .. } => {
2640 let (body, return_param) = match &mut self.deferred_task_return {
2641 DeferredTaskReturn::Generating {
2642 prev_src,
2643 return_param,
2644 } => {
2645 mem::swap(&mut self.src, prev_src);
2646 (mem::take(prev_src), return_param.clone())
2647 }
2648 _ => unreachable!(),
2649 };
2650 assert_eq!(params.len(), operands.len());
2651 self.deferred_task_return = DeferredTaskReturn::Emitted {
2652 body,
2653 params: params
2654 .iter()
2655 .zip(operands)
2656 .map(|(a, b)| (*a, b.clone()))
2657 .collect(),
2658 return_param,
2659 };
2660 }
2661
2662 Instruction::StreamLower { .. } => {
2663 let op = &operands[0];
2664 results.push(format!("{op}.handle"));
2665 }
2666
2667 Instruction::StreamLift { ty, .. } => {
2668 let result = self.locals.tmp("result");
2669 let op = &operands[0];
2670 let qualifier = self
2671 .r#gen
2672 .r#gen
2673 .pkg_resolver
2674 .qualify_package(self.r#gen.name, self.func_interface);
2675 let ty = self
2676 .r#gen
2677 .r#gen
2678 .pkg_resolver
2679 .type_name(self.r#gen.name, &Type::Id(*ty));
2680 let ffi = self
2681 .r#gen
2682 .r#gen
2683 .pkg_resolver
2684 .qualify_package(self.r#gen.name, FFI_DIR);
2685 let snake_name = format!(
2686 "static_{}_stream_table",
2687 ty.replace(&qualifier, "").to_snake_case(),
2688 );
2689
2690 uwriteln!(
2691 self.src,
2692 r#"let {result} = {ffi}StreamReader::new({op}, {snake_name});"#,
2693 );
2694
2695 results.push(result);
2696 }
2697 Instruction::ErrorContextLower { .. }
2698 | Instruction::ErrorContextLift { .. }
2699 | Instruction::DropHandle { .. } => todo!(),
2700 Instruction::FixedLengthListLift { .. } => todo!(),
2701 Instruction::FixedLengthListLower { .. } => todo!(),
2702 Instruction::FixedLengthListLowerToMemory { .. } => todo!(),
2703 Instruction::FixedLengthListLiftFromMemory { .. } => todo!(),
2704 }
2705 }
2706
2707 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
2708 if self.r#gen.direction == Direction::Import {
2709 self.r#gen.ffi_imports.insert(ffi::MALLOC);
2710 let address = self.locals.tmp("return_area");
2711 uwriteln!(
2712 self.src,
2713 "let {address} = mbt_ffi_malloc({})",
2714 size.size_wasm32(),
2715 );
2716 self.cleanup.push(Cleanup {
2717 address: address.clone(),
2718 });
2719 address
2720 } else {
2721 self.r#gen.r#gen.return_area_size = self.r#gen.r#gen.return_area_size.max(size);
2722 self.r#gen.r#gen.return_area_align = self.r#gen.r#gen.return_area_align.max(align);
2723 "return_area".into()
2724 }
2725 }
2726
2727 fn push_block(&mut self) {
2728 self.block_storage.push(BlockStorage {
2729 body: mem::take(&mut self.src),
2730 cleanup: mem::take(&mut self.cleanup),
2731 });
2732 }
2733
2734 fn finish_block(&mut self, operands: &mut Vec<String>) {
2735 let BlockStorage { body, cleanup } = self.block_storage.pop().unwrap();
2736
2737 if !self.cleanup.is_empty() {
2738 self.needs_cleanup_list = true;
2739 self.r#gen.ffi_imports.insert(ffi::FREE);
2740
2741 for cleanup in &self.cleanup {
2742 let address = &cleanup.address;
2743 uwriteln!(self.src, "mbt_ffi_free({address})",);
2744 }
2745 }
2746
2747 self.cleanup = cleanup;
2748
2749 self.blocks.push(Block {
2750 body: mem::replace(&mut self.src, body),
2751 results: mem::take(operands),
2752 });
2753 }
2754
2755 fn sizes(&self) -> &SizeAlign {
2756 &self.r#gen.r#gen.sizes
2757 }
2758
2759 fn is_list_canonical(&self, _resolve: &Resolve, element: &Type) -> bool {
2760 matches!(
2761 element,
2762 Type::U8 | Type::U32 | Type::U64 | Type::S32 | Type::S64 | Type::F32 | Type::F64
2763 )
2764 }
2765}
2766
2767fn perform_cast(op: &str, cast: &Bitcast) -> String {
2768 match cast {
2769 Bitcast::I32ToF32 => {
2770 format!("({op}).reinterpret_as_float()")
2771 }
2772 Bitcast::I64ToF32 => format!("({op}).to_int().reinterpret_as_float()"),
2773 Bitcast::F32ToI32 => {
2774 format!("({op}).reinterpret_as_int()")
2775 }
2776 Bitcast::F32ToI64 => format!("({op}).reinterpret_as_int().to_int64()"),
2777 Bitcast::I64ToF64 => {
2778 format!("({op}).reinterpret_as_double()")
2779 }
2780 Bitcast::F64ToI64 => {
2781 format!("({op}).reinterpret_as_int64()")
2782 }
2783 Bitcast::LToI64 | Bitcast::PToP64 | Bitcast::I32ToI64 => format!("Int::to_int64({op})"),
2784 Bitcast::I64ToL | Bitcast::P64ToP | Bitcast::I64ToI32 => format!("Int64::to_int({op})"),
2785 Bitcast::I64ToP64
2786 | Bitcast::P64ToI64
2787 | Bitcast::I32ToP
2788 | Bitcast::PToI32
2789 | Bitcast::I32ToL
2790 | Bitcast::LToI32
2791 | Bitcast::LToP
2792 | Bitcast::PToL
2793 | Bitcast::None => op.to_owned(),
2794
2795 Bitcast::Sequence(sequence) => {
2796 let [first, second] = &**sequence;
2797 perform_cast(&perform_cast(op, first), second)
2798 }
2799 }
2800}
2801
2802fn wasm_type(ty: WasmType) -> &'static str {
2803 match ty {
2804 WasmType::I32 => "Int",
2805 WasmType::I64 => "Int64",
2806 WasmType::F32 => "Float",
2807 WasmType::F64 => "Double",
2808 WasmType::Pointer => "Int",
2809 WasmType::PointerOrI64 => "Int64",
2810 WasmType::Length => "Int",
2811 }
2812}
2813
2814fn flags_repr(flags: &Flags) -> Int {
2815 match flags.repr() {
2816 FlagsRepr::U8 => Int::U8,
2817 FlagsRepr::U16 => Int::U16,
2818 FlagsRepr::U32(1) => Int::U32,
2819 FlagsRepr::U32(2) => Int::U64,
2820 repr => panic!("unimplemented flags {repr:?}"),
2821 }
2822}
2823
2824fn indent(code: &str) -> Source {
2825 let mut indented = Source::default();
2826 let mut was_empty = false;
2827 for line in code.lines() {
2828 let trimmed = line.trim();
2829 if trimmed.is_empty() {
2830 if was_empty {
2831 continue;
2832 }
2833 was_empty = true;
2834 } else {
2835 was_empty = false;
2836 }
2837
2838 if trimmed.starts_with('}') {
2839 indented.deindent(2)
2840 }
2841 indented.push_str(trimmed);
2842 if trimmed.ends_with('{') && !trimmed.starts_with("///") {
2843 indented.indent(2)
2844 }
2845 indented.push_str("\n");
2846 }
2847 indented
2848}
2849
2850fn generated_preamble(src: &mut Source, version: &str) {
2851 uwriteln!(src, "// Generated by `wit-bindgen` {version}.")
2852}
2853
2854fn print_docs(src: &mut String, docs: &Docs) {
2855 uwrite!(src, "///|");
2856 if let Some(docs) = &docs.contents {
2857 for line in docs.trim().lines() {
2858 uwrite!(src, "\n/// {line}");
2859 }
2860 }
2861}