1use anyhow::Result;
2use heck::*;
3use std::borrow::Cow;
4use std::collections::{BTreeSet, HashMap, HashSet};
5use std::mem::{replace, take};
6use std::path::PathBuf;
7use wit_bindgen_core::{
8 Direction, Files, InterfaceGenerator, Source, Types, WorldGenerator,
9 abi::{self, Bindgen, Bitcast, WasmType},
10 wit_parser::*,
11};
12
13type DType = String;
14#[derive(Default, Debug)]
15struct DSig {
16 static_member: bool,
17 result: DType,
18 arguments: Vec<(String, DType)>,
19 name: String,
20 implicit_self: bool,
21}
22
23#[derive(Default)]
24struct D {
25 root_pkg: String,
26 common_module: String,
27
28 used_interfaces: HashSet<(WorldKey, InterfaceId)>,
29 export_stubs: Vec<String>,
30
31 interface_imports: Vec<String>,
32 interface_exports: Vec<String>,
33 type_imports_src: Source,
34 function_imports_src: Source,
35 function_exports_src: Source,
36 export_stubs_src: Source,
37
38 opts: Opts,
39
40 world_id: Option<WorldId>,
41 world_fqn: String,
42 interface_fqns: HashMap<InterfaceId, InterfaceFQNSet>,
43
44 cur_interface: Option<InterfaceId>,
45
46 types: Types,
47}
48
49#[derive(Default, Debug)]
50struct InterfaceFQNSet {
51 import: Option<String>,
52 export: Option<String>,
53 common: Option<String>,
54}
55
56#[derive(Default, Debug, Clone)]
57#[cfg_attr(feature = "clap", derive(clap::Parser))]
58pub struct Opts {
59 #[cfg_attr(feature = "clap", arg(skip))]
61 out_dir: Option<PathBuf>,
62
63 #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
66 emit_export_stubs: bool,
67
68 #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
71 pub type_section_suffix: Option<String>,
72
73 #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
75 pub root_package: Option<String>,
76
77 #[cfg_attr(feature = "clap", arg(long, value_name = "VERSION"))]
90 pub required_d_versions: Vec<String>,
91}
92
93impl Opts {
94 pub fn build(mut self, out_dir: Option<&PathBuf>) -> Box<dyn WorldGenerator> {
95 let mut r = D::default();
96 self.out_dir = out_dir.cloned();
97 r.opts = self.clone();
98 Box::new(r)
99 }
100}
101
102fn escape_d_identifier(name: &str) -> &str {
103 match name {
104 "abstract" => "abstract_",
107 "alias" => "alias_",
108 "align" => "align_",
109 "asm" => "asm_",
110 "assert" => "assert_",
111 "auto" => "auto_",
112
113 "body" => "body_",
114 "bool" => "bool_",
115 "break" => "break_",
116 "byte" => "byte_",
117
118 "case" => "case_",
119 "cast" => "cast_",
120 "catch" => "catch_",
121 "cdouble" => "cdouble_",
122 "cent" => "cent_",
123 "cfloat" => "cfloat_",
124 "char" => "char_",
125 "class" => "class_",
126 "const" => "const_",
127 "continue" => "continue_",
128 "creal" => "creal_",
129
130 "dchar" => "dchar_",
131 "debug" => "debug_",
132 "default" => "default_",
133 "delegate" => "delegate_",
134 "delete" => "delete_",
135 "deprecated" => "deprecated_",
136 "do" => "do_",
137 "double" => "double_",
138
139 "else" => "else_",
140 "enum" => "enum_",
141 "export" => "export_",
142 "extern" => "extern_",
143
144 "false" => "false_",
145 "final" => "final_",
146 "finally" => "finally_",
147 "float" => "float_",
148 "for" => "for_",
149 "foreach" => "foreach_",
150 "foreach_reverse" => "foreach_reverse_",
151 "function" => "function_",
152
153 "goto" => "goto_",
154
155 "idouble" => "idouble_",
156 "if" => "if_",
157 "ifloat" => "ifloat_",
158 "immutable" => "immutable_",
159 "import" => "import_",
160 "in" => "in_",
161 "inout" => "inout_",
162 "int" => "int_",
163 "interface" => "interface_",
164 "invariant" => "invariant_",
165 "ireal" => "ireal_",
166 "is" => "is_",
167
168 "lazy" => "lazy_",
169 "long" => "long_",
170
171 "macro" => "macro_",
172 "mixin" => "mixin_",
173 "module" => "module_",
174
175 "new" => "new_",
176 "nothrow" => "nothrow_",
177 "null" => "null_",
178
179 "out" => "out_",
180 "override" => "override_",
181
182 "package" => "package_",
183 "pragma" => "pragma_",
184 "private" => "private_",
185 "protected" => "protected_",
186 "public" => "public_",
187 "pure" => "pure_",
188
189 "real" => "real_",
190 "ref" => "ref_",
191 "return" => "return_",
192
193 "scope" => "scope_",
194 "shared" => "shared_",
195 "short" => "short_",
196 "static" => "static_",
197 "struct" => "struct_",
198 "super" => "super_",
199 "switch" => "switch_",
200 "synchronized" => "synchronized_",
201
202 "template" => "template_",
203 "this" => "this_",
204 "throw" => "throw_",
205 "true" => "true_",
206 "try" => "try_",
207 "typeid" => "typeid_",
208 "typeof" => "typeof_",
209
210 "ubyte" => "ubyte_",
211 "ucent" => "ucent_",
212 "uint" => "uint_",
213 "ulong" => "ulong_",
214 "union" => "union_",
215 "unittest" => "unittest_",
216 "ushort" => "ushort_",
217
218 "version" => "version_",
219 "void" => "void_",
220
221 "wchar" => "wchar_",
222 "while" => "while_",
223 "with" => "with_",
224
225 "Object" => "Object_",
227 "Error" => "Error_",
228 "Throwable" => "Throwable_",
229 "Exception" => "Exception_",
230 "TypeInfo" => "TypeInfo_",
231
232 "WitList" => "WitList_",
234 "WitString" => "WitString_",
235 "WitFlags" => "WitFlags_",
236 "Option" => "Option_",
237 "Result" => "Result_",
238 "bits" => "bits_", "borrow" => "borrow_", "rep" => "rep_", "makeNew" => "makeNew_", "constructor" => "constructor_", s => s,
245 }
246}
247
248pub fn wasm_type(ty: WasmType) -> &'static str {
249 match ty {
250 WasmType::I32 => "uint",
251 WasmType::I64 => "ulong",
252 WasmType::F32 => "float",
253 WasmType::F64 => "double",
254 WasmType::Pointer => "void*",
255 WasmType::PointerOrI64 => "ulong",
256 WasmType::Length => "size_t",
257 }
258}
259
260fn get_package_fqn(root_pkg: &str, id: PackageId, resolve: &Resolve) -> String {
261 let pkg = &resolve.packages[id];
262 let pkg_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
263 p.name.namespace == pkg.name.namespace
264 && p.name.name == pkg.name.name
265 && p.name.version != pkg.name.version
266 });
267
268 format!(
269 "{root_pkg}.{}.{}{}",
270 escape_d_identifier(&pkg.name.namespace.to_snake_case()),
271 escape_d_identifier(&pkg.name.name.to_snake_case()),
272 if pkg_has_multiple_versions {
273 if let Some(version) = &pkg.name.version {
274 let version = version
275 .to_string()
276 .replace('.', "_")
277 .replace('-', "_")
278 .replace('+', "_");
279 format!("_{version}")
280 } else {
281 String::default()
282 }
283 } else {
284 String::default()
285 }
286 )
287}
288
289fn get_interface_fqn(
290 root_pkg: &str,
291 interface_id: &WorldKey,
292 world_fqn: &str,
293 resolve: &Resolve,
294 direction: Option<Direction>,
295) -> String {
296 match interface_id {
297 WorldKey::Name(name) => {
298 format!(
299 "{}.{}.{}",
300 world_fqn,
301 match direction {
302 None => panic!(
303 "Inline interfaces can only generate `import` or `export` module variant"
304 ),
305 Some(Direction::Import) => "imports",
306 Some(Direction::Export) => "exports",
307 },
308 escape_d_identifier(&name.to_snake_case())
309 )
310 }
311 WorldKey::Interface(id) => {
312 let iface = &resolve.interfaces[*id];
313
314 format!(
315 "{}.{}.{}",
316 get_package_fqn(root_pkg, iface.package.unwrap(), resolve),
317 escape_d_identifier(&iface.name.as_ref().unwrap().to_snake_case()),
318 match direction {
319 None => "common",
320 Some(Direction::Import) => "imports",
321 Some(Direction::Export) => "exports",
322 },
323 )
324 }
325 }
326}
327
328fn get_world_fqn(root_pkg: &str, id: WorldId, resolve: &Resolve) -> String {
329 let world = &resolve.worlds[id];
330 format!(
331 "{}.{}",
332 get_package_fqn(root_pkg, world.package.unwrap(), resolve),
333 escape_d_identifier(&world.name.to_snake_case())
334 )
335}
336
337impl D {
338 fn interface<'a>(
339 &'a mut self,
340 resolve: &'a Resolve,
341 direction: Option<Direction>,
342 name: Option<&'a WorldKey>,
343 wasm_import_module: Option<&'a str>,
344 ) -> DInterfaceGenerator<'a> {
345 let mut sizes = SizeAlign::default();
346 sizes.fill(resolve);
347
348 DInterfaceGenerator {
349 src: Source::default(),
350 stub_src: Source::default(),
351 stubs: Vec::default(),
352 fqn: "",
353 r#gen: self,
354 resolve,
355 interface: None,
356 name: name,
357 sizes,
358 direction,
359
360 wasm_import_module,
361
362 return_pointer_area_size: Default::default(),
363 return_pointer_area_align: Default::default(),
364 }
365 }
366
367 fn lookup_interface_fqn(&self, id: InterfaceId, direction: Option<Direction>) -> Option<&str> {
368 let all_fqns = &self.interface_fqns[&id];
369 match direction {
370 None => all_fqns.common.as_deref(),
371 Some(Direction::Import) => all_fqns.import.as_deref(),
372 Some(Direction::Export) => all_fqns.export.as_deref(),
373 }
374 }
375}
376
377impl WorldGenerator for D {
378 fn uses_nominal_type_ids(&self) -> bool {
379 false
380 }
381
382 fn preprocess(&mut self, resolve: &Resolve, world_id: WorldId) -> Result<()> {
383 self.root_pkg = self.opts.root_package.as_deref().unwrap_or("wit").into();
384 self.common_module = format!("{}.common", self.root_pkg);
385
386 self.world_fqn = get_world_fqn(&self.root_pkg, world_id, resolve);
387 self.world_id = Some(world_id);
388 self.types.analyze(resolve);
389
390 let world = &resolve.worlds[world_id];
391
392 for (name, import) in world.imports.iter() {
393 match import {
394 WorldItem::Interface { id, .. } => {
395 let fqns = self.interface_fqns.entry(*id).or_insert_with(|| {
396 let mut result = InterfaceFQNSet::default();
397
398 match name {
399 WorldKey::Interface(_) => {
400 result.common = Some(get_interface_fqn(
401 &self.root_pkg,
402 &name,
403 &self.world_fqn,
404 resolve,
405 None,
406 ));
407 }
408 WorldKey::Name(_) => {
409 result.common = Some(get_interface_fqn(
411 &self.root_pkg,
412 &name,
413 &self.world_fqn,
414 resolve,
415 Some(Direction::Import),
416 ));
417 }
418 }
419
420 result
421 });
422 (*fqns).import = Some(get_interface_fqn(
423 &self.root_pkg,
424 &name,
425 &self.world_fqn,
426 resolve,
427 Some(Direction::Import),
428 ))
429 }
430 _ => {}
431 }
432 }
433
434 for (name, export) in world.exports.iter() {
435 match export {
436 WorldItem::Interface { id, .. } => {
437 let fqns = self.interface_fqns.entry(*id).or_insert_with(|| {
438 let mut result = InterfaceFQNSet::default();
439
440 match name {
441 WorldKey::Interface(_) => {
442 result.common = Some(get_interface_fqn(
443 &self.root_pkg,
444 &name,
445 &self.world_fqn,
446 resolve,
447 None,
448 ));
449 }
450 WorldKey::Name(_) => {
451 result.common = Some(get_interface_fqn(
453 &self.root_pkg,
454 &name,
455 &self.world_fqn,
456 resolve,
457 Some(Direction::Export),
458 ));
459 }
460 }
461
462 result
463 });
464 (*fqns).export = Some(get_interface_fqn(
465 &self.root_pkg,
466 &name,
467 &self.world_fqn,
468 resolve,
469 Some(Direction::Export),
470 ))
471 }
472 _ => {}
473 }
474 }
475
476 Ok(())
477 }
478
479 fn import_interface(
480 &mut self,
481 resolve: &Resolve,
482 name: &WorldKey,
483 id: InterfaceId,
484 files: &mut Files,
485 ) -> Result<()> {
486 self.used_interfaces.insert((name.clone(), id));
487
488 self.cur_interface = Some(id);
489
490 let fqn = self.interface_fqns[&id].import.as_ref().unwrap().clone();
491
492 self.interface_imports.push(fqn.clone());
493
494 let wasm_import_module = resolve.name_world_key(name);
495 let mut r#gen = self.interface(
496 resolve,
497 Some(Direction::Import),
498 Some(name),
499 Some(&wasm_import_module),
500 );
501 r#gen.fqn = &fqn;
502 r#gen.interface = Some(id);
503 r#gen.prologue();
504
505 if let WorldKey::Name(_) = name {
506 r#gen.direction = None;
510 r#gen.types(id);
511 r#gen.direction = Some(Direction::Import);
512 }
513
514 r#gen.types(id);
515
516 for (_name, func) in &resolve.interfaces[id].functions {
517 match func.kind {
518 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
519 r#gen.import_func(func);
520 }
521 _ => {}
522 }
523 }
524
525 let mut interface_filepath = PathBuf::from_iter(
526 ["wit"]
527 .into_iter()
528 .chain(fqn.split(".").skip(r#gen.r#gen.root_pkg.split(".").count())),
529 );
530 interface_filepath.set_extension("d");
531
532 files.push(interface_filepath.to_str().unwrap(), r#gen.src.as_bytes());
533
534 self.cur_interface = None;
539 Ok(())
540 }
541
542 fn import_types(
543 &mut self,
544 resolve: &Resolve,
545 _world: WorldId,
546 types: &[(&str, TypeId)],
547 _files: &mut Files,
548 ) {
549 let fqn = self.world_fqn.clone();
550 let mut r#gen = self.interface(resolve, Some(Direction::Import), None, Some("$root"));
551 r#gen.fqn = &fqn;
552
553 for (name, id) in types.iter() {
554 r#gen.define_type(name, *id);
555 }
556
557 self.type_imports_src = take(&mut r#gen.src);
558 }
559
560 fn import_funcs(
561 &mut self,
562 resolve: &Resolve,
563 _world: WorldId,
564 funcs: &[(&str, &Function)],
565 _files: &mut Files,
566 ) {
567 let fqn = self.world_fqn.clone();
568 let mut r#gen = self.interface(resolve, Some(Direction::Import), None, Some("$root"));
569 r#gen.fqn = &fqn;
570
571 for (_name, func) in funcs {
572 r#gen.import_func(func);
573 }
574
575 self.function_imports_src = take(&mut r#gen.src);
576 }
577
578 fn export_interface(
579 &mut self,
580 resolve: &Resolve,
581 name: &WorldKey,
582 id: InterfaceId,
583 files: &mut Files,
584 ) -> Result<()> {
585 self.used_interfaces.insert((name.clone(), id));
586
587 self.cur_interface = Some(id);
588
589 let fqn = self.interface_fqns[&id].export.as_ref().unwrap().clone();
590
591 self.interface_exports.push(fqn.clone());
592
593 let wasm_import_module = resolve.name_world_key(name);
594 let emit_exports_stubs = self.opts.emit_export_stubs;
595
596 let mut r#gen = self.interface(
597 resolve,
598 Some(Direction::Export),
599 Some(name),
600 Some(&wasm_import_module),
601 );
602 r#gen.fqn = &fqn;
603 r#gen.interface = Some(id);
604 r#gen.prologue();
605
606 if let WorldKey::Name(_) = name {
607 r#gen.direction = None;
611 r#gen.types(id);
612 r#gen.direction = Some(Direction::Export);
613 }
614
615 r#gen.types(id);
616
617 r#gen.src.push_str(&format!(
618 "\npackage({}) template Exports(Impl...) {{\n",
619 r#gen.r#gen.root_pkg
620 ));
621
622 for (_name, func) in &resolve.interfaces[id].functions {
623 match func.kind {
624 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
625 r#gen.export_func(func);
626 }
627 _ => {}
628 }
629 }
630
631 for (type_name, type_id) in &resolve.interfaces[id].types {
632 let ty = &resolve.types[*type_id];
633
634 match &ty.kind {
635 TypeDefKind::Resource => {
636 let upper_name = ty.name.as_ref().unwrap().to_upper_camel_case();
637 let escaped_name = escape_d_identifier(&upper_name);
638
639 r#gen.src.push_str(&format!(
640 "\n/++\n{}\n+/\n",
641 ty.docs.contents.as_deref().unwrap_or_default()
642 ));
643
644 r#gen
645 .src
646 .push_str(&format!("/// ditto\nstruct {escaped_name}_Wrappers {{\n"));
647
648 r#gen.src.push_str(&format!(
649 "alias _Resource_Impl = findWitExportResource!(\"{wasm_import_module}\", \"{type_name}\", Impl);\n"
650 ));
651
652 if emit_exports_stubs {
653 r#gen.stub_src.push_str(&format!(
654 "@witExport(\"{}\", \"{}\")\nstruct {escaped_name}_STUB {{\n",
655 wasm_import_module,
656 ty.name.as_ref().unwrap()
657 ));
658
659 r#gen.stubs.push(escaped_name.to_owned() + "_STUB");
660 }
661
662 for (_, func) in &resolve.interfaces[id].functions {
663 match func.kind {
664 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
665 FunctionKind::Method(owner)
666 | FunctionKind::AsyncMethod(owner)
667 | FunctionKind::Constructor(owner)
668 | FunctionKind::Static(owner)
669 | FunctionKind::AsyncStatic(owner) => {
670 if owner == *type_id {
671 r#gen.export_func(func);
672 }
673 }
674 }
675 }
676
677 r#gen.src.push_str(&format!(
678 "\n@wasmExport!(\"{}#[dtor]{}\")\n",
679 wasm_import_module,
680 ty.name.as_ref().unwrap()
681 ));
682 r#gen.src.push_str(&format!(
683 "pragma(mangle, \"__wit_export_{}__:dtor:{}\")\n",
684 wasm_import_module.replace("/", "__").replace("-", "_"),
685 ty.name.as_ref().unwrap().replace("-", "_")
686 ));
687 r#gen.src.push_str(
688 "static private extern(C) void __export_dtor(void* ptr) {
689 (*cast(_Resource_Impl*)ptr).destroy!false;
690 free(ptr);
691 }
692 ",
693 );
694
695 r#gen.src.push_str("}\n");
696
697 if emit_exports_stubs {
698 r#gen.stub_src.push_str("}\n");
699 }
700 }
701 _ => {}
702 }
703 }
704
705 let ret_area_decl = r#gen.emit_ret_area_if_needed();
706
707 r#gen.src.push_str(&ret_area_decl);
708 r#gen.src.push_str("}\n\n");
709
710 let DInterfaceGenerator {
711 mut src,
712 stub_src,
713 stubs,
714 ..
715 } = r#gen;
716
717 if self.opts.emit_export_stubs {
718 src.append_src(&stub_src);
719
720 src.push_str("alias STUBS = AliasSeq!(\n");
721 src.indent(1);
722 src.push_str(&stubs.join(",\n"));
723 src.deindent(1);
724 src.push_str("\n);\n");
725
726 self.export_stubs.push(format!("{fqn}.STUBS"));
727 }
728
729 let mut interface_filepath = PathBuf::from_iter(
730 ["wit"]
731 .into_iter()
732 .chain(fqn.split(".").skip(self.root_pkg.split(".").count())),
733 );
734 interface_filepath.set_extension("d");
735
736 files.push(interface_filepath.to_str().unwrap(), src.as_bytes());
737
738 self.cur_interface = None;
739 Ok(())
740 }
741
742 fn export_funcs(
743 &mut self,
744 resolve: &Resolve,
745 _world: WorldId,
746 funcs: &[(&str, &Function)],
747 _files: &mut Files,
748 ) -> Result<()> {
749 let fqn = self.world_fqn.clone();
750 let mut r#gen = self.interface(resolve, Some(Direction::Export), None, Some("$root"));
751 r#gen.fqn = &fqn;
752
753 for (_name, func) in funcs {
754 match func.kind {
755 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
756 r#gen.export_func(func);
757 }
758 _ => {}
759 }
760 }
761
762 let ret_area_decl = r#gen.emit_ret_area_if_needed();
763
764 let DInterfaceGenerator {
765 src,
766 stub_src,
767 mut stubs,
768 ..
769 } = r#gen;
770
771 self.function_exports_src = src;
772 self.function_exports_src.push_str(&ret_area_decl);
773
774 if self.opts.emit_export_stubs {
775 self.export_stubs_src.append_src(&stub_src);
776 self.export_stubs.append(&mut stubs);
777 }
778
779 Ok(())
780 }
781
782 fn finish(&mut self, resolve: &Resolve, world_id: WorldId, files: &mut Files) -> Result<()> {
783 for (name, id) in take(&mut self.used_interfaces) {
784 if let WorldKey::Interface(_) = name {
785 let fqn = self.interface_fqns[&id].common.as_ref().unwrap().clone();
786
787 let wasm_import_module = resolve.name_world_key(&name);
788 let mut r#gen =
789 self.interface(resolve, None, Some(&name), Some(&wasm_import_module));
790 r#gen.fqn = &fqn;
791 r#gen.interface = Some(id);
792 r#gen.prologue();
793 r#gen.types(id);
794
795 let mut interface_filepath = PathBuf::from_iter(
796 ["wit"]
797 .into_iter()
798 .chain(fqn.split(".").skip(r#gen.r#gen.root_pkg.split(".").count())),
799 );
800 interface_filepath.set_extension("d");
801
802 files.push(interface_filepath.to_str().unwrap(), r#gen.src.as_bytes());
803 }
804 }
805
806 let mut world_src = Source::default();
807
808 let world = &resolve.worlds[world_id];
809
810 world_src.push_str(&format!(
811 "/++\n{}\n+/\n",
812 world.docs.contents.as_deref().unwrap_or_default()
813 ));
814
815 world_src.push_str(&format!("module {};\n\n", self.world_fqn));
816 world_src.push_str(&format!("import {};\n\n", self.common_module));
817 world_src.push_str(
818 &self
819 .interface_imports
820 .iter()
821 .map(|fqn| format!("public import {fqn};"))
822 .collect::<Vec<String>>()
823 .join("\n"),
824 );
825
826 world_src.push_str("\n");
827
828 world_src.push_str(
829 &self
830 .interface_exports
831 .iter()
832 .map(|fqn| format!("public import {fqn};"))
833 .collect::<Vec<String>>()
834 .join("\n"),
835 );
836
837 world_src.push_str("\n");
838
839 world_src.append_src(&self.type_imports_src);
840
841 world_src.append_src(&self.function_imports_src);
842
843 world_src.push_str("\n\nprivate alias AliasSeq(T...) = T;\n");
844 world_src.push_str("template Exports(Impl...) {\n");
845 world_src.push_str("alias InterfaceExports = AliasSeq!(\n");
846 world_src.indent(1);
847 world_src.push_str(
848 &self
849 .interface_exports
850 .iter()
851 .map(|fqn| format!("{fqn}.Exports!Impl"))
852 .collect::<Vec<String>>()
853 .join(",\n"),
854 );
855 world_src.deindent(1);
856 world_src.push_str("\n);\n");
857
858 world_src.push_str(&self.function_exports_src.as_str());
859 world_src.push_str("}\n");
860
861 if self.opts.emit_export_stubs {
862 self.export_stubs_src.push_str("alias STUBS = AliasSeq!(\n");
863 self.export_stubs_src.indent(1);
864 self.export_stubs_src
865 .push_str(&self.export_stubs.join(",\n"));
866 self.export_stubs_src.deindent(1);
867 self.export_stubs_src.push_str("\n);\n");
868
869 self.export_stubs_src
870 .push_str("alias Exports_STUB_INVOKE = Exports!(STUBS);\n");
871
872 world_src.append_src(&self.export_stubs_src);
873 }
874
875 {
877 let opts_suffix = self.opts.type_section_suffix.as_deref().unwrap_or("");
878 let world = &resolve.worlds[world_id];
879 let world_name = &world.name;
880 let pkg = &resolve.packages[world.package.unwrap()].name;
881 let version = env!("CARGO_PKG_VERSION");
882
883 let mut producers = wasm_metadata::Producers::empty();
884 producers.add(
885 "processed-by",
886 env!("CARGO_PKG_NAME"),
887 env!("CARGO_PKG_VERSION"),
888 );
889
890 let component_type = wit_component::metadata::encode(
891 resolve,
892 world_id,
893 wit_component::StringEncoding::UTF8,
894 Some(&producers),
895 )
896 .unwrap();
897
898 world_src.push_str(&format!(
899 "
900 pragma(inline, false)
901 package({}) void __wit_bindgen_component_type_force_link() pure @nogc nothrow {{}}
902
903
904 package({0}) void __wit_bindgen_component_type() {{
905 imported!\"ldc.llvmasm\".__irEx!(
906 \"\",
907 \"\",
908 `!wasm.custom_sections = !{{!0}}
909 !0 = !{{!\"component-type:wit-bindgen:{version}:{pkg}:{world_name}:{opts_suffix}\", !\"{}\"}}`,
910 void
911 );
912 }}
913 ",
914 self.root_pkg,
915 &component_type
916 .iter()
917 .map(|b| format!("\\{b:02X}"))
918 .enumerate()
919 .fold(String::default(), |a, (i, b)| {
920 if (i % 24) == 0 { a + "`\n~`" + &b } else { a + &b }
921 })
922 ));
923 }
924
925 let mut world_filepath = PathBuf::from_iter(
926 ["wit"].into_iter().chain(
927 get_world_fqn(&self.root_pkg, world_id, resolve)
928 .split(".")
929 .skip(self.root_pkg.split(".").count()),
930 ),
931 );
932 world_filepath.push("package.d");
933
934 files.push(world_filepath.to_str().unwrap(), world_src.as_bytes());
935
936 let mut wit_common_file = format!("module {};\n\n", self.common_module).into_bytes();
937 wit_common_file.extend_from_slice(include_bytes!("wit_common.d").as_slice());
938 files.push("wit/common.d", &wit_common_file);
939
940 Ok(())
941 }
942}
943
944struct DInterfaceGenerator<'a> {
945 src: Source,
946 stub_src: Source,
947 stubs: Vec<String>,
948 direction: Option<Direction>,
949 r#gen: &'a mut D,
950 resolve: &'a Resolve,
951 interface: Option<InterfaceId>,
952 name: Option<&'a WorldKey>,
953 wasm_import_module: Option<&'a str>,
954 fqn: &'a str,
955
956 sizes: SizeAlign,
957
958 return_pointer_area_size: ArchitectureSize,
959 return_pointer_area_align: Alignment,
960}
961
962impl<'a> DInterfaceGenerator<'a> {
963 fn scoped_type_name(&self, id: TypeId, from_module_fqn: &str) -> String {
964 let ty = &self.resolve.types[id];
965
966 let owner_fqn = self
967 .type_owner_fqn(&ty.owner, self.r#gen.types.get(id).has_resource)
968 .unwrap();
969
970 let upper_name = ty.name.as_ref().unwrap().to_upper_camel_case();
971 let escaped_name = escape_d_identifier(&upper_name);
972
973 if from_module_fqn == owner_fqn {
974 escaped_name.into()
975 } else {
976 format!("{owner_fqn}.{escaped_name}")
977 }
978 }
979 fn type_name(&self, ty: &Type, from_module_fqn: &str) -> Cow<'static, str> {
980 match ty {
981 Type::Bool => Cow::Borrowed("bool"),
982 Type::Char => Cow::Borrowed("dchar"),
983 Type::U8 => Cow::Borrowed("ubyte"),
984 Type::S8 => Cow::Borrowed("byte"),
985 Type::U16 => Cow::Borrowed("ushort"),
986 Type::S16 => Cow::Borrowed("short"),
987 Type::U32 => Cow::Borrowed("uint"),
988 Type::S32 => Cow::Borrowed("int"),
989 Type::U64 => Cow::Borrowed("ulong"),
990 Type::S64 => Cow::Borrowed("long"),
991 Type::F32 => Cow::Borrowed("float"),
992 Type::F64 => Cow::Borrowed("double"),
993 Type::String => Cow::Borrowed("WitString"),
994 Type::Id(id) => {
995 let typedef = &self.resolve.types[*id];
996
997 match typedef.owner {
998 TypeOwner::None => match &typedef.kind {
999 TypeDefKind::Record(_) => {
1000 Cow::Owned(self.scoped_type_name(*id, from_module_fqn))
1001 }
1002 TypeDefKind::Resource => {
1003 Cow::Owned(self.scoped_type_name(*id, from_module_fqn))
1004 }
1005 TypeDefKind::Handle(Handle::Own(id)) => {
1006 Cow::Owned(self.scoped_type_name(*id, from_module_fqn))
1007 }
1008 TypeDefKind::Handle(Handle::Borrow(id)) => {
1009 Cow::Owned(self.scoped_type_name(*id, from_module_fqn) + ".Borrow")
1010 }
1011 TypeDefKind::Tuple(t) => Cow::Owned(format!(
1012 "Tuple!({})",
1013 t.types
1014 .iter()
1015 .map(|ty| self.type_name(ty, from_module_fqn).into_owned())
1016 .collect::<Vec<String>>()
1017 .join(", ")
1018 )),
1019 TypeDefKind::Option(o) => {
1020 Cow::Owned(format!("Option!({})", self.type_name(o, from_module_fqn)))
1021 }
1022 TypeDefKind::Result(r) => Cow::Owned(format!(
1023 "Result!({}, {})",
1024 self.optional_type_name(r.ok.as_ref(), from_module_fqn),
1025 self.optional_type_name(r.err.as_ref(), from_module_fqn),
1026 )),
1027 TypeDefKind::List(ty) => Cow::Owned(format!(
1028 "WitList!({})",
1029 self.type_name(&ty, from_module_fqn)
1030 )),
1031 TypeDefKind::Future(_) => {
1032 todo!("type_name of `future`")
1033 }
1034 TypeDefKind::Stream(_) => {
1035 todo!("type_name of `stream`")
1036 }
1037 TypeDefKind::FixedLengthList(ty, size) => {
1038 Cow::Owned(format!("{}[{size}]", self.type_name(ty, from_module_fqn)))
1039 }
1040 TypeDefKind::Map(_, _) => todo!("type_name of `map`"),
1041 TypeDefKind::Unknown => unimplemented!(),
1042 unhandled => {
1043 panic!(
1044 "Encountered unexpected `type_name` invocation of ownerless typedef: {unhandled:?}."
1045 );
1046 }
1047 },
1048 _ => Cow::Owned(self.scoped_type_name(*id, from_module_fqn)),
1049 }
1050 }
1051 Type::ErrorContext => todo!(),
1052 }
1053 }
1054
1055 fn optional_type_name(&self, ty: Option<&Type>, from_module_fqn: &str) -> Cow<'static, str> {
1056 match ty {
1057 Some(ty) => self.type_name(ty, from_module_fqn),
1058 None => Cow::Borrowed("void"),
1059 }
1060 }
1061
1062 fn type_owner_fqn(&self, owner: &TypeOwner, imports_instead_of_common: bool) -> Option<&str> {
1063 match &owner {
1064 TypeOwner::None => None,
1065 TypeOwner::Interface(interface_id) => match self.direction {
1066 Some(_) => self
1067 .r#gen
1068 .lookup_interface_fqn(*interface_id, self.direction)
1069 .or_else(|| {
1070 if !imports_instead_of_common || self.direction != Some(Direction::Import) {
1071 self.r#gen.lookup_interface_fqn(
1072 *interface_id,
1073 if imports_instead_of_common {
1074 Some(Direction::Import)
1075 } else {
1076 None
1077 },
1078 )
1079 } else {
1080 None
1081 }
1082 }),
1083 None => self.r#gen.lookup_interface_fqn(*interface_id, None),
1084 },
1085 TypeOwner::World(world_id) => {
1086 if *world_id != self.r#gen.world_id.unwrap() {
1087 panic!("Dealing with type from different world?");
1088 }
1089
1090 Some(&self.r#gen.world_fqn)
1091 }
1092 }
1093 }
1094
1095 fn prologue(&mut self) {
1096 let id = self.interface.unwrap();
1097
1098 let interface = &self.resolve.interfaces[self.interface.unwrap()];
1099
1100 self.src.push_str(&format!(
1101 "/++\n{}\n+/\n",
1102 interface.docs.contents.as_deref().unwrap_or_default()
1103 ));
1104
1105 self.src.push_str(&format!("module {};\n\n", self.fqn));
1106
1107 for version in &self.r#gen.opts.required_d_versions {
1108 self.src.push_str(&format!("version({version}):\n"));
1109 }
1110
1111 self.src
1112 .push_str(&format!("\nimport {};\n\n", self.r#gen.common_module));
1113 if self.direction.is_some()
1114 && let Some(WorldKey::Interface(_)) = self.name
1115 {
1116 self.src.push_str("public import ");
1117 self.src
1118 .push_str(self.r#gen.lookup_interface_fqn(id, None).unwrap());
1119 self.src.push_str(";\n\n");
1120 }
1121
1122 let mut deps = BTreeSet::new();
1123
1124 for dep_id in self.resolve.interface_direct_deps(id) {
1125 deps.insert(dep_id);
1126 }
1127
1128 for dep_id in deps {
1129 let common_fqn = self.r#gen.lookup_interface_fqn(dep_id, None).unwrap();
1130 let directional_fqn = self.r#gen.lookup_interface_fqn(dep_id, self.direction);
1131
1132 if let Some(WorldKey::Interface(_)) = self.name {
1133 self.src.push_str(&format!(
1134 "static import {};\n",
1135 match self.direction {
1136 Some(_) => directional_fqn.unwrap_or(common_fqn),
1137 None => common_fqn,
1138 }
1139 ));
1140
1141 if self.direction == Some(Direction::Export) {
1142 if let Some(import_fqn) = self
1143 .r#gen
1144 .lookup_interface_fqn(dep_id, Some(Direction::Import))
1145 {
1146 self.src.push_str("static import ");
1147 self.src.push_str(import_fqn);
1148 self.src.push_str(";\n");
1149 }
1150 }
1151 } else {
1152 self.src.push_str(&format!("static import {common_fqn};\n"));
1153
1154 if let Some(fqn) = directional_fqn {
1155 self.src.push_str(&format!("static import {fqn};\n"));
1156 };
1157 }
1158 }
1159 self.src.push_str("\n");
1160 self.src.push_str(&format!("package ({}) void __wit_bindgen_component_type_force_link() pure @nogc nothrow => imported!\"{}\".__wit_bindgen_component_type_force_link();\n", self.r#gen.root_pkg, self.r#gen.world_fqn));
1161 }
1162
1163 fn type_is_direction_sensitive(&self, id: TypeId) -> bool {
1164 let type_info = &self.r#gen.types.get(id);
1165
1166 type_info.has_resource
1167 }
1168
1169 fn param_qualifier_for_type(&self, param_type: &Type) -> String {
1170 match param_type {
1171 Type::ErrorContext => todo!(),
1172 Type::String => "in ".to_owned(),
1173 Type::Id(id) => match &self.resolve.types[*id].kind {
1174 TypeDefKind::Enum(_) | TypeDefKind::Flags(_) | TypeDefKind::Handle(_) => {
1175 "".to_owned()
1176 }
1177 TypeDefKind::Future(_) | TypeDefKind::Map(_, _) | TypeDefKind::Stream(_) => {
1178 todo!()
1179 }
1180 TypeDefKind::Type(r#type) => self.param_qualifier_for_type(r#type),
1181 _ => {
1182 if matches!(self.direction, Some(Direction::Export))
1183 && self.r#gen.types.get(*id).has_resource
1184 {
1185 "scope ref ".to_owned()
1186 } else {
1187 "in ".to_owned()
1188 }
1189 }
1190 },
1191 _ => "".to_owned(),
1192 }
1193 }
1194
1195 fn get_d_signature(&mut self, func: &Function) -> DSig {
1196 match &func.kind {
1197 FunctionKind::Freestanding
1198 | FunctionKind::Method(_)
1199 | FunctionKind::Static(_)
1200 | FunctionKind::Constructor(_) => {}
1201
1202 FunctionKind::AsyncFreestanding
1203 | FunctionKind::AsyncMethod(_)
1204 | FunctionKind::AsyncStatic(_) => {
1205 todo!()
1206 }
1207 }
1208
1209 let mut res = DSig::default();
1210
1211 let split_name = match &func.kind {
1212 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &func.name,
1213 FunctionKind::Constructor(_) => "",
1214 FunctionKind::Method(_)
1215 | FunctionKind::Static(_)
1216 | FunctionKind::AsyncMethod(_)
1217 | FunctionKind::AsyncStatic(_) => func.name.split(".").skip(1).next().unwrap(),
1218 };
1219
1220 let lower_name = split_name.to_lower_camel_case();
1221 let escaped_name = if let FunctionKind::Constructor(_) = &func.kind {
1222 match self.direction {
1223 Some(Direction::Import) => "makeNew",
1224 _ => "constructor",
1225 }
1226 } else {
1227 escape_d_identifier(&lower_name)
1228 };
1229
1230 res.name = escaped_name.into();
1231 res.static_member = match &func.kind {
1232 FunctionKind::Static(_) => true,
1233 FunctionKind::Constructor(_) => true,
1234 _ => false,
1235 };
1236
1237 res.result
1238 .push_str(&(self.optional_type_name(func.result.as_ref(), self.fqn)));
1239
1240 for (
1241 i,
1242 Param {
1243 name, ty: param, ..
1244 },
1245 ) in func.params.iter().enumerate()
1246 {
1247 if i == 0 && name == "self" {
1248 match &func.kind {
1249 FunctionKind::Method(_) => {
1250 res.implicit_self = true;
1251 continue;
1252 }
1253 _ => {}
1254 }
1255 }
1256
1257 let lower_param_name = name.to_lower_camel_case();
1258 let escaped_param_name = escape_d_identifier(&lower_param_name);
1259
1260 let qualifier = self.param_qualifier_for_type(param);
1261
1262 res.arguments.push((
1263 escaped_param_name.into(),
1264 qualifier + &self.type_name(¶m, self.fqn),
1265 ));
1266 }
1267
1268 res
1269 }
1270
1271 fn import_func(&mut self, func: &Function) {
1272 match &func.kind {
1273 FunctionKind::Freestanding
1274 | FunctionKind::Constructor(_)
1275 | FunctionKind::Method(_)
1276 | FunctionKind::Static(_) => {}
1277 kind => {
1278 todo!("Import {kind:?} - {}\n", func.name);
1279 }
1280 }
1281
1282 let wasm_sig = self
1283 .resolve
1284 .wasm_signature(abi::AbiVariant::GuestImport, func);
1285
1286 let d_sig = self.get_d_signature(func);
1287
1288 self.src.push_str(&format!(
1289 "\n/++\n{}\n+/\n",
1290 func.docs.contents.as_deref().unwrap_or_default()
1291 ));
1292
1293 if d_sig.static_member {
1294 self.src.push_str("static ");
1295 }
1296 self.src.push_str(&format!(
1297 "{} {}({}) @trusted nothrow {{\n",
1298 d_sig.result,
1299 d_sig.name,
1300 d_sig
1301 .arguments
1302 .iter()
1303 .map(|(name, ty)| ty.to_owned() + " " + name)
1304 .collect::<Vec<String>>()
1305 .join(", ")
1306 ));
1307
1308 let mut params = Vec::new();
1309
1310 if d_sig.implicit_self {
1311 params.push("this");
1312 }
1313 for (arg, _ty) in &d_sig.arguments {
1314 params.push(arg);
1315 }
1316
1317 let mut f = FunctionBindgen::new(self, ¶ms);
1318 abi::call(
1319 f.r#gen.resolve,
1320 abi::AbiVariant::GuestImport,
1321 abi::LiftLower::LowerArgsLiftResults,
1322 func,
1323 &mut f,
1324 false,
1325 );
1326 let ret_area_decl = f.emit_ret_area_if_needed();
1327
1328 let FunctionBindgen {
1329 src,
1330 needs_deallocate,
1331 ..
1332 } = f;
1333 self.src.push_str(&ret_area_decl);
1334 if needs_deallocate {
1335 self.src.push_str(&format!(
1336 "{}.DeallocateBuffer deallocate;\n",
1337 self.r#gen.common_module
1338 ));
1339 }
1340 self.src.push_str(&src);
1341
1342 self.src.push_str("}\n");
1343
1344 self.src.push_str("/// ditto\n");
1345 self.src.push_str(&format!(
1346 "@wasmImport!(\"{}\", \"{}\")\n",
1347 self.wasm_import_module.unwrap(),
1348 func.name
1349 ));
1350
1351 self.src.push_str(&format!(
1355 "pragma(mangle, \"__wit_import_{}__{}\")\n",
1356 self.wasm_import_module
1357 .unwrap()
1358 .replace("/", "__")
1359 .replace("-", "_"),
1360 func.name
1361 .replace("-", "_")
1362 .replace("[", ":")
1363 .replace("]", ":")
1364 ));
1365
1366 if d_sig.implicit_self || d_sig.static_member {
1367 self.src.push_str("static ");
1368 }
1369 self.src.push_str(&format!(
1370 "private extern(C) {} __import_{}({}) nothrow;\n",
1371 match wasm_sig.results.len() {
1372 0 => "void",
1373 1 => wasm_type(wasm_sig.results[0]),
1374 _ => unimplemented!("multi-value return not supported"),
1375 },
1376 d_sig.name,
1377 wasm_sig
1378 .params
1379 .iter()
1380 .map(|param| wasm_type(*param))
1381 .collect::<Vec<&str>>()
1382 .join(", ")
1383 ));
1384 }
1385
1386 fn export_func(&mut self, func: &Function) {
1387 match &func.kind {
1388 FunctionKind::Freestanding
1389 | FunctionKind::Constructor(_)
1390 | FunctionKind::Method(_)
1391 | FunctionKind::Static(_) => {}
1392 kind => {
1393 todo!("Export {kind:?} - {}\n", func.name);
1394 }
1395 }
1396
1397 let wasm_sig = self
1398 .resolve
1399 .wasm_signature(abi::AbiVariant::GuestExport, func);
1400
1401 let d_sig = self.get_d_signature(func);
1402
1403 let mut params_data = Vec::new();
1404 let mut params = Vec::new();
1405
1406 if d_sig.implicit_self {
1407 params.push("self");
1408 }
1409 for (arg, _ty) in wasm_sig.params.iter().enumerate() {
1410 params_data.push(format!("arg{arg}"));
1411 }
1412 for param in ¶ms_data {
1413 params.push(¶m);
1414 }
1415
1416 self.src.push_str(&format!(
1417 "\n/++\n{}\n+/\n",
1418 func.docs.contents.as_deref().unwrap_or_default()
1419 ));
1420
1421 self.src.push_str(&format!(
1422 "alias {}_Sig = {} function({});\n",
1423 d_sig.name,
1424 d_sig.result,
1425 d_sig
1426 .arguments
1427 .iter()
1428 .map(|(name, ty)| ty.to_owned() + " " + name)
1429 .collect::<Vec<String>>()
1430 .join(", ")
1431 ));
1432
1433 self.src.push_str(&format!(
1434 "/// ditto\nalias {}_Impl = findWitExportFunc!(\"{}\", \"{}\", {0}_Sig, {}, {});\n",
1435 d_sig.name,
1436 self.wasm_import_module.unwrap(),
1437 func.name,
1438 d_sig.implicit_self,
1439 match &func.kind {
1440 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => "Impl",
1441 _ => {
1442 "witExportsIn!_Resource_Impl"
1443 }
1444 }
1445 ));
1446
1447 if self.r#gen.opts.emit_export_stubs {
1448 self.stub_src.push_str(&format!(
1449 "@witExport(\"{}\", \"{}\")\n",
1450 self.wasm_import_module.unwrap(),
1451 func.name
1452 ));
1453 if d_sig.static_member {
1454 self.stub_src.push_str("static ");
1455 }
1456 self.stub_src.push_str(&format!(
1457 "{} {}_STUB({});\n",
1458 d_sig.result,
1459 d_sig.name,
1460 d_sig
1461 .arguments
1462 .iter()
1463 .map(|(name, ty)| ty.to_owned() + " " + name)
1464 .collect::<Vec<String>>()
1465 .join(", ")
1466 ));
1467
1468 match func.kind {
1469 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1470 self.stubs.push(d_sig.name.clone() + "_STUB");
1471 }
1472 _ => {}
1473 }
1474 }
1475
1476 let core_module_name = self.name.map(|s| self.resolve.name_world_key(s));
1477 let export_name = func.legacy_core_export_name(core_module_name.as_deref());
1478
1479 self.src.push_str("/// ditto\n");
1480 self.src
1481 .push_str(&format!("@wasmExport!(\"{export_name}\")\n"));
1482
1483 self.src.push_str(&format!(
1484 "pragma(mangle, \"__wit_export_{}\")\n",
1485 export_name
1486 .replace("/", "__")
1487 .replace("-", "_")
1488 .replace("[", ":")
1489 .replace("]", ":")
1490 .replace("#", "::")
1491 ));
1492
1493 if d_sig.implicit_self || d_sig.static_member {
1494 self.src.push_str("static ");
1495 }
1496 self.src.push_str(&format!(
1497 "private extern(C) {} __export_{}({}) {{\n",
1498 match wasm_sig.results.len() {
1499 0 => "void",
1500 1 => wasm_type(wasm_sig.results[0]),
1501 _ => unimplemented!("multi-value return not supported"),
1502 },
1503 d_sig.name,
1504 wasm_sig
1505 .params
1506 .iter()
1507 .zip(¶ms)
1508 .map(|(ty, name)| format!("{} {name}", wasm_type(*ty)))
1509 .collect::<Vec<String>>()
1510 .join(", ")
1511 ));
1512
1513 let mut f = FunctionBindgen::new(self, ¶ms);
1514 abi::call(
1515 f.r#gen.resolve,
1516 abi::AbiVariant::GuestExport,
1517 abi::LiftLower::LiftArgsLowerResults,
1518 func,
1519 &mut f,
1520 false,
1521 );
1522
1523 let ret_area_decl = f.emit_ret_area_if_needed();
1524
1525 let FunctionBindgen {
1526 src,
1527 return_pointer_area_size,
1528 return_pointer_area_align,
1529 needs_deallocate,
1530 ..
1531 } = f;
1532 self.return_pointer_area_size = self.return_pointer_area_size.max(return_pointer_area_size);
1533 self.return_pointer_area_align = self
1534 .return_pointer_area_align
1535 .max(return_pointer_area_align);
1536
1537 self.src.push_str(&ret_area_decl);
1538 if needs_deallocate {
1539 self.src.push_str(&format!(
1540 "{}.DeallocateBuffer deallocate;\n",
1541 self.r#gen.common_module
1542 ));
1543 }
1544 self.src.push_str(&src);
1545
1546 self.src.push_str("}\n");
1547
1548 if abi::guest_export_needs_post_return(self.resolve, func) {
1549 let mut param_data = Vec::new();
1550 let mut params = Vec::<&str>::new();
1551
1552 for (arg, _ty) in wasm_sig.results.iter().enumerate() {
1553 param_data.push(format!("arg{arg}"));
1554 }
1555 for param in ¶m_data {
1556 params.push(¶m);
1557 }
1558
1559 self.src
1560 .push_str(&format!("@wasmExport!(\"cabi_post_{export_name}\")\n"));
1561
1562 self.src.push_str(&format!(
1563 "pragma(mangle, \"__wit_cabi_post_{}\")\n",
1564 export_name
1565 .replace("/", "__")
1566 .replace("-", "_")
1567 .replace("[", ":")
1568 .replace("]", ":")
1569 .replace("#", "::")
1570 ));
1571
1572 if d_sig.implicit_self || d_sig.static_member {
1573 self.src.push_str("static ");
1574 }
1575 self.src.push_str(&format!(
1576 "private extern(C) void __cabi_post_{}({}) {{\n",
1577 d_sig.name,
1578 wasm_sig
1579 .results
1580 .iter()
1581 .zip(¶ms)
1582 .map(|(ty, name)| format!("{} {name}", wasm_type(*ty)))
1583 .collect::<Vec<String>>()
1584 .join(", ")
1585 ));
1586
1587 let mut f = FunctionBindgen::new(self, ¶ms);
1588 abi::post_return(f.r#gen.resolve, func, &mut f);
1589
1590 let ret_area_decl = f.emit_ret_area_if_needed();
1591
1592 let FunctionBindgen {
1593 src,
1594 return_pointer_area_size,
1595 return_pointer_area_align,
1596 ..
1597 } = f;
1598 self.return_pointer_area_size =
1599 self.return_pointer_area_size.max(return_pointer_area_size);
1600 self.return_pointer_area_align = self
1601 .return_pointer_area_align
1602 .max(return_pointer_area_align);
1603
1604 self.src.push_str(&ret_area_decl);
1605 self.src.push_str(&src);
1606
1607 self.src.push_str("}\n");
1608 }
1609 }
1610
1611 fn emit_ret_area_if_needed(&self) -> String {
1612 if !self.return_pointer_area_size.is_empty() {
1613 format!(
1614 "\nalign({}) private void[{}] _exportsRetArea;\n",
1615 self.return_pointer_area_align.format("size_t.sizeof"),
1616 self.return_pointer_area_size.format("size_t.sizeof")
1617 )
1618 } else {
1619 String::new()
1620 }
1621 }
1622
1623 fn needs_wit_free(&self, ty: Type) -> bool {
1624 match ty {
1625 Type::String => true,
1626 Type::Id(id) => {
1627 let typeinfo = &self.r#gen.types.get(id);
1628 typeinfo.has_list
1629 }
1630 _ => false,
1631 }
1632 }
1633
1634 fn needs_wit_drop(&self, ty: Type) -> bool {
1635 match ty {
1636 Type::Id(id) => {
1637 let typeinfo = &self.r#gen.types.get(id);
1638 typeinfo.has_resource
1639 }
1640 _ => false,
1641 }
1642 }
1643
1644 fn can_have_wit_clone(&self, _ty: Type) -> bool {
1645 true
1646 }
1647}
1648
1649impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
1650 fn resolve(&self) -> &'a Resolve {
1651 self.resolve
1652 }
1653
1654 fn types(&mut self, iface: InterfaceId) {
1656 let iface = &self.resolve().interfaces[iface];
1657 for (name, id) in iface.types.iter() {
1658 if self.direction.is_some() == self.type_is_direction_sensitive(*id) {
1659 self.define_type(name, *id);
1660 }
1661 }
1662 }
1663
1664 fn type_record(&mut self, id: TypeId, name: &str, record: &Record, docs: &Docs) {
1665 let upper_name = name.to_upper_camel_case();
1666 let escaped_name = escape_d_identifier(&upper_name);
1667
1668 let owner_fqn = self
1669 .type_owner_fqn(&self.resolve.types[id].owner, false)
1670 .unwrap()
1671 .to_string();
1672
1673 self.src.push_str(&format!(
1674 "\n/++\n{}\n+/\n",
1675 docs.contents.as_deref().unwrap_or_default()
1676 ));
1677 self.src.push_str(&format!("struct {escaped_name} {{\n"));
1678
1679 let mut is_first = true;
1680 for field in &record.fields {
1681 let lower_name = field.name.to_lower_camel_case();
1682 let escaped_name = escape_d_identifier(&lower_name);
1683
1684 if is_first {
1685 is_first = false;
1686 } else {
1687 self.src.push_str("\n");
1688 }
1689
1690 self.src.push_str(&format!(
1691 "/++\n{}\n+/\n",
1692 field.docs.contents.as_deref().unwrap_or_default()
1693 ));
1694 self.src.push_str(&format!(
1695 "{} {escaped_name};\n",
1696 self.type_name(&field.ty, &owner_fqn)
1697 ));
1698 }
1699
1700 self.src.push_str("\nvoid witFree() @nogc nothrow {\n");
1701 for field in &record.fields {
1702 let lower_name = field.name.to_lower_camel_case();
1703 let escaped_name = escape_d_identifier(&lower_name);
1704
1705 if self.needs_wit_free(field.ty) {
1706 self.src.push_str(&format!("{escaped_name}.witFree;\n"));
1707 }
1708 }
1709 self.src.push_str("}\n");
1710
1711 self.src.push_str("\nvoid witDrop() @nogc nothrow {\n");
1712 for field in &record.fields {
1713 let lower_name = field.name.to_lower_camel_case();
1714 let escaped_name = escape_d_identifier(&lower_name);
1715
1716 if self.needs_wit_drop(field.ty) {
1717 self.src.push_str(&format!("{escaped_name}.witDrop;\n"));
1718 }
1719 }
1720 self.src.push_str("}\n");
1721
1722 if self.can_have_wit_clone(Type::Id(id)) {
1723 self.src.push_str(&format!(
1724 "\n{escaped_name} witClone() const @nogc nothrow {{\n"
1725 ));
1726 self.src
1727 .push_str(&format!("{escaped_name} clone = void;\n"));
1728 for field in &record.fields {
1729 let lower_name = field.name.to_lower_camel_case();
1730 let escaped_name = escape_d_identifier(&lower_name);
1731
1732 self.src.push_str(&format!(
1733 "clone.{escaped_name} = this.{escaped_name}.witClone;\n"
1734 ));
1735 }
1736 self.src.push_str("return clone;\n");
1737 self.src.push_str("}\n");
1738 }
1739
1740 self.src.push_str("}\n");
1741 }
1742
1743 fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs) {
1744 let upper_name = name.to_upper_camel_case();
1745 let escaped_name = escape_d_identifier(&upper_name);
1746
1747 let ty = &self.resolve.types[id];
1748
1749 match self.direction {
1750 None => panic!("Resources can only be generated for imports, or exports. Not common."),
1751 Some(Direction::Import) => {
1752 self.src.push_str(&format!(
1753 "\n/++\n{}\n+/\n",
1754 docs.contents.as_deref().unwrap_or_default()
1755 ));
1756
1757 self.src.push_str(&format!(
1758 "struct {escaped_name} {{
1759 package({}) uint __handle = 0;
1760
1761 package({0}) this(uint handle) @safe @nogc nothrow {{
1762 __handle = handle;
1763 }}
1764
1765 ",
1766 self.r#gen.root_pkg
1767 ));
1768
1769 match ty.owner {
1770 TypeOwner::Interface(owner_id) => {
1771 for (_, func) in &self.resolve.interfaces[owner_id].functions {
1772 if match &func.kind {
1773 FunctionKind::Freestanding => false,
1774 FunctionKind::Method(_) => false,
1775 FunctionKind::Static(mid) => *mid == id,
1776 FunctionKind::Constructor(mid) => *mid == id,
1777 FunctionKind::AsyncFreestanding => false,
1778 FunctionKind::AsyncMethod(_) => false,
1779 FunctionKind::AsyncStatic(_) => todo!(),
1780 } {
1781 self.import_func(func);
1782 }
1783 }
1784 }
1785 TypeOwner::World(owner_id) => {
1786 for (_, import) in &self.resolve.worlds[owner_id].imports {
1787 match &import {
1788 WorldItem::Function(func) => {
1789 if match &func.kind {
1790 FunctionKind::Freestanding => false,
1791 FunctionKind::Method(_) => false,
1792 FunctionKind::Static(mid) => *mid == id,
1793 FunctionKind::Constructor(mid) => *mid == id,
1794 FunctionKind::AsyncFreestanding => false,
1795 FunctionKind::AsyncMethod(_) => false,
1796 FunctionKind::AsyncStatic(_) => todo!(),
1797 } {
1798 self.import_func(func);
1799 }
1800 }
1801 _ => {}
1802 }
1803 }
1804 }
1805 TypeOwner::None => {
1806 panic!("Resource definition without owner?");
1807 }
1808 }
1809
1810 self.src.push_str(
1811 "\nvoid witDrop() @trusted @nogc nothrow {\nif (!__handle) return; __import_drop(__handle); __handle = 0;\n}\n",
1812 );
1813 self.src.push_str(&format!(
1814 "@wasmImport!(\"{}\", \"[resource-drop]{}\")\n",
1815 self.wasm_import_module.unwrap(),
1816 name
1817 ));
1818 self.src.push_str(&format!(
1819 "pragma(mangle, \"__wit_import_{}__:resource_drop:{}\")\n",
1820 self.wasm_import_module
1821 .unwrap()
1822 .replace("/", "__")
1823 .replace("-", "_"),
1824 name.replace("-", "_")
1825 ));
1826 self.src.push_str(
1827 "static private extern(C) void __import_drop(uint) @nogc nothrow;\n\n",
1828 );
1829 self.src.push_str("void witFree() @safe @nogc nothrow {}\n");
1830
1831 self.src.push_str("typeof(this) witClone() const @safe @nogc nothrow { return typeof(this)(__handle); }\n");
1832
1833 self.src.push_str(&format!(
1834 "// TODO: make RAII? disable copy for the own
1835
1836 Borrow borrow() => Borrow(__handle);
1837 alias borrow this;
1838
1839 struct Borrow {{
1840 package({}) uint __handle = 0;
1841
1842 package({0}) this(uint handle) @safe @nogc nothrow {{
1843 __handle = handle;
1844 }}
1845
1846 void witFree() @safe @nogc nothrow {{}}
1847 void witDrop() @trusted @nogc nothrow {{
1848 if (!__handle) return; __import_drop(__handle); __handle = 0;
1849 }}
1850 Borrow witClone() const @safe @nogc nothrow {{ return Borrow(__handle); }}
1851 ",
1852 self.r#gen.root_pkg
1853 ));
1854
1855 match ty.owner {
1856 TypeOwner::Interface(owner_id) => {
1857 for (_, func) in &self.resolve.interfaces[owner_id].functions {
1858 if match &func.kind {
1859 FunctionKind::Freestanding => false,
1860 FunctionKind::Method(mid) => *mid == id,
1861 FunctionKind::Static(_) => false,
1862 FunctionKind::Constructor(_) => false,
1863 FunctionKind::AsyncFreestanding => false,
1864 FunctionKind::AsyncMethod(_) => todo!(),
1865 FunctionKind::AsyncStatic(_) => false,
1866 } {
1867 self.import_func(func);
1868 }
1869 }
1870 }
1871 TypeOwner::World(owner_id) => {
1872 for (_, import) in &self.resolve.worlds[owner_id].imports {
1873 match &import {
1874 WorldItem::Function(func) => {
1875 if match &func.kind {
1876 FunctionKind::Freestanding => false,
1877 FunctionKind::Method(mid) => *mid == id,
1878 FunctionKind::Static(_) => false,
1879 FunctionKind::Constructor(_) => false,
1880 FunctionKind::AsyncFreestanding => false,
1881 FunctionKind::AsyncMethod(_) => todo!(),
1882 FunctionKind::AsyncStatic(_) => false,
1883 } {
1884 self.import_func(func);
1885 }
1886 }
1887 _ => {}
1888 }
1889 }
1890 }
1891 TypeOwner::None => {
1892 panic!("Resource definition without owner?");
1893 }
1894 }
1895 self.src.push_str("}\n");
1896 self.src.push_str("}\n");
1897 }
1898 Some(Direction::Export) => match ty.owner {
1899 TypeOwner::Interface(owner_id) => {
1900 if let Some(cur_interface) = self.interface
1901 && cur_interface == owner_id
1902 {
1903 } else {
1904 panic!("Emitting resource from `interface` outside that interface?");
1905 }
1906
1907 self.src.push_str(&format!(
1908 "\n/++\n{}\n+/\n",
1909 docs.contents.as_deref().unwrap_or_default()
1910 ));
1911
1912 self.src.push_str(&format!(
1913 "struct {escaped_name} {{
1914 package({}) uint __handle = 0;
1915
1916 package({0}) this(uint handle) @safe @nogc nothrow {{
1917 __handle = handle;
1918 }}
1919
1920",
1921 self.r#gen.root_pkg
1922 ));
1923
1924 self.src.push_str(&format!(
1925 "
1926 static {escaped_name} makeNew(T)(scope void delegate(out T) dg) if (is(T == struct)) {{
1927 if (dg is null) return {escaped_name}.init;
1928
1929 auto ptr = cast(T*)malloc(T.sizeof);
1930 if (ptr is null) return {escaped_name}.init;
1931
1932 dg(*ptr);
1933 return {escaped_name}(__import_makeNew(ptr));
1934 }}
1935 ",
1936 ));
1937 self.src.push_str(&format!(
1938 "@wasmImport!(\"[export]{}\", \"[resource-new]{}\")\n",
1939 self.wasm_import_module.unwrap(),
1940 name
1941 ));
1942 self.src.push_str(&format!(
1943 "pragma(mangle, \"__wit_import_:export:{}__:resource_new:{}\")\n",
1944 self.wasm_import_module
1945 .unwrap()
1946 .replace("/", "__")
1947 .replace("-", "_"),
1948 name.replace("-", "_")
1949 ));
1950 self.src
1951 .push_str("static private extern(C) uint __import_makeNew(void*);\n\n");
1952
1953 self.src
1954 .push_str("T* rep(T)() const @nogc nothrow if (is(T == struct)) {\nreturn cast(T*)__import_rep(__handle);\n}\n");
1955 self.src.push_str(&format!(
1956 "@wasmImport!(\"[export]{}\", \"[resource-rep]{}\")\n",
1957 self.wasm_import_module.unwrap(),
1958 name
1959 ));
1960 self.src.push_str(&format!(
1961 "pragma(mangle, \"__wit_import_:export:{}__:resource_rep:{}\")\n",
1962 self.wasm_import_module
1963 .unwrap()
1964 .replace("/", "__")
1965 .replace("-", "_"),
1966 name.replace("-", "_")
1967 ));
1968 self.src.push_str(
1969 "static private extern(C) void* __import_rep(uint) @nogc nothrow;\n\n",
1970 );
1971
1972 self.src.push_str(
1973 "void witDrop() @trusted @nogc nothrow {\nif (!__handle) return; __import_drop(__handle); __handle = 0;\n}\n",
1974 );
1975 self.src.push_str(&format!(
1976 "@wasmImport!(\"[export]{}\", \"[resource-drop]{}\")\n",
1977 self.wasm_import_module.unwrap(),
1978 name
1979 ));
1980 self.src.push_str(&format!(
1981 "pragma(mangle, \"__wit_import_:export:{}__:resource_drop:{}\")\n",
1982 self.wasm_import_module
1983 .unwrap()
1984 .replace("/", "__")
1985 .replace("-", "_"),
1986 name.replace("-", "_")
1987 ));
1988 self.src.push_str(
1989 "static private extern(C) void __import_drop(uint) @nogc nothrow;\n\n",
1990 );
1991 self.src.push_str("void witFree() @safe @nogc nothrow {}\n");
1992
1993 self.src.push_str("typeof(this) witClone() const @safe @nogc nothrow { return typeof(this)(__handle); }\n");
1994
1995 self.src.push_str(&format!(
1996 "// TODO: make RAII? disable copy for the own
1997 Borrow borrow() const @trusted @nogc nothrow => Borrow(__import_rep(__handle));
1998 //alias borrow this;
1999
2000 struct Borrow {{
2001 package({}) void* __handle = null;
2002
2003 package({0}) this(void* handle) @safe @nogc nothrow {{
2004 __handle = handle;
2005 }}
2006
2007 package({0}) this(uint handle) @safe @nogc nothrow {{
2008 __handle = cast(void*)handle;
2009 }}
2010
2011 void witFree() @safe @nogc nothrow {{}}
2012 void witDrop() @safe @nogc nothrow {{}}
2013 Borrow witClone() const @trusted @nogc nothrow {{ return Borrow(cast(void*)__handle); }}
2014
2015 ",
2016 self.r#gen.root_pkg
2017 ));
2018
2019 self.src
2020 .push_str("T* rep(T)() const @nogc nothrow if (is(T == struct)) {\nreturn cast(T*)__handle;\n}\n");
2021
2022 self.src.push_str("}\n");
2023
2024 self.src.push_str("}\n");
2025 }
2026 TypeOwner::World(_) => unimplemented!("resource exports in worlds"),
2027 TypeOwner::None => {
2028 panic!("Resource definition without owner?");
2029 }
2030 },
2031 }
2032 }
2033
2034 fn type_tuple(&mut self, id: TypeId, name: &str, tuple: &Tuple, docs: &Docs) {
2035 let upper_name = name.to_upper_camel_case();
2036 let escaped_name = escape_d_identifier(&upper_name);
2037
2038 self.src.push_str(&format!(
2039 "\n/++\n{}\n+/\n",
2040 docs.contents.as_deref().unwrap_or_default()
2041 ));
2042
2043 let owner_fqn = self
2044 .type_owner_fqn(&self.resolve.types[id].owner, false)
2045 .unwrap();
2046 self.src.push_str(&format!(
2047 "alias {escaped_name} = Tuple!({});",
2048 tuple
2049 .types
2050 .iter()
2051 .map(|ty| self.type_name(ty, owner_fqn).into_owned())
2052 .collect::<Vec<String>>()
2053 .join(", ")
2054 ));
2055 }
2056
2057 fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
2058 let upper_name = name.to_upper_camel_case();
2059 let escaped_name = escape_d_identifier(&upper_name);
2060
2061 let storage_type = match flags.repr() {
2062 FlagsRepr::U8 => "ubyte",
2063 FlagsRepr::U16 => "ushort",
2064 FlagsRepr::U32(1) => "uint",
2065 FlagsRepr::U32(2) => "ulong",
2066 repr => todo!("flags {repr:?}"),
2067 };
2068
2069 self.src.push_str(&format!(
2070 "\n/++\n{}\n+/\n",
2071 docs.contents.as_deref().unwrap_or_default()
2072 ));
2073 self.src.push_str(&format!("struct {escaped_name} {{\n"));
2074
2075 self.src
2076 .push_str(&format!("mixin WitFlags!{storage_type};\n\n"));
2077
2078 for (index, flag) in flags.flags.iter().enumerate() {
2079 if index != 0 {
2080 self.src.push_str("\n");
2081 }
2082 self.src.push_str(&format!(
2083 "/++\n{}\n+/\n",
2084 flag.docs.contents.as_deref().unwrap_or_default()
2085 ));
2086 self.src.push_str(&format!(
2087 "enum {} = {escaped_name}[{index}];\n",
2088 escape_d_identifier(&flag.name.to_lower_camel_case())
2089 ));
2090 }
2091 self.src.push_str(&format!("}}\n"));
2092 }
2093
2094 fn type_variant(&mut self, id: TypeId, name: &str, variant: &Variant, docs: &Docs) {
2095 let upper_name = name.to_upper_camel_case();
2096 let escaped_name = escape_d_identifier(&upper_name);
2097
2098 let storage_type = match variant.tag() {
2099 Int::U8 => "ubyte",
2100 Int::U16 => "ushort",
2101 Int::U32 => "uint",
2102 Int::U64 => "ulong",
2103 };
2104
2105 let owner_fqn = self
2106 .type_owner_fqn(&self.resolve.types[id].owner, false)
2107 .unwrap()
2108 .to_string();
2109
2110 self.src.push_str(&format!(
2111 "\n/++\n{}\n+/\n",
2112 docs.contents.as_deref().unwrap_or_default()
2113 ));
2114 self.src.push_str(&format!("struct {escaped_name} {{\n"));
2115
2116 self.src.push_str("mixin WitVariant!(\n");
2117 self.src.indent(1);
2118
2119 for case in &variant.cases {
2120 self.src.push_str(&format!(
2121 "{}, // {}\n",
2122 self.optional_type_name(case.ty.as_ref(), &owner_fqn),
2123 escape_d_identifier(&case.name.to_lower_camel_case())
2124 ));
2125 }
2126
2127 self.src.deindent(1);
2128 self.src.push_str(");\n");
2129
2130 self.src.deindent(1);
2131 self.src.indent(1);
2133
2134 self.src.deindent(1);
2135 self.src.push_str("\npublic:\n");
2136 self.src.indent(1);
2137
2138 self.src
2139 .push_str(&format!("enum Tag : {storage_type} {{\n"));
2140
2141 let mut is_first = true;
2142 for case in &variant.cases {
2143 if is_first {
2144 is_first = false;
2145 } else {
2146 self.src.push_str("\n");
2147 }
2148 self.src.push_str(&format!(
2149 "/++\n{}\n+/\n",
2150 case.docs.contents.as_deref().unwrap_or_default()
2151 ));
2152 self.src.push_str(&format!(
2153 "{},\n",
2154 escape_d_identifier(&case.name.to_lower_camel_case())
2155 ));
2156 }
2157
2158 self.src.push_str("}\n");
2159
2160 self.src
2161 .push_str("Tag tag() const @safe @nogc nothrow pure => _tag;\n");
2162
2163 for case in &variant.cases {
2164 self.src.push_str(&format!(
2165 "\n/++\n{}\n+/\n",
2166 case.docs.contents.as_deref().unwrap_or_default()
2167 ));
2168 let upper_case_name = case.name.to_upper_camel_case();
2169 let escaped_upper_case_name = escape_d_identifier(&upper_case_name);
2170
2171 let lower_case_name = case.name.to_lower_camel_case();
2172 let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2173
2174 self.src.push_str(&format!(
2175 "alias {escaped_lower_case_name} = _create!(Tag.{escaped_lower_case_name});\n",
2176 ));
2177 self.src.push_str(&format!(
2178 "/// ditto\nbool is{escaped_upper_case_name}() const => _tag == Tag.{escaped_lower_case_name};\n",
2179 ));
2180
2181 if case.ty.is_some() {
2182 self.src.push_str(&format!(
2183 "///ditto\nalias get{escaped_upper_case_name} = _get!(Tag.{escaped_lower_case_name});\n",
2184 ));
2185 }
2186 }
2187
2188 self.src.push_str("\nvoid witFree() @nogc nothrow {\n");
2189 if self.needs_wit_free(Type::Id(id)) {
2190 self.src.push_str("switch (_tag) with (Tag) {\n");
2191 for case in &variant.cases {
2192 let lower_case_name = case.name.to_lower_camel_case();
2193 let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2194
2195 if case.ty.is_some() && self.needs_wit_free(case.ty.unwrap()) {
2196 self.src.push_str(&format!(
2197 "case {escaped_lower_case_name}: _get!(Tag.{escaped_lower_case_name}).witFree; break;\n",
2198 ));
2199 }
2200 }
2201 self.src.push_str("default: break;\n");
2202 self.src.push_str("}\n");
2203 }
2204 self.src.push_str("}\n");
2205
2206 self.src.push_str("\nvoid witDrop() @nogc nothrow {\n");
2207 if self.needs_wit_drop(Type::Id(id)) {
2208 self.src.push_str("switch (_tag) with (Tag) {\n");
2209 for case in &variant.cases {
2210 let lower_case_name = case.name.to_lower_camel_case();
2211 let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2212
2213 if case.ty.is_some() && self.needs_wit_drop(case.ty.unwrap()) {
2214 self.src.push_str(&format!(
2215 "case {escaped_lower_case_name}: _get!(Tag.{escaped_lower_case_name}).witDrop; break;\n",
2216 ));
2217 }
2218 }
2219 self.src.push_str("default: break;\n");
2220 self.src.push_str("}\n");
2221 }
2222 self.src.push_str("}\n");
2223
2224 if self.can_have_wit_clone(Type::Id(id)) {
2225 self.src.push_str(&format!(
2226 "\n{escaped_name} witClone() const @nogc nothrow {{\n"
2227 ));
2228 self.src.push_str("final switch (_tag) {\n");
2229 for case in &variant.cases {
2230 let lower_case_name = case.name.to_lower_camel_case();
2231 let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2232
2233 if case.ty.is_some() {
2234 self.src.push_str(&format!(
2235 "case Tag.{escaped_lower_case_name}: return _create!(Tag.{escaped_lower_case_name})(this._get!(Tag.{escaped_lower_case_name}).witClone); break;\n",
2236 ));
2237 } else {
2238 self.src.push_str(&format!(
2239 "case Tag.{escaped_lower_case_name}: return _create!(Tag.{escaped_lower_case_name}); break;\n",
2240 ));
2241 }
2242 }
2243 self.src.push_str("}\n");
2244 self.src.push_str("}\n");
2245 }
2246
2247 self.src.push_str("}\n");
2248 }
2249
2250 fn type_option(&mut self, id: TypeId, name: &str, payload: &Type, docs: &Docs) {
2251 let upper_name = name.to_upper_camel_case();
2252 let escaped_name = escape_d_identifier(&upper_name);
2253
2254 self.src.push_str(&format!(
2255 "\n/++\n{}\n+/\n",
2256 docs.contents.as_deref().unwrap_or_default()
2257 ));
2258
2259 let owner_fqn = self
2260 .type_owner_fqn(&self.resolve.types[id].owner, false)
2261 .unwrap();
2262 self.src.push_str(&format!(
2263 "alias {escaped_name} = Option!({});",
2264 self.type_name(payload, owner_fqn)
2265 ));
2266 }
2267
2268 fn type_result(&mut self, id: TypeId, name: &str, result: &Result_, docs: &Docs) {
2269 let upper_name = name.to_upper_camel_case();
2270 let escaped_name = escape_d_identifier(&upper_name);
2271
2272 self.src.push_str(&format!(
2273 "\n/++\n{}\n+/\n",
2274 docs.contents.as_deref().unwrap_or_default()
2275 ));
2276
2277 let owner_fqn = self
2278 .type_owner_fqn(&self.resolve.types[id].owner, false)
2279 .unwrap();
2280 self.src.push_str(&format!(
2281 "alias {escaped_name} = Result!({}, {});",
2282 self.optional_type_name(result.ok.as_ref(), owner_fqn),
2283 self.optional_type_name(result.err.as_ref(), owner_fqn),
2284 ));
2285 }
2286
2287 fn type_enum(&mut self, _id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
2288 let upper_name = name.to_upper_camel_case();
2289 let escaped_name = escape_d_identifier(&upper_name);
2290
2291 let storage_type = match enum_.tag() {
2292 Int::U8 => "ubyte",
2293 Int::U16 => "ushort",
2294 Int::U32 => "uint",
2295 Int::U64 => "ulong",
2296 };
2297
2298 self.src.push_str(&format!(
2299 "\n/++\n{}\n+/\n",
2300 docs.contents.as_deref().unwrap_or_default()
2301 ));
2302 self.src
2303 .push_str(&format!("enum {escaped_name} : {storage_type} {{\n"));
2304
2305 let mut is_first = true;
2306 for case in &enum_.cases {
2307 if is_first {
2308 is_first = false;
2309 } else {
2310 self.src.push_str("\n");
2311 }
2312 self.src.push_str(&format!(
2313 "/++\n{}\n+/\n",
2314 case.docs.contents.as_deref().unwrap_or_default()
2315 ));
2316 self.src.push_str(&format!(
2317 "{},\n",
2318 escape_d_identifier(&case.name.to_lower_camel_case())
2319 ));
2320 }
2321
2322 self.src.push_str("}");
2323 }
2324
2325 fn type_alias(&mut self, id: TypeId, name: &str, alias_ty: &Type, docs: &Docs) {
2326 let upper_name = name.to_upper_camel_case();
2327 let escaped_name = escape_d_identifier(&upper_name);
2328
2329 self.src.push_str(&format!(
2330 "\n/++\n{}\n+/\n",
2331 docs.contents.as_deref().unwrap_or_default()
2332 ));
2333
2334 let typename = self.type_name(
2335 alias_ty,
2336 self.type_owner_fqn(&self.resolve.types[id].owner, false)
2337 .unwrap(),
2338 );
2339
2340 self.src
2341 .push_str(&format!("alias {escaped_name} = {typename};\n"));
2342 }
2343
2344 fn type_list(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
2345 let upper_name = name.to_upper_camel_case();
2346 let escaped_name = escape_d_identifier(&upper_name);
2347
2348 self.src.push_str(&format!(
2349 "\n/++\n{}\n+/\n",
2350 docs.contents.as_deref().unwrap_or_default()
2351 ));
2352
2353 let owner_fqn = self
2354 .type_owner_fqn(&self.resolve.types[id].owner, false)
2355 .unwrap();
2356 self.src.push_str(&format!(
2357 "alias {escaped_name} = WitList!({});",
2358 self.type_name(ty, owner_fqn)
2359 ));
2360 }
2361
2362 fn type_fixed_length_list(
2363 &mut self,
2364 id: TypeId,
2365 name: &str,
2366 ty: &Type,
2367 size: u32,
2368 docs: &Docs,
2369 ) {
2370 let upper_name = name.to_upper_camel_case();
2371 let escaped_name = escape_d_identifier(&upper_name);
2372
2373 self.src.push_str(&format!(
2374 "\n/++\n{}\n+/\n",
2375 docs.contents.as_deref().unwrap_or_default()
2376 ));
2377
2378 let owner_fqn = self
2379 .type_owner_fqn(&self.resolve.types[id].owner, false)
2380 .unwrap();
2381 self.src.push_str(&format!(
2382 "alias {escaped_name} = {}[{size}];",
2383 self.type_name(ty, owner_fqn)
2384 ));
2385 }
2386
2387 fn type_map(&mut self, _id: TypeId, name: &str, _key: &Type, _value: &Type, _docs: &Docs) {
2388 todo!("def of `map` - {name}");
2389 }
2390
2391 fn type_future(&mut self, _id: TypeId, name: &str, _ty: &Option<Type>, _docs: &Docs) {
2392 todo!("def of `future` - {name}");
2393 }
2394
2395 fn type_stream(&mut self, _id: TypeId, name: &str, _ty: &Option<Type>, _docs: &Docs) {
2396 todo!("def of `stream` - {name}");
2397 }
2398
2399 fn type_builtin(&mut self, _id: TypeId, name: &str, _ty: &Type, _docs: &Docs) {
2400 todo!("def of `builtin` - {name}");
2401 }
2402}
2403
2404struct Block {
2405 body: String,
2406 results: Vec<String>,
2407 element: String,
2408 base: String,
2409}
2410
2411struct BlockStorage {
2412 body: Source,
2413 element: String,
2414 base: String,
2415}
2416
2417struct FunctionBindgen<'a, 'b> {
2418 r#gen: &'b mut DInterfaceGenerator<'a>,
2419 params: &'b [&'b str],
2420 tmp: usize,
2421 src: Source,
2422 block_storage: Vec<BlockStorage>,
2423 blocks: Vec<Block>,
2425 payloads: Vec<String>,
2426 return_pointer_area_size: ArchitectureSize,
2427 return_pointer_area_align: Alignment,
2428 needs_deallocate: bool,
2429}
2430
2431fn tempname(base: &str, idx: usize) -> String {
2432 format!("{base}{idx}")
2433}
2434
2435impl<'a, 'b> FunctionBindgen<'a, 'b> {
2436 fn new(r#gen: &'b mut DInterfaceGenerator<'a>, params: &'b [&'b str]) -> Self {
2437 Self {
2438 r#gen,
2439 params,
2440 tmp: 0,
2441 src: Default::default(),
2442 block_storage: Default::default(),
2443 blocks: Default::default(),
2444 payloads: Default::default(),
2445 return_pointer_area_size: Default::default(),
2446 return_pointer_area_align: Default::default(),
2447 needs_deallocate: false,
2448 }
2449 }
2450
2451 fn tmp(&mut self) -> usize {
2452 let ret = self.tmp;
2453 self.tmp += 1;
2454 ret
2455 }
2456
2457 fn push_str(&mut self, s: &str) {
2458 self.src.push_str(s);
2459 }
2460
2461 fn load(
2462 &mut self,
2463 ty: &str,
2464 offset: ArchitectureSize,
2465 operands: &[String],
2466 results: &mut Vec<String>,
2467 ) {
2468 results.push(format!(
2469 "*(cast({}*)({} + {}))",
2470 ty,
2471 operands[0],
2472 offset.format("size_t.sizeof")
2473 ));
2474 }
2475
2476 fn load_ext(
2477 &mut self,
2478 ty: &str,
2479 offset: ArchitectureSize,
2480 operands: &[String],
2481 results: &mut Vec<String>,
2482 ) {
2483 self.load(ty, offset, operands, results);
2484 let result = results.pop().unwrap();
2485 results.push(format!("cast(uint)({result})"));
2486 }
2487
2488 fn store(&mut self, ty: &str, offset: ArchitectureSize, operands: &[String]) {
2489 self.push_str(&format!(
2490 "*cast({ty}*)({} + {}) = cast({ty})({});\n",
2491 operands[1],
2492 offset.format("size_t.sizeof"),
2493 operands[0]
2494 ));
2495 }
2496
2497 fn emit_ret_area_if_needed(&self) -> String {
2510 if !self.return_pointer_area_size.is_empty() {
2511 match self.r#gen.direction {
2512 Some(Direction::Import) => format!(
2513 "align({}) void[{}] _retArea = void;\n",
2514 self.return_pointer_area_align.format("size_t.sizeof"),
2515 self.return_pointer_area_size.format("size_t.sizeof")
2516 ),
2517 Some(Direction::Export) => "alias _retArea = _exportsRetArea;\n".to_string(),
2518 None => {
2519 unreachable!();
2520 }
2521 }
2522 } else {
2523 String::new()
2524 }
2525 }
2526}
2527
2528fn perform_cast(op: &str, cast: &Bitcast) -> String {
2529 match cast {
2530 Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
2531 format!("(cast(uint){op}).reinterpretCast!float")
2532 }
2533 Bitcast::F32ToI32 | Bitcast::F32ToI64 => {
2534 format!("({op}).reinterpretCast!uint")
2535 }
2536 Bitcast::I64ToF64 => {
2537 format!("({op}).reinterpretCast!double")
2538 }
2539 Bitcast::F64ToI64 => {
2540 format!("({op}).reinterpretCast!ulong")
2541 }
2542 Bitcast::I32ToI64 | Bitcast::LToI64 | Bitcast::PToP64 => {
2543 format!("cast(ulong)({op})")
2544 }
2545 Bitcast::I64ToI32 | Bitcast::PToI32 | Bitcast::LToI32 => {
2546 format!("cast(uint)({op})")
2547 }
2548 Bitcast::P64ToI64 | Bitcast::None | Bitcast::I64ToP64 => op.to_string(),
2549 Bitcast::P64ToP | Bitcast::I32ToP | Bitcast::LToP => {
2550 format!("cast(void*)({op})")
2551 }
2552 Bitcast::PToL | Bitcast::I32ToL | Bitcast::I64ToL => {
2553 format!("cast(size_t)({op})")
2554 }
2555 Bitcast::Sequence(sequence) => {
2556 let [first, second] = &**sequence;
2557 let inner = perform_cast(op, first);
2558 perform_cast(&inner, second)
2559 }
2560 }
2561}
2562
2563impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2564 type Operand = String;
2565
2566 fn emit(
2567 &mut self,
2568 _resolve: &Resolve,
2569 inst: &wit_bindgen_core::abi::Instruction<'_>,
2570 operands: &mut Vec<Self::Operand>,
2571 results: &mut Vec<Self::Operand>,
2572 ) {
2573 let mut top_as = |cvt: &str| {
2574 results.push(format!("cast({cvt})({})", operands.pop().unwrap()));
2575 };
2576
2577 match inst {
2578 abi::Instruction::GetArg { nth } => {
2579 if *nth == 0 && &self.params[0] == &"self" {
2580 results.push("this".into());
2581 } else {
2582 results.push(self.params[*nth].into());
2583 }
2584 }
2585
2586 abi::Instruction::I32Const { val } => results.push(val.to_string()),
2587 abi::Instruction::Bitcasts { casts } => {
2588 for (cast, op) in casts.iter().zip(operands) {
2589 let op = perform_cast(op, cast);
2590 results.push(op);
2591 }
2592 }
2593 abi::Instruction::ConstZero { tys } => {
2594 for ty in tys.iter() {
2595 results.push(
2596 match ty {
2597 WasmType::Pointer => "null",
2598 _ => "0",
2599 }
2600 .to_string(),
2601 );
2602 }
2603 }
2604
2605 abi::Instruction::I32Load { offset } => self.load("uint", *offset, operands, results),
2606 abi::Instruction::I32Load8U { offset } => {
2607 self.load_ext("ubyte", *offset, operands, results)
2608 }
2609 abi::Instruction::I32Load8S { offset } => {
2610 self.load_ext("byte", *offset, operands, results)
2611 }
2612 abi::Instruction::I32Load16U { offset } => {
2613 self.load_ext("ushort", *offset, operands, results)
2614 }
2615 abi::Instruction::I32Load16S { offset } => {
2616 self.load_ext("short", *offset, operands, results)
2617 }
2618 abi::Instruction::I64Load { offset } => self.load("ulong", *offset, operands, results),
2619 abi::Instruction::F32Load { offset } => self.load("float", *offset, operands, results),
2620 abi::Instruction::F64Load { offset } => self.load("double", *offset, operands, results),
2621
2622 abi::Instruction::PointerLoad { offset } => {
2623 self.load("void*", *offset, operands, results)
2624 }
2625 abi::Instruction::LengthLoad { offset } => {
2626 self.load("size_t", *offset, operands, results)
2627 }
2628
2629 abi::Instruction::I32Store { offset } => self.store("uint", *offset, operands),
2630 abi::Instruction::I32Store8 { offset } => self.store("ubyte", *offset, operands),
2631 abi::Instruction::I32Store16 { offset } => self.store("ushort", *offset, operands),
2632
2633 abi::Instruction::I64Store { offset } => self.store("ulong", *offset, operands),
2634 abi::Instruction::F32Store { offset } => self.store("float", *offset, operands),
2635 abi::Instruction::F64Store { offset } => self.store("double", *offset, operands),
2636
2637 abi::Instruction::PointerStore { offset } => self.store("void*", *offset, operands),
2638 abi::Instruction::LengthStore { offset } => self.store("size_t", *offset, operands),
2639
2640 abi::Instruction::I32FromChar
2641 | abi::Instruction::I32FromBool
2642 | abi::Instruction::I32FromU8
2643 | abi::Instruction::I32FromS8
2644 | abi::Instruction::I32FromU16
2645 | abi::Instruction::I32FromS16
2646 | abi::Instruction::I32FromS32 => top_as("uint"),
2647 abi::Instruction::I32FromU32 => results.push(operands.pop().unwrap()),
2648
2649 abi::Instruction::I64FromU64 => results.push(operands.pop().unwrap()),
2650 abi::Instruction::I64FromS64 => top_as("ulong"),
2651 abi::Instruction::CoreF32FromF32 => results.push(operands.pop().unwrap()),
2652 abi::Instruction::CoreF64FromF64 => results.push(operands.pop().unwrap()),
2653
2654 abi::Instruction::S8FromI32 => top_as("byte"),
2655 abi::Instruction::U8FromI32 => top_as("ubyte"),
2656 abi::Instruction::S16FromI32 => top_as("short"),
2657 abi::Instruction::U16FromI32 => top_as("ushort"),
2658 abi::Instruction::S32FromI32 => top_as("int"),
2659 abi::Instruction::U32FromI32 => results.push(operands.pop().unwrap()),
2660 abi::Instruction::S64FromI64 => top_as("long"),
2661 abi::Instruction::U64FromI64 => results.push(operands.pop().unwrap()),
2662 abi::Instruction::CharFromI32 => top_as("dchar"),
2663 abi::Instruction::F32FromCoreF32 => results.push(operands.pop().unwrap()),
2664 abi::Instruction::F64FromCoreF64 => results.push(operands.pop().unwrap()),
2665 abi::Instruction::BoolFromI32 => results.push(format!("({}) != 0", operands[0])),
2666
2667 abi::Instruction::ListCanonLower { .. } | abi::Instruction::StringLower { .. } => {
2668 results.push(format!("cast(void*)({}.ptr)", operands[0]));
2669 results.push(format!("{}.length", operands[0]));
2670 }
2671 abi::Instruction::ListLower { element, .. } => {
2672 let Block {
2673 body,
2674 element: block_element,
2675 base,
2676 ..
2677 } = self.blocks.pop().unwrap();
2678 let tmp = self.tmp();
2679
2680 let size = self.r#gen.sizes.size(element);
2681 let size_str = size.format("size_t.sizeof");
2682
2683 let list = tempname("_list", tmp);
2684 let list_src = tempname("_listSrc", tmp);
2685
2686 self.push_str(&format!(
2687 "auto {list_src} = {};
2688 auto {list} = {list_src}.length ? {}.malloc({list_src}.length * ({size_str})) : null;
2689 assert(!{list_src}.length || {list});\n",
2690 operands[0], self.r#gen.r#gen.common_module
2691 ));
2692
2693 if matches!(self.r#gen.direction, Some(Direction::Import)) {
2694 self.needs_deallocate = true;
2695 self.push_str(&format!("if ({list_src}.length) deallocate ~= {list};\n"));
2696 }
2697
2698 self.push_str(&format!(
2699 "foreach ({block_element}_idx, ref {block_element}; {list_src}) {{\n"
2700 ));
2701 self.push_str(&format!(
2702 "auto {base} = {list} + {block_element}_idx * ({size_str});\n"
2703 ));
2704 self.push_str(&body);
2705 self.push_str("\n}\n");
2707
2708 if !matches!(self.r#gen.direction, Some(Direction::Import)) {
2709 self.push_str(&format!(
2710 "if ({list_src}.length) {}.free({list_src}.ptr);\n",
2711 self.r#gen.r#gen.common_module
2712 ));
2713 }
2714
2715 results.push(format!("{list}"));
2716 results.push(format!("{}.length", operands[0]));
2717 }
2718
2719 abi::Instruction::ListCanonLift { element, ty, .. } => {
2720 let list_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
2721 let elem_name = self.r#gen.type_name(element, self.r#gen.fqn);
2722 let tmp = self.tmp();
2723
2724 let ptr = tempname("_ptr", tmp);
2725 let len = tempname("_len", tmp);
2726
2727 self.push_str(&format!(
2728 "auto {len} = {};
2729 auto {ptr} = {len} ? cast({elem_name}*)({}) : null;
2730 ",
2731 operands[1], operands[0]
2732 ));
2733
2734 if matches!(self.r#gen.direction, Some(Direction::Export)) {
2735 self.needs_deallocate = true;
2736 self.push_str(&format!("if ({len}) deallocate ~= cast(){ptr};\n"));
2737 }
2738
2739 let result = format!("{list_name}({ptr}[0..{len}])");
2740
2741 let tmpvar = tempname("_list", self.tmp());
2742 self.push_str(&format!("auto {tmpvar} = {result};\n"));
2743 results.push(tmpvar);
2744 }
2745 abi::Instruction::StringLift => {
2746 let tmp = self.tmp();
2747
2748 let ptr = tempname("_ptr", tmp);
2749 let len = tempname("_len", tmp);
2750
2751 self.push_str(&format!(
2752 "auto {len} = {};
2753 auto {ptr} = {len} ? cast(char*)({}) : null;
2754 ",
2755 operands[1], operands[0]
2756 ));
2757
2758 if matches!(self.r#gen.direction, Some(Direction::Export)) {
2759 self.needs_deallocate = true;
2760 self.push_str(&format!("if ({len}) deallocate ~= cast(){ptr};\n"));
2761 }
2762
2763 let result = format!("WitString({ptr}[0..{len}])");
2764
2765 let tmpvar = tempname("_list", self.tmp());
2766 self.push_str(&format!("auto {tmpvar} = {result};\n"));
2767 results.push(tmpvar);
2768 }
2769 abi::Instruction::ListLift { ty, element, .. } => {
2770 let Block {
2771 body,
2772 results: block_results,
2773 element: block_element,
2774 base,
2775 } = self.blocks.pop().unwrap();
2776 let tmp = self.tmp();
2777 let size = self.r#gen.sizes.size(element);
2778 let size_str = size.format("size_t.sizeof");
2779 let elem_type_name = self.r#gen.type_name(element, self.r#gen.fqn);
2780
2781 let list = tempname("_list", tmp);
2782 let list_len = tempname("_listLen", tmp);
2783 let list_src = tempname("_listSrcPtr", tmp);
2784 self.push_str(&format!("auto {list_src} = {};\n", operands[0]));
2785 self.push_str(&format!("auto {list_len} = {};\n", operands[1]));
2786 self.push_str(&format!(
2787 "auto {list} = {list_len} ? {}.mallocSlice!({elem_type_name})({list_len}) : [];
2788 assert(!{list_len} || {list}.ptr);\n",
2789 self.r#gen.r#gen.common_module
2790 ));
2791
2792 if matches!(self.r#gen.direction, Some(Direction::Export)) {
2793 self.needs_deallocate = true;
2794 self.push_str(&format!(
2795 "if ({list_len}) deallocate ~= cast(void*){list}.ptr;\n"
2796 ));
2797 }
2798
2799 self.push_str(&format!(
2800 "foreach ({block_element}_idx, ref {block_element}; {list}) {{\n",
2801 ));
2802 self.push_str(&format!(
2803 "const auto {base} = {list_src} + {block_element}_idx * {size_str};\n"
2804 ));
2805 self.push_str(&body);
2806 self.push_str(&format!("{block_element} = {};", block_results[0]));
2807 self.push_str("\n}\n");
2808
2809 if matches!(self.r#gen.direction, Some(Direction::Import)) {
2810 self.push_str(&format!(
2811 "if ({list_len}) {}.free({list_src});\n",
2812 self.r#gen.r#gen.common_module
2813 ));
2814 } else {
2815 self.needs_deallocate = true;
2816 self.push_str(&format!("if ({list_len}) deallocate ~= {list_src};\n"));
2817 }
2818
2819 let list_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
2820 let result = format!("{list_name}({list})");
2821
2822 let tmpvar = tempname("_witList", self.tmp());
2823 self.push_str(&format!("auto {tmpvar} = {result};\n"));
2824 results.push(tmpvar);
2825 }
2826
2827 abi::Instruction::FixedLengthListLift { size, id, .. } => {
2828 let result = tempname("_arr", self.tmp());
2829 let type_name = self.r#gen.type_name(&Type::Id(*id), self.r#gen.fqn);
2830 self.push_str(&format!("{type_name} {result} = [\n",));
2831 self.src.indent(1);
2832 for op in operands.drain(0..(*size as usize)) {
2833 self.push_str(&op);
2834 self.push_str(", \n");
2835 }
2836 self.src.deindent(1);
2837 self.push_str("];\n");
2838 results.push(result);
2839 }
2840 abi::Instruction::FixedLengthListLower { size, .. } => {
2841 for i in 0..(*size as usize) {
2842 results.push(format!("{}[{i}]", operands[0]));
2843 }
2844 }
2845 abi::Instruction::FixedLengthListLowerToMemory { element, .. } => {
2846 let Block {
2847 body,
2848 results: _,
2849 element: block_element,
2850 base,
2851 } = self.blocks.pop().unwrap();
2852 let arr_src = &operands[0];
2853 let arr_dst = &operands[1];
2854 let size_str = self.r#gen.sizes.size(element).format("size_t.sizeof");
2855
2856 self.push_str(&format!(
2857 "foreach ({block_element}_idx, ref {block_element}; {arr_src}) {{\n"
2858 ));
2859 self.push_str(&format!(
2860 "const auto {base} = {arr_dst} + {block_element}_idx * {size_str};\n"
2861 ));
2862 self.push_str(&body);
2863 self.push_str("\n}\n");
2864 }
2865 abi::Instruction::FixedLengthListLiftFromMemory { id, element, .. } => {
2866 let Block {
2867 body,
2868 results: block_results,
2869 element: block_element,
2870 base,
2871 } = self.blocks.pop().unwrap();
2872 let arr_src = &operands[0];
2873 let type_name = self.r#gen.type_name(&Type::Id(*id), self.r#gen.fqn);
2874 let size_str = self.r#gen.sizes.size(element).format("size_t.sizeof");
2875
2876 let result = tempname("_arr", self.tmp());
2877 self.push_str(&format!("{type_name} {result} = void;\n"));
2878
2879 self.push_str(&format!(
2880 "foreach ({block_element}_idx, ref {block_element}; {result}) {{\n"
2881 ));
2882 self.push_str(&format!(
2883 "const auto {base} = {arr_src} + {block_element}_idx * {size_str};\n"
2884 ));
2885 self.push_str(&body);
2886 self.push_str(&format!("{block_element} = {};", block_results[0]));
2887 self.push_str("\n}\n");
2888
2889 results.push(result);
2890 }
2891
2892 abi::Instruction::IterElem { .. } => {
2893 results.push(self.block_storage.last().unwrap().element.clone())
2894 }
2895 abi::Instruction::IterBasePointer => {
2896 results.push(self.block_storage.last().unwrap().base.clone())
2897 }
2898
2899 abi::Instruction::RecordLower { record, .. } => {
2900 for field in record.fields.iter() {
2901 let lower_name = field.name.to_lower_camel_case();
2902 let escaped_name = escape_d_identifier(&lower_name);
2903
2904 results.push(format!("{}.{escaped_name}", operands[0]));
2905 }
2906 }
2907 abi::Instruction::RecordLift { ty, record, .. } => {
2908 let name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
2909
2910 let tmpvar = tempname("_record", self.tmp());
2911
2912 self.push_str(&format!("{name} {tmpvar} = {{\n"));
2913 for (field, op) in record.fields.iter().zip(operands.iter()) {
2914 let lower_name = field.name.to_lower_camel_case();
2915 let escaped_name = escape_d_identifier(&lower_name);
2916
2917 self.push_str(&format!("{escaped_name}: {op},\n"));
2918 }
2919 self.push_str("};\n");
2920
2921 results.push(tmpvar);
2922 }
2923
2924 abi::Instruction::HandleLower { .. } => {
2925 let op = &operands[0];
2926 results.push(format!("{op}.__handle"))
2927 }
2928 abi::Instruction::HandleLift { ty, .. } => {
2929 let name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
2930 let result = format!("{name}({})", operands[0]);
2931
2932 if matches!(self.r#gen.direction, Some(Direction::Export)) && operands[0] == "this"
2933 {
2934 results.push(result);
2935 } else {
2936 let tmpvar = tempname("_handle", self.tmp());
2937 self.push_str(&format!("auto {tmpvar} = {result};\n"));
2938 results.push(tmpvar);
2939 }
2940 }
2941
2942 abi::Instruction::TupleLower { tuple, .. } => {
2943 for i in 0..tuple.types.len() {
2944 results.push(format!("{}[{i}]", &operands[0]));
2945 }
2946 }
2947 abi::Instruction::TupleLift { ty, .. } => {
2948 let name = tempname("_tuple", self.tmp());
2949 self.push_str(&format!(
2950 "auto {name} = {}(\n",
2951 self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn),
2952 ));
2953 self.src.indent(1);
2954 for op in operands.iter() {
2955 self.push_str(op);
2956 self.push_str(",\n");
2957 }
2958 self.src.deindent(1);
2959 self.push_str(");\n");
2960 results.push(name);
2961 }
2962
2963 abi::Instruction::FlagsLower { flags, .. } => match flags.repr() {
2964 FlagsRepr::U8 | FlagsRepr::U16 | FlagsRepr::U32(1) => {
2965 results.push(format!("cast(uint)({}.bits)", operands.pop().unwrap()));
2966 }
2967 FlagsRepr::U32(2) => {
2968 let tempname = tempname("_flags", self.tmp());
2969
2970 self.push_str(&format!("auto {tempname} = {};", operands[0]));
2971 results.push(format!("cast(uint)({tempname}.bits & 0xffffffff)"));
2972 results.push(format!("cast(uint)(({tempname}.bits >> 32) & 0xffffffff)"));
2973 }
2974 _ => todo!(),
2975 },
2976 abi::Instruction::FlagsLift { flags, ty, .. } => {
2977 let type_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
2978
2979 match flags.repr() {
2980 FlagsRepr::U8 => {
2981 results.push(format!(
2982 "{type_name}(cast(ubyte)({}))",
2983 operands.pop().unwrap()
2984 ));
2985 }
2986 FlagsRepr::U16 => {
2987 results.push(format!(
2988 "{type_name}(cast(ushort)({}))",
2989 operands.pop().unwrap()
2990 ));
2991 }
2992 FlagsRepr::U32(1) => {
2993 results.push(format!("{type_name}({})", operands.pop().unwrap()));
2994 }
2995 FlagsRepr::U32(2) => {
2996 results.push(format!(
2997 "({type_name}({}) | {type_name}({} << 32))",
2998 operands[0], operands[1]
2999 ));
3000 }
3001 _ => todo!(),
3002 }
3003 }
3004
3005 abi::Instruction::VariantPayloadName => {
3006 let name = tempname("_payload", self.tmp());
3007 results.push(name.clone());
3008 self.payloads.push(name);
3009 }
3010 abi::Instruction::VariantLower {
3011 ty,
3012 variant,
3013 results: result_types,
3014 ..
3015 } => {
3016 let blocks = self
3017 .blocks
3018 .drain(self.blocks.len() - variant.cases.len()..)
3019 .collect::<Vec<_>>();
3020 let payloads = self
3021 .payloads
3022 .drain(self.payloads.len() - variant.cases.len()..)
3023 .collect::<Vec<_>>();
3024
3025 let mut variant_results = Vec::with_capacity(result_types.len());
3026 for res_ty in result_types.iter() {
3027 let name = tempname("_variantPart", self.tmp());
3028 results.push(name.clone());
3029 self.src
3030 .push_str(&format!("{} {name} = void;\n", wasm_type(*res_ty)));
3031 variant_results.push(name);
3032 }
3033
3034 let ty_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
3035
3036 let tag_type = tempname("_Tag", self.tmp());
3037
3038 self.push_str(&format!("alias {tag_type} = {ty_name}.Tag;\n"));
3039 self.push_str(&format!("final switch ({}.tag) {{\n", operands[0]));
3040
3041 for ((case, block), payload) in variant.cases.iter().zip(blocks).zip(payloads) {
3042 let lower_name = case.name.to_lower_camel_case();
3043 let lower_escaped_name = escape_d_identifier(&lower_name);
3044
3045 let uppper_name = case.name.to_upper_camel_case();
3046 let upper_escaped_name = escape_d_identifier(&uppper_name);
3047
3048 self.push_str(&format!("case {tag_type}.{lower_escaped_name}: {{\n"));
3049 if let Some(ty) = case.ty.as_ref() {
3050 let ty_name = self.r#gen.type_name(ty, self.r#gen.fqn);
3051 self.push_str(&format!(
3052 "{}ref {ty_name} {payload} = {}.get{upper_escaped_name}();\n",
3053 if matches!(self.r#gen.direction, Some(Direction::Import)) {
3054 "const "
3055 } else {
3056 ""
3057 },
3058 operands[0],
3059 ));
3060 }
3061 self.src.push_str(&block.body);
3062
3063 for (name, result) in variant_results.iter().zip(&block.results) {
3064 self.push_str(&format!("{name} = {result};\n"));
3065 }
3066 self.src.push_str("break;\n}\n");
3067 }
3068
3069 self.src.push_str("}\n");
3070 }
3071 abi::Instruction::VariantLift { variant, ty, .. } => {
3072 let blocks = self
3073 .blocks
3074 .drain(self.blocks.len() - variant.cases.len()..)
3075 .collect::<Vec<_>>();
3076
3077 let ty = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
3078
3079 let tmp = self.tmp();
3080 let result = tempname("_variant", tmp);
3081 let tag = tempname("_tag", tmp);
3082 let tag_type = tempname("_Tag", tmp);
3083
3084 self.push_str(&format!("{ty} {result} = void;\n"));
3085 self.push_str(&format!("auto {tag} = {};\n", operands[0]));
3086
3087 self.push_str(&format!("alias {tag_type} = {ty}.Tag;\n"));
3088 self.push_str(&format!("final switch (cast({ty}.Tag){tag}) {{\n"));
3089 for (case, block) in variant.cases.iter().zip(blocks) {
3090 let lower_name = case.name.to_lower_camel_case();
3091 let escaped_name = escape_d_identifier(&lower_name);
3092
3093 let payload = tempname("_payload", self.tmp());
3094
3095 self.push_str(&format!("case {tag_type}.{escaped_name}: {{\n"));
3096 self.src.push_str(&block.body);
3097 assert!(block.results.len() == (case.ty.is_some() as usize));
3098
3099 let val = if let Some(_) = case.ty.as_ref() {
3100 self.push_str(&format!("auto {payload} = {};\n", block.results[0]));
3101 &payload
3102 } else {
3103 ""
3104 };
3105 self.push_str(&format!("{result} = {ty}.{escaped_name}({val});\n"));
3106 self.src.push_str("break;\n}\n");
3107 }
3108 self.src.push_str("}\n");
3109 results.push(result);
3110 }
3111
3112 abi::Instruction::EnumLower { .. } => {
3113 results.push(format!("cast(uint)({})", operands[0]))
3114 }
3115 abi::Instruction::EnumLift { ty, .. } => {
3116 let type_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
3117 results.push(format!("cast({})({})", type_name, operands.pop().unwrap()))
3118 }
3119
3120 abi::Instruction::OptionLower {
3121 results: result_types,
3122 ..
3123 } => {
3124 let Block {
3125 body: mut some,
3126 results: some_results,
3127 ..
3128 } = self.blocks.pop().unwrap();
3129 let Block {
3130 body: mut none,
3131 results: none_results,
3132 ..
3133 } = self.blocks.pop().unwrap();
3134 let some_payload = self.payloads.pop().unwrap();
3135 let _none_payload = self.payloads.pop().unwrap();
3136
3137 for (i, ty) in result_types.iter().enumerate() {
3138 let name = tempname("_option", self.tmp());
3139 results.push(name.clone());
3140 self.push_str(&format!("{} {name} = void;\n", wasm_type(*ty)));
3141 let some_result = &some_results[i];
3142 some.push_str(&format!("{name} = {some_result};\n"));
3143 let none_result = &none_results[i];
3144 none.push_str(&format!("{name} = {none_result};\n"));
3145 }
3146
3147 let bind_some = format!("ref {some_payload} = {}.unwrap();", operands[0]);
3148
3149 self.push_str(&format!(
3150 "\
3151 if ({}.isSome) {{
3152 {bind_some}
3153 {some}}} else {{
3154 {none}}}
3155 ",
3156 operands[0]
3157 ));
3158 }
3159 abi::Instruction::OptionLift { ty, .. } => {
3160 let Block {
3161 body: some,
3162 results: some_results,
3163 ..
3164 } = self.blocks.pop().unwrap();
3165 let Block {
3166 results: none_results,
3167 ..
3168 } = self.blocks.pop().unwrap();
3169 assert!(none_results.is_empty());
3170 assert!(some_results.len() == 1);
3171
3172 let type_name = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
3173 let op0 = &operands[0];
3174
3175 let tmp = self.tmp();
3176 let resultname = tempname("_option", tmp);
3177 let is_some = tempname("_isSome", tmp);
3178 let some_value = &some_results[0];
3179 self.push_str(&format!(
3180 "{type_name} {resultname} = void;
3181 bool {is_some} = ({op0}) != 0;
3182 if ({is_some}) {{
3183 {some}
3184 {resultname} = {type_name}.makeSome({some_value});
3185 }} else {{
3186 {resultname} = {type_name}.makeNone;
3187 }}
3188 "
3189 ));
3190 results.push(format!("{resultname}"));
3191 }
3192
3193 abi::Instruction::ResultLower {
3194 results: result_types,
3195 result,
3196 ..
3197 } => {
3198 let Block {
3199 body: mut err,
3200 results: err_results,
3201 ..
3202 } = self.blocks.pop().unwrap();
3203 let Block {
3204 body: mut ok,
3205 results: ok_results,
3206 ..
3207 } = self.blocks.pop().unwrap();
3208 let err_payload = self.payloads.pop().unwrap();
3209 let ok_payload = self.payloads.pop().unwrap();
3210
3211 for (i, ty) in result_types.iter().enumerate() {
3212 let tmp = self.tmp();
3213 let name = tempname("_resultPart", tmp);
3214 results.push(name.clone());
3215 self.src.push_str(wasm_type(*ty));
3216 self.src.push_str(" ");
3217 self.src.push_str(&name);
3218 self.src.push_str(";\n");
3219 let ok_result = &ok_results[i];
3220 ok.push_str(&format!("{name} = {ok_result};\n"));
3221 let err_result = &err_results[i];
3222 err.push_str(&format!("{name} = {err_result};\n"));
3223 }
3224
3225 let op0 = &operands[0];
3226 let bind_ok = if let Some(_ok) = result.ok.as_ref() {
3227 format!("ref {ok_payload} = {op0}.unwrap();")
3228 } else {
3229 String::new()
3230 };
3231 let bind_err = if let Some(_err) = result.err.as_ref() {
3232 format!("ref {err_payload} = {op0}.unwrapErr();")
3233 } else {
3234 String::new()
3235 };
3236
3237 self.push_str(&format!(
3238 "\
3239 if ({op0}.isErr) {{
3240 {bind_err}
3241 {err}}} else {{
3242 {bind_ok}
3243 {ok}}}
3244 "
3245 ));
3246 }
3247 abi::Instruction::ResultLift { result, ty, .. } => {
3248 let Block {
3249 body: err,
3250 results: err_results,
3251 ..
3252 } = self.blocks.pop().unwrap();
3253 assert!(err_results.len() == (result.err.is_some() as usize));
3254 let Block {
3255 body: ok,
3256 results: ok_results,
3257 ..
3258 } = self.blocks.pop().unwrap();
3259 assert!(ok_results.len() == (result.ok.is_some() as usize));
3260
3261 let full_type = self.r#gen.type_name(&Type::Id(*ty), self.r#gen.fqn);
3262 let op0 = &operands[0];
3263
3264 let tmp = self.tmp();
3265 let resultname = tempname("_result", tmp);
3266 let is_err = tempname("_isErr", tmp);
3267
3268 let ok_value = if result.ok.is_some() {
3269 &ok_results[0]
3270 } else {
3271 ""
3272 };
3273
3274 let err_value = if result.err.is_some() {
3275 &err_results[0]
3276 } else {
3277 ""
3278 };
3279
3280 self.push_str(&format!(
3281 "{full_type} {resultname} = void;
3282 bool {is_err} = ({op0}) != 0;
3283 if ({is_err}) {{
3284 {err}
3285 {resultname} = {full_type}.makeErr({err_value});
3286 }} else {{
3287 {ok}
3288 {resultname} = {full_type}.makeOk({ok_value});
3289 }}\n"
3290 ));
3291 results.push(resultname);
3292 }
3293
3294 abi::Instruction::CallWasm { name, sig } => {
3295 let split_name = if name.contains('.') {
3296 name.split(".").skip(1).next().unwrap()
3297 } else {
3298 name
3299 };
3300
3301 let lower_name = split_name.to_lower_camel_case();
3302 let escaped_name = if name.starts_with("[constructor]") {
3303 "makeNew"
3304 } else {
3305 escape_d_identifier(&lower_name)
3306 };
3307
3308 if !sig.results.is_empty() {
3309 self.src.push_str("auto _ret = ");
3310 results.push("_ret".to_string());
3311 }
3312 self.push_str(&format!(
3313 "__import_{escaped_name}({});\n",
3314 operands.iter().cloned().collect::<Vec<_>>().join(", ")
3315 ));
3316
3317 if self.needs_deallocate {
3318 self.push_str(&format!("deallocate.purge();\n"));
3319 }
3320 }
3321 abi::Instruction::CallInterface { func, async_ } => {
3322 if *async_ {
3323 todo!("CallInterface async");
3324 }
3325
3326 if func.result.is_some() {
3327 self.src.push_str("auto _ret = ");
3328 results.push("_ret".to_string());
3329 }
3330
3331 let split_name = match &func.kind {
3332 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &func.name,
3333 FunctionKind::Constructor(_) => "",
3334 FunctionKind::Method(_)
3335 | FunctionKind::Static(_)
3336 | FunctionKind::AsyncMethod(_)
3337 | FunctionKind::AsyncStatic(_) => func.name.split(".").skip(1).next().unwrap(),
3338 };
3339
3340 let lower_name = split_name.to_lower_camel_case();
3341 let escaped_name = if let FunctionKind::Constructor(_) = &func.kind {
3342 "constructor"
3343 } else {
3344 escape_d_identifier(&lower_name)
3345 };
3346
3347 let implicit_self = match &func.kind {
3348 FunctionKind::Freestanding
3349 | FunctionKind::AsyncFreestanding
3350 | FunctionKind::Static(_)
3351 | FunctionKind::AsyncStatic(_)
3352 | FunctionKind::Constructor(_) => {
3353 self.src.push_str(&format!("{escaped_name}_Impl("));
3354 false
3355 }
3356 FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
3357 self.src.push_str(&format!(
3358 "__traits(child, cast(_Resource_Impl*)self, {escaped_name}_Impl)("
3359 ));
3360 true
3361 }
3362 };
3363 self.src.push_str(
3364 &operands
3365 .iter()
3366 .skip(if implicit_self { 1 } else { 0 })
3367 .cloned()
3368 .collect::<Vec<_>>()
3369 .join(", "),
3370 );
3371 self.src.push_str(");\n");
3372
3373 if self.needs_deallocate {
3374 self.push_str(&format!("deallocate.purge();\n"));
3375 }
3376 }
3377 abi::Instruction::Return { amt, .. } => match amt {
3378 0 => {}
3379 _ => {
3380 assert!(*amt == operands.len());
3381
3382 if *amt == 1 {
3383 self.push_str("return ");
3384 self.src.push_str(&operands[0]);
3385 self.push_str(";\n");
3386 } else {
3387 todo!();
3388 }
3389 }
3390 },
3391
3392 abi::Instruction::Malloc { .. } => {
3393 todo!("instr: Malloc")
3394 }
3395 abi::Instruction::GuestDeallocate { .. } => {
3396 self.push_str(&format!("free({});", operands[0]));
3397 }
3398 abi::Instruction::GuestDeallocateString { .. } => {
3399 self.push_str(&format!("if ({} > 0) {{\n", operands[1]));
3400 self.push_str(&format!("free({});\n", operands[0]));
3401 self.push_str("}\n");
3402 }
3403 abi::Instruction::GuestDeallocateList { element } => {
3404 let Block {
3405 body,
3406 results: _,
3407 element: block_element,
3408 base,
3409 } = self.blocks.pop().unwrap();
3410 let tmp = self.tmp();
3411 let size = self.r#gen.sizes.size(element);
3412 let size_str = size.format("size_t.sizeof");
3413
3414 let list_len = tempname("_listLen", tmp);
3415 let list_src = tempname("_listSrcPtr", tmp);
3416 self.push_str(&format!("auto {list_src} = {};\n", operands[0]));
3417 self.push_str(&format!("auto {list_len} = {};\n", operands[1]));
3418
3419 self.push_str(&format!(
3420 "foreach ({block_element}_idx; 0..{list_len}) {{\n",
3421 ));
3422 self.push_str(&format!(
3423 "const auto {base} = {list_src} + {block_element}_idx * {size_str};\n"
3424 ));
3425 self.push_str(&body);
3426 self.push_str("\n}\n");
3427
3428 self.push_str(&format!("if ({} > 0) {{\n", operands[1]));
3429 self.push_str(&format!("free({});\n", operands[0]));
3430 self.push_str("}\n");
3431 }
3432 abi::Instruction::GuestDeallocateVariant {
3433 blocks: block_count,
3434 } => {
3435 let blocks = self
3436 .blocks
3437 .drain(self.blocks.len() - block_count..)
3438 .collect::<Vec<_>>();
3439
3440 self.push_str(&format!("switch ({}) {{\n", operands[0]));
3441 for (i, block) in blocks.into_iter().enumerate() {
3442 assert!(results.is_empty());
3443
3444 self.push_str(&format!("case {i}: {{\n"));
3445 self.src.push_str(&block.body);
3446 self.src.push_str("break;\n}\n");
3447 }
3448 self.src.push_str("default: break;\n}\n");
3449 }
3450 abi::Instruction::DropHandle { .. } => {
3451 todo!("instr: DropHandle")
3452 }
3453
3454 abi::Instruction::Flush { amt } => {
3455 for op in operands.iter().take(*amt) {
3456 let result = tempname("_flush", self.tmp());
3457 self.push_str(&format!("auto {result} = {op};\n"));
3458 results.push(result);
3459 }
3460 }
3461
3462 unk => todo!("emit instruction: {unk:?}"),
3463 }
3464 }
3465
3466 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> Self::Operand {
3467 self.return_pointer_area_size = self.return_pointer_area_size.max(size);
3469 self.return_pointer_area_align = self.return_pointer_area_align.max(align);
3470
3471 "_retArea.ptr".into()
3472 }
3473
3474 fn push_block(&mut self) {
3475 let tmp = self.tmp();
3476
3477 self.block_storage.push(BlockStorage {
3478 body: take(&mut self.src),
3479 element: tempname("_elem", tmp),
3480 base: tempname("_base", tmp),
3481 });
3482 }
3483
3484 fn finish_block(&mut self, operands: &mut Vec<Self::Operand>) {
3485 let BlockStorage {
3486 body,
3487 element,
3488 base,
3489 } = self.block_storage.pop().unwrap();
3490
3491 let src = replace(&mut self.src, body);
3492 self.blocks.push(Block {
3493 body: src.into(),
3494 results: take(operands),
3495 element,
3496 base,
3497 });
3498 }
3499
3500 fn sizes(&self) -> &SizeAlign {
3501 &self.r#gen.sizes
3502 }
3503
3504 fn is_list_canonical(&self, _resolve: &Resolve, ty: &Type) -> bool {
3505 self.r#gen.resolve.all_bits_valid(ty)
3506 }
3507}