Skip to main content

wit_bindgen_d/
lib.rs

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    /// Where to place output files
60    #[cfg_attr(feature = "clap", arg(skip))]
61    out_dir: Option<PathBuf>,
62
63    /// Whether stubs/declarations for exports should be emitted
64    /// Only for testing purposes.
65    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
66    emit_export_stubs: bool,
67
68    /// Add the specified suffix to the name of the custom section containing
69    /// the component type.
70    #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
71    pub type_section_suffix: Option<String>,
72
73    /// Choose root package other than `wit` to nest everything under.
74    #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
75    pub root_package: Option<String>,
76
77    // TODO: find new home for wit_common; dub package?
78    /*
79    /// Whether the generated bindings should be self-contained
80    ///
81    /// Instead of relying on DRuntime (and wasi-libc) to define
82    /// the common types, and `cabi_realloc`, `wit.common` is
83    /// emitted alongside the bindings.
84    #[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
85    pub self_contained: bool,
86    */
87    /// A series of D versions that all the generated bindings
88    /// will be gated behind.
89    #[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        // Escape D keywords.
105        // Source: https://dlang.org/spec/lex.html#keywords
106        "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        // Common DRuntime & Phobos symbols
226        "Object" => "Object_",
227        "Error" => "Error_",
228        "Throwable" => "Throwable_",
229        "Exception" => "Exception_",
230        "TypeInfo" => "TypeInfo_",
231
232        // Symbols we define as part of the bindings we want to avoid creating conflicts with
233        "WitList" => "WitList_",
234        "WitString" => "WitString_",
235        "WitFlags" => "WitFlags_",
236        "Option" => "Option_",
237        "Result" => "Result_",
238        "bits" => "bits_",               // part of WitFlags
239        "borrow" => "borrow_",           // part of the expansion of `resource`
240        "rep" => "rep_",                 // part of the expansion of `resource`
241        "makeNew" => "makeNew_",         // part of the expansion of `resource`
242        "constructor" => "constructor_", // part of the expansion of `resource`
243
244        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                                // For anonymous/inline imports, the common types are in the same file as the imports
410                                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                                // For anonymous/inline exports, the common types are in the same file as the exports
452                                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            // We have an inline interface imported in a world.
507            // Emit the "common" types as well
508
509            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.interface_imports.push(interface_src.fqn.clone());
535        //interface_src.src.push_str("\n// Function imports\n");
536        //interface_src.src.append_src(&tmp_src);
537
538        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            // We have an inline interface exported in a world.
608            // Emit the "common" types as well
609
610            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        // Linker `component-type` section
876        {
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(&param, 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, &params);
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        // The mangle is not important, as long as it won't conflict with other symbols
1352        // WebAssembly symbol identifiers are much more permissive than C (can be any UTF-8).
1353        // Yet, LDC before 1.42 doesn't allow full use of this fact. We make some substitutions.
1354        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 &params_data {
1413            params.push(&param);
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(&params)
1508                .map(|(ty, name)| format!("{} {name}", wasm_type(*ty)))
1509                .collect::<Vec<String>>()
1510                .join(", ")
1511        ));
1512
1513        let mut f = FunctionBindgen::new(self, &params);
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 &param_data {
1556                params.push(&param);
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(&params)
1582                    .map(|(ty, name)| format!("{} {name}", wasm_type(*ty)))
1583                    .collect::<Vec<String>>()
1584                    .join(", ")
1585            ));
1586
1587            let mut f = FunctionBindgen::new(self, &params);
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    // Override `types` to filter by `self.direction`
1655    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.push_str("@safe @nogc nothrow:\n");
2132        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    /// intermediate calculations for contained objects
2424    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    /// Emits a shared return area declaration if needed by this function.
2498    ///
2499    /// During code generation, `return_pointer()` may be called multiple times for:
2500    /// - Indirect parameter storage (when too many/large params)
2501    /// - Return value storage (when return type is too large)
2502    ///
2503    /// **Safety:** This is safe because return pointers are used sequentially:
2504    /// 1. Parameter marshaling (before call)
2505    /// 2. Function execution
2506    /// 3. Return value unmarshaling (after call)
2507    ///
2508    /// The scratch space is reused but never accessed simultaneously.
2509    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(&format!("_targetElem = {};", body.1[0]));
2706                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        // Track maximum return area requirements
3468        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}