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 WasmtimePy {
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) -> WasmtimePy {
66 let mut r = WasmtimePy::new();
67 r.opts = self;
68 r
69 }
70}
71
72impl WasmtimePy {
73 pub fn new() -> WasmtimePy {
74 WasmtimePy::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("c_uint8"),
106 Type::S8 => Some("c_int8"),
107 Type::U16 => Some("c_uint16"),
108 Type::S16 => Some("c_int16"),
109 Type::U32 => Some("c_uint32"),
110 Type::S32 => Some("c_int32"),
111 Type::U64 => Some("c_uint64"),
112 Type::S64 => Some("c_int64"),
113 Type::Float32 => Some("c_float"),
114 Type::Float64 => Some("c_double"),
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 WasmtimePy {
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!(
366 "def {}(caller: wasmtime.Caller",
367 func.name.to_snake_case(),
368 ));
369 let mut params = Vec::new();
370 for (i, param) in sig.params.iter().enumerate() {
371 builder.push_str(", ");
372 let name = format!("arg{}", i);
373 builder.push_str(&name);
374 builder.push_str(": ");
375 builder.push_str(wasm_ty_typing(*param));
376 params.push(name);
377 }
378 builder.push_str(") -> ");
379 match sig.results.len() {
380 0 => builder.push_str("None"),
381 1 => builder.push_str(wasm_ty_typing(sig.results[0])),
382 _ => unimplemented!(),
383 }
384 builder.push_str(":\n");
385 builder.indent();
386 drop(builder);
387
388 let mut f = FunctionBindgen::new(self, params);
389 iface.call(
390 AbiVariant::GuestImport,
391 LiftLower::LiftArgsLowerResults,
392 func,
393 &mut f,
394 );
395
396 let FunctionBindgen {
397 src,
398 needs_memory,
399 needs_realloc,
400 needs_free,
401 mut locals,
402 ..
403 } = f;
404
405 let mut builder = func_body.builder(&mut self.deps, iface);
406 if needs_memory {
407 builder.push_str("m = caller[\"memory\"]\n");
409 builder.push_str("assert(isinstance(m, wasmtime.Memory))\n");
410 builder.deps.pyimport("typing", "cast");
411 builder.push_str("memory = cast(wasmtime.Memory, m)\n");
412 locals.insert("memory").unwrap();
413 }
414
415 if let Some(name) = needs_realloc {
416 builder.push_str(&format!("realloc = caller[\"{}\"]\n", name));
417 builder.push_str("assert(isinstance(realloc, wasmtime.Func))\n");
418 locals.insert("realloc").unwrap();
419 }
420
421 if let Some(name) = needs_free {
422 builder.push_str(&format!("free = caller[\"{}\"]\n", name));
423 builder.push_str("assert(isinstance(free, wasmtime.Func))\n");
424 locals.insert("free").unwrap();
425 }
426 builder.push_str(&src);
427 builder.dedent();
428
429 let mut wasm_ty = String::from("wasmtime.FuncType([");
430 wasm_ty.push_str(
431 &sig.params
432 .iter()
433 .map(|t| wasm_ty_ctor(*t))
434 .collect::<Vec<_>>()
435 .join(", "),
436 );
437 wasm_ty.push_str("], [");
438 wasm_ty.push_str(
439 &sig.results
440 .iter()
441 .map(|t| wasm_ty_ctor(*t))
442 .collect::<Vec<_>>()
443 .join(", "),
444 );
445 wasm_ty.push_str("])");
446 let import = Import {
447 name: func.name.clone(),
448 src: func_body,
449 wasm_ty,
450 pysig,
451 };
452 let imports = self
453 .guest_imports
454 .entry(iface.name.to_string())
455 .or_default();
456 let dst = match &func.kind {
457 FunctionKind::Freestanding | FunctionKind::Static { .. } => {
458 &mut imports.freestanding_funcs
459 }
460 FunctionKind::Method { resource, .. } => {
461 imports.resource_funcs.entry(*resource).or_default()
462 }
463 };
464 dst.push(import);
465 }
466
467 fn import(&mut self, iface: &Interface, func: &Function) {
471 assert!(!func.is_async, "async not supported yet");
472 let mut func_body = Source::default();
473 let mut builder = func_body.builder(&mut self.deps, iface);
474
475 let params = builder.print_sig(func, self.in_import);
477 builder.push_str(":\n");
478 builder.indent();
479 drop(builder);
480
481 let src_object = match &func.kind {
483 FunctionKind::Freestanding => "self".to_string(),
484 FunctionKind::Static { .. } => "obj".to_string(),
485 FunctionKind::Method { .. } => "self._obj".to_string(),
486 };
487 let mut f = FunctionBindgen::new(self, params);
488 f.src_object = src_object;
489 iface.call(
490 AbiVariant::GuestExport,
491 LiftLower::LowerArgsLiftResults,
492 func,
493 &mut f,
494 );
495 let FunctionBindgen {
496 src,
497 needs_memory,
498 needs_realloc,
499 needs_free,
500 src_object,
501 ..
502 } = f;
503 let mut builder = func_body.builder(&mut self.deps, iface);
504 if needs_memory {
505 builder.push_str(&format!("memory = {}._memory;\n", src_object));
507 }
508
509 if let Some(name) = &needs_realloc {
510 builder.push_str(&format!(
511 "realloc = {}._{}\n",
512 src_object,
513 name.to_snake_case(),
514 ));
515 }
516
517 if let Some(name) = &needs_free {
518 builder.push_str(&format!(
519 "free = {}._{}\n",
520 src_object,
521 name.to_snake_case(),
522 ));
523 }
524 builder.push_str(&src);
525 builder.dedent();
526
527 let exports = self
528 .guest_exports
529 .entry(iface.name.to_string())
530 .or_insert_with(Exports::default);
531 if needs_memory {
532 exports
533 .fields
534 .insert("memory".to_string(), "wasmtime.Memory");
535 }
536 if let Some(name) = &needs_realloc {
537 exports.fields.insert(name.clone(), "wasmtime.Func");
538 }
539 if let Some(name) = &needs_free {
540 exports.fields.insert(name.clone(), "wasmtime.Func");
541 }
542 exports.fields.insert(func.name.clone(), "wasmtime.Func");
543
544 let dst = match &func.kind {
545 FunctionKind::Freestanding => &mut exports.freestanding_funcs,
546 FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => {
547 exports.resource_funcs.entry(*resource).or_default()
548 }
549 };
550 dst.push(func_body);
551 }
552
553 fn finish_one(&mut self, iface: &Interface, files: &mut Files) {
554 self.deps.pyimport("typing", "Any");
555 self.deps.pyimport("abc", "abstractmethod");
556
557 let types = mem::take(&mut self.src);
558 let intrinsics = self.intrinsics(iface);
559
560 for (k, v) in self.deps.pyimports.iter() {
561 match v {
562 Some(list) => {
563 let list = list.iter().cloned().collect::<Vec<_>>().join(", ");
564 self.src.push_str(&format!("from {} import {}\n", k, list));
565 }
566 None => {
567 self.src.push_str(&format!("import {}\n", k));
568 }
569 }
570 }
571 self.src.push_str("import wasmtime\n");
572 self.src.push_str(
573 "
574 try:
575 from typing import Protocol
576 except ImportError:
577 class Protocol: # type: ignore
578 pass
579 ",
580 );
581 self.src.push_str("\n");
582
583 if self.deps.needs_t_typevar {
584 self.src.push_str("T = TypeVar('T')\n");
585 }
586
587 self.src.push_str(&intrinsics);
588 for (id, r) in iface.resources.iter() {
589 let name = r.name.to_camel_case();
590 if self.in_import {
591 self.src.push_str("@runtime_checkable\n");
592 self.src.push_str(&format!("class {}(Protocol):\n", name));
593 self.src.indent();
594 self.src.push_str("def drop(self) -> None:\n");
595 self.src.indent();
596 self.src.push_str("pass\n");
597 self.src.dedent();
598
599 for (_, funcs) in self.guest_imports.iter() {
600 if let Some(funcs) = funcs.resource_funcs.get(&id) {
601 for func in funcs {
602 self.src.push_str("@abstractmethod\n");
603 self.src.push_str(&func.pysig);
604 self.src.push_str(":\n");
605 self.src.indent();
606 self.src.push_str("raise NotImplementedError\n");
607 self.src.dedent();
608 }
609 }
610 }
611 self.src.dedent();
612 } else {
613 self.src.push_str(&format!("class {}:\n", name));
614 self.src.indent();
615 self.src.push_str(&format!(
616 "
617 _wasm_val: int
618 _refcnt: int
619 _obj: '{iface}'
620 _destroyed: bool
621
622 def __init__(self, val: int, obj: '{iface}') -> None:
623 self._wasm_val = val
624 self._refcnt = 1
625 self._obj = obj
626 self._destroyed = False
627
628 def clone(self) -> '{name}':
629 self._refcnt += 1
630 return self
631
632 def drop(self, store: wasmtime.Storelike) -> None:
633 self._refcnt -= 1;
634 if self._refcnt != 0:
635 return
636 assert(not self._destroyed)
637 self._destroyed = True
638 self._obj._canonical_abi_drop_{drop}(store, self._wasm_val)
639
640 def __del__(self) -> None:
641 if not self._destroyed:
642 raise RuntimeError('wasm object not dropped')
643 ",
644 name = name,
645 iface = iface.name.to_camel_case(),
646 drop = name.to_snake_case(),
647 ));
648
649 for (_, exports) in self.guest_exports.iter() {
650 if let Some(funcs) = exports.resource_funcs.get(&id) {
651 for func in funcs {
652 self.src.push_str(func);
653 }
654 }
655 }
656
657 self.src.dedent();
658 }
659 }
660 self.src.push_str(&types);
661
662 for (module, funcs) in mem::take(&mut self.guest_imports) {
663 self.src
664 .push_str(&format!("class {}(Protocol):\n", module.to_camel_case()));
665 self.src.indent();
666 for func in funcs.freestanding_funcs.iter() {
667 self.src.push_str("@abstractmethod\n");
668 self.src.push_str(&func.pysig);
669 self.src.push_str(":\n");
670 self.src.indent();
671 self.src.push_str("raise NotImplementedError\n");
672 self.src.dedent();
673 }
674 self.src.dedent();
675 self.src.push_str("\n");
676
677 self.src.push_str(&format!(
678 "def add_{}_to_linker(linker: wasmtime.Linker, store: wasmtime.Store, host: {}) -> None:\n",
679 module.to_snake_case(),
680 module.to_camel_case(),
681 ));
682 self.src.indent();
683
684 for (id, r) in iface.resources.iter() {
685 self.src.push_str(&format!(
686 "_resources{}: Slab[{}] = Slab()\n",
687 id.index(),
688 r.name.to_camel_case()
689 ));
690 }
691
692 for func in funcs
693 .freestanding_funcs
694 .iter()
695 .chain(funcs.resource_funcs.values().flatten())
696 {
697 self.src.push_str(&format!("ty = {}\n", func.wasm_ty));
698 self.src.push_str(&func.src);
699 self.src.push_str(&format!(
700 "linker.define('{}', '{}', wasmtime.Func(store, ty, {}, access_caller = True))\n",
701 iface.name,
702 func.name,
703 func.name.to_snake_case(),
704 ));
705 }
706
707 for (id, resource) in iface.resources.iter() {
708 let snake = resource.name.to_snake_case();
709
710 self.src.push_str(&format!(
711 "def resource_drop_{}(i: int) -> None:\n _resources{}.remove(i).drop()\n",
712 snake,
713 id.index(),
714 ));
715 self.src
716 .push_str("ty = wasmtime.FuncType([wasmtime.ValType.i32()], [])\n");
717 self.src.push_str(&format!(
718 "linker.define(\
719 'canonical_abi', \
720 'resource_drop_{}', \
721 wasmtime.Func(store, ty, resource_drop_{})\
722 )\n",
723 resource.name, snake,
724 ));
725 }
726 self.src.dedent();
727 }
728
729 if !self.in_import && self.guest_exports.is_empty() {
732 self.src
733 .push_str(&format!("class {}:\n", iface.name.to_camel_case()));
734 self.src.indent();
735 if iface.resources.len() == 0 {
736 self.src.push_str("pass\n");
737 } else {
738 for (_, r) in iface.resources.iter() {
739 self.src.push_str(&format!(
740 "_canonical_abi_drop_{}: wasmtime.Func\n",
741 r.name.to_snake_case(),
742 ));
743 }
744 }
745 self.src.dedent();
746 }
747
748 for (module, exports) in mem::take(&mut self.guest_exports) {
749 let module = module.to_camel_case();
750 self.src.push_str(&format!("class {}:\n", module));
751 self.src.indent();
752
753 self.src.push_str("instance: wasmtime.Instance\n");
754 for (name, ty) in exports.fields.iter() {
755 self.src
756 .push_str(&format!("_{}: {}\n", name.to_snake_case(), ty));
757 }
758 for (id, r) in iface.resources.iter() {
759 self.src.push_str(&format!(
760 "_resource{}_slab: Slab[{}]\n",
761 id.index(),
762 r.name.to_camel_case(),
763 ));
764 self.src.push_str(&format!(
765 "_canonical_abi_drop_{}: wasmtime.Func\n",
766 r.name.to_snake_case(),
767 ));
768 }
769
770 self.src.push_str("def __init__(self, store: wasmtime.Store, linker: wasmtime.Linker, module: wasmtime.Module):\n");
771 self.src.indent();
772 for (id, r) in iface.resources.iter() {
773 self.src.push_str(&format!(
774 "
775 ty1 = wasmtime.FuncType([wasmtime.ValType.i32()], [])
776 ty2 = wasmtime.FuncType([wasmtime.ValType.i32()], [wasmtime.ValType.i32()])
777 def drop_{snake}(caller: wasmtime.Caller, idx: int) -> None:
778 self._resource{idx}_slab.remove(idx).drop(caller);
779 linker.define('canonical_abi', 'resource_drop_{name}', wasmtime.Func(store, ty1, drop_{snake}, access_caller = True))
780
781 def clone_{snake}(idx: int) -> int:
782 obj = self._resource{idx}_slab.get(idx)
783 return self._resource{idx}_slab.insert(obj.clone())
784 linker.define('canonical_abi', 'resource_clone_{name}', wasmtime.Func(store, ty2, clone_{snake}))
785
786 def get_{snake}(idx: int) -> int:
787 obj = self._resource{idx}_slab.get(idx)
788 return obj._wasm_val
789 linker.define('canonical_abi', 'resource_get_{name}', wasmtime.Func(store, ty2, get_{snake}))
790
791 def new_{snake}(val: int) -> int:
792 return self._resource{idx}_slab.insert({camel}(val, self))
793 linker.define('canonical_abi', 'resource_new_{name}', wasmtime.Func(store, ty2, new_{snake}))
794 ",
795 name = r.name,
796 camel = r.name.to_camel_case(),
797 snake = r.name.to_snake_case(),
798 idx = id.index(),
799 ));
800 }
801 self.src
802 .push_str("self.instance = linker.instantiate(store, module)\n");
803 self.src
804 .push_str("exports = self.instance.exports(store)\n");
805 for (name, ty) in exports.fields.iter() {
806 self.src.push_str(&format!(
807 "
808 {snake} = exports['{name}']
809 assert(isinstance({snake}, {ty}))
810 self._{snake} = {snake}
811 ",
812 name = name,
813 snake = name.to_snake_case(),
814 ty = ty,
815 ));
816 }
817 for (id, r) in iface.resources.iter() {
818 self.src.push_str(&format!(
819 "
820 self._resource{idx}_slab = Slab()
821 canon_drop_{snake} = exports['canonical_abi_drop_{name}']
822 assert(isinstance(canon_drop_{snake}, wasmtime.Func))
823 self._canonical_abi_drop_{snake} = canon_drop_{snake}
824 ",
825 idx = id.index(),
826 name = r.name,
827 snake = r.name.to_snake_case(),
828 ));
829 }
830 self.src.dedent();
831
832 for func in exports.freestanding_funcs.iter() {
833 self.src.push_str(func);
834 }
835
836 self.src.dedent();
837 }
838
839 files.push("bindings.py", self.src.as_bytes());
840 }
841}
842
843struct FunctionBindgen<'a> {
844 gen: &'a mut WasmtimePy,
845 locals: Ns,
846 src: Source,
847 block_storage: Vec<Source>,
848 blocks: Vec<(String, Vec<String>)>,
849 needs_memory: bool,
850 needs_realloc: Option<String>,
851 needs_free: Option<String>,
852 params: Vec<String>,
853 payloads: Vec<String>,
854 src_object: String,
855}
856
857impl FunctionBindgen<'_> {
858 fn new(gen: &mut WasmtimePy, params: Vec<String>) -> FunctionBindgen<'_> {
859 let mut locals = Ns::default();
860 locals.insert("len").unwrap(); locals.insert("base").unwrap(); locals.insert("i").unwrap(); for param in params.iter() {
864 locals.insert(param).unwrap();
865 }
866 FunctionBindgen {
867 gen,
868 locals,
869 src: Source::default(),
870 block_storage: Vec::new(),
871 blocks: Vec::new(),
872 needs_memory: false,
873 needs_realloc: None,
874 needs_free: None,
875 params,
876 payloads: Vec::new(),
877 src_object: "self".to_string(),
878 }
879 }
880
881 fn clamp<T>(&mut self, results: &mut Vec<String>, operands: &[String], min: T, max: T)
882 where
883 T: std::fmt::Display,
884 {
885 self.gen.deps.needs_clamp = true;
886 results.push(format!("_clamp({}, {}, {})", operands[0], min, max));
887 }
888
889 fn load(&mut self, ty: &str, offset: i32, operands: &[String], results: &mut Vec<String>) {
890 self.needs_memory = true;
891 self.gen.deps.needs_load = true;
892 let tmp = self.locals.tmp("load");
893 self.src.push_str(&format!(
894 "{} = _load(ctypes.{}, memory, caller, {}, {})\n",
895 tmp, ty, operands[0], offset,
896 ));
897 results.push(tmp);
898 }
899
900 fn store(&mut self, ty: &str, offset: i32, operands: &[String]) {
901 self.needs_memory = true;
902 self.gen.deps.needs_store = true;
903 self.src.push_str(&format!(
904 "_store(ctypes.{}, memory, caller, {}, {}, {})\n",
905 ty, operands[1], offset, operands[0]
906 ));
907 }
908}
909
910impl Bindgen for FunctionBindgen<'_> {
911 type Operand = String;
912
913 fn sizes(&self) -> &SizeAlign {
914 &self.gen.sizes
915 }
916
917 fn push_block(&mut self) {
918 let prev = mem::take(&mut self.src);
919 self.block_storage.push(prev);
920 }
921
922 fn finish_block(&mut self, operands: &mut Vec<String>) {
923 let to_restore = self.block_storage.pop().unwrap();
924 let src = mem::replace(&mut self.src, to_restore);
925 self.blocks.push((src.into(), mem::take(operands)));
926 }
927
928 fn return_pointer(&mut self, _iface: &Interface, _size: usize, _align: usize) -> String {
929 unimplemented!()
930 }
931
932 fn is_list_canonical(&self, iface: &Interface, ty: &Type) -> bool {
933 array_ty(iface, ty).is_some()
934 }
935
936 fn emit(
937 &mut self,
938 iface: &Interface,
939 inst: &Instruction<'_>,
940 operands: &mut Vec<String>,
941 results: &mut Vec<String>,
942 ) {
943 let mut builder = self.src.builder(&mut self.gen.deps, iface);
944 match inst {
945 Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
946 Instruction::I32Const { val } => results.push(val.to_string()),
947 Instruction::ConstZero { tys } => {
948 for t in tys.iter() {
949 match t {
950 WasmType::I32 | WasmType::I64 => results.push("0".to_string()),
951 WasmType::F32 | WasmType::F64 => results.push("0.0".to_string()),
952 }
953 }
954 }
955
956 Instruction::U8FromI32 => self.clamp(results, operands, u8::MIN, u8::MAX),
961 Instruction::S8FromI32 => self.clamp(results, operands, i8::MIN, i8::MAX),
962 Instruction::U16FromI32 => self.clamp(results, operands, u16::MIN, u16::MAX),
963 Instruction::S16FromI32 => self.clamp(results, operands, i16::MIN, i16::MAX),
964 Instruction::U32FromI32 => {
966 results.push(format!("{} & 0xffffffff", operands[0]));
967 }
968 Instruction::U64FromI64 => {
971 results.push(format!("{} & 0xffffffffffffffff", operands[0]));
972 }
973 Instruction::S32FromI32 | Instruction::S64FromI64 => {
976 results.push(operands.pop().unwrap())
977 }
978
979 Instruction::I32FromU8 => self.clamp(results, operands, u8::MIN, u8::MAX),
982 Instruction::I32FromS8 => self.clamp(results, operands, i8::MIN, i8::MAX),
983 Instruction::I32FromU16 => self.clamp(results, operands, u16::MIN, u16::MAX),
984 Instruction::I32FromS16 => self.clamp(results, operands, i16::MIN, i16::MAX),
985 Instruction::I32FromU32 => {
987 self.clamp(results, operands, u32::MIN, u32::MAX);
988 }
989 Instruction::I32FromS32 => self.clamp(results, operands, i32::MIN, i32::MAX),
990 Instruction::I64FromU64 => self.clamp(results, operands, u64::MIN, u64::MAX),
992 Instruction::I64FromS64 => self.clamp(results, operands, i64::MIN, i64::MAX),
993
994 Instruction::Float32FromF32
997 | Instruction::Float64FromF64
998 | Instruction::F32FromFloat32
999 | Instruction::F64FromFloat64 => results.push(operands.pop().unwrap()),
1000
1001 Instruction::CharFromI32 => {
1004 builder.deps.needs_validate_guest_char = true;
1005 results.push(format!("_validate_guest_char({})", operands[0]));
1006 }
1007
1008 Instruction::I32FromChar => {
1009 results.push(format!("ord({})", operands[0]));
1010 }
1011
1012 Instruction::Bitcasts { casts } => {
1013 for (cast, op) in casts.iter().zip(operands) {
1014 match cast {
1015 Bitcast::I32ToF32 => {
1016 builder.deps.needs_i32_to_f32 = true;
1017 results.push(format!("_i32_to_f32({})", op));
1018 }
1019 Bitcast::F32ToI32 => {
1020 builder.deps.needs_f32_to_i32 = true;
1021 results.push(format!("_f32_to_i32({})", op));
1022 }
1023 Bitcast::I64ToF64 => {
1024 builder.deps.needs_i64_to_f64 = true;
1025 results.push(format!("_i64_to_f64({})", op));
1026 }
1027 Bitcast::F64ToI64 => {
1028 builder.deps.needs_f64_to_i64 = true;
1029 results.push(format!("_f64_to_i64({})", op));
1030 }
1031 Bitcast::I64ToF32 => {
1032 builder.deps.needs_i32_to_f32 = true;
1033 results.push(format!("_i32_to_f32(({}) & 0xffffffff)", op));
1034 }
1035 Bitcast::F32ToI64 => {
1036 builder.deps.needs_f32_to_i32 = true;
1037 results.push(format!("_f32_to_i32({})", op));
1038 }
1039 Bitcast::I32ToI64 | Bitcast::I64ToI32 | Bitcast::None => {
1040 results.push(op.clone())
1041 }
1042 }
1043 }
1044 }
1045
1046 Instruction::UnitLower => {}
1047 Instruction::UnitLift => {
1048 results.push("None".to_string());
1049 }
1050 Instruction::BoolFromI32 => {
1051 let op = self.locals.tmp("operand");
1052 let ret = self.locals.tmp("boolean");
1053 builder.push_str(&format!(
1054 "
1055 {op} = {}
1056 if {op} == 0:
1057 {ret} = False
1058 elif {op} == 1:
1059 {ret} = True
1060 else:
1061 raise TypeError(\"invalid variant discriminant for bool\")
1062 ",
1063 operands[0]
1064 ));
1065 results.push(ret);
1066 }
1067 Instruction::I32FromBool => {
1068 results.push(format!("int({})", operands[0]));
1069 }
1070
1071 Instruction::I32FromOwnedHandle { ty } => {
1075 results.push(format!("_resources{}.insert({})", ty.index(), operands[0]));
1076 }
1077 Instruction::HandleBorrowedFromI32 { ty } => {
1078 results.push(format!("_resources{}.get({})", ty.index(), operands[0]));
1079 }
1080
1081 Instruction::I32FromBorrowedHandle { ty } => {
1085 let obj = self.locals.tmp("obj");
1086 builder.push_str(&format!("{} = {}\n", obj, operands[0]));
1087
1088 results.push(format!(
1089 "{}._resource{}_slab.insert({}.clone())",
1090 self.src_object,
1091 ty.index(),
1092 obj,
1093 ));
1094 }
1095 Instruction::HandleOwnedFromI32 { ty } => {
1096 results.push(format!(
1097 "{}._resource{}_slab.remove({})",
1098 self.src_object,
1099 ty.index(),
1100 operands[0],
1101 ));
1102 }
1103 Instruction::RecordLower { record, .. } => {
1104 if record.fields.is_empty() {
1105 return;
1106 }
1107 let tmp = self.locals.tmp("record");
1108 builder.push_str(&format!("{} = {}\n", tmp, operands[0]));
1109 for field in record.fields.iter() {
1110 let name = self.locals.tmp("field");
1111 builder.push_str(&format!(
1112 "{} = {}.{}\n",
1113 name,
1114 tmp,
1115 field.name.to_snake_case(),
1116 ));
1117 results.push(name);
1118 }
1119 }
1120
1121 Instruction::RecordLift { name, .. } => {
1122 results.push(format!("{}({})", name.to_camel_case(), operands.join(", ")));
1123 }
1124 Instruction::TupleLower { tuple, .. } => {
1125 if tuple.types.is_empty() {
1126 return;
1127 }
1128 builder.push_str("(");
1129 for _ in 0..tuple.types.len() {
1130 let name = self.locals.tmp("tuplei");
1131 builder.push_str(&name);
1132 builder.push_str(",");
1133 results.push(name);
1134 }
1135 builder.push_str(") = ");
1136 builder.push_str(&operands[0]);
1137 builder.push_str("\n");
1138 }
1139 Instruction::TupleLift { .. } => {
1140 if operands.is_empty() {
1141 results.push("None".to_string());
1142 } else {
1143 results.push(format!("({},)", operands.join(", ")));
1144 }
1145 }
1146 Instruction::FlagsLift { name, .. } => {
1147 let operand = match operands.len() {
1148 1 => operands[0].clone(),
1149 _ => {
1150 let tmp = self.locals.tmp("flags");
1151 builder.push_str(&format!("{tmp} = 0\n"));
1152 for (i, op) in operands.iter().enumerate() {
1153 let i = 32 * i;
1154 builder.push_str(&format!("{tmp} |= {op} << {i}\n"));
1155 }
1156 tmp
1157 }
1158 };
1159 results.push(format!("{}({})", name.to_camel_case(), operand));
1160 }
1161 Instruction::FlagsLower { flags, .. } => match flags.repr().count() {
1162 1 => results.push(format!("({}).value", operands[0])),
1163 n => {
1164 let tmp = self.locals.tmp("flags");
1165 self.src
1166 .push_str(&format!("{tmp} = ({}).value\n", operands[0]));
1167 for i in 0..n {
1168 let i = 32 * i;
1169 results.push(format!("({tmp} >> {i}) & 0xffffffff"));
1170 }
1171 }
1172 },
1173
1174 Instruction::VariantPayloadName => {
1175 let name = self.locals.tmp("payload");
1176 results.push(name.clone());
1177 self.payloads.push(name);
1178 }
1179
1180 Instruction::VariantLower {
1181 variant,
1182 results: result_types,
1183 name,
1184 ..
1185 } => {
1186 let blocks = self
1187 .blocks
1188 .drain(self.blocks.len() - variant.cases.len()..)
1189 .collect::<Vec<_>>();
1190 let payloads = self
1191 .payloads
1192 .drain(self.payloads.len() - variant.cases.len()..)
1193 .collect::<Vec<_>>();
1194
1195 for _ in 0..result_types.len() {
1196 results.push(self.locals.tmp("variant"));
1197 }
1198
1199 for (i, ((case, (block, block_results)), payload)) in
1200 variant.cases.iter().zip(blocks).zip(payloads).enumerate()
1201 {
1202 if i == 0 {
1203 builder.push_str("if ");
1204 } else {
1205 builder.push_str("elif ");
1206 }
1207
1208 builder.push_str(&format!(
1209 "isinstance({}, {}{}):\n",
1210 operands[0],
1211 name.to_camel_case(),
1212 case.name.to_camel_case()
1213 ));
1214 builder.indent();
1215 builder.push_str(&format!("{} = {}.value\n", payload, operands[0]));
1216 builder.push_str(&block);
1217
1218 for (i, result) in block_results.iter().enumerate() {
1219 builder.push_str(&format!("{} = {}\n", results[i], result));
1220 }
1221 builder.dedent();
1222 }
1223 let variant_name = name.to_camel_case();
1224 builder.push_str("else:\n");
1225 builder.indent();
1226 builder.push_str(&format!(
1227 "raise TypeError(\"invalid variant specified for {}\")\n",
1228 variant_name
1229 ));
1230 builder.dedent();
1231 }
1232
1233 Instruction::VariantLift {
1234 variant, name, ty, ..
1235 } => {
1236 let blocks = self
1237 .blocks
1238 .drain(self.blocks.len() - variant.cases.len()..)
1239 .collect::<Vec<_>>();
1240
1241 let result = self.locals.tmp("variant");
1242 builder.print_var_declaration(&result, &Type::Id(*ty));
1243 for (i, (case, (block, block_results))) in
1244 variant.cases.iter().zip(blocks).enumerate()
1245 {
1246 if i == 0 {
1247 builder.push_str("if ");
1248 } else {
1249 builder.push_str("elif ");
1250 }
1251 builder.push_str(&format!("{} == {}:\n", operands[0], i));
1252 builder.indent();
1253 builder.push_str(&block);
1254
1255 builder.push_str(&format!(
1256 "{} = {}{}(",
1257 result,
1258 name.to_camel_case(),
1259 case.name.to_camel_case()
1260 ));
1261 assert!(block_results.len() == 1);
1262 builder.push_str(&block_results[0]);
1263 builder.push_str(")\n");
1264 builder.dedent();
1265 }
1266 builder.push_str("else:\n");
1267 builder.indent();
1268 let variant_name = name.to_camel_case();
1269 builder.push_str(&format!(
1270 "raise TypeError(\"invalid variant discriminant for {}\")\n",
1271 variant_name
1272 ));
1273 builder.dedent();
1274 results.push(result);
1275 }
1276
1277 Instruction::UnionLower {
1278 union,
1279 results: result_types,
1280 name,
1281 ..
1282 } => {
1283 let blocks = self
1284 .blocks
1285 .drain(self.blocks.len() - union.cases.len()..)
1286 .collect::<Vec<_>>();
1287 let payloads = self
1288 .payloads
1289 .drain(self.payloads.len() - union.cases.len()..)
1290 .collect::<Vec<_>>();
1291
1292 for _ in 0..result_types.len() {
1293 results.push(self.locals.tmp("variant"));
1294 }
1295
1296 let union_representation = *self
1298 .gen
1299 .union_representation
1300 .get(&name.to_string())
1301 .unwrap();
1302 let name = name.to_camel_case();
1303 let op0 = &operands[0];
1304 for (i, ((case, (block, block_results)), payload)) in
1305 union.cases.iter().zip(blocks).zip(payloads).enumerate()
1306 {
1307 builder.push_str(if i == 0 { "if " } else { "elif " });
1308 builder.push_str(&format!("isinstance({op0}, "));
1309 match union_representation {
1310 PyUnionRepresentation::Raw => {
1312 builder.print_ty(&case.ty, false);
1313 }
1314 PyUnionRepresentation::Wrapped => {
1316 builder.push_str(&format!("{name}{i}"));
1317 }
1318 }
1319 builder.push_str("):\n");
1320 builder.indent();
1321 match union_representation {
1322 PyUnionRepresentation::Raw => {
1324 builder.push_str(&format!("{payload} = {op0}\n"))
1325 }
1326 PyUnionRepresentation::Wrapped => {
1328 builder.push_str(&format!("{payload} = {op0}.value\n"))
1329 }
1330 }
1331 builder.push_str(&block);
1332 for (i, result) in block_results.iter().enumerate() {
1333 builder.push_str(&format!("{} = {result}\n", results[i]));
1334 }
1335 builder.dedent();
1336 }
1337 builder.push_str("else:\n");
1338 builder.indent();
1339 builder.push_str(&format!(
1340 "raise TypeError(\"invalid variant specified for {name}\")\n"
1341 ));
1342 builder.dedent();
1343 }
1344
1345 Instruction::UnionLift {
1346 union, name, ty, ..
1347 } => {
1348 let blocks = self
1349 .blocks
1350 .drain(self.blocks.len() - union.cases.len()..)
1351 .collect::<Vec<_>>();
1352
1353 let result = self.locals.tmp("variant");
1354 builder.print_var_declaration(&result, &Type::Id(*ty));
1355 let union_representation = *self
1357 .gen
1358 .union_representation
1359 .get(&name.to_string())
1360 .unwrap();
1361 let name = name.to_camel_case();
1362 let op0 = &operands[0];
1363 for (i, (_case, (block, block_results))) in
1364 union.cases.iter().zip(blocks).enumerate()
1365 {
1366 builder.push_str(if i == 0 { "if " } else { "elif " });
1367 builder.push_str(&format!("{op0} == {i}:\n"));
1368 builder.indent();
1369 builder.push_str(&block);
1370 assert!(block_results.len() == 1);
1371 let block_result = &block_results[0];
1372 builder.push_str(&format!("{result} = "));
1373 match union_representation {
1374 PyUnionRepresentation::Raw => builder.push_str(block_result),
1376 PyUnionRepresentation::Wrapped => {
1378 builder.push_str(&format!("{name}{i}({block_result})"))
1379 }
1380 }
1381 builder.newline();
1382 builder.dedent();
1383 }
1384 builder.push_str("else:\n");
1385 builder.indent();
1386 builder.push_str(&format!(
1387 "raise TypeError(\"invalid variant discriminant for {name}\")\n",
1388 ));
1389 builder.dedent();
1390 results.push(result);
1391 }
1392
1393 Instruction::OptionLower {
1394 results: result_types,
1395 ..
1396 } => {
1397 let (some, some_results) = self.blocks.pop().unwrap();
1398 let (none, none_results) = self.blocks.pop().unwrap();
1399 let some_payload = self.payloads.pop().unwrap();
1400 let _none_payload = self.payloads.pop().unwrap();
1401
1402 for _ in 0..result_types.len() {
1403 results.push(self.locals.tmp("variant"));
1404 }
1405
1406 let op0 = &operands[0];
1407 builder.push_str(&format!("if {op0} is None:\n"));
1408
1409 builder.indent();
1410 builder.push_str(&none);
1411 for (dst, result) in results.iter().zip(&none_results) {
1412 builder.push_str(&format!("{dst} = {result}\n"));
1413 }
1414 builder.dedent();
1415 builder.push_str("else:\n");
1416 builder.indent();
1417 builder.push_str(&format!("{some_payload} = {op0}\n"));
1418 builder.push_str(&some);
1419 for (dst, result) in results.iter().zip(&some_results) {
1420 builder.push_str(&format!("{dst} = {result}\n"));
1421 }
1422 builder.dedent();
1423 }
1424
1425 Instruction::OptionLift { ty, .. } => {
1426 let (some, some_results) = self.blocks.pop().unwrap();
1427 let (none, none_results) = self.blocks.pop().unwrap();
1428 assert!(none_results.len() == 1);
1429 assert!(some_results.len() == 1);
1430 let some_result = &some_results[0];
1431 assert_eq!(none_results[0], "None");
1432
1433 let result = self.locals.tmp("option");
1434 builder.print_var_declaration(&result, &Type::Id(*ty));
1435
1436 let op0 = &operands[0];
1437 builder.push_str(&format!("if {op0} == 0:\n"));
1438 builder.indent();
1439 builder.push_str(&none);
1440 builder.push_str(&format!("{result} = None\n"));
1441 builder.dedent();
1442 builder.push_str(&format!("elif {op0} == 1:\n"));
1443 builder.indent();
1444 builder.push_str(&some);
1445 builder.push_str(&format!("{result} = {some_result}\n"));
1446 builder.dedent();
1447
1448 builder.push_str("else:\n");
1449 builder.indent();
1450 builder.push_str("raise TypeError(\"invalid variant discriminant for option\")\n");
1451 builder.dedent();
1452
1453 results.push(result);
1454 }
1455
1456 Instruction::ExpectedLower {
1457 results: result_types,
1458 ..
1459 } => {
1460 let (err, err_results) = self.blocks.pop().unwrap();
1461 let (ok, ok_results) = self.blocks.pop().unwrap();
1462 let err_payload = self.payloads.pop().unwrap();
1463 let ok_payload = self.payloads.pop().unwrap();
1464
1465 for _ in 0..result_types.len() {
1466 results.push(self.locals.tmp("variant"));
1467 }
1468
1469 let op0 = &operands[0];
1470 builder.push_str(&format!("if isinstance({op0}, Ok):\n"));
1471
1472 builder.indent();
1473 builder.push_str(&format!("{ok_payload} = {op0}.value\n"));
1474 builder.push_str(&ok);
1475 for (dst, result) in results.iter().zip(&ok_results) {
1476 builder.push_str(&format!("{dst} = {result}\n"));
1477 }
1478 builder.dedent();
1479 builder.push_str(&format!("elif isinstance({op0}, Err):\n"));
1480 builder.indent();
1481 builder.push_str(&format!("{err_payload} = {op0}.value\n"));
1482 builder.push_str(&err);
1483 for (dst, result) in results.iter().zip(&err_results) {
1484 builder.push_str(&format!("{dst} = {result}\n"));
1485 }
1486 builder.dedent();
1487 builder.push_str("else:\n");
1488 builder.indent();
1489 builder.push_str("raise TypeError(\"invalid variant specified for expected\")\n");
1490 builder.dedent();
1491 }
1492
1493 Instruction::ExpectedLift { ty, .. } => {
1494 let (err, err_results) = self.blocks.pop().unwrap();
1495 let (ok, ok_results) = self.blocks.pop().unwrap();
1496 assert!(err_results.len() == 1);
1497 let err_result = &err_results[0];
1498 assert!(ok_results.len() == 1);
1499 let ok_result = &ok_results[0];
1500
1501 let result = self.locals.tmp("expected");
1502 builder.print_var_declaration(&result, &Type::Id(*ty));
1503
1504 let op0 = &operands[0];
1505 builder.push_str(&format!("if {op0} == 0:\n"));
1506 builder.indent();
1507 builder.push_str(&ok);
1508 builder.push_str(&format!("{result} = Ok({ok_result})\n"));
1509 builder.dedent();
1510 builder.push_str(&format!("elif {op0} == 1:\n"));
1511 builder.indent();
1512 builder.push_str(&err);
1513 builder.push_str(&format!("{result} = Err({err_result})\n"));
1514 builder.dedent();
1515
1516 builder.push_str("else:\n");
1517 builder.indent();
1518 builder
1519 .push_str("raise TypeError(\"invalid variant discriminant for expected\")\n");
1520 builder.dedent();
1521
1522 results.push(result);
1523 }
1524
1525 Instruction::EnumLower { .. } => results.push(format!("({}).value", operands[0])),
1526
1527 Instruction::EnumLift { name, .. } => {
1528 results.push(format!("{}({})", name.to_camel_case(), operands[0]));
1529 }
1530
1531 Instruction::ListCanonLower { element, realloc } => {
1532 let realloc = realloc.unwrap();
1536 self.needs_memory = true;
1537 self.needs_realloc = Some(realloc.to_string());
1538
1539 let ptr = self.locals.tmp("ptr");
1540 let len = self.locals.tmp("len");
1541 let array_ty = array_ty(iface, element).unwrap();
1542 builder.deps.needs_list_canon_lower = true;
1543 let size = self.gen.sizes.size(element);
1544 let align = self.gen.sizes.align(element);
1545 builder.push_str(&format!(
1546 "{}, {} = _list_canon_lower({}, ctypes.{}, {}, {}, realloc, memory, caller)\n",
1547 ptr, len, operands[0], array_ty, size, align,
1548 ));
1549 results.push(ptr);
1550 results.push(len);
1551 }
1552 Instruction::ListCanonLift { element, free, .. } => {
1553 self.needs_memory = true;
1554 let ptr = self.locals.tmp("ptr");
1555 let len = self.locals.tmp("len");
1556 builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1557 builder.push_str(&format!("{} = {}\n", len, operands[1]));
1558 let array_ty = array_ty(iface, element).unwrap();
1559 builder.deps.needs_list_canon_lift = true;
1560 let lift = format!(
1561 "_list_canon_lift({}, {}, {}, ctypes.{}, memory, caller)",
1562 ptr,
1563 len,
1564 self.gen.sizes.size(element),
1565 array_ty,
1566 );
1567 builder.deps.pyimport("typing", "cast");
1568 let align = self.gen.sizes.align(element);
1569 match free {
1570 Some(free) => {
1571 self.needs_free = Some(free.to_string());
1572 let list = self.locals.tmp("list");
1573 builder.push_str(&list);
1574 builder.push_str(" = cast(");
1575 builder.print_list(element);
1576 builder.push_str(", ");
1577 builder.push_str(&lift);
1578 builder.push_str(")\n");
1579 builder.push_str(&format!("free(caller, {}, {}, {})\n", ptr, len, align));
1580 results.push(list);
1581 }
1582 None => {
1583 let mut result_src = Source::default();
1584 drop(builder);
1585 let mut builder = result_src.builder(&mut self.gen.deps, iface);
1586 builder.push_str("cast(");
1587 builder.print_list(element);
1588 builder.push_str(", ");
1589 builder.push_str(&lift);
1590 builder.push_str(")");
1591 results.push(result_src.to_string());
1592 }
1593 }
1594 }
1595 Instruction::StringLower { realloc } => {
1596 let realloc = realloc.unwrap();
1600 self.needs_memory = true;
1601 self.needs_realloc = Some(realloc.to_string());
1602
1603 let ptr = self.locals.tmp("ptr");
1604 let len = self.locals.tmp("len");
1605 builder.deps.needs_encode_utf8 = true;
1606 builder.push_str(&format!(
1607 "{}, {} = _encode_utf8({}, realloc, memory, caller)\n",
1608 ptr, len, operands[0],
1609 ));
1610 results.push(ptr);
1611 results.push(len);
1612 }
1613 Instruction::StringLift { free, .. } => {
1614 self.needs_memory = true;
1615 let ptr = self.locals.tmp("ptr");
1616 let len = self.locals.tmp("len");
1617 builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1618 builder.push_str(&format!("{} = {}\n", len, operands[1]));
1619 builder.deps.needs_decode_utf8 = true;
1620 let result = format!("_decode_utf8(memory, caller, {}, {})", ptr, len);
1621 match free {
1622 Some(free) => {
1623 self.needs_free = Some(free.to_string());
1624 let list = self.locals.tmp("list");
1625 builder.push_str(&format!("{} = {}\n", list, result));
1626 self.src
1627 .push_str(&format!("free(caller, {}, {}, 1)\n", ptr, len));
1628 results.push(list);
1629 }
1630 None => results.push(result),
1631 }
1632 }
1633
1634 Instruction::ListLower { element, realloc } => {
1635 let base = self.payloads.pop().unwrap();
1636 let e = self.payloads.pop().unwrap();
1637 let realloc = realloc.unwrap();
1638 let (body, body_results) = self.blocks.pop().unwrap();
1639 assert!(body_results.is_empty());
1640 let vec = self.locals.tmp("vec");
1641 let result = self.locals.tmp("result");
1642 let len = self.locals.tmp("len");
1643 self.needs_realloc = Some(realloc.to_string());
1644 let size = self.gen.sizes.size(element);
1645 let align = self.gen.sizes.align(element);
1646
1647 builder.push_str(&format!("{} = {}\n", vec, operands[0]));
1650 builder.push_str(&format!("{} = len({})\n", len, vec));
1651
1652 builder.push_str(&format!(
1654 "{} = realloc(caller, 0, 0, {}, {} * {})\n",
1655 result, align, len, size,
1656 ));
1657 builder.push_str(&format!("assert(isinstance({}, int))\n", result));
1658
1659 let i = self.locals.tmp("i");
1662 builder.push_str(&format!("for {} in range(0, {}):\n", i, len));
1663 builder.indent();
1664 builder.push_str(&format!("{} = {}[{}]\n", e, vec, i));
1665 builder.push_str(&format!("{} = {} + {} * {}\n", base, result, i, size));
1666 builder.push_str(&body);
1667 builder.dedent();
1668
1669 results.push(result);
1670 results.push(len);
1671 }
1672
1673 Instruction::ListLift { element, free, .. } => {
1674 let (body, body_results) = self.blocks.pop().unwrap();
1675 let base = self.payloads.pop().unwrap();
1676 let size = self.gen.sizes.size(element);
1677 let align = self.gen.sizes.align(element);
1678 let ptr = self.locals.tmp("ptr");
1679 let len = self.locals.tmp("len");
1680 builder.push_str(&format!("{} = {}\n", ptr, operands[0]));
1681 builder.push_str(&format!("{} = {}\n", len, operands[1]));
1682 let result = self.locals.tmp("result");
1683 builder.push_str(&format!("{}: List[", result));
1684 builder.print_ty(element, true);
1685 builder.push_str("] = []\n");
1686
1687 let i = self.locals.tmp("i");
1688 builder.push_str(&format!("for {} in range(0, {}):\n", i, len));
1689 builder.indent();
1690 builder.push_str(&format!("{} = {} + {} * {}\n", base, ptr, i, size));
1691 builder.push_str(&body);
1692 assert_eq!(body_results.len(), 1);
1693 builder.push_str(&format!("{}.append({})\n", result, body_results[0]));
1694 builder.dedent();
1695
1696 if let Some(free) = free {
1697 self.needs_free = Some(free.to_string());
1698 builder.push_str(&format!(
1699 "free(caller, {}, {} * {}, {})\n",
1700 ptr, len, size, align,
1701 ));
1702 }
1703 results.push(result);
1704 }
1705
1706 Instruction::IterElem { .. } => {
1707 let name = self.locals.tmp("e");
1708 results.push(name.clone());
1709 self.payloads.push(name);
1710 }
1711 Instruction::IterBasePointer => {
1712 let name = self.locals.tmp("base");
1713 results.push(name.clone());
1714 self.payloads.push(name);
1715 }
1716 Instruction::CallWasm {
1717 iface: _,
1718 name,
1719 sig,
1720 } => {
1721 if !sig.results.is_empty() {
1722 for i in 0..sig.results.len() {
1723 if i > 0 {
1724 builder.push_str(", ");
1725 }
1726 let ret = self.locals.tmp("ret");
1727 builder.push_str(&ret);
1728 results.push(ret);
1729 }
1730 builder.push_str(" = ");
1731 }
1732 builder.push_str(&self.src_object);
1733 builder.push_str("._");
1734 builder.push_str(&name.to_snake_case());
1735 builder.push_str("(caller");
1736 if !operands.is_empty() {
1737 builder.push_str(", ");
1738 }
1739 builder.push_str(&operands.join(", "));
1740 builder.push_str(")\n");
1741 for (ty, name) in sig.results.iter().zip(results.iter()) {
1742 let ty = match ty {
1743 WasmType::I32 | WasmType::I64 => "int",
1744 WasmType::F32 | WasmType::F64 => "float",
1745 };
1746 self.src
1747 .push_str(&format!("assert(isinstance({}, {}))\n", name, ty));
1748 }
1749 }
1750 Instruction::CallInterface { module: _, func } => {
1751 match &func.result {
1752 Type::Unit => {
1753 results.push("".to_string());
1754 }
1755 _ => {
1756 let result = self.locals.tmp("ret");
1757 builder.push_str(&result);
1758 results.push(result);
1759 builder.push_str(" = ");
1760 }
1761 }
1762 match &func.kind {
1763 FunctionKind::Freestanding | FunctionKind::Static { .. } => {
1764 builder.push_str(&format!(
1765 "host.{}({})",
1766 func.name.to_snake_case(),
1767 operands.join(", "),
1768 ));
1769 }
1770 FunctionKind::Method { name, .. } => {
1771 builder.push_str(&format!(
1772 "{}.{}({})",
1773 operands[0],
1774 name.to_snake_case(),
1775 operands[1..].join(", "),
1776 ));
1777 }
1778 }
1779 builder.push_str("\n");
1780 }
1781
1782 Instruction::Return { amt, .. } => match amt {
1783 0 => {}
1784 1 => builder.push_str(&format!("return {}\n", operands[0])),
1785 _ => {
1786 self.src
1787 .push_str(&format!("return ({})\n", operands.join(", ")));
1788 }
1789 },
1790
1791 Instruction::I32Load { offset } => self.load("c_int32", *offset, operands, results),
1792 Instruction::I64Load { offset } => self.load("c_int64", *offset, operands, results),
1793 Instruction::F32Load { offset } => self.load("c_float", *offset, operands, results),
1794 Instruction::F64Load { offset } => self.load("c_double", *offset, operands, results),
1795 Instruction::I32Load8U { offset } => self.load("c_uint8", *offset, operands, results),
1796 Instruction::I32Load8S { offset } => self.load("c_int8", *offset, operands, results),
1797 Instruction::I32Load16U { offset } => self.load("c_uint16", *offset, operands, results),
1798 Instruction::I32Load16S { offset } => self.load("c_int16", *offset, operands, results),
1799 Instruction::I32Store { offset } => self.store("c_uint32", *offset, operands),
1800 Instruction::I64Store { offset } => self.store("c_uint64", *offset, operands),
1801 Instruction::F32Store { offset } => self.store("c_float", *offset, operands),
1802 Instruction::F64Store { offset } => self.store("c_double", *offset, operands),
1803 Instruction::I32Store8 { offset } => self.store("c_uint8", *offset, operands),
1804 Instruction::I32Store16 { offset } => self.store("c_uint16", *offset, operands),
1805
1806 Instruction::Malloc {
1807 realloc,
1808 size,
1809 align,
1810 } => {
1811 self.needs_realloc = Some(realloc.to_string());
1812 let ptr = self.locals.tmp("ptr");
1813 builder.push_str(&format!(
1814 "
1815 {ptr} = realloc(caller, 0, 0, {align}, {size})
1816 assert(isinstance({ptr}, int))
1817 ",
1818 ));
1819 results.push(ptr);
1820 }
1821
1822 i => unimplemented!("{:?}", i),
1823 }
1824 }
1825}
1826
1827fn py_type_class_of(ty: &Type) -> PyTypeClass {
1828 match ty {
1829 Type::Unit => PyTypeClass::None,
1830 Type::Bool
1831 | Type::U8
1832 | Type::U16
1833 | Type::U32
1834 | Type::U64
1835 | Type::S8
1836 | Type::S16
1837 | Type::S32
1838 | Type::S64 => PyTypeClass::Int,
1839 Type::Float32 | Type::Float64 => PyTypeClass::Float,
1840 Type::Char | Type::String => PyTypeClass::Str,
1841 Type::Handle(_) | Type::Id(_) => PyTypeClass::Custom,
1842 }
1843}
1844
1845#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1846enum PyTypeClass {
1847 None,
1848 Int,
1849 Str,
1850 Float,
1851 Custom,
1852}
1853
1854fn wasm_ty_ctor(ty: WasmType) -> &'static str {
1855 match ty {
1856 WasmType::I32 => "wasmtime.ValType.i32()",
1857 WasmType::I64 => "wasmtime.ValType.i64()",
1858 WasmType::F32 => "wasmtime.ValType.f32()",
1859 WasmType::F64 => "wasmtime.ValType.f64()",
1860 }
1861}
1862
1863fn wasm_ty_typing(ty: WasmType) -> &'static str {
1864 match ty {
1865 WasmType::I32 => "int",
1866 WasmType::I64 => "int",
1867 WasmType::F32 => "float",
1868 WasmType::F64 => "float",
1869 }
1870}