From 4254b3bd046c64be680c73e2eb39d8e0f576171e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Jan 2023 11:57:17 -0800 Subject: [PATCH 1/5] Update WIT bindgen tooling This pulls in support for `use` and works with more recently generated components. --- ci/download-wasmtime.py | 1 + rust/Cargo.lock | 138 ++-- rust/Cargo.toml | 7 +- rust/bindgen.wit | 6 +- rust/bindgen/Cargo.toml | 6 +- rust/bindgen/src/bindgen.rs | 862 +++++++++++++------------ rust/bindgen/src/imports.rs | 76 ++- rust/bindgen/src/lib.rs | 4 +- rust/bindgen/src/source.rs | 4 + rust/python.wit | 2 +- rust/wasi_snapshot_preview1/src/lib.rs | 2 +- tests/codegen/test_records.py | 117 ++-- tests/codegen/test_variants.py | 273 ++++---- wasmtime/_error.py | 14 +- 14 files changed, 819 insertions(+), 693 deletions(-) diff --git a/ci/download-wasmtime.py b/ci/download-wasmtime.py index 5b39ceab..a77dd5c0 100644 --- a/ci/download-wasmtime.py +++ b/ci/download-wasmtime.py @@ -11,6 +11,7 @@ import zipfile WASMTIME_VERSION = "v5.0.0" +WASMTIME_VERSION = "dev" def main(platform, arch): diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 714aa8e6..248f0227 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "autocfg" @@ -52,9 +52,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-entity" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13" +version = "0.93.0" +source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" dependencies = [ "serde", ] @@ -157,9 +156,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "log" @@ -190,9 +189,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "percent-encoding" @@ -202,9 +201,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -222,27 +221,27 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] name = "serde" -version = "1.0.148" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.148" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -257,9 +256,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.104" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -274,18 +273,18 @@ checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -318,15 +317,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -382,28 +381,27 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +checksum = "29ab2fe77b325731603297debb4573e002d06ae0aa1f4dc108585c81961e0609" dependencies = [ "leb128", ] [[package]] -name = "wasmparser" -version = "0.95.0" +name = "wasm-encoder" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +checksum = "ef126be0e14bdf355ac1a8b41afc89195289e5c7179f80118e3abddb472f0810" dependencies = [ - "indexmap", - "url", + "leb128", ] [[package]] name = "wasmparser" -version = "0.96.0" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adde01ade41ab9a5d10ec8ed0bb954238cf8625b5cd5a13093d6de2ad9c2be1a" +checksum = "b98123a0d2bacf9286239231b116cbd66c65d9b89793f7c9bba3a3ae7f1b15f3" dependencies = [ "indexmap", "url", @@ -411,9 +409,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.97.0" +version = "0.98.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98123a0d2bacf9286239231b116cbd66c65d9b89793f7c9bba3a3ae7f1b15f3" +checksum = "8724c724dc595495979c055f4bd8b7ed9fab1069623178a28016ae43a9666f36" dependencies = [ "indexmap", "url", @@ -421,25 +419,23 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.2.46" +version = "0.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595cca929e47a7bec3c941b5a8e133f51b17e6d9dd8c82ab97902196f5a07b42" +checksum = "322949f382cd5e4bad4330e144bf2124b3182846194ac01e2423c07a6a15ba85" dependencies = [ "anyhow", - "wasmparser 0.97.0", + "wasmparser 0.98.1", ] [[package]] name = "wasmtime-component-util" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048583c2e765cac3e8842dd18a50d4feb3049ef3f182880db6626d6eb8a29383" +version = "6.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" [[package]] name = "wasmtime-environ" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a2a5f0fb93aa837a727a48dd1076e8a9f882cc2fee20b433c04a18740ff63b" +version = "6.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" dependencies = [ "anyhow", "cranelift-entity", @@ -450,8 +446,8 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasm-encoder", - "wasmparser 0.96.0", + "wasm-encoder 0.21.0", + "wasmparser 0.97.0", "wasmprinter", "wasmtime-component-util", "wasmtime-types", @@ -459,20 +455,19 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d015ba8b231248a811e323cf7a525cd3f982d4be0b9e62d27685102e5f12b1" +version = "6.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" dependencies = [ "cranelift-entity", "serde", "thiserror", - "wasmparser 0.96.0", + "wasmparser 0.97.0", ] [[package]] name = "wit-bindgen-core" version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" +source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" dependencies = [ "anyhow", "wit-component", @@ -482,7 +477,7 @@ dependencies = [ [[package]] name = "wit-bindgen-gen-guest-rust" version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" +source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" dependencies = [ "heck", "wit-bindgen-core", @@ -493,7 +488,7 @@ dependencies = [ [[package]] name = "wit-bindgen-gen-rust-lib" version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" +source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" dependencies = [ "heck", "wit-bindgen-core", @@ -502,7 +497,7 @@ dependencies = [ [[package]] name = "wit-bindgen-guest-rust" version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" +source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" dependencies = [ "bitflags", "wit-bindgen-guest-rust-macro", @@ -511,50 +506,43 @@ dependencies = [ [[package]] name = "wit-bindgen-guest-rust-macro" version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" +source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" dependencies = [ + "anyhow", "proc-macro2", "syn", "wit-bindgen-core", "wit-bindgen-gen-guest-rust", - "wit-bindgen-rust-macro-shared", -] - -[[package]] -name = "wit-bindgen-rust-macro-shared" -version = "0.3.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen#9c40084d14f50d18f1bb1c80c04e06ac50188c17" -dependencies = [ - "proc-macro2", - "syn", - "wit-bindgen-core", "wit-component", ] [[package]] name = "wit-component" -version = "0.3.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292a4db4b7de170ce349e2575f305ad592623ce16cbe824344894a10e60ab879" +checksum = "2f1781394df3f08797267cb455bac2b67cd13051d16279bd93e6c63d632c98e1" dependencies = [ "anyhow", "bitflags", "indexmap", "log", - "wasm-encoder", - "wasmparser 0.95.0", + "url", + "wasm-encoder 0.22.0", + "wasmparser 0.98.1", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703eb1d2f89ff2c52d50f7ff002735e423cea75f0a5dc5c8a4626c4c47cd9ca6" +checksum = "02cfa79275011530f37e0e164183c606bae1cdc466ea90bcd364d50605486a4d" dependencies = [ "anyhow", "id-arena", "indexmap", + "log", "pulldown-cmark", "unicode-xid", + "url", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2a4e4360..7ce256d4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -2,9 +2,14 @@ members = ['bindgen', 'wasi_snapshot_preview1'] [workspace.dependencies.wit-bindgen-guest-rust] -git = 'https://github.com/bytecodealliance/wit-bindgen' +# git = 'https://github.com/bytecodealliance/wit-bindgen' +git = 'https://github.com/alexcrichton/witx-bindgen' +branch = 'fix-bindings' default-features = false features = ['macros'] [profile.release] strip = 'debuginfo' + +[patch.crates-io] +wasmtime-environ = { git = 'https://github.com/bytecodealliance/wasmtime' } diff --git a/rust/bindgen.wit b/rust/bindgen.wit index e94cd6dd..13b8e41e 100644 --- a/rust/bindgen.wit +++ b/rust/bindgen.wit @@ -1,5 +1,3 @@ -world wasmtime-py { - default export interface { - generate: func(name: string, wit: list) -> result>>, string> - } +default world wasmtime-py { + export generate: func(name: string, wit: list) -> result>>, string> } diff --git a/rust/bindgen/Cargo.toml b/rust/bindgen/Cargo.toml index 32068fc4..d18a0fc3 100644 --- a/rust/bindgen/Cargo.toml +++ b/rust/bindgen/Cargo.toml @@ -11,10 +11,10 @@ crate-type = ['cdylib', 'rlib'] [dependencies] anyhow = "1.0" heck = { version = "0.4", features = ["unicode"] } -wit-component = "0.3" -wit-parser = "0.3" +wit-component = "0.4" +wit-parser = "0.4" indexmap = "1.0" -wasmtime-environ = { version = "5.0.0", features = ['component-model'] } +wasmtime-environ = { version = "6.0.0", features = ['component-model'] } wit-bindgen-guest-rust = { workspace = true, features = ['default'] } [features] diff --git a/rust/bindgen/src/bindgen.rs b/rust/bindgen/src/bindgen.rs index cf9568ed..b67e1afe 100644 --- a/rust/bindgen/src/bindgen.rs +++ b/rust/bindgen/src/bindgen.rs @@ -29,10 +29,10 @@ use crate::files::Files; use crate::ns::Ns; use crate::source::{self, Source}; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use heck::*; use indexmap::IndexMap; -use std::collections::{BTreeMap, BTreeSet, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Write; use std::mem; use wasmtime_environ::component::{ @@ -42,6 +42,7 @@ use wasmtime_environ::component::{ }; use wasmtime_environ::wasmparser::{Validator, WasmFeatures}; use wasmtime_environ::{EntityIndex, ModuleTranslation, PrimaryMap, ScopeVec, Tunables}; +use wit_component::DecodedWasm; use wit_parser::{ abi::{AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType}, *, @@ -66,6 +67,11 @@ pub struct WasmtimePy { /// All intrinsics emitted to `self.intrinsics` so far. all_intrinsics: BTreeSet<&'static str>, + + sizes: SizeAlign, + + imported_interfaces: HashMap, + exported_interfaces: HashMap, } impl WasmtimePy { @@ -79,8 +85,13 @@ impl WasmtimePy { // will likely change as worlds are iterated on in the component model // standard. Regardless though this is the step where types are learned // and `Interface`s are constructed for further code generation below. - let world = wit_component::decode_world(name, binary) - .context("failed to extract interface information from component")?; + let (resolve, id) = match wit_component::decode(name, binary) + .context("failed to extract interface information from component")? + { + DecodedWasm::Component(resolve, world) => (resolve, world), + DecodedWasm::WitPackage(..) => bail!("expected a component"), + }; + self.sizes.fill(&resolve); // Components are complicated, there's no real way around that. To // handle all the work of parsing a component and figuring out how to @@ -116,34 +127,38 @@ impl WasmtimePy { // With all that prep work delegate to `generate` here // to generate all the type-level descriptions for this component now // that the interfaces in/out are understood. + let world = &resolve.worlds[id]; for (name, import) in world.imports.iter() { - self.import(name, import, files); + match import { + WorldItem::Function(_) => unimplemented!(), + WorldItem::Interface(id) => self.import_interface(&resolve, name, *id, files), + } } for (name, export) in world.exports.iter() { - self.export(name, export, files); - } - if let Some(iface) = &world.default { - self.export_default(name, iface, files); + match export { + WorldItem::Function(_) => {} + WorldItem::Interface(id) => self.export_interface(&resolve, name, *id, files), + } } self.finish_interfaces(&world, files); // And finally generate the code necessary to instantiate the given // component to this method using the `Component` that // `wasmtime-environ` parsed. - self.instantiate(&world, &component, &modules); + self.instantiate(&resolve, id, &component, &modules); self.finish_component(name, files); Ok(()) } - fn interface<'a>(&'a mut self, iface: &'a Interface, at_root: bool) -> InterfaceGenerator<'a> { + fn interface<'a>(&'a mut self, resolve: &'a Resolve) -> InterfaceGenerator<'a> { InterfaceGenerator { gen: self, - iface, + resolve, src: Source::default(), - at_root, - self_module_path: "", + interface: None, + at_root: false, } } @@ -174,12 +189,14 @@ impl WasmtimePy { fn instantiate( &mut self, - world: &World, + resolve: &Resolve, + id: WorldId, component: &Component, modules: &PrimaryMap>, ) { self.init.pyimport("wasmtime", None); + let world = &resolve.worlds[id]; let camel = world.name.to_upper_camel_case(); let imports = if !component.import_types.is_empty() { self.init @@ -202,9 +219,10 @@ impl WasmtimePy { let mut i = Instantiator { name: &world.name, gen: self, + resolve: &resolve, modules, component, - world, + world: id, instances: PrimaryMap::default(), lifts: 0, }; @@ -214,7 +232,7 @@ impl WasmtimePy { if component.initializers.len() == 0 { i.gen.init.push_str("pass\n"); } - let (lifts, nested) = i.exports(&component.exports, world.default.as_ref()); + let (lifts, nested) = i.exports(&component.exports); i.gen.init.dedent(); i.generate_lifts(&camel, None, &lifts); @@ -250,9 +268,17 @@ impl WasmtimePy { files.push("__init__.py", self.init.finish().as_bytes()); } - fn import(&mut self, name: &str, iface: &Interface, files: &mut Files) { - let mut gen = self.interface(iface, false); - gen.types(); + fn import_interface( + &mut self, + resolve: &Resolve, + name: &str, + iface: InterfaceId, + files: &mut Files, + ) { + self.imported_interfaces.insert(iface, name.to_string()); + let mut gen = self.interface(resolve); + gen.interface = Some(iface); + gen.types(iface); // Generate a "protocol" class which I'm led to believe is the rough // equivalent of a Rust trait in Python for this imported interface. @@ -262,7 +288,7 @@ impl WasmtimePy { gen.src.pyimport("typing", "Protocol"); uwriteln!(gen.src, "class {camel}(Protocol):"); gen.src.indent(); - for func in iface.functions.iter() { + for (_, func) in resolve.interfaces[iface].functions.iter() { gen.src.pyimport("abc", "abstractmethod"); gen.src.push_str("@abstractmethod\n"); gen.print_sig(func, true); @@ -271,7 +297,7 @@ impl WasmtimePy { gen.src.push_str("raise NotImplementedError\n"); gen.src.dedent(); } - if iface.functions.is_empty() { + if resolve.interfaces[iface].functions.is_empty() { gen.src.push_str("pass\n"); } gen.src.dedent(); @@ -282,9 +308,17 @@ impl WasmtimePy { self.imports.push(name.to_string()); } - fn export(&mut self, name: &str, iface: &Interface, _files: &mut Files) { - let mut gen = self.interface(iface, false); - gen.types(); + fn export_interface( + &mut self, + resolve: &Resolve, + name: &str, + iface: InterfaceId, + _files: &mut Files, + ) { + self.exported_interfaces.insert(iface, name.to_string()); + let mut gen = self.interface(resolve); + gen.interface = Some(iface); + gen.types(iface); // Only generate types for exports and this will get finished later on // as lifted functions need to be inserted into these files as they're @@ -293,17 +327,6 @@ impl WasmtimePy { self.exports.insert(name.to_string(), src); } - fn export_default(&mut self, _name: &str, iface: &Interface, _files: &mut Files) { - let mut gen = self.interface(iface, true); - - // Generate types and imports directly into `__init__.py` for the - // default export, and exported functions (lifted functions) will get - // generate later. - mem::swap(&mut gen.src, &mut gen.gen.init); - gen.types(); - mem::swap(&mut gen.src, &mut gen.gen.init); - } - fn finish_interfaces(&mut self, world: &World, _files: &mut Files) { if !self.imports.is_empty() { let camel = world.name.to_upper_camel_case(); @@ -323,7 +346,7 @@ impl WasmtimePy { } } -fn array_ty(iface: &Interface, ty: &Type) -> Option<&'static str> { +fn array_ty(resolve: &Resolve, ty: &Type) -> Option<&'static str> { match ty { Type::Bool => None, Type::U8 => Some("c_uint8"), @@ -338,8 +361,8 @@ fn array_ty(iface: &Interface, ty: &Type) -> Option<&'static str> { Type::Float64 => Some("c_double"), Type::Char => None, Type::String => None, - Type::Id(id) => match &iface.types[*id].kind { - TypeDefKind::Type(t) => array_ty(iface, t), + Type::Id(id) => match &resolve.types[*id].kind { + TypeDefKind::Type(t) => array_ty(resolve, t), _ => None, }, } @@ -350,16 +373,17 @@ struct Instantiator<'a> { gen: &'a mut WasmtimePy, modules: &'a PrimaryMap>, instances: PrimaryMap, - world: &'a World, + world: WorldId, component: &'a Component, lifts: usize, + resolve: &'a Resolve, } struct Lift<'a> { callee: String, opts: &'a CanonicalOptions, - iface: &'a Interface, func: &'a Function, + interface: Option, } impl<'a> Instantiator<'a> { @@ -464,9 +488,17 @@ impl<'a> Instantiator<'a> { // where instances export functions. let (import_index, path) = &self.component.imports[import.import]; let (import_name, _import_ty) = &self.component.import_types[*import_index]; - assert_eq!(path.len(), 1); - let iface = &self.world.imports[import_name.as_str()]; - let func = iface.functions.iter().find(|f| f.name == path[0]).unwrap(); + let item = &self.resolve.worlds[self.world].imports[import_name.as_str()]; + let (func, interface) = match item { + WorldItem::Function(f) => { + assert_eq!(path.len(), 0); + (f, None) + } + WorldItem::Interface(i) => { + assert_eq!(path.len(), 1); + (&self.resolve.interfaces[*i].functions[&path[0]], Some(*i)) + } + }; let index = import.index.as_u32(); let callee = format!( @@ -483,7 +515,7 @@ impl<'a> Instantiator<'a> { self.gen.init, "def lowering{index}_callee(caller: wasmtime.Caller" ); - let sig = iface.wasm_signature(AbiVariant::GuestImport, func); + let sig = self.resolve.wasm_signature(AbiVariant::GuestImport, func); let mut params = Vec::new(); for (i, param_ty) in sig.params.iter().enumerate() { self.gen.init.push_str(", "); @@ -500,19 +532,14 @@ impl<'a> Instantiator<'a> { self.gen.init.push_str(":\n"); self.gen.init.indent(); - let iface_snake = iface.name.to_snake_case(); - self.gen.init.pyimport(".imports", iface_snake.as_str()); - let self_module_path = format!("{iface_snake}."); - self.bindgen( params, callee, &import.options, - iface, func, AbiVariant::GuestImport, "self", - self_module_path, + interface, true, ); self.gen.init.dedent(); @@ -541,11 +568,10 @@ impl<'a> Instantiator<'a> { params: Vec, callee: String, opts: &CanonicalOptions, - iface: &Interface, func: &Function, abi: AbiVariant, this: &str, - self_module_path: String, + interface: Option, at_root: bool, ) { // Technically it wouldn't be the hardest thing in the world to support @@ -568,31 +594,31 @@ impl<'a> Instantiator<'a> { None => None, }; - let mut sizes = SizeAlign::default(); - sizes.fill(iface); let mut locals = Ns::default(); locals.insert("len").unwrap(); // python built-in locals.insert("base").unwrap(); // may be used as loop var locals.insert("i").unwrap(); // may be used as loop var - let mut f = FunctionBindgen { - locals, - payloads: Vec::new(), - sizes, + let mut gen = InterfaceGenerator { // Generate source directly onto `init` src: mem::take(&mut self.gen.init), gen: self.gen, + resolve: self.resolve, + interface, + at_root, + }; + let mut f = FunctionBindgen { + locals, + payloads: Vec::new(), block_storage: Vec::new(), blocks: Vec::new(), + gen: &mut gen, callee, memory, realloc, params, post_return, - iface, - self_module_path, - at_root, }; - iface.call( + self.resolve.call( abi, match abi { AbiVariant::GuestImport => LiftLower::LiftArgsLowerResults, @@ -604,8 +630,8 @@ impl<'a> Instantiator<'a> { // Swap the printed source back into the destination of our `init`, and // at this time `f.src` should be empty. - mem::swap(&mut f.src, &mut f.gen.init); - assert!(f.src.is_empty()); + mem::swap(&mut f.gen.src, &mut f.gen.gen.init); + assert!(f.gen.src.is_empty()); } fn core_def(&self, def: &CoreDef) -> String { @@ -648,45 +674,54 @@ impl<'a> Instantiator<'a> { fn exports( &mut self, exports: &'a IndexMap, - iface: Option<&'a Interface>, ) -> (Vec>, BTreeMap<&'a str, Vec>>) { let mut toplevel = Vec::new(); let mut nested = BTreeMap::new(); for (name, export) in exports { let name = name.as_str(); + let item = &self.resolve.worlds[self.world].exports[name]; match export { Export::LiftedFunction { ty: _, func, options, } => { - // For each lifted function the callee `wasmtime.Func` is - // saved into a per-instance field which is then referenced - // as the callee when the relevant function is invoked. - let def = self.core_def(func); - let callee = format!("lift_callee{}", self.lifts); - self.lifts += 1; - uwriteln!(self.gen.init, "{callee} = {def}"); - uwriteln!(self.gen.init, "assert(isinstance({callee}, wasmtime.Func))"); - uwriteln!(self.gen.init, "self.{callee} = {callee}"); - let iface = iface.unwrap(); - let func = iface.functions.iter().find(|f| f.name == *name).unwrap(); + let callee = self.gen_lift_callee(func); + let func = match item { + WorldItem::Function(f) => f, + WorldItem::Interface(_) => unreachable!(), + }; toplevel.push(Lift { callee, opts: options, - iface, func, + interface: None, }); } Export::Instance(exports) => { - let iface = &self.world.exports[name]; - let (my_toplevel, my_nested) = self.exports(exports, Some(iface)); - // More than one level of nesting not supported at this - // time. - assert!(my_nested.is_empty()); + let id = match item { + WorldItem::Interface(id) => *id, + WorldItem::Function(_) => unreachable!(), + }; + let mut lifts = Vec::new(); + for (name, export) in exports { + let (callee, options) = match export { + Export::LiftedFunction { func, options, .. } => (func, options), + Export::Type(_) => continue, + Export::Module(_) | Export::Instance(_) => unreachable!(), + }; + let callee = self.gen_lift_callee(callee); + let func = &self.resolve.interfaces[id].functions[name]; + lifts.push(Lift { + callee, + opts: options, + func, + interface: Some(id), + }); + } - let prev = nested.insert(name, my_toplevel); + let prev = nested.insert(name, lifts); assert!(prev.is_none()); } @@ -700,6 +735,19 @@ impl<'a> Instantiator<'a> { (toplevel, nested) } + fn gen_lift_callee(&mut self, callee: &CoreDef) -> String { + // For each lifted function the callee `wasmtime.Func` is + // saved into a per-instance field which is then referenced + // as the callee when the relevant function is invoked. + let def = self.core_def(callee); + let callee = format!("lift_callee{}", self.lifts); + self.lifts += 1; + uwriteln!(self.gen.init, "{callee} = {def}"); + uwriteln!(self.gen.init, "assert(isinstance({callee}, wasmtime.Func))"); + uwriteln!(self.gen.init, "self.{callee} = {callee}"); + callee + } + fn generate_lifts(&mut self, camel_component: &str, ns: Option<&str>, lifts: &[Lift<'_>]) { let mut this = "self".to_string(); @@ -715,11 +763,11 @@ impl<'a> Instantiator<'a> { let snake = ns.to_snake_case(); uwriteln!(src, "class {camel}:"); src.indent(); - src.pyimport("..", camel_component); - uwriteln!(src, "component: {camel_component}\n"); + src.typing_import("..", camel_component); + uwriteln!(src, "component: '{camel_component}'\n"); uwriteln!( src, - "def __init__(self, component: {camel_component}) -> None:" + "def __init__(self, component: '{camel_component}') -> None:" ); src.indent(); uwriteln!(src, "self.component = component"); @@ -741,10 +789,15 @@ impl<'a> Instantiator<'a> { for lift in lifts { // Go through some small gymnastics to print the function signature // here. - let mut src = mem::take(&mut self.gen.init); - let params = with_igen(&mut src, self.gen, lift.iface, ns.is_none(), "", |gen| { - gen.print_sig(lift.func, false) - }); + let mut gen = InterfaceGenerator { + resolve: self.resolve, + src: mem::take(&mut self.gen.init), + gen: self.gen, + interface: lift.interface, + at_root: ns.is_none(), + }; + let params = gen.print_sig(lift.func, false); + let src = mem::take(&mut gen.src); self.gen.init = src; self.gen.init.push_str(":\n"); @@ -755,11 +808,10 @@ impl<'a> Instantiator<'a> { params, format!("{this}.{}", lift.callee), lift.opts, - lift.iface, lift.func, AbiVariant::GuestExport, &this, - String::new(), + lift.interface, ns.is_none(), ); self.gen.init.dedent(); @@ -776,9 +828,9 @@ impl<'a> Instantiator<'a> { struct InterfaceGenerator<'a> { src: Source, gen: &'a mut WasmtimePy, - iface: &'a Interface, + resolve: &'a Resolve, + interface: Option, at_root: bool, - self_module_path: &'a str, } #[derive(Debug, Clone, Copy)] @@ -792,8 +844,7 @@ enum PyUnionRepresentation { impl InterfaceGenerator<'_> { fn import_result_type(&mut self) { self.gen.print_result(); - let path = if self.at_root { ".types" } else { "..types" }; - self.src.pyimport(path, "Result"); + self.import_shared_type("Result"); } fn print_ty(&mut self, ty: &Type, forward_ref: bool) { @@ -811,10 +862,33 @@ impl InterfaceGenerator<'_> { Type::Char => self.src.push_str("str"), Type::String => self.src.push_str("str"), Type::Id(id) => { - let ty = &self.iface.types[*id]; + let ty = &self.resolve.types[*id]; if let Some(name) = &ty.name { - self.src.push_str(self.self_module_path); - self.src.push_str(&name.to_upper_camel_case()); + let owner = match ty.owner { + TypeOwner::Interface(id) => id, + _ => unreachable!(), + }; + if Some(owner) == self.interface { + let name = self.name_of(name); + self.src.push_str(&name); + } else { + let (module, iface) = match self.gen.imported_interfaces.get(&owner) { + Some(name) => ("imports", name), + None => ("exports", &self.gen.exported_interfaces[&owner]), + }; + let module = if self.at_root { + format!(".{module}") + } else { + format!("..{module}") + }; + let iface = iface.to_snake_case(); + self.src.pyimport(&module, iface.as_str()); + uwrite!( + self.src, + "{iface}.{name}", + name = name.to_upper_camel_case() + ) + } return; } match &ty.kind { @@ -854,6 +928,7 @@ impl InterfaceGenerator<'_> { self.print_optional_ty(s.end.as_ref(), true); self.src.push_str("]"); } + TypeDefKind::Unknown => unreachable!(), } } } @@ -986,12 +1061,10 @@ impl InterfaceGenerator<'_> { self.src.push_str("]\n\n"); } - fn types(&mut self) { - for (id, ty) in self.iface.types.iter() { - let name = match &ty.name { - Some(name) => name, - None => continue, - }; + fn types(&mut self, interface: InterfaceId) { + for (name, id) in self.resolve.interfaces[interface].types.iter() { + let id = *id; + let ty = &self.resolve.types[id]; match &ty.kind { TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs), TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs), @@ -1005,6 +1078,7 @@ impl InterfaceGenerator<'_> { TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), TypeDefKind::Future(_) => todo!("generate for future"), TypeDefKind::Stream(_) => todo!("generate for stream"), + TypeDefKind::Unknown => unreachable!(), } } } @@ -1166,28 +1240,43 @@ impl InterfaceGenerator<'_> { self.print_list(ty); self.src.push_str("\n"); } + + fn import_shared_type(&mut self, ty: &str) { + let path = if self.at_root { ".types" } else { "..types" }; + self.src.pyimport(path, ty); + } + + fn name_of(&mut self, ty: &str) -> String { + let ty = ty.to_upper_camel_case(); + if !self.at_root { + return ty; + } + let id = self.interface.unwrap(); + let (module, iface) = match self.gen.imported_interfaces.get(&id) { + Some(name) => (".imports", name), + None => (".exports", &self.gen.exported_interfaces[&id]), + }; + let iface = iface.to_snake_case(); + self.src.pyimport(&module, iface.as_str()); + format!("{iface}.{ty}") + } } -struct FunctionBindgen<'a> { - gen: &'a mut WasmtimePy, - iface: &'a Interface, +struct FunctionBindgen<'a, 'b> { + gen: &'a mut InterfaceGenerator<'b>, locals: Ns, - src: Source, block_storage: Vec, blocks: Vec<(String, Vec)>, params: Vec, payloads: Vec, - sizes: SizeAlign, memory: Option, realloc: Option, post_return: Option, callee: String, - self_module_path: String, - at_root: bool, } -impl FunctionBindgen<'_> { +impl FunctionBindgen<'_, '_> { fn clamp(&mut self, results: &mut Vec, operands: &[String], min: T, max: T) where T: std::fmt::Display, @@ -1200,9 +1289,9 @@ impl FunctionBindgen<'_> { let load = self.print_load(); let memory = self.memory.as_ref().unwrap(); let tmp = self.locals.tmp("load"); - self.src.pyimport("ctypes", None); + self.gen.src.pyimport("ctypes", None); uwriteln!( - self.src, + self.gen.src, "{tmp} = {load}(ctypes.{ty}, {memory}, caller, {}, {offset})", operands[0], ); @@ -1212,9 +1301,9 @@ impl FunctionBindgen<'_> { fn store(&mut self, ty: &str, offset: i32, operands: &[String]) { let store = self.print_store(); let memory = self.memory.as_ref().unwrap(); - self.src.pyimport("ctypes", None); + self.gen.src.pyimport("ctypes", None); uwriteln!( - self.src, + self.gen.src, "{store}(ctypes.{ty}, {memory}, caller, {}, {offset}, {})", operands[1], operands[0] @@ -1222,25 +1311,11 @@ impl FunctionBindgen<'_> { } fn print_ty(&mut self, ty: &Type) { - with_igen( - &mut self.src, - self.gen, - self.iface, - self.at_root, - &self.self_module_path, - |gen| gen.print_ty(ty, false), - ) + self.gen.print_ty(ty, false) } fn print_list(&mut self, element: &Type) { - with_igen( - &mut self.src, - self.gen, - self.iface, - self.at_root, - &self.self_module_path, - |gen| gen.print_list(element), - ) + self.gen.print_list(element) } fn print_intrinsic( @@ -1248,16 +1323,16 @@ impl FunctionBindgen<'_> { name: &'static str, gen: impl FnOnce(&str, &mut Source), ) -> &'static str { - let path = if self.at_root { + let path = if self.gen.at_root { ".intrinsics" } else { "..intrinsics" }; - self.src.pyimport(path, name); - if !self.gen.all_intrinsics.insert(name) { + self.gen.src.pyimport(path, name); + if !self.gen.gen.all_intrinsics.insert(name) { return name; } - gen(name, &mut self.gen.intrinsics); + gen(name, &mut self.gen.gen.intrinsics); return name; } @@ -1304,14 +1379,15 @@ impl FunctionBindgen<'_> { } fn print_i32_to_f32_cvts(&mut self) { - if !self.gen.all_intrinsics.insert("i32_to_f32_cvts") { + if !self.gen.gen.all_intrinsics.insert("i32_to_f32_cvts") { return; } - self.gen.intrinsics.pyimport("ctypes", None); + self.gen.gen.intrinsics.pyimport("ctypes", None); self.gen + .gen .intrinsics .push_str("_i32_to_f32_i32 = ctypes.pointer(ctypes.c_int32(0))\n"); - self.gen.intrinsics.push_str( + self.gen.gen.intrinsics.push_str( "_i32_to_f32_f32 = ctypes.cast(_i32_to_f32_i32, ctypes.POINTER(ctypes.c_float))\n", ); } @@ -1345,14 +1421,15 @@ impl FunctionBindgen<'_> { } fn print_i64_to_f64_cvts(&mut self) { - if !self.gen.all_intrinsics.insert("i64_to_f64_cvts") { + if !self.gen.gen.all_intrinsics.insert("i64_to_f64_cvts") { return; } - self.gen.intrinsics.pyimport("ctypes", None); + self.gen.gen.intrinsics.pyimport("ctypes", None); self.gen + .gen .intrinsics .push_str("_i64_to_f64_i64 = ctypes.pointer(ctypes.c_int64(0))\n"); - self.gen.intrinsics.push_str( + self.gen.gen.intrinsics.push_str( "_i64_to_f64_f64 = ctypes.cast(_i64_to_f64_i64, ctypes.POINTER(ctypes.c_double))\n", ); } @@ -1524,36 +1601,40 @@ impl FunctionBindgen<'_> { ); }) } + + fn name_of(&mut self, ty: &str) -> String { + self.gen.name_of(ty) + } } -impl Bindgen for FunctionBindgen<'_> { +impl Bindgen for FunctionBindgen<'_, '_> { type Operand = String; fn sizes(&self) -> &SizeAlign { - &self.sizes + &self.gen.gen.sizes } fn push_block(&mut self) { - self.block_storage.push(self.src.take_body()); + self.block_storage.push(self.gen.src.take_body()); } fn finish_block(&mut self, operands: &mut Vec) { let to_restore = self.block_storage.pop().unwrap(); - let src = self.src.replace_body(to_restore); + let src = self.gen.src.replace_body(to_restore); self.blocks.push((src, mem::take(operands))); } - fn return_pointer(&mut self, _iface: &Interface, _size: usize, _align: usize) -> String { + fn return_pointer(&mut self, _size: usize, _align: usize) -> String { unimplemented!() } - fn is_list_canonical(&self, iface: &Interface, ty: &Type) -> bool { - array_ty(iface, ty).is_some() + fn is_list_canonical(&self, resolve: &Resolve, ty: &Type) -> bool { + array_ty(resolve, ty).is_some() } fn emit( &mut self, - iface: &Interface, + resolve: &Resolve, inst: &Instruction<'_>, operands: &mut Vec, results: &mut Vec, @@ -1664,22 +1745,22 @@ impl Bindgen for FunctionBindgen<'_> { let op = self.locals.tmp("operand"); let ret = self.locals.tmp("boolean"); - uwriteln!(self.src, "{op} = {}", operands[0]); - uwriteln!(self.src, "if {op} == 0:"); - self.src.indent(); - uwriteln!(self.src, "{ret} = False"); - self.src.dedent(); - uwriteln!(self.src, "elif {op} == 1:"); - self.src.indent(); - uwriteln!(self.src, "{ret} = True"); - self.src.dedent(); - uwriteln!(self.src, "else:"); - self.src.indent(); + uwriteln!(self.gen.src, "{op} = {}", operands[0]); + uwriteln!(self.gen.src, "if {op} == 0:"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{ret} = False"); + self.gen.src.dedent(); + uwriteln!(self.gen.src, "elif {op} == 1:"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{ret} = True"); + self.gen.src.dedent(); + uwriteln!(self.gen.src, "else:"); + self.gen.src.indent(); uwriteln!( - self.src, + self.gen.src, "raise TypeError(\"invalid variant discriminant for bool\")" ); - self.src.dedent(); + self.gen.src.dedent(); results.push(ret); } Instruction::I32FromBool => { @@ -1691,33 +1772,32 @@ impl Bindgen for FunctionBindgen<'_> { return; } let tmp = self.locals.tmp("record"); - uwriteln!(self.src, "{tmp} = {}", operands[0]); + uwriteln!(self.gen.src, "{tmp} = {}", operands[0]); for field in record.fields.iter() { let name = self.locals.tmp("field"); - uwriteln!(self.src, "{name} = {tmp}.{}", field.name.to_snake_case(),); + uwriteln!( + self.gen.src, + "{name} = {tmp}.{}", + field.name.to_snake_case(), + ); results.push(name); } } Instruction::RecordLift { name, .. } => { - results.push(format!( - "{}{}({})", - self.self_module_path, - name.to_upper_camel_case(), - operands.join(", ") - )); + results.push(format!("{}({})", self.name_of(name), operands.join(", "))); } Instruction::TupleLower { tuple, .. } => { if tuple.types.is_empty() { return; } - self.src.push_str("("); + self.gen.src.push_str("("); for _ in 0..tuple.types.len() { let name = self.locals.tmp("tuplei"); - uwrite!(self.src, "{name},"); + uwrite!(self.gen.src, "{name},"); results.push(name); } - uwriteln!(self.src, ") = {}", operands[0]); + uwriteln!(self.gen.src, ") = {}", operands[0]); } Instruction::TupleLift { .. } => { if operands.is_empty() { @@ -1731,25 +1811,22 @@ impl Bindgen for FunctionBindgen<'_> { 1 => operands[0].clone(), _ => { let tmp = self.locals.tmp("bits"); - uwriteln!(self.src, "{tmp} = 0"); + uwriteln!(self.gen.src, "{tmp} = 0"); for (i, op) in operands.iter().enumerate() { let i = 32 * i; - uwriteln!(self.src, "{tmp} |= ({op} & 0xffffffff) << {i}\n"); + uwriteln!(self.gen.src, "{tmp} |= ({op} & 0xffffffff) << {i}\n"); } tmp } }; - results.push(format!( - "{}{}({operand})", - self.self_module_path, - name.to_upper_camel_case() - )); + results.push(format!("{}({operand})", self.name_of(name))); } Instruction::FlagsLower { flags, .. } => match flags.repr().count() { 1 => results.push(format!("({}).value", operands[0])), n => { let tmp = self.locals.tmp("bits"); - self.src + self.gen + .src .push_str(&format!("{tmp} = ({}).value\n", operands[0])); for i in 0..n { let i = 32 * i; @@ -1787,38 +1864,37 @@ impl Bindgen for FunctionBindgen<'_> { variant.cases.iter().zip(blocks).zip(payloads).enumerate() { if i == 0 { - self.src.push_str("if "); + self.gen.src.push_str("if "); } else { - self.src.push_str("elif "); + self.gen.src.push_str("elif "); } + let name = self.name_of(name); uwriteln!( - self.src, - "isinstance({}, {}{}{}):", + self.gen.src, + "isinstance({}, {name}{}):", operands[0], - self.self_module_path, - name.to_upper_camel_case(), case.name.to_upper_camel_case() ); - self.src.indent(); + self.gen.src.indent(); if case.ty.is_some() { - uwriteln!(self.src, "{payload} = {}.value", operands[0]); + uwriteln!(self.gen.src, "{payload} = {}.value", operands[0]); } - self.src.push_str(&block); + self.gen.src.push_str(&block); for (i, result) in block_results.iter().enumerate() { - uwriteln!(self.src, "{} = {result}", results[i]); + uwriteln!(self.gen.src, "{} = {result}", results[i]); } - self.src.dedent(); + self.gen.src.dedent(); } let variant_name = name.to_upper_camel_case(); - self.src.push_str("else:\n"); - self.src.indent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); uwriteln!( - self.src, + self.gen.src, "raise TypeError(\"invalid variant specified for {variant_name}\")", ); - self.src.dedent(); + self.gen.src.dedent(); } Instruction::VariantLift { @@ -1830,43 +1906,42 @@ impl Bindgen for FunctionBindgen<'_> { .collect::>(); let result = self.locals.tmp("variant"); - uwrite!(self.src, "{result}: "); + uwrite!(self.gen.src, "{result}: "); self.print_ty(&Type::Id(*ty)); - self.src.push_str("\n"); + self.gen.src.push_str("\n"); for (i, (case, (block, block_results))) in variant.cases.iter().zip(blocks).enumerate() { if i == 0 { - self.src.push_str("if "); + self.gen.src.push_str("if "); } else { - self.src.push_str("elif "); + self.gen.src.push_str("elif "); } - uwriteln!(self.src, "{} == {i}:", operands[0]); - self.src.indent(); - self.src.push_str(&block); + uwriteln!(self.gen.src, "{} == {i}:", operands[0]); + self.gen.src.indent(); + self.gen.src.push_str(&block); + let name = self.name_of(name); uwrite!( - self.src, - "{result} = {}{}{}(", - self.self_module_path, - name.to_upper_camel_case(), + self.gen.src, + "{result} = {name}{}(", case.name.to_upper_camel_case() ); if block_results.len() > 0 { assert!(block_results.len() == 1); - self.src.push_str(&block_results[0]); + self.gen.src.push_str(&block_results[0]); } - self.src.push_str(")\n"); - self.src.dedent(); + self.gen.src.push_str(")\n"); + self.gen.src.dedent(); } - self.src.push_str("else:\n"); - self.src.indent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); let variant_name = name.to_upper_camel_case(); uwriteln!( - self.src, + self.gen.src, "raise TypeError(\"invalid variant discriminant for {variant_name}\")", ); - self.src.dedent(); + self.gen.src.dedent(); results.push(result); } @@ -1890,46 +1965,46 @@ impl Bindgen for FunctionBindgen<'_> { } let union_representation = classify_union(union.cases.iter().map(|c| c.ty)); - let name = name.to_upper_camel_case(); let op0 = &operands[0]; for (i, ((case, (block, block_results)), payload)) in union.cases.iter().zip(blocks).zip(payloads).enumerate() { - self.src.push_str(if i == 0 { "if " } else { "elif " }); - uwrite!(self.src, "isinstance({op0}, "); + self.gen.src.push_str(if i == 0 { "if " } else { "elif " }); + uwrite!(self.gen.src, "isinstance({op0}, "); match union_representation { // Prints the Python type for this union case PyUnionRepresentation::Raw => self.print_ty(&case.ty), // Prints the name of this union cases dataclass PyUnionRepresentation::Wrapped => { - uwrite!(self.src, "{}{name}{i}", self.self_module_path); + let name = self.name_of(name); + uwrite!(self.gen.src, "{name}{i}"); } } - uwriteln!(self.src, "):"); - self.src.indent(); + uwriteln!(self.gen.src, "):"); + self.gen.src.indent(); match union_representation { // Uses the value directly PyUnionRepresentation::Raw => { - uwriteln!(self.src, "{payload} = {op0}") + uwriteln!(self.gen.src, "{payload} = {op0}") } // Uses this union case dataclass's inner value PyUnionRepresentation::Wrapped => { - uwriteln!(self.src, "{payload} = {op0}.value") + uwriteln!(self.gen.src, "{payload} = {op0}.value") } } - self.src.push_str(&block); + self.gen.src.push_str(&block); for (i, result) in block_results.iter().enumerate() { - uwriteln!(self.src, "{} = {result}", results[i]); + uwriteln!(self.gen.src, "{} = {result}", results[i]); } - self.src.dedent(); + self.gen.src.dedent(); } - self.src.push_str("else:\n"); - self.src.indent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); uwriteln!( - self.src, + self.gen.src, "raise TypeError(\"invalid variant specified for {name}\")" ); - self.src.dedent(); + self.gen.src.dedent(); } Instruction::UnionLift { @@ -1941,44 +2016,40 @@ impl Bindgen for FunctionBindgen<'_> { .collect::>(); let result = self.locals.tmp("variant"); - uwrite!(self.src, "{result}: "); + uwrite!(self.gen.src, "{result}: "); self.print_ty(&Type::Id(*ty)); - self.src.push_str("\n"); + self.gen.src.push_str("\n"); let union_representation = classify_union(union.cases.iter().map(|c| c.ty)); - let name = name.to_upper_camel_case(); let op0 = &operands[0]; for (i, (_case, (block, block_results))) in union.cases.iter().zip(blocks).enumerate() { - self.src.push_str(if i == 0 { "if " } else { "elif " }); - uwriteln!(self.src, "{op0} == {i}:"); - self.src.indent(); - self.src.push_str(&block); + self.gen.src.push_str(if i == 0 { "if " } else { "elif " }); + uwriteln!(self.gen.src, "{op0} == {i}:"); + self.gen.src.indent(); + self.gen.src.push_str(&block); assert!(block_results.len() == 1); let block_result = &block_results[0]; - uwrite!(self.src, "{result} = "); + uwrite!(self.gen.src, "{result} = "); match union_representation { // Uses the passed value directly - PyUnionRepresentation::Raw => self.src.push_str(block_result), + PyUnionRepresentation::Raw => self.gen.src.push_str(block_result), // Constructs an instance of the union cases dataclass PyUnionRepresentation::Wrapped => { - uwrite!( - self.src, - "{}{name}{i}({block_result})", - self.self_module_path - ) + let name = self.name_of(name); + uwrite!(self.gen.src, "{name}{i}({block_result})") } } - self.src.newline(); - self.src.dedent(); + self.gen.src.newline(); + self.gen.src.dedent(); } - self.src.push_str("else:\n"); - self.src.indent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); uwriteln!( - self.src, + self.gen.src, "raise TypeError(\"invalid variant discriminant for {name}\")\n", ); - self.src.dedent(); + self.gen.src.dedent(); results.push(result); } @@ -1996,22 +2067,22 @@ impl Bindgen for FunctionBindgen<'_> { } let op0 = &operands[0]; - uwriteln!(self.src, "if {op0} is None:"); + uwriteln!(self.gen.src, "if {op0} is None:"); - self.src.indent(); - self.src.push_str(&none); + self.gen.src.indent(); + self.gen.src.push_str(&none); for (dst, result) in results.iter().zip(&none_results) { - uwriteln!(self.src, "{dst} = {result}"); + uwriteln!(self.gen.src, "{dst} = {result}"); } - self.src.dedent(); - self.src.push_str("else:\n"); - self.src.indent(); - uwriteln!(self.src, "{some_payload} = {op0}"); - self.src.push_str(&some); + self.gen.src.dedent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{some_payload} = {op0}"); + self.gen.src.push_str(&some); for (dst, result) in results.iter().zip(&some_results) { - uwriteln!(self.src, "{dst} = {result}"); + uwriteln!(self.gen.src, "{dst} = {result}"); } - self.src.dedent(); + self.gen.src.dedent(); } Instruction::OptionLift { ty, .. } => { @@ -2022,27 +2093,28 @@ impl Bindgen for FunctionBindgen<'_> { let some_result = &some_results[0]; let result = self.locals.tmp("option"); - uwrite!(self.src, "{result}: "); + uwrite!(self.gen.src, "{result}: "); self.print_ty(&Type::Id(*ty)); - self.src.push_str("\n"); + self.gen.src.push_str("\n"); let op0 = &operands[0]; - uwriteln!(self.src, "if {op0} == 0:"); - self.src.indent(); - self.src.push_str(&none); - uwriteln!(self.src, "{result} = None"); - self.src.dedent(); - uwriteln!(self.src, "elif {op0} == 1:"); - self.src.indent(); - self.src.push_str(&some); - uwriteln!(self.src, "{result} = {some_result}"); - self.src.dedent(); - - self.src.push_str("else:\n"); - self.src.indent(); - self.src + uwriteln!(self.gen.src, "if {op0} == 0:"); + self.gen.src.indent(); + self.gen.src.push_str(&none); + uwriteln!(self.gen.src, "{result} = None"); + self.gen.src.dedent(); + uwriteln!(self.gen.src, "elif {op0} == 1:"); + self.gen.src.indent(); + self.gen.src.push_str(&some); + uwriteln!(self.gen.src, "{result} = {some_result}"); + self.gen.src.dedent(); + + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); + self.gen + .src .push_str("raise TypeError(\"invalid variant discriminant for option\")\n"); - self.src.dedent(); + self.gen.src.dedent(); results.push(result); } @@ -2055,38 +2127,37 @@ impl Bindgen for FunctionBindgen<'_> { let (ok, ok_results) = self.blocks.pop().unwrap(); let err_payload = self.payloads.pop().unwrap(); let ok_payload = self.payloads.pop().unwrap(); - let path = if self.at_root { ".types" } else { "..types" }; - self.src.pyimport(path, "Ok"); - self.src.pyimport(path, "Err"); + self.gen.import_shared_type("Ok"); + self.gen.import_shared_type("Err"); for _ in 0..result_types.len() { results.push(self.locals.tmp("variant")); } let op0 = &operands[0]; - uwriteln!(self.src, "if isinstance({op0}, Ok):"); + uwriteln!(self.gen.src, "if isinstance({op0}, Ok):"); - self.src.indent(); - uwriteln!(self.src, "{ok_payload} = {op0}.value"); - self.src.push_str(&ok); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{ok_payload} = {op0}.value"); + self.gen.src.push_str(&ok); for (dst, result) in results.iter().zip(&ok_results) { - uwriteln!(self.src, "{dst} = {result}"); + uwriteln!(self.gen.src, "{dst} = {result}"); } - self.src.dedent(); - uwriteln!(self.src, "elif isinstance({op0}, Err):"); - self.src.indent(); - uwriteln!(self.src, "{err_payload} = {op0}.value"); - self.src.push_str(&err); + self.gen.src.dedent(); + uwriteln!(self.gen.src, "elif isinstance({op0}, Err):"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{err_payload} = {op0}.value"); + self.gen.src.push_str(&err); for (dst, result) in results.iter().zip(&err_results) { - uwriteln!(self.src, "{dst} = {result}"); + uwriteln!(self.gen.src, "{dst} = {result}"); } - self.src.dedent(); - self.src.push_str("else:\n"); - self.src.indent(); - self.src.push_str(&format!( + self.gen.src.dedent(); + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); + self.gen.src.push_str(&format!( "raise TypeError(\"invalid variant specified for expected\")\n", )); - self.src.dedent(); + self.gen.src.dedent(); } Instruction::ResultLift { ty, .. } => { @@ -2096,32 +2167,32 @@ impl Bindgen for FunctionBindgen<'_> { let err_result = err_results.get(0).unwrap_or(&none); let ok_result = ok_results.get(0).unwrap_or(&none); - let path = if self.at_root { ".types" } else { "..types" }; - self.src.pyimport(path, "Ok"); - self.src.pyimport(path, "Err"); + self.gen.import_shared_type("Ok"); + self.gen.import_shared_type("Err"); let result = self.locals.tmp("expected"); - uwrite!(self.src, "{result}: "); + uwrite!(self.gen.src, "{result}: "); self.print_ty(&Type::Id(*ty)); - self.src.push_str("\n"); + self.gen.src.push_str("\n"); let op0 = &operands[0]; - uwriteln!(self.src, "if {op0} == 0:"); - self.src.indent(); - self.src.push_str(&ok); - uwriteln!(self.src, "{result} = Ok({ok_result})"); - self.src.dedent(); - uwriteln!(self.src, "elif {op0} == 1:"); - self.src.indent(); - self.src.push_str(&err); - uwriteln!(self.src, "{result} = Err({err_result})"); - self.src.dedent(); - - self.src.push_str("else:\n"); - self.src.indent(); - self.src + uwriteln!(self.gen.src, "if {op0} == 0:"); + self.gen.src.indent(); + self.gen.src.push_str(&ok); + uwriteln!(self.gen.src, "{result} = Ok({ok_result})"); + self.gen.src.dedent(); + uwriteln!(self.gen.src, "elif {op0} == 1:"); + self.gen.src.indent(); + self.gen.src.push_str(&err); + uwriteln!(self.gen.src, "{result} = Err({err_result})"); + self.gen.src.dedent(); + + self.gen.src.push_str("else:\n"); + self.gen.src.indent(); + self.gen + .src .push_str("raise TypeError(\"invalid variant discriminant for expected\")\n"); - self.src.dedent(); + self.gen.src.dedent(); results.push(result); } @@ -2129,12 +2200,7 @@ impl Bindgen for FunctionBindgen<'_> { Instruction::EnumLower { .. } => results.push(format!("({}).value", operands[0])), Instruction::EnumLift { name, .. } => { - results.push(format!( - "{}{}({})", - self.self_module_path, - name.to_upper_camel_case(), - operands[0] - )); + results.push(format!("{}({})", self.name_of(name), operands[0])); } Instruction::ListCanonLower { element, .. } => { @@ -2144,11 +2210,11 @@ impl Bindgen for FunctionBindgen<'_> { let ptr = self.locals.tmp("ptr"); let len = self.locals.tmp("len"); - let array_ty = array_ty(iface, element).unwrap(); - let size = self.sizes.size(element); - let align = self.sizes.align(element); + let array_ty = array_ty(resolve, element).unwrap(); + let size = self.gen.gen.sizes.size(element); + let align = self.gen.gen.sizes.align(element); uwriteln!( - self.src, + self.gen.src, "{ptr}, {len} = {lower}({}, ctypes.{array_ty}, {size}, {align}, {realloc}, {memory}, caller)", operands[0], ); @@ -2160,19 +2226,19 @@ impl Bindgen for FunctionBindgen<'_> { let memory = self.memory.as_ref().unwrap(); let ptr = self.locals.tmp("ptr"); let len = self.locals.tmp("len"); - uwriteln!(self.src, "{ptr} = {}", operands[0]); - uwriteln!(self.src, "{len} = {}", operands[1]); - let array_ty = array_ty(iface, element).unwrap(); - self.src.pyimport("ctypes", None); + uwriteln!(self.gen.src, "{ptr} = {}", operands[0]); + uwriteln!(self.gen.src, "{len} = {}", operands[1]); + let array_ty = array_ty(resolve, element).unwrap(); + self.gen.src.pyimport("ctypes", None); let lift = format!( "{lift}({ptr}, {len}, {}, ctypes.{array_ty}, {memory}, caller)", - self.sizes.size(element), + self.gen.gen.sizes.size(element), ); - self.src.pyimport("typing", "cast"); + self.gen.src.pyimport("typing", "cast"); let list = self.locals.tmp("list"); - uwrite!(self.src, "{list} = cast("); + uwrite!(self.gen.src, "{list} = cast("); self.print_list(element); - uwriteln!(self.src, ", {lift})"); + uwriteln!(self.gen.src, ", {lift})"); results.push(list); } Instruction::StringLower { .. } => { @@ -2183,7 +2249,7 @@ impl Bindgen for FunctionBindgen<'_> { let ptr = self.locals.tmp("ptr"); let len = self.locals.tmp("len"); uwriteln!( - self.src, + self.gen.src, "{ptr}, {len} = {encode}({}, {realloc}, {memory}, caller)", operands[0], ); @@ -2195,11 +2261,11 @@ impl Bindgen for FunctionBindgen<'_> { let memory = self.memory.as_ref().unwrap(); let ptr = self.locals.tmp("ptr"); let len = self.locals.tmp("len"); - uwriteln!(self.src, "{ptr} = {}", operands[0]); - uwriteln!(self.src, "{len} = {}", operands[1]); + uwriteln!(self.gen.src, "{ptr} = {}", operands[0]); + uwriteln!(self.gen.src, "{len} = {}", operands[1]); let list = self.locals.tmp("list"); uwriteln!( - self.src, + self.gen.src, "{list} = {decode}({memory}, caller, {ptr}, {len})" ); results.push(list); @@ -2214,30 +2280,30 @@ impl Bindgen for FunctionBindgen<'_> { let vec = self.locals.tmp("vec"); let result = self.locals.tmp("result"); let len = self.locals.tmp("len"); - let size = self.sizes.size(element); - let align = self.sizes.align(element); + let size = self.gen.gen.sizes.size(element); + let align = self.gen.gen.sizes.align(element); // first store our vec-to-lower in a temporary since we'll // reference it multiple times. - uwriteln!(self.src, "{vec} = {}", operands[0]); - uwriteln!(self.src, "{len} = len({vec})"); + uwriteln!(self.gen.src, "{vec} = {}", operands[0]); + uwriteln!(self.gen.src, "{len} = len({vec})"); // ... then realloc space for the result in the guest module uwriteln!( - self.src, + self.gen.src, "{result} = {realloc}(caller, 0, 0, {align}, {len} * {size})", ); - uwriteln!(self.src, "assert(isinstance({result}, int))"); + uwriteln!(self.gen.src, "assert(isinstance({result}, int))"); // ... then consume the vector and use the block to lower the // result. let i = self.locals.tmp("i"); - uwriteln!(self.src, "for {i} in range(0, {len}):"); - self.src.indent(); - uwriteln!(self.src, "{e} = {vec}[{i}]"); - uwriteln!(self.src, "{base} = {result} + {i} * {size}"); - self.src.push_str(&body); - self.src.dedent(); + uwriteln!(self.gen.src, "for {i} in range(0, {len}):"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{e} = {vec}[{i}]"); + uwriteln!(self.gen.src, "{base} = {result} + {i} * {size}"); + self.gen.src.push_str(&body); + self.gen.src.dedent(); results.push(result); results.push(len); @@ -2246,26 +2312,26 @@ impl Bindgen for FunctionBindgen<'_> { Instruction::ListLift { element, .. } => { let (body, body_results) = self.blocks.pop().unwrap(); let base = self.payloads.pop().unwrap(); - let size = self.sizes.size(element); + let size = self.gen.gen.sizes.size(element); let ptr = self.locals.tmp("ptr"); let len = self.locals.tmp("len"); - uwriteln!(self.src, "{ptr} = {}", operands[0]); - uwriteln!(self.src, "{len} = {}", operands[1]); + uwriteln!(self.gen.src, "{ptr} = {}", operands[0]); + uwriteln!(self.gen.src, "{len} = {}", operands[1]); let result = self.locals.tmp("result"); - uwrite!(self.src, "{result}: "); + uwrite!(self.gen.src, "{result}: "); self.print_list(element); - uwriteln!(self.src, " = []"); + uwriteln!(self.gen.src, " = []"); let i = self.locals.tmp("i"); assert_eq!(body_results.len(), 1); let body_result0 = &body_results[0]; - uwriteln!(self.src, "for {i} in range(0, {len}):"); - self.src.indent(); - uwriteln!(self.src, "{base} = {ptr} + {i} * {size}"); - self.src.push_str(&body); - uwriteln!(self.src, "{result}.append({body_result0})"); - self.src.dedent(); + uwriteln!(self.gen.src, "for {i} in range(0, {len}):"); + self.gen.src.indent(); + uwriteln!(self.gen.src, "{base} = {ptr} + {i} * {size}"); + self.gen.src.push_str(&body); + uwriteln!(self.gen.src, "{result}.append({body_result0})"); + self.gen.src.dedent(); results.push(result); } @@ -2283,60 +2349,63 @@ impl Bindgen for FunctionBindgen<'_> { if sig.results.len() > 0 { for i in 0..sig.results.len() { if i > 0 { - self.src.push_str(", "); + self.gen.src.push_str(", "); } let ret = self.locals.tmp("ret"); - self.src.push_str(&ret); + self.gen.src.push_str(&ret); results.push(ret); } - self.src.push_str(" = "); + self.gen.src.push_str(" = "); } - self.src.push_str(&self.callee); - self.src.push_str("(caller"); + self.gen.src.push_str(&self.callee); + self.gen.src.push_str("(caller"); if operands.len() > 0 { - self.src.push_str(", "); + self.gen.src.push_str(", "); } - self.src.push_str(&operands.join(", ")); - self.src.push_str(")\n"); + self.gen.src.push_str(&operands.join(", ")); + self.gen.src.push_str(")\n"); for (ty, name) in sig.results.iter().zip(results.iter()) { let ty = match ty { WasmType::I32 | WasmType::I64 => "int", WasmType::F32 | WasmType::F64 => "float", }; - self.src + self.gen + .src .push_str(&format!("assert(isinstance({}, {}))\n", name, ty)); } } Instruction::CallInterface { func } => { for i in 0..func.results.len() { if i > 0 { - self.src.push_str(", "); + self.gen.src.push_str(", "); } let result = self.locals.tmp("ret"); - self.src.push_str(&result); + self.gen.src.push_str(&result); results.push(result); } if func.results.len() > 0 { - self.src.push_str(" = "); + self.gen.src.push_str(" = "); } match &func.kind { FunctionKind::Freestanding => { - self.src + self.gen + .src .push_str(&format!("{}({})", self.callee, operands.join(", "),)); } } - self.src.push_str("\n"); + self.gen.src.push_str("\n"); } Instruction::Return { amt, .. } => { if let Some(s) = &self.post_return { - self.src.push_str(&format!("{s}(caller, ret)\n")); + self.gen.src.push_str(&format!("{s}(caller, ret)\n")); } match amt { 0 => {} - 1 => self.src.push_str(&format!("return {}\n", operands[0])), + 1 => self.gen.src.push_str(&format!("return {}\n", operands[0])), _ => { - self.src + self.gen + .src .push_str(&format!("return ({})\n", operands.join(", "))); } } @@ -2360,8 +2429,11 @@ impl Bindgen for FunctionBindgen<'_> { Instruction::Malloc { size, align, .. } => { let realloc = self.realloc.as_ref().unwrap(); let ptr = self.locals.tmp("ptr"); - uwriteln!(self.src, "{ptr} = {realloc}(caller, 0, 0, {align}, {size})"); - uwriteln!(self.src, "assert(isinstance({ptr}, int))"); + uwriteln!( + self.gen.src, + "{ptr} = {realloc}(caller, 0, 0, {align}, {size})" + ); + uwriteln!(self.gen.src, "assert(isinstance({ptr}, int))"); results.push(ptr); } @@ -2420,27 +2492,3 @@ fn wasm_ty_typing(ty: WasmType) -> &'static str { WasmType::F64 => "float", } } - -/// Creates a temporary `InterfaceGenerator` with the given parameters to get -/// access to the various `print_*` methods on it. -fn with_igen( - src: &mut Source, - gen: &mut WasmtimePy, - iface: &Interface, - at_root: bool, - self_module_path: &str, - f: impl FnOnce(&mut InterfaceGenerator<'_>) -> R, -) -> R { - // The `print_ty` method is on `InterfaceGenerator` so jerry-rig one of - // those "quickly" to defer to it. - let mut gen = InterfaceGenerator { - src: mem::take(src), - gen, - iface, - at_root, - self_module_path, - }; - let ret = f(&mut gen); - *src = gen.src; - ret -} diff --git a/rust/bindgen/src/imports.rs b/rust/bindgen/src/imports.rs index 0a399fba..9c8c1eea 100644 --- a/rust/bindgen/src/imports.rs +++ b/rust/bindgen/src/imports.rs @@ -6,26 +6,17 @@ use std::fmt::Write; #[derive(Default)] pub struct PyImports { pyimports: BTreeMap>>, + typing_imports: BTreeMap>>, } impl PyImports { /// Record that a Python import is required pub fn pyimport<'a>(&mut self, module: &str, name: impl Into>) { - let name = name.into(); - let list = self - .pyimports - .entry(module.to_string()) - .or_insert(match name { - Some(_) => Some(BTreeSet::new()), - None => None, - }); - match name { - Some(name) => { - assert!(list.is_some()); - list.as_mut().unwrap().insert(name.to_string()); - } - None => assert!(list.is_none()), - } + push(&mut self.pyimports, module, name.into()) + } + + pub fn typing_import<'a>(&mut self, module: &str, name: impl Into>) { + push(&mut self.typing_imports, module, name.into()) } pub fn is_empty(&self) -> bool { @@ -33,23 +24,58 @@ impl PyImports { } pub fn finish(&self) -> String { - let mut result = String::new(); - for (k, list) in self.pyimports.iter() { - match list { - Some(list) => { - let list = list.iter().cloned().collect::>().join(", "); - uwriteln!(result, "from {k} import {list}"); + let mut result = render(&self.pyimports); + + if !self.typing_imports.is_empty() { + result.push_str("from typing import TYPE_CHECKING\n"); + result.push_str("if TYPE_CHECKING:\n"); + for line in render(&self.typing_imports).lines() { + if !line.is_empty() { + result.push_str(" "); + result.push_str(line); } - None => uwriteln!(result, "import {k}"), + result.push_str("\n"); } } - if !self.pyimports.is_empty() { - result.push_str("\n"); + result + } +} + +fn push( + imports: &mut BTreeMap>>, + module: &str, + name: Option<&str>, +) { + let list = imports.entry(module.to_string()).or_insert(match name { + Some(_) => Some(BTreeSet::new()), + None => None, + }); + match name { + Some(name) => { + assert!(list.is_some()); + list.as_mut().unwrap().insert(name.to_string()); + } + None => assert!(list.is_none()), + } +} + +fn render(imports: &BTreeMap>>) -> String { + let mut result = String::new(); + for (k, list) in imports.iter() { + match list { + Some(list) => { + let list = list.iter().cloned().collect::>().join(", "); + uwriteln!(result, "from {k} import {list}"); + } + None => uwriteln!(result, "import {k}"), } + } - result + if !imports.is_empty() { + result.push_str("\n"); } + result } #[cfg(test)] diff --git a/rust/bindgen/src/lib.rs b/rust/bindgen/src/lib.rs index 2165ffd3..41031bff 100644 --- a/rust/bindgen/src/lib.rs +++ b/rust/bindgen/src/lib.rs @@ -35,13 +35,13 @@ pub use files::Files; #[cfg(target_arch = "wasm32")] mod bindings { - wit_bindgen_guest_rust::generate!("../bindgen.wit"); + wit_bindgen_guest_rust::generate!("bindgen" in "../bindgen.wit"); export_wasmtime_py!(PythonBindings); struct PythonBindings; - impl wasmtime_py::WasmtimePy for PythonBindings { + impl WasmtimePy for PythonBindings { fn generate(name: String, component: Vec) -> Result)>, String> { let mut gen = crate::WasmtimePy::default(); let mut files = Default::default(); diff --git a/rust/bindgen/src/source.rs b/rust/bindgen/src/source.rs index 46aafbef..29e959d3 100644 --- a/rust/bindgen/src/source.rs +++ b/rust/bindgen/src/source.rs @@ -117,6 +117,10 @@ impl Source { self.imports.pyimport(module, name.into()) } + pub fn typing_import<'a>(&mut self, module: &str, name: impl Into>) { + self.imports.typing_import(module, name.into()) + } + pub fn finish(&self) -> String { let mut ret = self.imports.finish(); ret.push_str(&self.body.contents); diff --git a/rust/python.wit b/rust/python.wit index 707aba00..b0b24e2f 100644 --- a/rust/python.wit +++ b/rust/python.wit @@ -1,4 +1,4 @@ -world python { +default world python { import python: interface { print: func(slice: list) eprint: func(slice: list) diff --git a/rust/wasi_snapshot_preview1/src/lib.rs b/rust/wasi_snapshot_preview1/src/lib.rs index fbf8e2f0..998bb69c 100644 --- a/rust/wasi_snapshot_preview1/src/lib.rs +++ b/rust/wasi_snapshot_preview1/src/lib.rs @@ -1,7 +1,7 @@ use std::arch::wasm32::unreachable; use wasi::*; -wit_bindgen_guest_rust::generate!("../python.wit"); +wit_bindgen_guest_rust::generate!("python" in "../python.wit"); #[no_mangle] pub extern "C" fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Errno { diff --git a/tests/codegen/test_records.py b/tests/codegen/test_records.py index 7cee671a..749828c7 100644 --- a/tests/codegen/test_records.py +++ b/tests/codegen/test_records.py @@ -33,24 +33,25 @@ (export "multiple-results" (func (result "a" u8) (result "b" u16))) (export "swap" (func (param "a" $tuple) (result $tuple))) - (export "flag1" (type (eq $flag1))) - (export "flag2" (type (eq $flag2))) - (export "flag8" (type (eq $flag8))) - (export "flag16" (type (eq $flag16))) - (export "flag32" (type (eq $flag32))) - (export "flag64" (type (eq $flag64))) - - (export "roundtrip-flag1" (func (param "a" $flag1) (result $flag1))) - (export "roundtrip-flag2" (func (param "a" $flag2) (result $flag2))) - (export "roundtrip-flag8" (func (param "a" $flag8) (result $flag8))) - (export "roundtrip-flag16" (func (param "a" $flag16) (result $flag16))) - (export "roundtrip-flag32" (func (param "a" $flag32) (result $flag32))) - (export "roundtrip-flag64" (func (param "a" $flag64) (result $flag64))) + (export $f1 "flag1" (type (eq $flag1))) + (export $f2 "flag2" (type (eq $flag2))) + (export $f8 "flag8" (type (eq $flag8))) + (export $f16 "flag16" (type (eq $flag16))) + (export $f32 "flag32" (type (eq $flag32))) + (export $f64 "flag64" (type (eq $flag64))) + + (export "roundtrip-flag1" (func (param "a" $f1) (result $f1))) + (export "roundtrip-flag2" (func (param "a" $f2) (result $f2))) + (export "roundtrip-flag8" (func (param "a" $f8) (result $f8))) + (export "roundtrip-flag16" (func (param "a" $f16) (result $f16))) + (export "roundtrip-flag32" (func (param "a" $f32) (result $f32))) + (export "roundtrip-flag64" (func (param "a" $f64) (result $f64))) (export "empty-tuple" (func (param "a" (tuple)) (result (tuple)))) - (export "r1" (type (eq $r1))) - (export "roundtrip-r1" (func (param "a" $r1) (result $r1))) + (type $r1 (record (field "a" u8) (field "b" $f1))) + (export $r1' "r1" (type (eq $r1))) + (export "roundtrip-r1" (func (param "a" $r1') (result $r1'))) )) (core module $libc @@ -126,39 +127,53 @@ )) )) - (export "flag1" (type $flag1)) - (export "flag2" (type $flag2)) - (export "flag8" (type $flag8)) - (export "flag16" (type $flag16)) - (export "flag32" (type $flag32)) - (export "flag64" (type $flag64)) - (export "r1" (type $r1)) - - (func (export "multiple-results") (result "a" u8) (result "b" u16) + (func $multiple-results (result "a" u8) (result "b" u16) (canon lift (core func $i "multi") (memory $libc "mem"))) - (func (export "swap") (param "a" $tuple) (result "a" $tuple) + (func $swap (param "a" $tuple) (result "a" $tuple) (canon lift (core func $i "swap") (memory $libc "mem"))) - (func (export "roundtrip-flag1") (param "a" $flag1) (result "a" $flag1) + (func $roundtrip-flag1 (param "a" $flag1) (result "a" $flag1) (canon lift (core func $i "r-flag1"))) - (func (export "roundtrip-flag2") (param "a" $flag2) (result "a" $flag2) + (func $roundtrip-flag2 (param "a" $flag2) (result "a" $flag2) (canon lift (core func $i "r-flag2"))) - (func (export "roundtrip-flag8") (param "a" $flag8) (result "a" $flag8) + (func $roundtrip-flag8 (param "a" $flag8) (result "a" $flag8) (canon lift (core func $i "r-flag8"))) - (func (export "roundtrip-flag16") (param "a" $flag16) (result "a" $flag16) + (func $roundtrip-flag16 (param "a" $flag16) (result "a" $flag16) (canon lift (core func $i "r-flag16"))) - (func (export "roundtrip-flag32") (param "a" $flag32) (result "a" $flag32) + (func $roundtrip-flag32 (param "a" $flag32) (result "a" $flag32) (canon lift (core func $i "r-flag32"))) - (func (export "roundtrip-flag64") (param "a" $flag64) (result "a" $flag64) + (func $roundtrip-flag64 (param "a" $flag64) (result "a" $flag64) (canon lift (core func $i "r-flag64") (memory $libc "mem"))) - (func (export "empty-tuple") (param "a" (tuple)) (result "a" (tuple)) + (func $empty-tuple (param "a" (tuple)) (result "a" (tuple)) (canon lift (core func $i "r-empty"))) - (func (export "roundtrip-r1") (param "a" $r1) (result "b" $r1) + (func $roundtrip-r1 (param "a" $r1) (result "b" $r1) (canon lift (core func $i "r-r1") (memory $libc "mem"))) + + (instance (export "e") + (export "flag1" (type $flag1)) + (export "flag2" (type $flag2)) + (export "flag8" (type $flag8)) + (export "flag16" (type $flag16)) + (export "flag32" (type $flag32)) + (export "flag64" (type $flag64)) + (export "r1" (type $r1)) + + (export "multiple-results" (func $multiple-results)) + (export "swap" (func $swap)) + (export "roundtrip-flag1" (func $roundtrip-flag1)) + (export "roundtrip-flag2" (func $roundtrip-flag2)) + (export "roundtrip-flag8" (func $roundtrip-flag8)) + (export "roundtrip-flag16" (func $roundtrip-flag16)) + (export "roundtrip-flag32" (func $roundtrip-flag32)) + (export "roundtrip-flag64" (func $roundtrip-flag64)) + (export "empty-tuple" (func $empty-tuple)) + (export "roundtrip-r1" (func $roundtrip-r1)) + ) ) """ bindgen('records', module) -from .generated.records import Records, RecordsImports, imports, Flag1, Flag2, Flag8, Flag16, Flag32, Flag64, R1 +from .generated.records import Records, RecordsImports, imports +from .generated.records.exports.e import Flag1, Flag2, Flag8, Flag16, Flag32, Flag64, R1 from .generated.records.imports import host @@ -199,34 +214,34 @@ def test_bindings(): store = Store() bindings = Records(store, RecordsImports(host=Host())) - assert bindings.multiple_results(store) == (1, 2) - assert bindings.swap(store, (3, 4)) == (4, 3) + assert bindings.e().multiple_results(store) == (1, 2) + assert bindings.e().swap(store, (3, 4)) == (4, 3) - assert bindings.roundtrip_flag1(store, Flag1(0)) == Flag1(0) + assert bindings.e().roundtrip_flag1(store, Flag1(0)) == Flag1(0) for f1 in Flag1: - assert bindings.roundtrip_flag1(store, f1) == f1 - assert bindings.roundtrip_flag2(store, Flag2(0)) == Flag2(0) + assert bindings.e().roundtrip_flag1(store, f1) == f1 + assert bindings.e().roundtrip_flag2(store, Flag2(0)) == Flag2(0) for f2 in Flag2: - assert bindings.roundtrip_flag2(store, f2) == f2 - assert bindings.roundtrip_flag8(store, Flag8(0)) == Flag8(0) + assert bindings.e().roundtrip_flag2(store, f2) == f2 + assert bindings.e().roundtrip_flag8(store, Flag8(0)) == Flag8(0) for f8 in Flag8: - assert bindings.roundtrip_flag8(store, f8) == f8 - assert bindings.roundtrip_flag16(store, Flag16(0)) == Flag16(0) + assert bindings.e().roundtrip_flag8(store, f8) == f8 + assert bindings.e().roundtrip_flag16(store, Flag16(0)) == Flag16(0) for f16 in Flag16: - assert bindings.roundtrip_flag16(store, f16) == f16 - assert bindings.roundtrip_flag32(store, Flag32(0)) == Flag32(0) + assert bindings.e().roundtrip_flag16(store, f16) == f16 + assert bindings.e().roundtrip_flag32(store, Flag32(0)) == Flag32(0) for f32 in Flag32: - assert bindings.roundtrip_flag32(store, f32) == f32 - assert bindings.roundtrip_flag64(store, Flag64(0)) == Flag64(0) + assert bindings.e().roundtrip_flag32(store, f32) == f32 + assert bindings.e().roundtrip_flag64(store, Flag64(0)) == Flag64(0) for f64 in Flag64: - assert bindings.roundtrip_flag64(store, f64) == f64 + assert bindings.e().roundtrip_flag64(store, f64) == f64 - bindings.empty_tuple(store, None) + bindings.e().empty_tuple(store, None) - r = bindings.roundtrip_r1(store, R1(8, Flag1(0))) + r = bindings.e().roundtrip_r1(store, R1(8, Flag1(0))) assert r.a == 8 assert r.b == Flag1(0) - r = bindings.roundtrip_r1(store, R1(a=100, b=Flag1.A | Flag1.B)) + r = bindings.e().roundtrip_r1(store, R1(a=100, b=Flag1.A | Flag1.B)) assert r.a == 100 assert r.b == Flag1.A | Flag1.B diff --git a/tests/codegen/test_variants.py b/tests/codegen/test_variants.py index e3258a16..85426d4e 100644 --- a/tests/codegen/test_variants.py +++ b/tests/codegen/test_variants.py @@ -4,62 +4,62 @@ module = """ (component - (type $e1 (enum "a" "b")) - - (type $c1 (variant (case "a" s32) (case "b" s64))) - (type $c2 (variant (case "a" s32) (case "b" float32))) - (type $c3 (variant (case "a" s32) (case "b" float64))) - (type $c4 (variant (case "a" s64) (case "b" float32))) - (type $c5 (variant (case "a" s64) (case "b" float64))) - (type $c6 (variant (case "a" float32) (case "b" float64))) - (type $casts (tuple $c1 $c2 $c3 $c4 $c5 $c6)) - - (type $z1 (variant (case "a" s32) (case "b"))) - (type $z2 (variant (case "a" s64) (case "b"))) - (type $z3 (variant (case "a" float32) (case "b"))) - (type $z4 (variant (case "a" float64) (case "b"))) - (type $zeros (tuple $z1 $z2 $z3 $z4)) - - (type $all-integers (union bool u8 u16 u32 u64 s8 s16 s32 s64)) - (type $all-floats (union float32 float64)) - (type $duplicated-s32 (union s32 s32 s32)) - (type $distinguished (union s32 float32)) - (import "host" (instance $i - (export "e1" (type (eq $e1))) - - (export "c1" (type (eq $c1))) - (export "c2" (type (eq $c2))) - (export "c3" (type (eq $c3))) - (export "c4" (type (eq $c4))) - (export "c5" (type (eq $c5))) - (export "c6" (type (eq $c6))) - (export "casts" (type (eq $casts))) - - (export "z1" (type (eq $z1))) - (export "z2" (type (eq $z2))) - (export "z3" (type (eq $z3))) - (export "z4" (type (eq $z4))) - (export "zeros" (type (eq $zeros))) - - (export "all-integers" (type (eq $all-integers))) - (export "all-floats" (type (eq $all-floats))) - (export "duplicated-s32" (type (eq $duplicated-s32))) - (export "distinguished" (type (eq $distinguished))) + (type $e1 (enum "a" "b")) + + (type $c1 (variant (case "a" s32) (case "b" s64))) + (type $c2 (variant (case "a" s32) (case "b" float32))) + (type $c3 (variant (case "a" s32) (case "b" float64))) + (type $c4 (variant (case "a" s64) (case "b" float32))) + (type $c5 (variant (case "a" s64) (case "b" float64))) + (type $c6 (variant (case "a" float32) (case "b" float64))) + + (type $z1 (variant (case "a" s32) (case "b"))) + (type $z2 (variant (case "a" s64) (case "b"))) + (type $z3 (variant (case "a" float32) (case "b"))) + (type $z4 (variant (case "a" float64) (case "b"))) + + (type $all-integers (union bool u8 u16 u32 u64 s8 s16 s32 s64)) + (type $all-floats (union float32 float64)) + (type $duplicated-s32 (union s32 s32 s32)) + (type $distinguished (union s32 float32)) + + (export $e1' "e1" (type (eq $e1))) + + (export $c1' "c1" (type (eq $c1))) + (export $c2' "c2" (type (eq $c2))) + (export $c3' "c3" (type (eq $c3))) + (export $c4' "c4" (type (eq $c4))) + (export $c5' "c5" (type (eq $c5))) + (export $c6' "c6" (type (eq $c6))) + (type $casts (tuple $c1' $c2' $c3' $c4' $c5' $c6')) + (export $casts' "casts" (type (eq $casts))) + + (export $z1' "z1" (type (eq $z1))) + (export $z2' "z2" (type (eq $z2))) + (export $z3' "z3" (type (eq $z3))) + (export $z4' "z4" (type (eq $z4))) + (type $zeros (tuple $z1' $z2' $z3' $z4')) + (export $zeros' "zeros" (type (eq $zeros))) + + (export $all-integers' "all-integers" (type (eq $all-integers))) + (export $all-floats' "all-floats" (type (eq $all-floats))) + (export $duplicated-s32' "duplicated-s32" (type (eq $duplicated-s32))) + (export $distinguished' "distinguished" (type (eq $distinguished))) (export "roundtrip-option" (func (param "a" (option float32)) (result (option u8)))) (export "roundtrip-result" (func (param "a" (result u32 (error float32))) (result (result float64 (error u8))) )) - (export "roundtrip-enum" (func (param "a" $e1) (result $e1))) - (export "variant-casts" (func (param "a" $casts) (result $casts))) - (export "variant-zeros" (func (param "a" $zeros) (result $zeros))) - - (export "add-one-all-integers" (func (param "a" $all-integers) (result $all-integers))) - (export "add-one-all-floats" (func (param "a" $all-floats) (result $all-floats))) - (export "add-one-duplicated-s32" (func (param "a" $duplicated-s32) (result $duplicated-s32))) - (export "add-one-distinguished" (func (param "a" $distinguished) (result $distinguished))) + (export "roundtrip-enum" (func (param "a" $e1') (result $e1'))) + (export "variant-casts" (func (param "a" $casts') (result $casts'))) + (export "variant-zeros" (func (param "a" $zeros') (result $zeros'))) + + (export "add-one-all-integers" (func (param "a" $all-integers') (result $all-integers'))) + (export "add-one-all-floats" (func (param "a" $all-floats') (result $all-floats'))) + (export "add-one-duplicated-s32" (func (param "a" $duplicated-s32') (result $duplicated-s32'))) + (export "add-one-distinguished" (func (param "a" $distinguished') (result $distinguished'))) )) (core module $libc (memory (export "m") 1)) @@ -161,54 +161,88 @@ )) )) - (export "e1" (type $e1)) + (type $e1 (enum "a" "b")) - (export "c1" (type $c1)) - (export "c2" (type $c2)) - (export "c3" (type $c3)) - (export "c4" (type $c4)) - (export "c5" (type $c5)) - (export "c6" (type $c6)) - (export "casts" (type $casts)) + (type $c1 (variant (case "a" s32) (case "b" s64))) + (type $c2 (variant (case "a" s32) (case "b" float32))) + (type $c3 (variant (case "a" s32) (case "b" float64))) + (type $c4 (variant (case "a" s64) (case "b" float32))) + (type $c5 (variant (case "a" s64) (case "b" float64))) + (type $c6 (variant (case "a" float32) (case "b" float64))) + (type $casts (tuple $c1 $c2 $c3 $c4 $c5 $c6)) - (export "z1" (type $z1)) - (export "z2" (type $z2)) - (export "z3" (type $z3)) - (export "z4" (type $z4)) - (export "zeros" (type $zeros)) + (type $z1 (variant (case "a" s32) (case "b"))) + (type $z2 (variant (case "a" s64) (case "b"))) + (type $z3 (variant (case "a" float32) (case "b"))) + (type $z4 (variant (case "a" float64) (case "b"))) + (type $zeros (tuple $z1 $z2 $z3 $z4)) - (export "all-integers" (type $all-integers)) - (export "all-floats" (type $all-floats)) - (export "duplicated-s32" (type $duplicated-s32)) - (export "distinguished" (type $distinguished)) + (type $all-integers (union bool u8 u16 u32 u64 s8 s16 s32 s64)) + (type $all-floats (union float32 float64)) + (type $duplicated-s32 (union s32 s32 s32)) + (type $distinguished (union s32 float32)) - (func (export "roundtrip-option") (param "a" (option float32)) (result (option u8)) + (func $roundtrip-option (param "a" (option float32)) (result (option u8)) (canon lift (core func $i "r-opt") (memory $libc "m"))) - (func (export "roundtrip-result") + (func $roundtrip-result (param "a" (result u32 (error float32))) (result (result float64 (error u8))) (canon lift (core func $i "r-result") (memory $libc "m"))) - (func (export "roundtrip-enum") (param "a" $e1) (result $e1) + (func $roundtrip-enum (param "a" $e1) (result $e1) (canon lift (core func $i "r-enum"))) - (func (export "variant-casts") (param "a" $casts) (result $casts) + (func $variant-casts (param "a" $casts) (result $casts) (canon lift (core func $i "v-casts") (memory $libc "m"))) - (func (export "variant-zeros") (param "a" $zeros) (result $zeros) + (func $variant-zeros (param "a" $zeros) (result $zeros) (canon lift (core func $i "v-zeros") (memory $libc "m"))) - (func (export "add-one-all-integers") (param "a" $all-integers) (result $all-integers) + (func $add-one-all-integers (param "a" $all-integers) (result $all-integers) (canon lift (core func $i "a-int") (memory $libc "m"))) - (func (export "add-one-all-floats") (param "a" $all-floats) (result $all-floats) + (func $add-one-all-floats (param "a" $all-floats) (result $all-floats) (canon lift (core func $i "a-float") (memory $libc "m"))) - (func (export "add-one-duplicated-s32") (param "a" $duplicated-s32) (result $duplicated-s32) + (func $add-one-duplicated-s32 (param "a" $duplicated-s32) (result $duplicated-s32) (canon lift (core func $i "a-dup") (memory $libc "m"))) - (func (export "add-one-distinguished") (param "a" $distinguished) (result $distinguished) + (func $add-one-distinguished (param "a" $distinguished) (result $distinguished) (canon lift (core func $i "a-dist") (memory $libc "m"))) + + (instance (export "e") + (export "e1" (type $e1)) + + (export "c1" (type $c1)) + (export "c2" (type $c2)) + (export "c3" (type $c3)) + (export "c4" (type $c4)) + (export "c5" (type $c5)) + (export "c6" (type $c6)) + (export "casts" (type $casts)) + + (export "z1" (type $z1)) + (export "z2" (type $z2)) + (export "z3" (type $z3)) + (export "z4" (type $z4)) + (export "zeros" (type $zeros)) + + (export "all-integers" (type $all-integers)) + (export "all-floats" (type $all-floats)) + (export "duplicated-s32" (type $duplicated-s32)) + (export "distinguished" (type $distinguished)) + + (export "roundtrip-option" (func $roundtrip-option)) + (export "roundtrip-result" (func $roundtrip-result)) + (export "roundtrip-enum" (func $roundtrip-enum)) + (export "variant-casts" (func $variant-casts)) + (export "variant-zeros" (func $variant-zeros)) + (export "add-one-all-integers" (func $add-one-all-integers)) + (export "add-one-all-floats" (func $add-one-all-floats)) + (export "add-one-duplicated-s32" (func $add-one-duplicated-s32)) + (export "add-one-distinguished" (func $add-one-distinguished)) + + ) ) """ bindgen('variants', module) from .generated.variants import Variants, VariantsImports, imports -from .generated import variants as e +from .generated.variants import e from .generated.variants.imports import host from .generated.variants.types import Result, Ok, Err @@ -309,18 +343,19 @@ def test_bindings(): store = Store() wasm = Variants(store, VariantsImports(host=Host())) - assert wasm.roundtrip_option(store, 1.) == 1 - assert wasm.roundtrip_option(store, None) is None - assert wasm.roundtrip_option(store, 2.) == 2 + exports = wasm.e() + assert exports.roundtrip_option(store, 1.) == 1 + assert exports.roundtrip_option(store, None) is None + assert exports.roundtrip_option(store, 2.) == 2 - assert wasm.roundtrip_result(store, Ok(2)) == Ok(2) - assert wasm.roundtrip_result(store, Ok(4)) == Ok(4) - assert wasm.roundtrip_result(store, Err(5)) == Err(5) + assert exports.roundtrip_result(store, Ok(2)) == Ok(2) + assert exports.roundtrip_result(store, Ok(4)) == Ok(4) + assert exports.roundtrip_result(store, Err(5)) == Err(5) - assert wasm.roundtrip_enum(store, e.E1.A) == e.E1.A - assert wasm.roundtrip_enum(store, e.E1.B) == e.E1.B + assert exports.roundtrip_enum(store, e.E1.A) == e.E1.A + assert exports.roundtrip_enum(store, e.E1.B) == e.E1.B - a1, a2, a3, a4, a5, a6 = wasm.variant_casts(store, ( + a1, a2, a3, a4, a5, a6 = exports.variant_casts(store, ( e.C1A(1), e.C2A(2), e.C3A(3), @@ -335,7 +370,7 @@ def test_bindings(): assert a5 == e.C5A(5) assert a6 == e.C6A(6.) - b1, b2, b3, b4, b5, b6 = wasm.variant_casts(store, ( + b1, b2, b3, b4, b5, b6 = exports.variant_casts(store, ( e.C1B(1), e.C2B(2), e.C3B(3), @@ -350,7 +385,7 @@ def test_bindings(): assert b5 == e.C5B(5) assert b6 == e.C6B(6.) - z1, z2, z3, z4 = wasm.variant_zeros(store, ( + z1, z2, z3, z4 = exports.variant_zeros(store, ( e.Z1A(1), e.Z2A(2), e.Z3A(3.), @@ -363,37 +398,37 @@ def test_bindings(): # All-Integers # Booleans - assert wasm.add_one_all_integers(store, e.AllIntegers0(False)) == e.AllIntegers0(True) - assert wasm.add_one_all_integers(store, e.AllIntegers0(True)) == e.AllIntegers0(False) + assert exports.add_one_all_integers(store, e.AllIntegers0(False)) == e.AllIntegers0(True) + assert exports.add_one_all_integers(store, e.AllIntegers0(True)) == e.AllIntegers0(False) # Unsigned integers - assert wasm.add_one_all_integers(store, e.AllIntegers1(0)) == e.AllIntegers1(1) - assert wasm.add_one_all_integers(store, e.AllIntegers1(2**8 - 1)) == e.AllIntegers1(0) - assert wasm.add_one_all_integers(store, e.AllIntegers2(0)) == e.AllIntegers2(1) - assert wasm.add_one_all_integers(store, e.AllIntegers2(2**16 - 1)) == e.AllIntegers2(0) - assert wasm.add_one_all_integers(store, e.AllIntegers3(0)) == e.AllIntegers3(1) - assert wasm.add_one_all_integers(store, e.AllIntegers3(2**32 - 1)) == e.AllIntegers3(0) - assert wasm.add_one_all_integers(store, e.AllIntegers4(0)) == e.AllIntegers4(1) - assert wasm.add_one_all_integers(store, e.AllIntegers4(2**64 - 1)) == e.AllIntegers4(0) + assert exports.add_one_all_integers(store, e.AllIntegers1(0)) == e.AllIntegers1(1) + assert exports.add_one_all_integers(store, e.AllIntegers1(2**8 - 1)) == e.AllIntegers1(0) + assert exports.add_one_all_integers(store, e.AllIntegers2(0)) == e.AllIntegers2(1) + assert exports.add_one_all_integers(store, e.AllIntegers2(2**16 - 1)) == e.AllIntegers2(0) + assert exports.add_one_all_integers(store, e.AllIntegers3(0)) == e.AllIntegers3(1) + assert exports.add_one_all_integers(store, e.AllIntegers3(2**32 - 1)) == e.AllIntegers3(0) + assert exports.add_one_all_integers(store, e.AllIntegers4(0)) == e.AllIntegers4(1) + assert exports.add_one_all_integers(store, e.AllIntegers4(2**64 - 1)) == e.AllIntegers4(0) # Signed integers - assert wasm.add_one_all_integers(store, e.AllIntegers5(0)) == e.AllIntegers5(1) - assert wasm.add_one_all_integers(store, e.AllIntegers5(2**7 - 2)) == e.AllIntegers5(2**7 - 1) - assert wasm.add_one_all_integers(store, e.AllIntegers5(-8)) == e.AllIntegers5(-7) - assert wasm.add_one_all_integers(store, e.AllIntegers6(0)) == e.AllIntegers6(1) - assert wasm.add_one_all_integers(store, e.AllIntegers6(2**15 - 2)) == e.AllIntegers6(2**15 - 1) - assert wasm.add_one_all_integers(store, e.AllIntegers6(-8)) == e.AllIntegers6(-7) - assert wasm.add_one_all_integers(store, e.AllIntegers7(0)) == e.AllIntegers7(1) - assert wasm.add_one_all_integers(store, e.AllIntegers7(2**31 - 2)) == e.AllIntegers7(2**31 - 1) - assert wasm.add_one_all_integers(store, e.AllIntegers7(-8)) == e.AllIntegers7(-7) - assert wasm.add_one_all_integers(store, e.AllIntegers8(0)) == e.AllIntegers8(1) - assert wasm.add_one_all_integers(store, e.AllIntegers8(2**63 - 2)) == e.AllIntegers8(2**63 - 1) - assert wasm.add_one_all_integers(store, e.AllIntegers8(-8)) == e.AllIntegers8(-7) - - assert wasm.add_one_all_floats(store, e.AllFloats0(0.0)) == e.AllFloats0(1.0) - assert wasm.add_one_all_floats(store, e.AllFloats1(0.0)) == e.AllFloats1(1.0) - - assert wasm.add_one_duplicated_s32(store, e.DuplicatedS320(0)) == e.DuplicatedS320(1) - assert wasm.add_one_duplicated_s32(store, e.DuplicatedS321(1)) == e.DuplicatedS321(2) - assert wasm.add_one_duplicated_s32(store, e.DuplicatedS322(2)) == e.DuplicatedS322(3) - - assert wasm.add_one_distinguished(store, 1) == 2 - assert wasm.add_one_distinguished(store, 2.) == 3. + assert exports.add_one_all_integers(store, e.AllIntegers5(0)) == e.AllIntegers5(1) + assert exports.add_one_all_integers(store, e.AllIntegers5(2**7 - 2)) == e.AllIntegers5(2**7 - 1) + assert exports.add_one_all_integers(store, e.AllIntegers5(-8)) == e.AllIntegers5(-7) + assert exports.add_one_all_integers(store, e.AllIntegers6(0)) == e.AllIntegers6(1) + assert exports.add_one_all_integers(store, e.AllIntegers6(2**15 - 2)) == e.AllIntegers6(2**15 - 1) + assert exports.add_one_all_integers(store, e.AllIntegers6(-8)) == e.AllIntegers6(-7) + assert exports.add_one_all_integers(store, e.AllIntegers7(0)) == e.AllIntegers7(1) + assert exports.add_one_all_integers(store, e.AllIntegers7(2**31 - 2)) == e.AllIntegers7(2**31 - 1) + assert exports.add_one_all_integers(store, e.AllIntegers7(-8)) == e.AllIntegers7(-7) + assert exports.add_one_all_integers(store, e.AllIntegers8(0)) == e.AllIntegers8(1) + assert exports.add_one_all_integers(store, e.AllIntegers8(2**63 - 2)) == e.AllIntegers8(2**63 - 1) + assert exports.add_one_all_integers(store, e.AllIntegers8(-8)) == e.AllIntegers8(-7) + + assert exports.add_one_all_floats(store, e.AllFloats0(0.0)) == e.AllFloats0(1.0) + assert exports.add_one_all_floats(store, e.AllFloats1(0.0)) == e.AllFloats1(1.0) + + assert exports.add_one_duplicated_s32(store, e.DuplicatedS320(0)) == e.DuplicatedS320(1) + assert exports.add_one_duplicated_s32(store, e.DuplicatedS321(1)) == e.DuplicatedS321(2) + assert exports.add_one_duplicated_s32(store, e.DuplicatedS322(2)) == e.DuplicatedS322(3) + + assert exports.add_one_distinguished(store, 1) == 2 + assert exports.add_one_distinguished(store, 2.) == 3. diff --git a/wasmtime/_error.py b/wasmtime/_error.py index 10f1bde9..0f593ae7 100644 --- a/wasmtime/_error.py +++ b/wasmtime/_error.py @@ -1,13 +1,16 @@ from ctypes import byref, POINTER, c_int from . import _ffi as ffi import ctypes +from typing import Optional class WasmtimeError(Exception): - _ptr: "ctypes._Pointer[ffi.wasmtime_error_t]" + _ptr: "Optional[ctypes._Pointer[ffi.wasmtime_error_t]]" + _message: Optional[str] - # def __init__(self, message: str): - # self.message = message + def __init__(self, message: str): + self._message = message + self._ptr = None @classmethod def _from_ptr(cls, ptr: "ctypes._Pointer") -> 'WasmtimeError': @@ -24,9 +27,12 @@ def _from_ptr(cls, ptr: "ctypes._Pointer") -> 'WasmtimeError': err: WasmtimeError = cls.__new__(cls) err._ptr = ptr + err._message = None return err def __str__(self) -> str: + if self._message: + return self._message message_vec = ffi.wasm_byte_vec_t() ffi.wasmtime_error_message(self._ptr, byref(message_vec)) message = ffi.to_str(message_vec) @@ -34,7 +40,7 @@ def __str__(self) -> str: return message def __del__(self) -> None: - if hasattr(self, '_ptr'): + if hasattr(self, '_ptr') and self._ptr: ffi.wasmtime_error_delete(self._ptr) From db2065d1b702be4ef249651aa683ba5b1aa1e0ac Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Jan 2023 12:02:11 -0800 Subject: [PATCH 2/5] Bump wasm-tools on CI --- .github/actions/setup/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 5fe2650a..f5dd3671 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -36,12 +36,12 @@ runs: - uses: actions/cache@v3 with: path: ${{ runner.tool_cache }}/wasm-tools - key: wasm-tools-bin-1.0.15-${{ runner.os }} + key: wasm-tools-bin-1.0.18-${{ runner.os }} - run: echo '${{ runner.tool_cache }}/wasm-tools/bin' >> $GITHUB_PATH shell: bash - run: | cargo install \ - wasm-tools@1.0.15 \ + wasm-tools@1.0.18 \ --root '${{ runner.tool_cache }}/wasm-tools' \ --locked \ --no-default-features \ From 2ddd0095be7336b26b70a169a793075133767036 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Jan 2023 17:42:07 -0800 Subject: [PATCH 3/5] Update deps to latest --- .github/actions/setup/action.yml | 4 ++-- rust/Cargo.lock | 38 ++++++++++++++++---------------- rust/Cargo.toml | 4 +--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index f5dd3671..5c35168d 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -36,12 +36,12 @@ runs: - uses: actions/cache@v3 with: path: ${{ runner.tool_cache }}/wasm-tools - key: wasm-tools-bin-1.0.18-${{ runner.os }} + key: wasm-tools-bin-1.0.19-${{ runner.os }} - run: echo '${{ runner.tool_cache }}/wasm-tools/bin' >> $GITHUB_PATH shell: bash - run: | cargo install \ - wasm-tools@1.0.18 \ + wasm-tools@1.0.19 \ --root '${{ runner.tool_cache }}/wasm-tools' \ --locked \ --no-default-features \ diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 248f0227..2662acc9 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -53,7 +53,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-entity" version = "0.93.0" -source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" +source = "git+https://github.com/bytecodealliance/wasmtime#b58a197d33f044193c3d608010f5e6ec394ac07e" dependencies = [ "serde", ] @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.98.1" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8724c724dc595495979c055f4bd8b7ed9fab1069623178a28016ae43a9666f36" +checksum = "9ef3b717afc67f848f412d4f02c127dd3e35a0eecd58c684580414df4fde01d3" dependencies = [ "indexmap", "url", @@ -419,23 +419,23 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.2.48" +version = "0.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322949f382cd5e4bad4330e144bf2124b3182846194ac01e2423c07a6a15ba85" +checksum = "27c13dff901f9354fa9a6a877152d9c5642513645985635c9b83bcca99e40ea1" dependencies = [ "anyhow", - "wasmparser 0.98.1", + "wasmparser 0.99.0", ] [[package]] name = "wasmtime-component-util" version = "6.0.0" -source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" +source = "git+https://github.com/bytecodealliance/wasmtime#b58a197d33f044193c3d608010f5e6ec394ac07e" [[package]] name = "wasmtime-environ" version = "6.0.0" -source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" +source = "git+https://github.com/bytecodealliance/wasmtime#b58a197d33f044193c3d608010f5e6ec394ac07e" dependencies = [ "anyhow", "cranelift-entity", @@ -456,7 +456,7 @@ dependencies = [ [[package]] name = "wasmtime-types" version = "6.0.0" -source = "git+https://github.com/bytecodealliance/wasmtime#bfc6aad184df4ac02d5337b63357b1adbcade801" +source = "git+https://github.com/bytecodealliance/wasmtime#b58a197d33f044193c3d608010f5e6ec394ac07e" dependencies = [ "cranelift-entity", "serde", @@ -467,7 +467,7 @@ dependencies = [ [[package]] name = "wit-bindgen-core" version = "0.3.0" -source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" +source = "git+https://github.com/bytecodealliance/wit-bindgen#808d3119804bad5a50bca260d325fa51dc1ef885" dependencies = [ "anyhow", "wit-component", @@ -477,7 +477,7 @@ dependencies = [ [[package]] name = "wit-bindgen-gen-guest-rust" version = "0.3.0" -source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" +source = "git+https://github.com/bytecodealliance/wit-bindgen#808d3119804bad5a50bca260d325fa51dc1ef885" dependencies = [ "heck", "wit-bindgen-core", @@ -488,7 +488,7 @@ dependencies = [ [[package]] name = "wit-bindgen-gen-rust-lib" version = "0.3.0" -source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" +source = "git+https://github.com/bytecodealliance/wit-bindgen#808d3119804bad5a50bca260d325fa51dc1ef885" dependencies = [ "heck", "wit-bindgen-core", @@ -497,7 +497,7 @@ dependencies = [ [[package]] name = "wit-bindgen-guest-rust" version = "0.3.0" -source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" +source = "git+https://github.com/bytecodealliance/wit-bindgen#808d3119804bad5a50bca260d325fa51dc1ef885" dependencies = [ "bitflags", "wit-bindgen-guest-rust-macro", @@ -506,7 +506,7 @@ dependencies = [ [[package]] name = "wit-bindgen-guest-rust-macro" version = "0.3.0" -source = "git+https://github.com/alexcrichton/witx-bindgen?branch=fix-bindings#930de78ed42b6bcf91020ef01a066163cffac24c" +source = "git+https://github.com/bytecodealliance/wit-bindgen#808d3119804bad5a50bca260d325fa51dc1ef885" dependencies = [ "anyhow", "proc-macro2", @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1781394df3f08797267cb455bac2b67cd13051d16279bd93e6c63d632c98e1" +checksum = "03db9831d4147baa1bae36410ec29c27caed0e0b5a592d5adad54698681b952b" dependencies = [ "anyhow", "bitflags", @@ -528,15 +528,15 @@ dependencies = [ "log", "url", "wasm-encoder 0.22.0", - "wasmparser 0.98.1", + "wasmparser 0.99.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cfa79275011530f37e0e164183c606bae1cdc466ea90bcd364d50605486a4d" +checksum = "2e60c4242d4cf4394fac7587c0d96c39b3c0fb09e638815c3f244f6bb5356f04" dependencies = [ "anyhow", "id-arena", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7ce256d4..c90da550 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -2,9 +2,7 @@ members = ['bindgen', 'wasi_snapshot_preview1'] [workspace.dependencies.wit-bindgen-guest-rust] -# git = 'https://github.com/bytecodealliance/wit-bindgen' -git = 'https://github.com/alexcrichton/witx-bindgen' -branch = 'fix-bindings' +git = 'https://github.com/bytecodealliance/wit-bindgen' default-features = false features = ['macros'] From 0707893d995b3a9420d7116b527093a5e4558f1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jan 2023 07:29:13 -0800 Subject: [PATCH 4/5] Pull in a fix for wit-component --- rust/Cargo.lock | 22 ++++++++++++++-------- rust/Cargo.toml | 2 ++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2662acc9..c7ded6f5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -391,8 +391,7 @@ dependencies = [ [[package]] name = "wasm-encoder" version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef126be0e14bdf355ac1a8b41afc89195289e5c7179f80118e3abddb472f0810" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" dependencies = [ "leb128", ] @@ -417,6 +416,15 @@ dependencies = [ "url", ] +[[package]] +name = "wasmparser" +version = "0.99.0" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" +dependencies = [ + "indexmap", + "url", +] + [[package]] name = "wasmprinter" version = "0.2.49" @@ -424,7 +432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c13dff901f9354fa9a6a877152d9c5642513645985635c9b83bcca99e40ea1" dependencies = [ "anyhow", - "wasmparser 0.99.0", + "wasmparser 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -519,8 +527,7 @@ dependencies = [ [[package]] name = "wit-component" version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03db9831d4147baa1bae36410ec29c27caed0e0b5a592d5adad54698681b952b" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" dependencies = [ "anyhow", "bitflags", @@ -528,15 +535,14 @@ dependencies = [ "log", "url", "wasm-encoder 0.22.0", - "wasmparser 0.99.0", + "wasmparser 0.99.0 (git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map)", "wit-parser", ] [[package]] name = "wit-parser" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e60c4242d4cf4394fac7587c0d96c39b3c0fb09e638815c3f244f6bb5356f04" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" dependencies = [ "anyhow", "id-arena", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c90da550..8611b60d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,3 +11,5 @@ strip = 'debuginfo' [patch.crates-io] wasmtime-environ = { git = 'https://github.com/bytecodealliance/wasmtime' } +wit-component = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'remove-type-src-map' } +wit-parser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'remove-type-src-map' } From 0d7b9c53c757f981a918d21617e576564653b351 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jan 2023 10:29:03 -0800 Subject: [PATCH 5/5] Switch to upstream git deps --- rust/Cargo.lock | 10 +++++----- rust/Cargo.toml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c7ded6f5..f83fa150 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -391,7 +391,7 @@ dependencies = [ [[package]] name = "wasm-encoder" version = "0.22.0" -source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" +source = "git+https://github.com/bytecodealliance/wasm-tools#e49e0252467408603669d8186929d4b7ff6e48af" dependencies = [ "leb128", ] @@ -419,7 +419,7 @@ dependencies = [ [[package]] name = "wasmparser" version = "0.99.0" -source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" +source = "git+https://github.com/bytecodealliance/wasm-tools#e49e0252467408603669d8186929d4b7ff6e48af" dependencies = [ "indexmap", "url", @@ -527,7 +527,7 @@ dependencies = [ [[package]] name = "wit-component" version = "0.4.3" -source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" +source = "git+https://github.com/bytecodealliance/wasm-tools#e49e0252467408603669d8186929d4b7ff6e48af" dependencies = [ "anyhow", "bitflags", @@ -535,14 +535,14 @@ dependencies = [ "log", "url", "wasm-encoder 0.22.0", - "wasmparser 0.99.0 (git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map)", + "wasmparser 0.99.0 (git+https://github.com/bytecodealliance/wasm-tools)", "wit-parser", ] [[package]] name = "wit-parser" version = "0.4.1" -source = "git+https://github.com/alexcrichton/wasm-tools?branch=remove-type-src-map#6796b295f0e3cc9989a4fbf0c038130a3451ff17" +source = "git+https://github.com/bytecodealliance/wasm-tools#e49e0252467408603669d8186929d4b7ff6e48af" dependencies = [ "anyhow", "id-arena", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 8611b60d..bb9e67d4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,5 +11,5 @@ strip = 'debuginfo' [patch.crates-io] wasmtime-environ = { git = 'https://github.com/bytecodealliance/wasmtime' } -wit-component = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'remove-type-src-map' } -wit-parser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'remove-type-src-map' } +wit-component = { git = 'https://github.com/bytecodealliance/wasm-tools' } +wit-parser = { git = 'https://github.com/bytecodealliance/wasm-tools' }