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