wai_bindgen_gen_wasmer_py/
lib.rs

1use heck::*;
2use std::collections::{BTreeMap, BTreeSet, HashMap};
3use std::mem;
4use wai_bindgen_gen_core::wai_parser::abi::{
5    AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType,
6};
7use wai_bindgen_gen_core::{wai_parser::*, Direction, Files, Generator, Ns};
8
9pub mod dependencies;
10pub mod source;
11
12use dependencies::Dependencies;
13use source::Source;
14
15#[derive(Default)]
16pub struct WasmerPy {
17    src: Source,
18    in_import: bool,
19    opts: Opts,
20    guest_imports: HashMap<String, Imports>,
21    guest_exports: HashMap<String, Exports>,
22    sizes: SizeAlign,
23    /// Tracks the intrinsics and Python imports needed
24    deps: Dependencies,
25    /// Whether the Python Union being emitted will wrap its cases with dataclasses
26    union_representation: HashMap<String, PyUnionRepresentation>,
27}
28
29#[derive(Debug, Clone, Copy)]
30enum PyUnionRepresentation {
31    /// A union whose inner types are used directly
32    Raw,
33    /// A union whose inner types have been wrapped in dataclasses
34    Wrapped,
35}
36
37#[derive(Default)]
38struct Imports {
39    freestanding_funcs: Vec<Import>,
40    resource_funcs: BTreeMap<ResourceId, Vec<Import>>,
41}
42
43struct Import {
44    name: String,
45    src: Source,
46    wasm_ty: String,
47    pysig: String,
48}
49
50#[derive(Default)]
51struct Exports {
52    freestanding_funcs: Vec<Source>,
53    resource_funcs: BTreeMap<ResourceId, Vec<Source>>,
54    fields: BTreeMap<String, &'static str>,
55}
56
57#[derive(Default, Debug, Clone)]
58#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))]
59pub struct Opts {
60    #[cfg_attr(feature = "structopt", structopt(long = "no-typescript"))]
61    pub no_typescript: bool,
62}
63
64impl Opts {
65    pub fn build(self) -> WasmerPy {
66        let mut r = WasmerPy::new();
67        r.opts = self;
68        r
69    }
70}
71
72impl WasmerPy {
73    pub fn new() -> WasmerPy {
74        WasmerPy::default()
75    }
76
77    fn abi_variant(dir: Direction) -> AbiVariant {
78        // This generator uses a reversed mapping! In the Wasmer-py host-side
79        // bindings, we don't use any extra adapter layer between guest wasm
80        // modules and the host. When the guest imports functions using the
81        // `GuestImport` ABI, the host directly implements the `GuestImport`
82        // ABI, even though the host is *exporting* functions. Similarly, when
83        // the guest exports functions using the `GuestExport` ABI, the host
84        // directly imports them with the `GuestExport` ABI, even though the
85        // host is *importing* functions.
86        match dir {
87            Direction::Import => AbiVariant::GuestExport,
88            Direction::Export => AbiVariant::GuestImport,
89        }
90    }
91
92    /// Creates a `Source` with all of the required intrinsics
93    fn intrinsics(&mut self, iface: &Interface) -> Source {
94        if iface.resources.len() > 0 {
95            self.deps.needs_resources = true;
96            self.deps.pyimport("typing", "runtime_checkable");
97        }
98        self.deps.intrinsics()
99    }
100}
101
102fn array_ty(iface: &Interface, ty: &Type) -> Option<&'static str> {
103    match ty {
104        Type::Unit | Type::Bool => None,
105        Type::U8 => Some("uint8"),
106        Type::S8 => Some("int8"),
107        Type::U16 => Some("uint16"),
108        Type::S16 => Some("int16"),
109        Type::U32 => Some("uint32"),
110        Type::S32 => Some("int32"),
111        Type::U64 => Some("uint64"),
112        Type::S64 => Some("int64"),
113        Type::Float32 => Some("float32"),
114        Type::Float64 => Some("float64"),
115        Type::Char => None,
116        Type::Handle(_) => None,
117        Type::String => None,
118        Type::Id(id) => match &iface.types[*id].kind {
119            TypeDefKind::Type(t) => array_ty(iface, t),
120            _ => None,
121        },
122    }
123}
124
125impl Generator for WasmerPy {
126    fn preprocess_one(&mut self, iface: &Interface, dir: Direction) {
127        let variant = Self::abi_variant(dir);
128        self.sizes.fill(iface);
129        self.in_import = variant == AbiVariant::GuestImport;
130    }
131
132    fn type_record(
133        &mut self,
134        iface: &Interface,
135        _id: TypeId,
136        name: &str,
137        record: &Record,
138        docs: &Docs,
139    ) {
140        let mut builder = self.src.builder(&mut self.deps, iface);
141        builder.pyimport("dataclasses", "dataclass");
142        builder.push_str("@dataclass\n");
143        builder.push_str(&format!("class {}:\n", name.to_camel_case()));
144        builder.indent();
145        builder.docstring(docs);
146        for field in record.fields.iter() {
147            builder.comment(&field.docs);
148            let field_name = field.name.to_snake_case();
149            builder.push_str(&format!("{field_name}: "));
150            builder.print_ty(&field.ty, true);
151            builder.push_str("\n");
152        }
153        if record.fields.is_empty() {
154            builder.push_str("pass\n");
155        }
156        builder.dedent();
157        builder.push_str("\n");
158    }
159
160    fn type_tuple(
161        &mut self,
162        iface: &Interface,
163        _id: TypeId,
164        name: &str,
165        tuple: &Tuple,
166        docs: &Docs,
167    ) {
168        let mut builder = self.src.builder(&mut self.deps, iface);
169        builder.comment(docs);
170        builder.push_str(&format!("{} = ", name.to_camel_case()));
171        builder.print_tuple(tuple);
172        builder.push_str("\n");
173    }
174
175    fn type_flags(
176        &mut self,
177        iface: &Interface,
178        _id: TypeId,
179        name: &str,
180        flags: &Flags,
181        docs: &Docs,
182    ) {
183        let mut builder = self.src.builder(&mut self.deps, iface);
184        builder.pyimport("enum", "Flag");
185        builder.pyimport("enum", "auto");
186        builder.push_str(&format!("class {}(Flag):\n", name.to_camel_case()));
187        builder.indent();
188        builder.docstring(docs);
189        for flag in flags.flags.iter() {
190            let flag_name = flag.name.to_shouty_snake_case();
191            builder.comment(&flag.docs);
192            builder.push_str(&format!("{flag_name} = auto()\n"));
193        }
194        if flags.flags.is_empty() {
195            builder.push_str("pass\n");
196        }
197        builder.dedent();
198        builder.push_str("\n");
199    }
200
201    fn type_variant(
202        &mut self,
203        iface: &Interface,
204        _id: TypeId,
205        name: &str,
206        variant: &Variant,
207        docs: &Docs,
208    ) {
209        let mut builder = self.src.builder(&mut self.deps, iface);
210        builder.pyimport("dataclasses", "dataclass");
211        let mut cases = Vec::new();
212        for case in variant.cases.iter() {
213            builder.docstring(&case.docs);
214            builder.push_str("@dataclass\n");
215            let case_name = format!("{}{}", name.to_camel_case(), case.name.to_camel_case());
216            builder.push_str(&format!("class {case_name}:\n"));
217            builder.indent();
218            builder.push_str("value: ");
219            builder.print_ty(&case.ty, true);
220            builder.push_str("\n");
221            builder.dedent();
222            builder.push_str("\n");
223            cases.push(case_name);
224        }
225
226        builder.deps.pyimport("typing", "Union");
227        builder.comment(docs);
228        builder.push_str(&format!(
229            "{} = Union[{}]\n",
230            name.to_camel_case(),
231            cases.join(", "),
232        ));
233        builder.push_str("\n");
234    }
235
236    /// Appends a Python definition for the provided Union to the current `Source`.
237    /// e.g. `MyUnion = Union[float, str, int]`
238    fn type_union(
239        &mut self,
240        iface: &Interface,
241        _id: TypeId,
242        name: &str,
243        union: &Union,
244        docs: &Docs,
245    ) {
246        let mut py_type_classes = BTreeSet::new();
247        for case in union.cases.iter() {
248            py_type_classes.insert(py_type_class_of(&case.ty));
249        }
250
251        let mut builder = self.src.builder(&mut self.deps, iface);
252        if py_type_classes.len() != union.cases.len() {
253            // Some of the cases are not distinguishable
254            self.union_representation
255                .insert(name.to_string(), PyUnionRepresentation::Wrapped);
256            builder.print_union_wrapped(name, union, docs);
257        } else {
258            // All of the cases are distinguishable
259            self.union_representation
260                .insert(name.to_string(), PyUnionRepresentation::Raw);
261            builder.print_union_raw(name, union, docs);
262        }
263    }
264
265    fn type_option(
266        &mut self,
267        iface: &Interface,
268        _id: TypeId,
269        name: &str,
270        payload: &Type,
271        docs: &Docs,
272    ) {
273        let mut builder = self.src.builder(&mut self.deps, iface);
274        builder.pyimport("typing", "Optional");
275        builder.comment(docs);
276        builder.push_str(&name.to_camel_case());
277        builder.push_str(" = Optional[");
278        builder.print_ty(payload, true);
279        builder.push_str("]\n\n");
280    }
281
282    fn type_expected(
283        &mut self,
284        iface: &Interface,
285        _id: TypeId,
286        name: &str,
287        expected: &Expected,
288        docs: &Docs,
289    ) {
290        self.deps.needs_expected = true;
291
292        let mut builder = self.src.builder(&mut self.deps, iface);
293        builder.comment(docs);
294        builder.push_str(&format!("{} = Expected[", name.to_camel_case()));
295        builder.print_ty(&expected.ok, true);
296        builder.push_str(", ");
297        builder.print_ty(&expected.err, true);
298        builder.push_str("]\n\n");
299    }
300
301    fn type_enum(&mut self, iface: &Interface, _id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
302        let mut builder = self.src.builder(&mut self.deps, iface);
303        builder.pyimport("enum", "Enum");
304        builder.push_str(&format!("class {}(Enum):\n", name.to_camel_case()));
305        builder.indent();
306        builder.docstring(docs);
307        for (i, case) in enum_.cases.iter().enumerate() {
308            builder.comment(&case.docs);
309
310            // TODO this handling of digits should be more general and
311            // shouldn't be here just to fix the one case in wasi where an
312            // enum variant is "2big" and doesn't generate valid Python. We
313            // should probably apply this to all generated Python
314            // identifiers.
315            let mut name = case.name.to_shouty_snake_case();
316            if name.chars().next().unwrap().is_ascii_digit() {
317                name = format!("_{}", name);
318            }
319            builder.push_str(&format!("{} = {}\n", name, i));
320        }
321        builder.dedent();
322        builder.push_str("\n");
323    }
324
325    fn type_resource(&mut self, _iface: &Interface, _ty: ResourceId) {
326        // if !self.in_import {
327        //     self.exported_resources.insert(ty);
328        // }
329    }
330
331    fn type_alias(&mut self, iface: &Interface, _id: TypeId, name: &str, ty: &Type, docs: &Docs) {
332        let mut builder = self.src.builder(&mut self.deps, iface);
333        builder.comment(docs);
334        builder.push_str(&format!("{} = ", name.to_camel_case()));
335        builder.print_ty(ty, false);
336        builder.push_str("\n");
337    }
338
339    fn type_list(&mut self, iface: &Interface, _id: TypeId, name: &str, ty: &Type, docs: &Docs) {
340        let mut builder = self.src.builder(&mut self.deps, iface);
341        builder.comment(docs);
342        builder.push_str(&format!("{} = ", name.to_camel_case()));
343        builder.print_list(ty);
344        builder.push_str("\n");
345    }
346
347    fn type_builtin(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
348        self.type_alias(iface, id, name, ty, docs);
349    }
350
351    // As with `abi_variant` above, we're generating host-side bindings here
352    // so a user "export" uses the "guest import" ABI variant on the inside of
353    // this `Generator` implementation.
354    fn export(&mut self, iface: &Interface, func: &Function) {
355        assert!(!func.is_async, "async not supported yet");
356        let mut pysig = Source::default();
357        let mut builder = pysig.builder(&mut self.deps, iface);
358        builder.print_sig(func, self.in_import);
359        let pysig = pysig.to_string();
360
361        let mut func_body = Source::default();
362        let mut builder = func_body.builder(&mut self.deps, iface);
363
364        let sig = iface.wasm_signature(AbiVariant::GuestImport, func);
365        builder.push_str(&format!("def {}(", func.name.to_snake_case(),));
366        let mut params = Vec::new();
367        for (i, param) in sig.params.iter().enumerate() {
368            if i != 0 {
369                builder.push_str(", ");
370            }
371            let name = format!("arg{}", i);
372            builder.push_str(&name);
373            builder.push_str(": ");
374            builder.push_str(wasm_ty_typing(*param));
375            params.push(name);
376        }
377        builder.push_str(") -> ");
378        match sig.results.len() {
379            0 => builder.push_str("None"),
380            1 => builder.push_str(wasm_ty_typing(sig.results[0])),
381            _ => unimplemented!(),
382        }
383        builder.push_str(":\n");
384        builder.indent();
385        drop(builder);
386
387        let mut f = FunctionBindgen::new(self, params);
388        iface.call(
389            AbiVariant::GuestImport,
390            LiftLower::LiftArgsLowerResults,
391            func,
392            &mut f,
393        );
394
395        let FunctionBindgen {
396            src,
397            needs_memory,
398            needs_realloc,
399            needs_free,
400            mut locals,
401            ..
402        } = f;
403
404        let mut builder = func_body.builder(&mut self.deps, iface);
405        if needs_memory {
406            // TODO: hardcoding "memory"
407            builder.push_str("m = get_export(\"memory\")\n");
408            builder.push_str("assert(isinstance(m, wasmer.Memory))\n");
409            builder.deps.pyimport("typing", "cast");
410            builder.push_str("memory = cast(wasmer.Memory, m)\n");
411            locals.insert("memory").unwrap();
412        }
413
414        if let Some(name) = needs_realloc {
415            builder.push_str(&format!("realloc = get_export(\"{}\")\n", name));
416            builder.push_str("assert(isinstance(realloc, wasmer.Function))\n");
417            locals.insert("realloc").unwrap();
418        }
419
420        if let Some(name) = needs_free {
421            builder.push_str(&format!("free = get_export(\"{}\")\n", name));
422            builder.push_str("assert(isinstance(free, wasmer.Function))\n");
423            locals.insert("free").unwrap();
424        }
425        builder.push_str(&src);
426        builder.dedent();
427
428        let mut wasm_ty = String::from("wasmer.FunctionType([");
429        wasm_ty.push_str(
430            &sig.params
431                .iter()
432                .map(|t| wasm_ty_ctor(*t))
433                .collect::<Vec<_>>()
434                .join(", "),
435        );
436        wasm_ty.push_str("], [");
437        wasm_ty.push_str(
438            &sig.results
439                .iter()
440                .map(|t| wasm_ty_ctor(*t))
441                .collect::<Vec<_>>()
442                .join(", "),
443        );
444        wasm_ty.push_str("])");
445        let import = Import {
446            name: func.name.clone(),
447            src: func_body,
448            wasm_ty,
449            pysig,
450        };
451        let imports = self
452            .guest_imports
453            .entry(iface.name.to_string())
454            .or_default();
455        let dst = match &func.kind {
456            FunctionKind::Freestanding | FunctionKind::Static { .. } => {
457                &mut imports.freestanding_funcs
458            }
459            FunctionKind::Method { resource, .. } => {
460                imports.resource_funcs.entry(*resource).or_default()
461            }
462        };
463        dst.push(import);
464    }
465
466    // As with `abi_variant` above, we're generating host-side bindings here
467    // so a user "import" uses the "export" ABI variant on the inside of
468    // this `Generator` implementation.
469    fn import(&mut self, iface: &Interface, func: &Function) {
470        assert!(!func.is_async, "async not supported yet");
471        let mut func_body = Source::default();
472        let mut builder = func_body.builder(&mut self.deps, iface);
473
474        // Print the function signature
475        let params = builder.print_sig(func, self.in_import);
476        builder.push_str(":\n");
477        builder.indent();
478        drop(builder);
479
480        // Use FunctionBindgen call
481        let src_object = match &func.kind {
482            FunctionKind::Freestanding => "self".to_string(),
483            FunctionKind::Static { .. } => "obj".to_string(),
484            FunctionKind::Method { .. } => "self._obj".to_string(),
485        };
486        let mut f = FunctionBindgen::new(self, params);
487        f.src_object = src_object;
488        iface.call(
489            AbiVariant::GuestExport,
490            LiftLower::LowerArgsLiftResults,
491            func,
492            &mut f,
493        );
494        let FunctionBindgen {
495            src,
496            needs_memory,
497            needs_realloc,
498            needs_free,
499            src_object,
500            ..
501        } = f;
502        let mut builder = func_body.builder(&mut self.deps, iface);
503        if needs_memory {
504            // TODO: hardcoding "memory"
505            builder.push_str(&format!("memory = {}._memory;\n", src_object));
506        }
507
508        if let Some(name) = &needs_realloc {
509            builder.push_str(&format!(
510                "realloc = {}._{}\n",
511                src_object,
512                name.to_snake_case(),
513            ));
514        }
515
516        if let Some(name) = &needs_free {
517            builder.push_str(&format!(
518                "free = {}._{}\n",
519                src_object,
520                name.to_snake_case(),
521            ));
522        }
523        builder.push_str(&src);
524        builder.dedent();
525
526        let exports = self
527            .guest_exports
528            .entry(iface.name.to_string())
529            .or_insert_with(Exports::default);
530        if needs_memory {
531            exports.fields.insert("memory".to_string(), "wasmer.Memory");
532        }
533        if let Some(name) = &needs_realloc {
534            exports.fields.insert(name.clone(), "wasmer.Function");
535        }
536        if let Some(name) = &needs_free {
537            exports.fields.insert(name.clone(), "wasmer.Function");
538        }
539        exports.fields.insert(func.name.clone(), "wasmer.Function");
540
541        let dst = match &func.kind {
542            FunctionKind::Freestanding => &mut exports.freestanding_funcs,
543            FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => {
544                exports.resource_funcs.entry(*resource).or_default()
545            }
546        };
547        dst.push(func_body);
548    }
549
550    fn finish_one(&mut self, iface: &Interface, files: &mut Files) {
551        self.deps.pyimport("typing", "Any");
552        self.deps.pyimport("abc", "abstractmethod");
553        self.deps.pyimport("typing", "Callable");
554
555        let types = mem::take(&mut self.src);
556        let intrinsics = self.intrinsics(iface);
557
558        for (k, v) in self.deps.pyimports.iter() {
559            match v {
560                Some(list) => {
561                    let list = list.iter().cloned().collect::<Vec<_>>().join(", ");
562                    self.src.push_str(&format!("from {} import {}\n", k, list));
563                }
564                None => {
565                    self.src.push_str(&format!("import {}\n", k));
566                }
567            }
568        }
569        self.src.push_str("import wasmer # type: ignore\n");
570        self.src.push_str(
571            "
572                try:
573                    from typing import Protocol
574                except ImportError:
575                    class Protocol: # type: ignore
576                        pass
577            ",
578        );
579        self.src.push_str("\n");
580
581        if self.deps.needs_t_typevar {
582            self.src.push_str("T = TypeVar('T')\n");
583        }
584
585        self.src.push_str(&intrinsics);
586        for (id, r) in iface.resources.iter() {
587            let name = r.name.to_camel_case();
588            if self.in_import {
589                self.src.push_str("@runtime_checkable\n");
590                self.src.push_str(&format!("class {}(Protocol):\n", name));
591                self.src.indent();
592                self.src.push_str("def drop(self) -> None:\n");
593                self.src.indent();
594                self.src.push_str("pass\n");
595                self.src.dedent();
596
597                for (_, funcs) in self.guest_imports.iter() {
598                    if let Some(funcs) = funcs.resource_funcs.get(&id) {
599                        for func in funcs {
600                            self.src.push_str("@abstractmethod\n");
601                            self.src.push_str(&func.pysig);
602                            self.src.push_str(":\n");
603                            self.src.indent();
604                            self.src.push_str("raise NotImplementedError\n");
605                            self.src.dedent();
606                        }
607                    }
608                }
609                self.src.dedent();
610            } else {
611                self.src.push_str(&format!("class {}:\n", name));
612                self.src.indent();
613                self.src.push_str(&format!(
614                    "
615                        _wasm_val: int
616                        _refcnt: int
617                        _obj: '{iface}'
618                        _destroyed: bool
619
620                        def __init__(self, val: int, obj: '{iface}') -> None:
621                            self._wasm_val = val
622                            self._refcnt = 1
623                            self._obj = obj
624                            self._destroyed = False
625
626                        def clone(self) -> '{name}':
627                            self._refcnt += 1
628                            return self
629
630                        def drop(self) -> None:
631                            self._refcnt -= 1;
632                            if self._refcnt != 0:
633                                return
634                            assert(not self._destroyed)
635                            self._destroyed = True
636                            self._obj._canonical_abi_drop_{drop}(self._wasm_val)
637
638                        def __del__(self) -> None:
639                            if not self._destroyed:
640                                raise RuntimeError('wasm object not dropped')
641                    ",
642                    name = name,
643                    iface = iface.name.to_camel_case(),
644                    drop = name.to_snake_case(),
645                ));
646
647                for (_, exports) in self.guest_exports.iter() {
648                    if let Some(funcs) = exports.resource_funcs.get(&id) {
649                        for func in funcs {
650                            self.src.push_str(func);
651                        }
652                    }
653                }
654
655                self.src.dedent();
656            }
657        }
658        self.src.push_str(&types);
659
660        for (module, funcs) in mem::take(&mut self.guest_imports) {
661            self.src
662                .push_str(&format!("class {}(Protocol):\n", module.to_camel_case()));
663            self.src.indent();
664            for func in funcs.freestanding_funcs.iter() {
665                self.src.push_str("@abstractmethod\n");
666                self.src.push_str(&func.pysig);
667                self.src.push_str(":\n");
668                self.src.indent();
669                self.src.push_str("raise NotImplementedError\n");
670                self.src.dedent();
671            }
672            self.src.dedent();
673            self.src.push_str("\n");
674
675            self.src.push_str(&format!(
676                "def add_{}_to_imports(store: wasmer.Store, imports: dict[str, dict[str, Any]], host: {}, get_export: Callable[[str], Any]) -> None:\n",
677                module.to_snake_case(),
678                module.to_camel_case(),
679            ));
680            self.src.indent();
681
682            for (id, r) in iface.resources.iter() {
683                self.src.push_str(&format!(
684                    "_resources{}: Slab[{}] = Slab()\n",
685                    id.index(),
686                    r.name.to_camel_case()
687                ));
688            }
689
690            for func in funcs
691                .freestanding_funcs
692                .iter()
693                .chain(funcs.resource_funcs.values().flatten())
694            {
695                self.src.push_str(&format!("ty = {}\n", func.wasm_ty));
696                self.src.push_str(&func.src);
697                self.src.push_str(&format!(
698                    "imports.setdefault('{}', {{}})['{}'] = wasmer.Function(store, {}, ty)\n",
699                    iface.name,
700                    func.name,
701                    func.name.to_snake_case(),
702                ));
703            }
704
705            for (id, resource) in iface.resources.iter() {
706                let snake = resource.name.to_snake_case();
707
708                self.src.push_str(&format!(
709                    "def resource_drop_{}(i: int) -> None:\n  _resources{}.remove(i).drop()\n",
710                    snake,
711                    id.index(),
712                ));
713                self.src
714                    .push_str("ty = wasmer.FunctionType([wasmer.Type.I32], [])\n");
715                self.src.push_str(&format!(
716                    "imports.setdefault('canonical_abi', {{}})['resource_drop_{}'] = \
717                        wasmer.Function(store, resource_drop_{}, ty)\n",
718                    resource.name, snake,
719                ));
720            }
721            self.src.dedent();
722        }
723
724        // This is exculsively here to get mypy to not complain about empty
725        // modules, this probably won't really get triggered much in practice
726        if !self.in_import && self.guest_exports.is_empty() {
727            self.src
728                .push_str(&format!("class {}:\n", iface.name.to_camel_case()));
729            self.src.indent();
730            if iface.resources.len() == 0 {
731                self.src.push_str("pass\n");
732            } else {
733                for (_, r) in iface.resources.iter() {
734                    self.src.push_str(&format!(
735                        "_canonical_abi_drop_{}: wasmer.Function\n",
736                        r.name.to_snake_case(),
737                    ));
738                }
739            }
740            self.src.dedent();
741        }
742
743        for (module, exports) in mem::take(&mut self.guest_exports) {
744            let module = module.to_camel_case();
745            self.src.push_str(&format!("class {}:\n", module));
746            self.src.indent();
747
748            self.src.push_str("instance: wasmer.Instance\n");
749            for (name, ty) in exports.fields.iter() {
750                self.src
751                    .push_str(&format!("_{}: {}\n", name.to_snake_case(), ty));
752            }
753            for (id, r) in iface.resources.iter() {
754                self.src.push_str(&format!(
755                    "_resource{}_slab: Slab[{}]\n",
756                    id.index(),
757                    r.name.to_camel_case(),
758                ));
759                self.src.push_str(&format!(
760                    "_canonical_abi_drop_{}: wasmer.Function\n",
761                    r.name.to_snake_case(),
762                ));
763            }
764
765            self.src.push_str("def __init__(self, store: wasmer.Store, imports: dict[str, dict[str, Any]], module: wasmer.Module):\n");
766            self.src.indent();
767            for (id, r) in iface.resources.iter() {
768                self.src.push_str(&format!(
769                    "
770                       ty1 = wasmer.FunctionType([wasmer.Type.I32], [])
771                       ty2 = wasmer.FunctionType([wasmer.Type.I32], [wasmer.Type.I32])
772                       def drop_{snake}(idx: int) -> None:
773                            self._resource{idx}_slab.remove(idx).drop();
774                       imports.setdefault('canonical_abi', {{}})['resource_drop_{name}'] = wasmer.Function(store, drop_{snake}, ty1)
775
776                       def clone_{snake}(idx: int) -> int:
777                            obj = self._resource{idx}_slab.get(idx)
778                            return self._resource{idx}_slab.insert(obj.clone())
779                       imports.setdefault('canonical_abi', {{}})['resource_clone_{name}'] = wasmer.Function(store, clone_{snake}, ty2)
780
781                       def get_{snake}(idx: int) -> int:
782                            obj = self._resource{idx}_slab.get(idx)
783                            return obj._wasm_val
784                       imports.setdefault('canonical_abi', {{}})['resource_get_{name}'] = wasmer.Function(store, get_{snake}, ty2)
785
786                       def new_{snake}(val: int) -> int:
787                            return self._resource{idx}_slab.insert({camel}(val, self))
788                       imports.setdefault('canonical_abi', {{}})['resource_new_{name}'] = wasmer.Function(store, new_{snake}, ty2)
789                   ",
790                    name = r.name,
791                    camel = r.name.to_camel_case(),
792                    snake = r.name.to_snake_case(),
793                    idx = id.index(),
794                ));
795            }
796            self.src
797                .push_str("self.instance = wasmer.Instance(module, imports)\n");
798            for (name, ty) in exports.fields.iter() {
799                self.src.push_str(&format!(
800                    "
801                        {snake} = self.instance.exports.__getattribute__('{name}')
802                        assert(isinstance({snake}, {ty}))
803                        self._{snake} = {snake}
804                    ",
805                    name = name,
806                    snake = name.to_snake_case(),
807                    ty = ty,
808                ));
809            }
810            for (id, r) in iface.resources.iter() {
811                self.src.push_str(&format!(
812                    "
813                        self._resource{idx}_slab = Slab()
814                        canon_drop_{snake} = self.instance.exports.__getattribute__('canonical_abi_drop_{name}')
815                        assert(isinstance(canon_drop_{snake}, wasmer.Function))
816                        self._canonical_abi_drop_{snake} = canon_drop_{snake}
817                    ",
818                    idx = id.index(),
819                    name = r.name,
820                    snake = r.name.to_snake_case(),
821                ));
822            }
823            self.src.dedent();
824
825            for func in exports.freestanding_funcs.iter() {
826                self.src.push_str(func);
827            }
828
829            self.src.dedent();
830        }
831
832        files.push("bindings.py", self.src.as_bytes());
833    }
834}
835
836struct FunctionBindgen<'a> {
837    gen: &'a mut WasmerPy,
838    locals: Ns,
839    src: Source,
840    block_storage: Vec<Source>,
841    blocks: Vec<(String, Vec<String>)>,
842    needs_memory: bool,
843    needs_realloc: Option<String>,
844    needs_free: Option<String>,
845    params: Vec<String>,
846    payloads: Vec<String>,
847    src_object: String,
848}
849
850impl FunctionBindgen<'_> {
851    fn new(gen: &mut WasmerPy, params: Vec<String>) -> FunctionBindgen<'_> {
852        let mut locals = Ns::default();
853        locals.insert("len").unwrap(); // python built-in
854        locals.insert("base").unwrap(); // may be used as loop var
855        locals.insert("i").unwrap(); // may be used as loop var
856        for param in params.iter() {
857            locals.insert(param).unwrap();
858        }
859        FunctionBindgen {
860            gen,
861            locals,
862            src: Source::default(),
863            block_storage: Vec::new(),
864            blocks: Vec::new(),
865            needs_memory: false,
866            needs_realloc: None,
867            needs_free: None,
868            params,
869            payloads: Vec::new(),
870            src_object: "self".to_string(),
871        }
872    }
873
874    fn clamp<T>(&mut self, results: &mut Vec<String>, operands: &[String], min: T, max: T)
875    where
876        T: std::fmt::Display,
877    {
878        self.gen.deps.needs_clamp = true;
879        results.push(format!("_clamp({}, {}, {})", operands[0], min, max));
880    }
881
882    fn load(&mut self, ty: &str, offset: i32, operands: &[String], results: &mut Vec<String>) {
883        self.needs_memory = true;
884        self.gen.deps.needs_load = true;
885        let tmp = self.locals.tmp("load");
886        self.src.push_str(&format!(
887            "{} = _load(memory.{}_view, memory, {}, {})\n",
888            tmp, ty, operands[0], offset,
889        ));
890        results.push(tmp);
891    }
892
893    fn store(&mut self, ty: &str, offset: i32, operands: &[String]) {
894        self.needs_memory = true;
895        self.gen.deps.needs_store = true;
896        self.src.push_str(&format!(
897            "_store(memory.{}_view, memory, {}, {}, {})\n",
898            ty, operands[1], offset, operands[0]
899        ));
900    }
901}
902
903impl Bindgen for FunctionBindgen<'_> {
904    type Operand = String;
905
906    fn sizes(&self) -> &SizeAlign {
907        &self.gen.sizes
908    }
909
910    fn push_block(&mut self) {
911        let prev = mem::take(&mut self.src);
912        self.block_storage.push(prev);
913    }
914
915    fn finish_block(&mut self, operands: &mut Vec<String>) {
916        let to_restore = self.block_storage.pop().unwrap();
917        let src = mem::replace(&mut self.src, to_restore);
918        self.blocks.push((src.into(), mem::take(operands)));
919    }
920
921    fn return_pointer(&mut self, _iface: &Interface, _size: usize, _align: usize) -> String {
922        unimplemented!()
923    }
924
925    fn is_list_canonical(&self, iface: &Interface, ty: &Type) -> bool {
926        array_ty(iface, ty).is_some()
927    }
928
929    fn emit(
930        &mut self,
931        iface: &Interface,
932        inst: &Instruction<'_>,
933        operands: &mut Vec<String>,
934        results: &mut Vec<String>,
935    ) {
936        let mut builder = self.src.builder(&mut self.gen.deps, iface);
937        match inst {
938            Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
939            Instruction::I32Const { val } => results.push(val.to_string()),
940            Instruction::ConstZero { tys } => {
941                for t in tys.iter() {
942                    match t {
943                        WasmType::I32 | WasmType::I64 => results.push("0".to_string()),
944                        WasmType::F32 | WasmType::F64 => results.push("0.0".to_string()),
945                    }
946                }
947            }
948
949            // The representation of i32 in Python is a number, so 8/16-bit
950            // values get further clamped to ensure that the upper bits aren't
951            // set when we pass the value, ensuring that only the right number
952            // of bits are transferred.
953            Instruction::U8FromI32 => self.clamp(results, operands, u8::MIN, u8::MAX),
954            Instruction::S8FromI32 => self.clamp(results, operands, i8::MIN, i8::MAX),
955            Instruction::U16FromI32 => self.clamp(results, operands, u16::MIN, u16::MAX),
956            Instruction::S16FromI32 => self.clamp(results, operands, i16::MIN, i16::MAX),
957            // Ensure the bits of the number are treated as unsigned.
958            Instruction::U32FromI32 => {
959                results.push(format!("{} & 0xffffffff", operands[0]));
960            }
961            // All bigints coming from wasm are treated as signed, so convert
962            // it to ensure it's treated as unsigned.
963            Instruction::U64FromI64 => {
964                results.push(format!("{} & 0xffffffffffffffff", operands[0]));
965            }
966            // Nothing to do signed->signed where the representations are the
967            // same.
968            Instruction::S32FromI32 | Instruction::S64FromI64 => {
969                results.push(operands.pop().unwrap())
970            }
971
972            // All values coming from the host and going to wasm need to have
973            // their ranges validated, since the host could give us any value.
974            Instruction::I32FromU8 => self.clamp(results, operands, u8::MIN, u8::MAX),
975            Instruction::I32FromS8 => self.clamp(results, operands, i8::MIN, i8::MAX),
976            Instruction::I32FromU16 => self.clamp(results, operands, u16::MIN, u16::MAX),
977            Instruction::I32FromS16 => self.clamp(results, operands, i16::MIN, i16::MAX),
978            // TODO: need to do something to get this to be represented as signed?
979            Instruction::I32FromU32 => {
980                self.clamp(results, operands, u32::MIN, u32::MAX);
981            }
982            Instruction::I32FromS32 => self.clamp(results, operands, i32::MIN, i32::MAX),
983            // TODO: need to do something to get this to be represented as signed?
984            Instruction::I64FromU64 => self.clamp(results, operands, u64::MIN, u64::MAX),
985            Instruction::I64FromS64 => self.clamp(results, operands, i64::MIN, i64::MAX),
986
987            // Python uses `float` for f32/f64, so everything is equivalent
988            // here.
989            Instruction::Float32FromF32
990            | Instruction::Float64FromF64
991            | Instruction::F32FromFloat32
992            | Instruction::F64FromFloat64 => results.push(operands.pop().unwrap()),
993
994            // Validate that i32 values coming from wasm are indeed valid code
995            // points.
996            Instruction::CharFromI32 => {
997                builder.deps.needs_validate_guest_char = true;
998                results.push(format!("_validate_guest_char({})", operands[0]));
999            }
1000
1001            Instruction::I32FromChar => {
1002                results.push(format!("ord({})", operands[0]));
1003            }
1004
1005            Instruction::Bitcasts { casts } => {
1006                for (cast, op) in casts.iter().zip(operands) {
1007                    match cast {
1008                        Bitcast::I32ToF32 => {
1009                            builder.deps.needs_i32_to_f32 = true;
1010                            results.push(format!("_i32_to_f32({})", op));
1011                        }
1012                        Bitcast::F32ToI32 => {
1013                            builder.deps.needs_f32_to_i32 = true;
1014                            results.push(format!("_f32_to_i32({})", op));
1015                        }
1016                        Bitcast::I64ToF64 => {
1017                            builder.deps.needs_i64_to_f64 = true;
1018                            results.push(format!("_i64_to_f64({})", op));
1019                        }
1020                        Bitcast::F64ToI64 => {
1021                            builder.deps.needs_f64_to_i64 = true;
1022                            results.push(format!("_f64_to_i64({})", op));
1023                        }
1024                        Bitcast::I64ToF32 => {
1025                            builder.deps.needs_i32_to_f32 = true;
1026                            results.push(format!("_i32_to_f32(({}) & 0xffffffff)", op));
1027                        }
1028                        Bitcast::F32ToI64 => {
1029                            builder.deps.needs_f32_to_i32 = true;
1030                            results.push(format!("_f32_to_i32({})", op));
1031                        }
1032                        Bitcast::I32ToI64 | Bitcast::I64ToI32 | Bitcast::None => {
1033                            results.push(op.clone())
1034                        }
1035                    }
1036                }
1037            }
1038
1039            Instruction::UnitLower => {}
1040            Instruction::UnitLift => {
1041                results.push("None".to_string());
1042            }
1043            Instruction::BoolFromI32 => {
1044                let op = self.locals.tmp("operand");
1045                let ret = self.locals.tmp("boolean");
1046                builder.push_str(&format!(
1047                    "
1048                        {op} = {}
1049                        if {op} == 0:
1050                            {ret} = False
1051                        elif {op} == 1:
1052                            {ret} = True
1053                        else:
1054                            raise TypeError(\"invalid variant discriminant for bool\")
1055                    ",
1056                    operands[0]
1057                ));
1058                results.push(ret);
1059            }
1060            Instruction::I32FromBool => {
1061                results.push(format!("int({})", operands[0]));
1062            }
1063
1064            // These instructions are used with handles when we're implementing
1065            // imports. This means we interact with the `resources` slabs to
1066            // translate the wasm-provided index into a Python value.
1067            Instruction::I32FromOwnedHandle { ty } => {
1068                results.push(format!("_resources{}.insert({})", ty.index(), operands[0]));
1069            }
1070            Instruction::HandleBorrowedFromI32 { ty } => {
1071                results.push(format!("_resources{}.get({})", ty.index(), operands[0]));
1072            }
1073
1074            // These instructions are used for handles to objects owned in wasm.
1075            // This means that they're interacting with a wrapper class defined
1076            // in Python.
1077            Instruction::I32FromBorrowedHandle { ty } => {
1078                let obj = self.locals.tmp("obj");
1079                builder.push_str(&format!("{} = {}\n", obj, operands[0]));
1080
1081                results.push(format!(
1082                    "{}._resource{}_slab.insert({}.clone())",
1083                    self.src_object,
1084                    ty.index(),
1085                    obj,
1086                ));
1087            }
1088            Instruction::HandleOwnedFromI32 { ty } => {
1089                results.push(format!(
1090                    "{}._resource{}_slab.remove({})",
1091                    self.src_object,
1092                    ty.index(),
1093                    operands[0],
1094                ));
1095            }
1096            Instruction::RecordLower { record, .. } => {
1097                if record.fields.is_empty() {
1098                    return;
1099                }
1100                let tmp = self.locals.tmp("record");
1101                builder.push_str(&format!("{} = {}\n", tmp, operands[0]));
1102                for field in record.fields.iter() {
1103                    let name = self.locals.tmp("field");
1104                    builder.push_str(&format!(
1105                        "{} = {}.{}\n",
1106                        name,
1107                        tmp,
1108                        field.name.to_snake_case(),
1109                    ));
1110                    results.push(name);
1111                }
1112            }
1113
1114            Instruction::RecordLift { name, .. } => {
1115                results.push(format!("{}({})", name.to_camel_case(), operands.join(", ")));
1116            }
1117            Instruction::TupleLower { tuple, .. } => {
1118                if tuple.types.is_empty() {
1119                    return;
1120                }
1121                builder.push_str("(");
1122                for _ in 0..tuple.types.len() {
1123                    let name = self.locals.tmp("tuplei");
1124                    builder.push_str(&name);
1125                    builder.push_str(",");
1126                    results.push(name);
1127                }
1128                builder.push_str(") = ");
1129                builder.push_str(&operands[0]);
1130                builder.push_str("\n");
1131            }
1132            Instruction::TupleLift { .. } => {
1133                if operands.is_empty() {
1134                    results.push("None".to_string());
1135                } else {
1136                    results.push(format!("({},)", operands.join(", ")));
1137                }
1138            }
1139            Instruction::FlagsLift { name, .. } => {
1140                let operand = match operands.len() {
1141                    1 => operands[0].clone(),
1142                    _ => {
1143                        let tmp = self.locals.tmp("flags");
1144                        builder.push_str(&format!("{tmp} = 0\n"));
1145                        for (i, op) in operands.iter().enumerate() {
1146                            let i = 32 * i;
1147                            builder.push_str(&format!("{tmp} |= {op} << {i}\n"));
1148                        }
1149                        tmp
1150                    }
1151                };
1152                results.push(format!("{}({})", name.to_camel_case(), operand));
1153            }
1154            Instruction::FlagsLower { flags, .. } => match flags.repr().count() {
1155                1 => results.push(format!("({}).value", operands[0])),
1156                n => {
1157                    let tmp = self.locals.tmp("flags");
1158                    self.src
1159                        .push_str(&format!("{tmp} = ({}).value\n", operands[0]));
1160                    for i in 0..n {
1161                        let i = 32 * i;
1162                        results.push(format!("({tmp} >> {i}) & 0xffffffff"));
1163                    }
1164                }
1165            },
1166
1167            Instruction::VariantPayloadName => {
1168                let name = self.locals.tmp("payload");
1169                results.push(name.clone());
1170                self.payloads.push(name);
1171            }
1172
1173            Instruction::VariantLower {
1174                variant,
1175                results: result_types,
1176                name,
1177                ..
1178            } => {
1179                let blocks = self
1180                    .blocks
1181                    .drain(self.blocks.len() - variant.cases.len()..)
1182                    .collect::<Vec<_>>();
1183                let payloads = self
1184                    .payloads
1185                    .drain(self.payloads.len() - variant.cases.len()..)
1186                    .collect::<Vec<_>>();
1187
1188                for _ in 0..result_types.len() {
1189                    results.push(self.locals.tmp("variant"));
1190                }
1191
1192                for (i, ((case, (block, block_results)), payload)) in
1193                    variant.cases.iter().zip(blocks).zip(payloads).enumerate()
1194                {
1195                    if i == 0 {
1196                        builder.push_str("if ");
1197                    } else {
1198                        builder.push_str("elif ");
1199                    }
1200
1201                    builder.push_str(&format!(
1202                        "isinstance({}, {}{}):\n",
1203                        operands[0],
1204                        name.to_camel_case(),
1205                        case.name.to_camel_case()
1206                    ));
1207                    builder.indent();
1208                    builder.push_str(&format!("{} = {}.value\n", payload, operands[0]));
1209                    builder.push_str(&block);
1210
1211                    for (i, result) in block_results.iter().enumerate() {
1212                        builder.push_str(&format!("{} = {}\n", results[i], result));
1213                    }
1214                    builder.dedent();
1215                }
1216                let variant_name = name.to_camel_case();
1217                builder.push_str("else:\n");
1218                builder.indent();
1219                builder.push_str(&format!(
1220                    "raise TypeError(\"invalid variant specified for {}\")\n",
1221                    variant_name
1222                ));
1223                builder.dedent();
1224            }
1225
1226            Instruction::VariantLift {
1227                variant, name, ty, ..
1228            } => {
1229                let blocks = self
1230                    .blocks
1231                    .drain(self.blocks.len() - variant.cases.len()..)
1232                    .collect::<Vec<_>>();
1233
1234                let result = self.locals.tmp("variant");
1235                builder.print_var_declaration(&result, &Type::Id(*ty));
1236                for (i, (case, (block, block_results))) in
1237                    variant.cases.iter().zip(blocks).enumerate()
1238                {
1239                    if i == 0 {
1240                        builder.push_str("if ");
1241                    } else {
1242                        builder.push_str("elif ");
1243                    }
1244                    builder.push_str(&format!("{} == {}:\n", operands[0], i));
1245                    builder.indent();
1246                    builder.push_str(&block);
1247
1248                    builder.push_str(&format!(
1249                        "{} = {}{}(",
1250                        result,
1251                        name.to_camel_case(),
1252                        case.name.to_camel_case()
1253                    ));
1254                    assert!(block_results.len() == 1);
1255                    builder.push_str(&block_results[0]);
1256                    builder.push_str(")\n");
1257                    builder.dedent();
1258                }
1259                builder.push_str("else:\n");
1260                builder.indent();
1261                let variant_name = name.to_camel_case();
1262                builder.push_str(&format!(
1263                    "raise TypeError(\"invalid variant discriminant for {}\")\n",
1264                    variant_name
1265                ));
1266                builder.dedent();
1267                results.push(result);
1268            }
1269
1270            Instruction::UnionLower {
1271                union,
1272                results: result_types,
1273                name,
1274                ..
1275            } => {
1276                let blocks = self
1277                    .blocks
1278                    .drain(self.blocks.len() - union.cases.len()..)
1279                    .collect::<Vec<_>>();
1280                let payloads = self
1281                    .payloads
1282                    .drain(self.payloads.len() - union.cases.len()..)
1283                    .collect::<Vec<_>>();
1284
1285                for _ in 0..result_types.len() {
1286                    results.push(self.locals.tmp("variant"));
1287                }
1288
1289                // Assumes that type_union has been called for this union
1290                let union_representation = *self
1291                    .gen
1292                    .union_representation
1293                    .get(&name.to_string())
1294                    .unwrap();
1295                let name = name.to_camel_case();
1296                let op0 = &operands[0];
1297                for (i, ((case, (block, block_results)), payload)) in
1298                    union.cases.iter().zip(blocks).zip(payloads).enumerate()
1299                {
1300                    builder.push_str(if i == 0 { "if " } else { "elif " });
1301                    builder.push_str(&format!("isinstance({op0}, "));
1302                    match union_representation {
1303                        // Prints the Python type for this union case
1304                        PyUnionRepresentation::Raw => {
1305                            builder.print_ty(&case.ty, false);
1306                        }
1307                        // Prints the name of this union cases dataclass
1308                        PyUnionRepresentation::Wrapped => {
1309                            builder.push_str(&format!("{name}{i}"));
1310                        }
1311                    }
1312                    builder.push_str("):\n");
1313                    builder.indent();
1314                    match union_representation {
1315                        // Uses the value directly
1316                        PyUnionRepresentation::Raw => {
1317                            builder.push_str(&format!("{payload} = {op0}\n"))
1318                        }
1319                        // Uses this union case dataclass's inner value
1320                        PyUnionRepresentation::Wrapped => {
1321                            builder.push_str(&format!("{payload} = {op0}.value\n"))
1322                        }
1323                    }
1324                    builder.push_str(&block);
1325                    for (i, result) in block_results.iter().enumerate() {
1326                        builder.push_str(&format!("{} = {result}\n", results[i]));
1327                    }
1328                    builder.dedent();
1329                }
1330                builder.push_str("else:\n");
1331                builder.indent();
1332                builder.push_str(&format!(
1333                    "raise TypeError(\"invalid variant specified for {name}\")\n"
1334                ));
1335                builder.dedent();
1336            }
1337
1338            Instruction::UnionLift {
1339                union, name, ty, ..
1340            } => {
1341                let blocks = self
1342                    .blocks
1343                    .drain(self.blocks.len() - union.cases.len()..)
1344                    .collect::<Vec<_>>();
1345
1346                let result = self.locals.tmp("variant");
1347                builder.print_var_declaration(&result, &Type::Id(*ty));
1348                // Assumes that type_union has been called for this union
1349                let union_representation = *self
1350                    .gen
1351                    .union_representation
1352                    .get(&name.to_string())
1353                    .unwrap();
1354                let name = name.to_camel_case();
1355                let op0 = &operands[0];
1356                for (i, (_case, (block, block_results))) in
1357                    union.cases.iter().zip(blocks).enumerate()
1358                {
1359                    builder.push_str(if i == 0 { "if " } else { "elif " });
1360                    builder.push_str(&format!("{op0} == {i}:\n"));
1361                    builder.indent();
1362                    builder.push_str(&block);
1363                    assert!(block_results.len() == 1);
1364                    let block_result = &block_results[0];
1365                    builder.push_str(&format!("{result} = "));
1366                    match union_representation {
1367                        // Uses the passed value directly
1368                        PyUnionRepresentation::Raw => builder.push_str(block_result),
1369                        // Constructs an instance of the union cases dataclass
1370                        PyUnionRepresentation::Wrapped => {
1371                            builder.push_str(&format!("{name}{i}({block_result})"))
1372                        }
1373                    }
1374                    builder.newline();
1375                    builder.dedent();
1376                }
1377                builder.push_str("else:\n");
1378                builder.indent();
1379                builder.push_str(&format!(
1380                    "raise TypeError(\"invalid variant discriminant for {name}\")\n",
1381                ));
1382                builder.dedent();
1383                results.push(result);
1384            }
1385
1386            Instruction::OptionLower {
1387                results: result_types,
1388                ..
1389            } => {
1390                let (some, some_results) = self.blocks.pop().unwrap();
1391                let (none, none_results) = self.blocks.pop().unwrap();
1392                let some_payload = self.payloads.pop().unwrap();
1393                let _none_payload = self.payloads.pop().unwrap();
1394
1395                for _ in 0..result_types.len() {
1396                    results.push(self.locals.tmp("variant"));
1397                }
1398
1399                let op0 = &operands[0];
1400                builder.push_str(&format!("if {op0} is None:\n"));
1401
1402                builder.indent();
1403                builder.push_str(&none);
1404                for (dst, result) in results.iter().zip(&none_results) {
1405                    builder.push_str(&format!("{dst} = {result}\n"));
1406                }
1407                builder.dedent();
1408                builder.push_str("else:\n");
1409                builder.indent();
1410                builder.push_str(&format!("{some_payload} = {op0}\n"));
1411                builder.push_str(&some);
1412                for (dst, result) in results.iter().zip(&some_results) {
1413                    builder.push_str(&format!("{dst} = {result}\n"));
1414                }
1415                builder.dedent();
1416            }
1417
1418            Instruction::OptionLift { ty, .. } => {
1419                let (some, some_results) = self.blocks.pop().unwrap();
1420                let (none, none_results) = self.blocks.pop().unwrap();
1421                assert!(none_results.len() == 1);
1422                assert!(some_results.len() == 1);
1423                let some_result = &some_results[0];
1424                assert_eq!(none_results[0], "None");
1425
1426                let result = self.locals.tmp("option");
1427                builder.print_var_declaration(&result, &Type::Id(*ty));
1428
1429                let op0 = &operands[0];
1430                builder.push_str(&format!("if {op0} == 0:\n"));
1431                builder.indent();
1432                builder.push_str(&none);
1433                builder.push_str(&format!("{result} = None\n"));
1434                builder.dedent();
1435                builder.push_str(&format!("elif {op0} == 1:\n"));
1436                builder.indent();
1437                builder.push_str(&some);
1438                builder.push_str(&format!("{result} = {some_result}\n"));
1439                builder.dedent();
1440
1441                builder.push_str("else:\n");
1442                builder.indent();
1443                builder.push_str("raise TypeError(\"invalid variant discriminant for option\")\n");
1444                builder.dedent();
1445
1446                results.push(result);
1447            }
1448
1449            Instruction::ExpectedLower {
1450                results: result_types,
1451                ..
1452            } => {
1453                let (err, err_results) = self.blocks.pop().unwrap();
1454                let (ok, ok_results) = self.blocks.pop().unwrap();
1455                let err_payload = self.payloads.pop().unwrap();
1456                let ok_payload = self.payloads.pop().unwrap();
1457
1458                for _ in 0..result_types.len() {
1459                    results.push(self.locals.tmp("variant"));
1460                }
1461
1462                let op0 = &operands[0];
1463                builder.push_str(&format!("if isinstance({op0}, Ok):\n"));
1464
1465                builder.indent();
1466                builder.push_str(&format!("{ok_payload} = {op0}.value\n"));
1467                builder.push_str(&ok);
1468                for (dst, result) in results.iter().zip(&ok_results) {
1469                    builder.push_str(&format!("{dst} = {result}\n"));
1470                }
1471                builder.dedent();
1472                builder.push_str(&format!("elif isinstance({op0}, Err):\n"));
1473                builder.indent();
1474                builder.push_str(&format!("{err_payload} = {op0}.value\n"));
1475                builder.push_str(&err);
1476                for (dst, result) in results.iter().zip(&err_results) {
1477                    builder.push_str(&format!("{dst} = {result}\n"));
1478                }
1479                builder.dedent();
1480                builder.push_str("else:\n");
1481                builder.indent();
1482                builder.push_str("raise TypeError(\"invalid variant specified for expected\")\n");
1483                builder.dedent();
1484            }
1485            Instruction::ExpectedLift { ty, .. } => {
1486                let (err, err_results) = self.blocks.pop().unwrap();
1487                let (ok, ok_results) = self.blocks.pop().unwrap();
1488                assert!(err_results.len() == 1);
1489                let err_result = &err_results[0];
1490                assert!(ok_results.len() == 1);
1491                let ok_result = &ok_results[0];
1492
1493                let result = self.locals.tmp("expected");
1494                builder.print_var_declaration(&result, &Type::Id(*ty));
1495
1496                let op0 = &operands[0];
1497                builder.push_str(&format!("if {op0} == 0:\n"));
1498                builder.indent();
1499                builder.push_str(&ok);
1500                builder.push_str(&format!("{result} = Ok({ok_result})\n"));
1501                builder.dedent();
1502                builder.push_str(&format!("elif {op0} == 1:\n"));
1503                builder.indent();
1504                builder.push_str(&err);
1505                builder.push_str(&format!("{result} = Err({err_result})\n"));
1506                builder.dedent();
1507
1508                builder.push_str("else:\n");
1509                builder.indent();
1510                builder
1511                    .push_str("raise TypeError(\"invalid variant discriminant for expected\")\n");
1512                builder.dedent();
1513
1514                results.push(result);
1515            }
1516
1517            Instruction::EnumLower { .. } => results.push(format!("({}).value", operands[0])),
1518
1519            Instruction::EnumLift { name, .. } => {
1520                results.push(format!("{}({})", name.to_camel_case(), operands[0]));
1521            }
1522
1523            Instruction::ListCanonLower { element, realloc } => {
1524                // Lowering only happens when we're passing lists into wasm,
1525                // which forces us to always allocate, so this should always be
1526                // `Some`.
1527                let realloc = realloc.unwrap();
1528                self.needs_memory = true;
1529                self.needs_realloc = Some(realloc.to_string());
1530
1531                let ptr = self.locals.tmp("ptr");
1532                let len = self.locals.tmp("len");
1533                let array_ty = array_ty(iface, element).unwrap();
1534                builder.deps.needs_list_canon_lower = true;
1535                let size = self.gen.sizes.size(element);
1536                let align = self.gen.sizes.align(element);
1537                builder.push_str(&format!(
1538                    "{}, {} = _list_canon_lower({}, memory.{}_view, {}, {}, realloc, memory)\n",
1539                    ptr, len, operands[0], array_ty, size, align,
1540                ));
1541                results.push(ptr);
1542                results.push(len);
1543            }
1544            Instruction::ListCanonLift { element, free, .. } => {
1545                self.needs_memory = true;
1546                let ptr = self.locals.tmp("ptr");
1547                let len = self.locals.tmp("len");
1548                builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1549                builder.push_str(&format!("{} = {}\n", len, operands[1]));
1550                let array_ty = array_ty(iface, element).unwrap();
1551                builder.deps.needs_list_canon_lift = true;
1552                let lift = format!(
1553                    "_list_canon_lift({}, {}, {}, memory.{}_view, memory)",
1554                    ptr,
1555                    len,
1556                    self.gen.sizes.size(element),
1557                    array_ty,
1558                );
1559                builder.deps.pyimport("typing", "cast");
1560                let align = self.gen.sizes.align(element);
1561                match free {
1562                    Some(free) => {
1563                        self.needs_free = Some(free.to_string());
1564                        let list = self.locals.tmp("list");
1565                        builder.push_str(&list);
1566                        builder.push_str(" = cast(");
1567                        builder.print_list(element);
1568                        builder.push_str(", ");
1569                        builder.push_str(&lift);
1570                        builder.push_str(")\n");
1571                        builder.push_str(&format!("free({}, {}, {})\n", ptr, len, align));
1572                        results.push(list);
1573                    }
1574                    None => {
1575                        let mut result_src = Source::default();
1576                        drop(builder);
1577                        let mut builder = result_src.builder(&mut self.gen.deps, iface);
1578                        builder.push_str("cast(");
1579                        builder.print_list(element);
1580                        builder.push_str(", ");
1581                        builder.push_str(&lift);
1582                        builder.push_str(")");
1583                        results.push(result_src.to_string());
1584                    }
1585                }
1586            }
1587
1588            Instruction::StringLower { realloc } => {
1589                // Lowering only happens when we're passing strings into wasm,
1590                // which forces us to always allocate, so this should always be
1591                // `Some`.
1592                let realloc = realloc.unwrap();
1593                self.needs_memory = true;
1594                self.needs_realloc = Some(realloc.to_string());
1595
1596                let ptr = self.locals.tmp("ptr");
1597                let len = self.locals.tmp("len");
1598                builder.deps.needs_encode_utf8 = true;
1599                builder.push_str(&format!(
1600                    "{}, {} = _encode_utf8({}, realloc, memory)\n",
1601                    ptr, len, operands[0],
1602                ));
1603                results.push(ptr);
1604                results.push(len);
1605            }
1606            Instruction::StringLift { free, .. } => {
1607                self.needs_memory = true;
1608                let ptr = self.locals.tmp("ptr");
1609                let len = self.locals.tmp("len");
1610                builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1611                builder.push_str(&format!("{} = {}\n", len, operands[1]));
1612                builder.deps.needs_decode_utf8 = true;
1613                let result = format!("_decode_utf8(memory, {}, {})", ptr, len);
1614                match free {
1615                    Some(free) => {
1616                        self.needs_free = Some(free.to_string());
1617                        let list = self.locals.tmp("list");
1618                        builder.push_str(&format!("{} = {}\n", list, result));
1619                        self.src.push_str(&format!("free({}, {}, 1)\n", ptr, len));
1620                        results.push(list);
1621                    }
1622                    None => results.push(result),
1623                }
1624            }
1625
1626            Instruction::ListLower { element, realloc } => {
1627                let base = self.payloads.pop().unwrap();
1628                let e = self.payloads.pop().unwrap();
1629                let realloc = realloc.unwrap();
1630                let (body, body_results) = self.blocks.pop().unwrap();
1631                assert!(body_results.is_empty());
1632                let vec = self.locals.tmp("vec");
1633                let result = self.locals.tmp("result");
1634                let len = self.locals.tmp("len");
1635                self.needs_realloc = Some(realloc.to_string());
1636                let size = self.gen.sizes.size(element);
1637                let align = self.gen.sizes.align(element);
1638
1639                // first store our vec-to-lower in a temporary since we'll
1640                // reference it multiple times.
1641                builder.push_str(&format!("{} = {}\n", vec, operands[0]));
1642                builder.push_str(&format!("{} = len({})\n", len, vec));
1643
1644                // ... then realloc space for the result in the guest module
1645                builder.push_str(&format!(
1646                    "{} = realloc(0, 0, {}, {} * {})\n",
1647                    result, align, len, size,
1648                ));
1649                builder.push_str(&format!("assert(isinstance({}, int))\n", result));
1650
1651                // ... then consume the vector and use the block to lower the
1652                // result.
1653                let i = self.locals.tmp("i");
1654                builder.push_str(&format!("for {} in range(0, {}):\n", i, len));
1655                builder.indent();
1656                builder.push_str(&format!("{} = {}[{}]\n", e, vec, i));
1657                builder.push_str(&format!("{} = {} + {} * {}\n", base, result, i, size));
1658                builder.push_str(&body);
1659                builder.dedent();
1660
1661                results.push(result);
1662                results.push(len);
1663            }
1664
1665            Instruction::ListLift { element, free, .. } => {
1666                let (body, body_results) = self.blocks.pop().unwrap();
1667                let base = self.payloads.pop().unwrap();
1668                let size = self.gen.sizes.size(element);
1669                let align = self.gen.sizes.align(element);
1670                let ptr = self.locals.tmp("ptr");
1671                let len = self.locals.tmp("len");
1672                builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1673                builder.push_str(&format!("{} = {}\n", len, operands[1]));
1674                let result = self.locals.tmp("result");
1675                builder.push_str(&format!("{}: List[", result));
1676                builder.print_ty(element, true);
1677                builder.push_str("] = []\n");
1678
1679                let i = self.locals.tmp("i");
1680                builder.push_str(&format!("for {} in range(0, {}):\n", i, len));
1681                builder.indent();
1682                builder.push_str(&format!("{} = {} + {} * {}\n", base, ptr, i, size));
1683                builder.push_str(&body);
1684                assert_eq!(body_results.len(), 1);
1685                builder.push_str(&format!("{}.append({})\n", result, body_results[0]));
1686                builder.dedent();
1687
1688                if let Some(free) = free {
1689                    self.needs_free = Some(free.to_string());
1690                    builder.push_str(&format!("free({}, {} * {}, {})\n", ptr, len, size, align,));
1691                }
1692                results.push(result);
1693            }
1694
1695            Instruction::IterElem { .. } => {
1696                let name = self.locals.tmp("e");
1697                results.push(name.clone());
1698                self.payloads.push(name);
1699            }
1700            Instruction::IterBasePointer => {
1701                let name = self.locals.tmp("base");
1702                results.push(name.clone());
1703                self.payloads.push(name);
1704            }
1705            Instruction::CallWasm {
1706                iface: _,
1707                name,
1708                sig,
1709            } => {
1710                if !sig.results.is_empty() {
1711                    for i in 0..sig.results.len() {
1712                        if i > 0 {
1713                            builder.push_str(", ");
1714                        }
1715                        let ret = self.locals.tmp("ret");
1716                        builder.push_str(&ret);
1717                        results.push(ret);
1718                    }
1719                    builder.push_str(" = ");
1720                }
1721                builder.push_str(&self.src_object);
1722                builder.push_str("._");
1723                builder.push_str(&name.to_snake_case());
1724                builder.push_str("(");
1725                builder.push_str(&operands.join(", "));
1726                builder.push_str(")\n");
1727                for (ty, name) in sig.results.iter().zip(results.iter()) {
1728                    let ty = match ty {
1729                        WasmType::I32 | WasmType::I64 => "int",
1730                        WasmType::F32 | WasmType::F64 => "float",
1731                    };
1732                    self.src
1733                        .push_str(&format!("assert(isinstance({}, {}))\n", name, ty));
1734                }
1735            }
1736            Instruction::CallInterface { module: _, func } => {
1737                match &func.result {
1738                    Type::Unit => {
1739                        results.push("".to_string());
1740                    }
1741                    _ => {
1742                        let result = self.locals.tmp("ret");
1743                        builder.push_str(&result);
1744                        results.push(result);
1745                        builder.push_str(" = ");
1746                    }
1747                }
1748                match &func.kind {
1749                    FunctionKind::Freestanding | FunctionKind::Static { .. } => {
1750                        builder.push_str(&format!(
1751                            "host.{}({})",
1752                            func.name.to_snake_case(),
1753                            operands.join(", "),
1754                        ));
1755                    }
1756                    FunctionKind::Method { name, .. } => {
1757                        builder.push_str(&format!(
1758                            "{}.{}({})",
1759                            operands[0],
1760                            name.to_snake_case(),
1761                            operands[1..].join(", "),
1762                        ));
1763                    }
1764                }
1765                builder.push_str("\n");
1766            }
1767
1768            Instruction::Return { amt, .. } => match amt {
1769                0 => {}
1770                1 => builder.push_str(&format!("return {}\n", operands[0])),
1771                _ => {
1772                    self.src
1773                        .push_str(&format!("return ({})\n", operands.join(", ")));
1774                }
1775            },
1776
1777            Instruction::I32Load { offset } => self.load("int32", *offset, operands, results),
1778            Instruction::I64Load { offset } => self.load("int64", *offset, operands, results),
1779            Instruction::F32Load { offset } => self.load("float32", *offset, operands, results),
1780            Instruction::F64Load { offset } => self.load("float64", *offset, operands, results),
1781            Instruction::I32Load8U { offset } => self.load("uint8", *offset, operands, results),
1782            Instruction::I32Load8S { offset } => self.load("int8", *offset, operands, results),
1783            Instruction::I32Load16U { offset } => self.load("uint16", *offset, operands, results),
1784            Instruction::I32Load16S { offset } => self.load("int16", *offset, operands, results),
1785            Instruction::I32Store { offset } => self.store("uint32", *offset, operands),
1786            Instruction::I64Store { offset } => self.store("uint64", *offset, operands),
1787            Instruction::F32Store { offset } => self.store("float32", *offset, operands),
1788            Instruction::F64Store { offset } => self.store("float64", *offset, operands),
1789            Instruction::I32Store8 { offset } => self.store("uint8", *offset, operands),
1790            Instruction::I32Store16 { offset } => self.store("uint16", *offset, operands),
1791
1792            Instruction::Malloc {
1793                realloc,
1794                size,
1795                align,
1796            } => {
1797                self.needs_realloc = Some(realloc.to_string());
1798                let ptr = self.locals.tmp("ptr");
1799                builder.push_str(&format!(
1800                    "
1801                        {ptr} = realloc(0, 0, {align}, {size})
1802                        assert(isinstance({ptr}, int))
1803                    ",
1804                ));
1805                results.push(ptr);
1806            }
1807
1808            i => unimplemented!("{:?}", i),
1809        }
1810    }
1811}
1812
1813fn py_type_class_of(ty: &Type) -> PyTypeClass {
1814    match ty {
1815        Type::Unit => PyTypeClass::None,
1816        Type::Bool
1817        | Type::U8
1818        | Type::U16
1819        | Type::U32
1820        | Type::U64
1821        | Type::S8
1822        | Type::S16
1823        | Type::S32
1824        | Type::S64 => PyTypeClass::Int,
1825        Type::Float32 | Type::Float64 => PyTypeClass::Float,
1826        Type::Char | Type::String => PyTypeClass::Str,
1827        Type::Handle(_) | Type::Id(_) => PyTypeClass::Custom,
1828    }
1829}
1830
1831#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1832enum PyTypeClass {
1833    None,
1834    Int,
1835    Str,
1836    Float,
1837    Custom,
1838}
1839
1840fn wasm_ty_ctor(ty: WasmType) -> &'static str {
1841    match ty {
1842        WasmType::I32 => "wasmer.Type.I32",
1843        WasmType::I64 => "wasmer.Type.I64",
1844        WasmType::F32 => "wasmer.Type.F32",
1845        WasmType::F64 => "wasmer.Type.F64",
1846    }
1847}
1848
1849fn wasm_ty_typing(ty: WasmType) -> &'static str {
1850    match ty {
1851        WasmType::I32 => "int",
1852        WasmType::I64 => "int",
1853        WasmType::F32 => "float",
1854        WasmType::F64 => "float",
1855    }
1856}