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