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 deps: Dependencies,
25 union_representation: HashMap<String, PyUnionRepresentation>,
27}
28
29#[derive(Debug, Clone, Copy)]
30enum PyUnionRepresentation {
31 Raw,
33 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 match dir {
87 Direction::Import => AbiVariant::GuestExport,
88 Direction::Export => AbiVariant::GuestImport,
89 }
90 }
91
92 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 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 self.union_representation
255 .insert(name.to_string(), PyUnionRepresentation::Wrapped);
256 builder.print_union_wrapped(name, union, docs);
257 } else {
258 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 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 }
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 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 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 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 let params = builder.print_sig(func, self.in_import);
476 builder.push_str(":\n");
477 builder.indent();
478 drop(builder);
479
480 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 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 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(); locals.insert("base").unwrap(); locals.insert("i").unwrap(); 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 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 Instruction::U32FromI32 => {
959 results.push(format!("{} & 0xffffffff", operands[0]));
960 }
961 Instruction::U64FromI64 => {
964 results.push(format!("{} & 0xffffffffffffffff", operands[0]));
965 }
966 Instruction::S32FromI32 | Instruction::S64FromI64 => {
969 results.push(operands.pop().unwrap())
970 }
971
972 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 Instruction::I32FromU32 => {
980 self.clamp(results, operands, u32::MIN, u32::MAX);
981 }
982 Instruction::I32FromS32 => self.clamp(results, operands, i32::MIN, i32::MAX),
983 Instruction::I64FromU64 => self.clamp(results, operands, u64::MIN, u64::MAX),
985 Instruction::I64FromS64 => self.clamp(results, operands, i64::MIN, i64::MAX),
986
987 Instruction::Float32FromF32
990 | Instruction::Float64FromF64
991 | Instruction::F32FromFloat32
992 | Instruction::F64FromFloat64 => results.push(operands.pop().unwrap()),
993
994 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 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 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 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 PyUnionRepresentation::Raw => {
1305 builder.print_ty(&case.ty, false);
1306 }
1307 PyUnionRepresentation::Wrapped => {
1309 builder.push_str(&format!("{name}{i}"));
1310 }
1311 }
1312 builder.push_str("):\n");
1313 builder.indent();
1314 match union_representation {
1315 PyUnionRepresentation::Raw => {
1317 builder.push_str(&format!("{payload} = {op0}\n"))
1318 }
1319 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 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 PyUnionRepresentation::Raw => builder.push_str(block_result),
1369 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 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 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 builder.push_str(&format!("{} = {}\n", vec, operands[0]));
1642 builder.push_str(&format!("{} = len({})\n", len, vec));
1643
1644 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 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}