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