diff --git a/Cargo.lock b/Cargo.lock index d74f314039..11b4a11615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,9 +53,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -68,33 +68,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -156,9 +156,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" dependencies = [ "arrayref", "arrayvec", @@ -187,13 +187,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.101" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -231,9 +230,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", "clap_derive", @@ -241,9 +240,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -253,18 +252,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.6" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbca90c87c2a04da41e95d1856e8bcd22f159bdbfa147314d2ce5218057b0e58" +checksum = "c6ae69fbb0833c6fcd5a8d4b8609f108c7ad95fc11e248d853ff2c42a90df26a" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -274,9 +273,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cobs" @@ -286,9 +285,9 @@ checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "component" @@ -509,17 +508,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "diff" version = "0.1.13" @@ -567,9 +555,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -577,9 +565,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -630,9 +618,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flagset" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb3aa5e95cf9aabc17f060cfa0ced7b83f042390760ca53bf09df9968acaa1" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" dependencies = [ "serde", ] @@ -841,9 +829,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -880,9 +868,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -1051,9 +1039,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "crc32fast", "flate2", @@ -1071,9 +1059,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "paste" @@ -1273,12 +1261,11 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" +checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" dependencies = [ "byteorder", - "derive_more", "twox-hash", ] @@ -1308,18 +1295,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -1328,9 +1315,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.118" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1416,9 +1403,9 @@ checksum = "7c68d531d83ec6c531150584c42a4290911964d5f0d79132b193b67252a23b71" [[package]] name = "syn" -version = "2.0.68" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -1427,9 +1414,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" [[package]] name = "tempfile" @@ -1454,18 +1441,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -1545,9 +1532,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -2119,9 +2106,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2135,51 +2122,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen-rt" @@ -2219,10 +2206,12 @@ dependencies = [ name = "wit-encoder" version = "0.215.0" dependencies = [ + "id-arena", "indoc", "pretty_assertions", "semver", "serde", + "wit-parser 0.215.0", ] [[package]] @@ -2297,18 +2286,18 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 9cdd5ad695..051028564c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ ahash = { version = "0.8.11", default-features = false } termcolor = "1.2.0" indoc = "2.0.5" gimli = "0.30.0" +id-arena = "2" wasm-compose = { version = "0.215.0", path = "crates/wasm-compose" } wasm-encoder = { version = "0.215.0", path = "crates/wasm-encoder" } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index 800107c327..9c98d9ff02 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -162,6 +162,27 @@ define_wasm_features! { } } +impl WasmFeatures { + /// Returns the feature set associated with the 1.0 version of the + /// WebAssembly specification or the "MVP" feature set. + pub fn wasm1() -> WasmFeatures { + WasmFeatures::FLOATS + } + + /// Returns the feature set associated with the 2.0 version of the + /// WebAssembly specification. + pub fn wasm2() -> WasmFeatures { + WasmFeatures::wasm1() + | WasmFeatures::BULK_MEMORY + | WasmFeatures::REFERENCE_TYPES + | WasmFeatures::SIGN_EXTENSION + | WasmFeatures::MUTABLE_GLOBAL + | WasmFeatures::SATURATING_FLOAT_TO_INT + | WasmFeatures::MULTI_VALUE + | WasmFeatures::SIMD + } +} + impl From for WasmFeatures { #[inline] fn from(inflated: WasmFeaturesInflated) -> Self { diff --git a/crates/wit-encoder/Cargo.toml b/crates/wit-encoder/Cargo.toml index 626959e60c..1f8a0700ce 100644 --- a/crates/wit-encoder/Cargo.toml +++ b/crates/wit-encoder/Cargo.toml @@ -11,7 +11,7 @@ version.workspace = true workspace = true [features] -default = ["serde"] +default = ["serde", "from-parser"] # Enables JSON serialization/deserialization of the wit-encoder structures. @@ -23,11 +23,14 @@ default = ["serde"] # *Note*: The exact structure of the JSON is likely not going to be very stable over time, # so slight tweaks and variants should be expected as this crate evolves. serde = ["dep:serde", "semver/serde"] +from-parser = ["wit-parser", "id-arena"] [dependencies] semver = { workspace = true } pretty_assertions = { workspace = true } serde = { workspace = true, optional = true, features = ["derive"] } +wit-parser = { workspace = true, optional = true } +id-arena = { workspace = true, optional = true } [dev-dependencies] indoc = { workspace = true } diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs new file mode 100644 index 0000000000..a9306c6fff --- /dev/null +++ b/crates/wit-encoder/src/from_parser.rs @@ -0,0 +1,506 @@ +use id_arena::Id; + +use crate::{ + Enum, Flags, Interface, InterfaceItem, Package, PackageName, Params, Record, Resource, + ResourceFunc, Result_, Results, StandaloneFunc, Tuple, Type, TypeDef, TypeDefKind, Variant, + World, WorldItem, +}; + +pub fn packages_from_parsed(resolve: &wit_parser::Resolve) -> Vec { + let converter = Converter::new(resolve); + converter.convert() +} + +struct Converter<'a> { + resolve: &'a wit_parser::Resolve, +} + +impl<'a> Converter<'a> { + fn new(resolve: &'a wit_parser::Resolve) -> Self { + Self { resolve } + } + + fn convert(&self) -> Vec { + self.resolve + .packages + .iter() + .map(|(_, p)| self.convert_package(p)) + .collect() + } + + fn convert_package(&self, package: &wit_parser::Package) -> Package { + let mut output = Package::new(self.convert_package_name(&package.name)); + for (_, id) in &package.interfaces { + let interface = self.resolve.interfaces.get(*id).unwrap(); + output.interface(self.convert_interface( + interface, + None, + wit_parser::TypeOwner::Interface(*id), + )); + } + for (_, id) in &package.worlds { + let world = self.resolve.worlds.get(*id).unwrap(); + output.world(self.convert_world(world, wit_parser::TypeOwner::World(*id))); + } + output + } + + fn convert_package_name(&self, package: &wit_parser::PackageName) -> PackageName { + PackageName::new( + package.namespace.clone(), + package.name.clone(), + package.version.clone(), + ) + } + + fn convert_world(&self, world: &wit_parser::World, owner: wit_parser::TypeOwner) -> World { + let mut output = World::new(world.name.clone()); + + for (key, item) in &world.imports { + match item { + wit_parser::WorldItem::Interface { id, .. } => { + let interface = self.resolve.interfaces.get(*id).unwrap(); + output.item(match &interface.name { + Some(name) => { + // standalone + WorldItem::named_interface_import(name.clone()) + } + None => { + // inlined + let name = match key { + wit_parser::WorldKey::Name(name) => name.clone(), + wit_parser::WorldKey::Interface(_) => { + unreachable!("inlined interface must have a kye name") + } + }; + WorldItem::inline_interface_import(self.convert_interface( + interface, + Some(name), + owner, + )) + } + }); + } + wit_parser::WorldItem::Function(func) => { + if let Some(func) = self.standalone_func_convert(func) { + output.item(WorldItem::function_import(func)); + } + } + wit_parser::WorldItem::Type(_) => { + todo!(); + } + } + } + for (key, item) in &world.exports { + match item { + wit_parser::WorldItem::Interface { id, .. } => { + let interface = self.resolve.interfaces.get(*id).unwrap(); + output.item(match &interface.name { + Some(name) => { + // standalone + WorldItem::named_interface_export(name.clone()) + } + None => { + // inlined + let name = match key { + wit_parser::WorldKey::Name(name) => name.clone(), + wit_parser::WorldKey::Interface(_) => { + unreachable!("inlined interface must have a kye name") + } + }; + WorldItem::inline_interface_export(self.convert_interface( + interface, + Some(name), + owner, + )) + } + }); + } + wit_parser::WorldItem::Function(func) => { + if let Some(func) = self.standalone_func_convert(func) { + output.item(WorldItem::function_export(func)); + } + } + wit_parser::WorldItem::Type(_) => { + todo!(); + } + } + } + + output + } + + fn convert_interface( + &self, + interface: &wit_parser::Interface, + inlined_name: Option, + owner: wit_parser::TypeOwner, + ) -> Interface { + let mut output = Interface::new(interface.name.clone().unwrap_or_else(|| { + inlined_name + .clone() + .expect("inlined interface must pass in inlined_name") + })); + + for (_, func) in &interface.functions { + if let Some(func) = self.standalone_func_convert(func) { + output.items.push(InterfaceItem::Function(func)); + } + } + for (_, type_id) in &interface.types { + let type_def = self.resolve.types.get(*type_id).unwrap(); + + let underlying_type_def = match &type_def.kind { + wit_parser::TypeDefKind::Type(type_) => match &type_ { + wit_parser::Type::Id(type_id) => { + let type_def = self.resolve.types.get(*type_id).unwrap(); + type_def + } + _ => type_def, + }, + _ => type_def, + }; + + if underlying_type_def.owner == owner { + if let Some(type_def) = self.convert_type_def(type_def, *type_id) { + output.item(InterfaceItem::TypeDef(type_def)); + } + } else { + let interface_name = match underlying_type_def.owner { + wit_parser::TypeOwner::Interface(id) => self + .resolve + .interfaces + .get(id) + .unwrap() + .name + .clone() + .expect("can't use type from inline interface"), + _ => panic!("Type not part of an interface"), + }; + let local_type_name = type_def.name.clone().unwrap(); + let underlying_local_type_name = underlying_type_def.name.clone().unwrap(); + if underlying_local_type_name == local_type_name { + output.use_type(interface_name, local_type_name, None); + } else { + output.use_type( + interface_name, + underlying_local_type_name, + Some(local_type_name.into()), + ); + } + } + } + + output + } + + fn convert_type_def( + &self, + type_def: &wit_parser::TypeDef, + type_def_id: Id, + ) -> Option { + match &type_def.name { + None => None, + Some(name) => { + let kind = match &type_def.kind { + wit_parser::TypeDefKind::Record(record) => { + let output = self.convert_record(record); + TypeDefKind::Record(output) + } + wit_parser::TypeDefKind::Resource => { + let output = self.convert_resource(type_def_id, name, &type_def.owner); + TypeDefKind::Resource(output) + } + wit_parser::TypeDefKind::Flags(flags) => { + let output = self.convert_flags(flags); + TypeDefKind::Flags(output) + } + wit_parser::TypeDefKind::Variant(variant) => { + let output = self.convert_variant(variant); + TypeDefKind::Variant(output) + } + wit_parser::TypeDefKind::Enum(enum_) => { + let output = self.convert_enum(enum_); + TypeDefKind::Enum(output) + } + wit_parser::TypeDefKind::Future(_) => { + todo!("Enable once wit-encoder supports `future`") + } + wit_parser::TypeDefKind::Stream(_) => { + todo!("Enable once wit-encoder supports `stream`") + } + // all the following are just `type` declarations + wit_parser::TypeDefKind::Option(ty) => { + let output = Type::option(self.convert_type(ty)); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::List(ty) => { + let output = Type::list(self.convert_type(ty)); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::Handle(handle) => { + let output = self.handle_to_type(handle); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::Result(result) => { + let output = Type::result(self.convert_result(result)); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::Tuple(tuple) => { + let output = Type::Tuple(self.convert_tuple(tuple)); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::Type(ty) => { + let output = self.convert_type(ty); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::Unknown => unreachable!(), + }; + + Some(TypeDef::new(name.clone(), kind)) + } + } + } + + fn convert_type(&self, type_: &wit_parser::Type) -> Type { + match type_ { + wit_parser::Type::Bool => Type::Bool, + wit_parser::Type::U8 => Type::U8, + wit_parser::Type::U16 => Type::U16, + wit_parser::Type::U32 => Type::U32, + wit_parser::Type::U64 => Type::U64, + wit_parser::Type::S8 => Type::S8, + wit_parser::Type::S16 => Type::S16, + wit_parser::Type::S32 => Type::S32, + wit_parser::Type::S64 => Type::S64, + wit_parser::Type::F32 => Type::F32, + wit_parser::Type::F64 => Type::F64, + wit_parser::Type::Char => Type::Char, + wit_parser::Type::String => Type::String, + wit_parser::Type::Id(id) => { + let type_def = self.resolve.types.get(*id).expect("Type not found"); + match &type_def.name { + Some(name) => Type::named(name.clone()), + None => match &type_def.kind { + wit_parser::TypeDefKind::Tuple(tuple) => { + Type::Tuple(self.convert_tuple(tuple)) + } + wit_parser::TypeDefKind::Option(type_) => { + Type::option(self.convert_type(type_)) + } + wit_parser::TypeDefKind::Result(result) => { + Type::result(self.convert_result(result)) + } + wit_parser::TypeDefKind::List(type_) => { + Type::list(self.convert_type(type_)) + } + wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle), + wit_parser::TypeDefKind::Future(_) => { + todo!("Enable once wit-encoder supports `future`") + } + wit_parser::TypeDefKind::Stream(_) => { + todo!("Enable once wit-encoder supports `stream`") + } + wit_parser::TypeDefKind::Record(_) + | wit_parser::TypeDefKind::Resource + | wit_parser::TypeDefKind::Flags(_) + | wit_parser::TypeDefKind::Variant(_) + | wit_parser::TypeDefKind::Enum(_) + | wit_parser::TypeDefKind::Type(_) => { + panic!("type doesn't have a name, and can't be inlined") + } + wit_parser::TypeDefKind::Unknown => unreachable!(), + }, + } + } + } + } + + fn convert_enum(&self, enum_: &wit_parser::Enum) -> Enum { + let mut output = Enum::empty(); + for case in &enum_.cases { + output.case(case.name.clone()) + } + output + } + fn convert_record(&self, record: &wit_parser::Record) -> Record { + Record::new(record.fields.iter().map(|field| { + let name = field.name.clone(); + let type_ = self.convert_type(&field.ty); + (name, type_) + })) + } + fn convert_variant(&self, variant: &wit_parser::Variant) -> Variant { + let mut output = Variant::empty(); + for case in &variant.cases { + match &case.ty { + Some(ty) => { + let ty = self.convert_type(ty); + output.case((case.name.clone(), ty)) + } + None => output.case((case.name.clone(),)), + } + } + output + } + fn convert_flags(&self, flags: &wit_parser::Flags) -> Flags { + Flags::new(flags.flags.iter().map(|flag| (flag.name.clone(),))) + } + + fn convert_resource( + &self, + resource_id: Id, + name: &str, + owner: &wit_parser::TypeOwner, + ) -> Resource { + let functions = match owner { + wit_parser::TypeOwner::World(_) => { + todo!("Enable once win-encoder supports `include`") + } + wit_parser::TypeOwner::Interface(id) => { + &self.resolve.interfaces.get(*id).unwrap().functions + } + wit_parser::TypeOwner::None => panic!("Resource has to have an owner"), + }; + + let mut output = Resource::empty(); + for (_, func) in functions { + if let Some(method) = self.convert_resource_func(resource_id, name, func) { + output.func(method); + } + } + output + } + + fn convert_resource_func( + &self, + resource_id: Id, + resource_name: &str, + func: &wit_parser::Function, + ) -> Option { + // skip first argument for methods, as they're just `self`. + let mut skip_first_param = false; + // constructors can't return anything + let mut with_returns = true; + let mut method = match func.kind { + wit_parser::FunctionKind::Freestanding => return None, + wit_parser::FunctionKind::Method(id) => { + if id != resource_id { + return None; + } + skip_first_param = true; + let name = clean_func_name(resource_name, &func.name); + ResourceFunc::method(name) + } + wit_parser::FunctionKind::Static(id) => { + if id != resource_id { + return None; + } + let name = clean_func_name(resource_name, &func.name); + ResourceFunc::static_(name) + } + wit_parser::FunctionKind::Constructor(id) => { + if id != resource_id { + return None; + } + with_returns = false; + ResourceFunc::constructor() + } + }; + + method.set_params(self.convert_params(&func.params)); + if skip_first_param { + method.params_mut().items_mut().remove(0); + } + + if with_returns { + method.set_results(self.convert_results(&func.results)); + } + + Some(method) + } + + fn standalone_func_convert(&self, func: &wit_parser::Function) -> Option { + match func.kind { + wit_parser::FunctionKind::Method(_) + | wit_parser::FunctionKind::Static(_) + | wit_parser::FunctionKind::Constructor(_) => None, + wit_parser::FunctionKind::Freestanding => { + let mut output = StandaloneFunc::new(func.name.clone()); + + output.set_params(self.convert_params(&func.params)); + output.set_results(self.convert_results(&func.results)); + + Some(output) + } + } + } + + fn convert_params(&self, params: &wit_parser::Params) -> Params { + let mut output = Params::empty(); + for (name, ty) in params.iter() { + let name = name.to_string(); + let ty = self.convert_type(ty); + output.push(name, ty); + } + output + } + + fn convert_results(&self, results: &wit_parser::Results) -> Results { + match results { + wit_parser::Results::Named(named) => Results::named(named.iter().map(|(name, ty)| { + let ty = self.convert_type(ty); + (name.to_owned(), ty) + })), + wit_parser::Results::Anon(ty) => Results::Anon(self.convert_type(ty)), + } + } + + fn handle_to_type(&self, handle: &wit_parser::Handle) -> Type { + let id = match handle { + wit_parser::Handle::Own(id) => id, + wit_parser::Handle::Borrow(id) => id, + }; + let type_def = self.resolve.types.get(*id).expect("Type not found"); + let name = type_def + .name + .clone() + .expect("Handles should only be for resources, and resources should have names"); + match handle { + wit_parser::Handle::Own(_) => Type::named(name), + wit_parser::Handle::Borrow(_) => Type::borrow(name), + } + } + + fn convert_result(&self, result: &wit_parser::Result_) -> Result_ { + match (&result.ok, &result.err) { + (None, None) => Result_::empty(), + (Some(ok), None) => Result_::ok(self.convert_type(ok)), + (None, Some(err)) => Result_::err(self.convert_type(err)), + (Some(ok), Some(err)) => Result_::both(self.convert_type(ok), self.convert_type(err)), + } + } + + fn convert_tuple(&self, tuple: &wit_parser::Tuple) -> Tuple { + let mut output = Tuple::empty(); + for ty in tuple.types.iter() { + output.types_mut().push(self.convert_type(ty)); + } + output + } +} + +fn clean_func_name(resource_name: &str, method_name: &str) -> String { + const METHOD_PREFIX: &str = "[method]"; + const STATIC_PREFIX: &str = "[static]"; + + let method_name = method_name + .strip_prefix(METHOD_PREFIX) + .unwrap_or(method_name); + let method_name = method_name + .strip_prefix(STATIC_PREFIX) + .unwrap_or(method_name); + let method_name = method_name.strip_prefix(resource_name).unwrap(); + let method_name = method_name.strip_prefix(".").unwrap(); + method_name.to_string() +} diff --git a/crates/wit-encoder/src/interface.rs b/crates/wit-encoder/src/interface.rs index 1485bcad4c..46b50cb59a 100644 --- a/crates/wit-encoder/src/interface.rs +++ b/crates/wit-encoder/src/interface.rs @@ -9,6 +9,9 @@ pub struct Interface { /// Name of this interface. pub(crate) name: Ident, + // Interface uses + pub(crate) uses: Vec, + // Interface items pub(crate) items: Vec, @@ -21,6 +24,7 @@ impl Interface { pub fn new(name: impl Into) -> Self { Self { name: name.into(), + uses: vec![], items: vec![], docs: None, } @@ -38,7 +42,28 @@ impl Interface { /// Add a `Use` to the interface pub fn use_(&mut self, use_: Use) { - self.items.push(InterfaceItem::Use(use_)); + self.uses.push(use_); + } + + /// Use a type in the interface. + pub fn use_type( + &mut self, + target: impl Into, + item: impl Into, + rename: Option, + ) { + let target = target.into(); + let use_ = self.uses.iter_mut().find(|u| u.target() == &target); + match use_ { + Some(use_) => use_.item(item, rename), + None => { + self.use_({ + let mut use_ = Use::new(target); + use_.item(item, rename); + use_ + }); + } + } } pub fn item(&mut self, item: impl Into) { @@ -68,7 +93,6 @@ impl Interface { #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum InterfaceItem { TypeDef(TypeDef), - Use(Use), Function(StandaloneFunc), } @@ -91,11 +115,19 @@ impl Render for InterfaceItems { } write!(f, ";\n")?; } - InterfaceItem::Use(use_) => { - use_.render(f, opts)?; - } } } Ok(()) } } + +pub type InterfaceUses = Vec; + +impl Render for InterfaceUses { + fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result { + for use_ in self { + use_.render(f, opts)?; + } + Ok(()) + } +} diff --git a/crates/wit-encoder/src/lib.rs b/crates/wit-encoder/src/lib.rs index 902ffc007a..d8d9df29cd 100644 --- a/crates/wit-encoder/src/lib.rs +++ b/crates/wit-encoder/src/lib.rs @@ -6,6 +6,8 @@ mod docs; mod enum_; mod flags; +#[cfg(feature = "from-parser")] +mod from_parser; mod function; mod ident; mod include; @@ -24,6 +26,8 @@ mod world; pub use docs::*; pub use enum_::*; pub use flags::*; +#[cfg(feature = "from-parser")] +pub use from_parser::*; pub use function::*; pub use ident::*; pub use include::*; diff --git a/crates/wit-encoder/src/package.rs b/crates/wit-encoder/src/package.rs index 749fd6508e..5734548f3e 100644 --- a/crates/wit-encoder/src/package.rs +++ b/crates/wit-encoder/src/package.rs @@ -63,8 +63,9 @@ impl Render for Package { docs.render(f, opts)?; } write!(f, "{}interface {} {{", opts.spaces(), interface.name)?; - if !interface.items.is_empty() { + if !interface.uses.is_empty() || !interface.items.is_empty() { write!(f, "\n")?; + interface.uses.render(f, &opts.indent())?; interface.items.render(f, &opts.indent())?; write!(f, "{}}}\n", opts.spaces())?; } else { diff --git a/crates/wit-encoder/src/use_.rs b/crates/wit-encoder/src/use_.rs index bb549adba6..edb6867c24 100644 --- a/crates/wit-encoder/src/use_.rs +++ b/crates/wit-encoder/src/use_.rs @@ -8,7 +8,7 @@ use crate::{Ident, Render}; #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Use { target: Ident, - use_names_list: Vec<(String, Option)>, + use_names_list: Vec<(Ident, Option)>, } impl Use { @@ -19,9 +19,18 @@ impl Use { } } - pub fn item(&mut self, id: &str, alias: Option<&str>) { + pub fn target(&self) -> &Ident { + &self.target + } + + pub fn set_target(&mut self, target: Ident) { + self.target = target; + } + + // `alias` is a concrete type because of https://github.com/rust-lang/rust/issues/36887 + pub fn item(&mut self, id: impl Into, alias: Option) { self.use_names_list - .push((id.to_string(), alias.map(|s| s.to_string()))); + .push((id.into(), alias.map(|s| s.into()))); } } diff --git a/crates/wit-encoder/src/world.rs b/crates/wit-encoder/src/world.rs index 320d890cd8..91f419b2ac 100644 --- a/crates/wit-encoder/src/world.rs +++ b/crates/wit-encoder/src/world.rs @@ -101,8 +101,9 @@ impl Render for World { } import(f, opts)?; write!(f, "{}: interface {{", interface.name)?; - if !interface.items.is_empty() { + if !interface.uses.is_empty() || !interface.items.is_empty() { write!(f, "\n")?; + interface.uses.render(f, &opts.indent())?; interface.items.render(f, &opts.indent())?; write!(f, "{}}}\n", opts.spaces())?; } else { diff --git a/crates/wit-encoder/tests/parse-to-encoder.rs b/crates/wit-encoder/tests/parse-to-encoder.rs new file mode 100644 index 0000000000..45cb39b632 --- /dev/null +++ b/crates/wit-encoder/tests/parse-to-encoder.rs @@ -0,0 +1,84 @@ +use pretty_assertions::assert_eq; +use wit_encoder::packages_from_parsed; + +const WIT: &str = r#"package foo:functions; + +interface foo-interface { + flags %flags { + flag-a, + flag-b, + } +} + +interface bar-interface { + use foo-interface.{ %flags as external-type }; + enum some-enum { + first-case, + second-case, + } +} + +interface %interface { + use bar-interface.{ some-enum, external-type }; + statndalone-func: func(a: u32, b: s32) -> f32; + variant %variant { + empty-case, + valued-case(u32), + } + resource %resource { + constructor(); + method: func(arg: list) -> char; + static-method: static func(arg: tuple) -> list; + } + resource other-resource { + constructor(values: list); + static-method: func(arg: tuple); + } + record some-record { + optinal: option, + %own: %resource, + %borrow: borrow<%resource>, + result-a: result, + result-b: result, + result-c: result<_, f64>, + result-d: result, + result-e: result>, + } + type type-list = list; + type type-option = option; + type type-result-a = result; + type type-result-b = result; + type type-result-c = result<_, f64>; + type type-result-d = result; + type type-result-e = result>; + type type-handle-own = %resource; + type type-handle-borrow = borrow<%resource>; + type type-tuple = tuple, borrow<%resource>>; +} + +world my-world { + import foo-interface; + import bar-interface; + import %interface; + import inline-import: interface { + do-something: func(a: string) -> string; + } + import import-func: func(); + export export-func: func(a: u32, b: s32) -> f32; + export %interface; + export inline-export: interface { + do-nothing: func(); + } +} +"#; + +#[test] +fn round_trip() { + let mut resolve = wit_parser::Resolve::new(); + resolve.push_str("", WIT).unwrap(); + let packages = packages_from_parsed(&resolve); + + assert!(packages.len() == 1, "Should create exactly one package"); + let package = &packages[0]; + assert_eq!(WIT, package.to_string()); +} diff --git a/crates/wit-encoder/tests/use.rs b/crates/wit-encoder/tests/use.rs index c3d891c6fc..0f154b4ca3 100644 --- a/crates/wit-encoder/tests/use.rs +++ b/crates/wit-encoder/tests/use.rs @@ -30,7 +30,7 @@ fn concrete_types() { let mut interface = Interface::new("bar"); let mut use_ = Use::new("foo"); - use_.item("bar", Some("foobar")); + use_.item("bar", Some("foobar".into())); interface.use_(use_); interface.type_def(TypeDef::resource("baz", Vec::::new())); package.interface(interface); diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml index 577ec4a4aa..29e11c4686 100644 --- a/crates/wit-parser/Cargo.toml +++ b/crates/wit-parser/Cargo.toml @@ -17,7 +17,7 @@ rust-version.workspace = true workspace = true [dependencies] -id-arena = "2" +id-arena = { workspace = true } anyhow = { workspace = true } indexmap = { workspace = true, features = ['std'] } unicode-xid = "0.2.2" diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index b94596b51d..7283c4da0b 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -1,5 +1,5 @@ use addr2line::LookupResult; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use bitflags::Flags; use rayon::prelude::*; use std::fmt::Write; @@ -17,31 +17,42 @@ use wasmparser::{ /// specification. The process will exit with 0 and no output if the binary is /// valid, or nonzero and an error message on stderr if the binary is not valid. /// -/// Examples: -/// -/// ```sh -/// # Validate `foo.wasm` with the default Wasm feature proposals. -/// $ wasm-tools validate foo.wasm -/// -/// # Validate `foo.wasm` with more verbose output -/// $ wasm-tools validate -vv foo.wasm -/// -/// # Validate `fancy.wasm` with all Wasm feature proposals enabled. -/// $ wasm-tools validate --features all fancy.wasm -/// -/// # Validate `mvp.wasm` without any Wasm feature proposals enabled. -/// $ wasm-tools validate --features=-all mvp.wasm -/// ``` #[derive(clap::Parser)] +#[clap(after_help = "\ +Examples: + + # Validate `foo.wasm` with the default Wasm feature proposals. + $ wasm-tools validate foo.wasm + + # Validate `foo.wasm` with more verbose output + $ wasm-tools validate -vv foo.wasm + + # Validate `fancy.wasm` with all Wasm feature proposals enabled. + $ wasm-tools validate --features all fancy.wasm + + # Validate `mvp.wasm` with the original wasm feature set enabled. + $ wasm-tools validate --features=wasm1 mvp.wasm + $ wasm-tools validate --features=mvp mvp.wasm +")] pub struct Opts { - /// Comma-separated list of WebAssembly features to enable during validation. + /// Comma-separated list of WebAssembly features to enable during + /// validation. + /// + /// If a "-" character is present in front of a feature it will disable that + /// feature. For example "-simd" will disable the simd proposal. /// - /// The placeholder "all" can be used to enable all wasm features. If a "-" - /// character is present in front of a feature it will disable that feature. - /// For example "all,-simd" would enable everything but simd. + /// The placeholder "all" can be used to enable all wasm features and the + /// term "-all" can be used to disable all features. + /// + /// The default set of features enabled are all WebAssembly proposals that + /// are at phase 4 or after. This means that the default set of features + /// accepted are relatively bleeding edge. Versions of the WebAssembly + /// specification can also be selected. The "wasm1" or "mvp" feature can + /// select the original WebAssembly specification and "wasm2" can be used to + /// select the 2.0 version. /// /// Available feature options can be found in the wasmparser crate: - /// https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wasmparser/src/validator.rs + /// #[clap(long, short = 'f', value_parser = parse_features)] features: Option, @@ -188,6 +199,18 @@ fn parse_features(arg: &str) -> Result { ret.set(*flag.value(), enable); } } + "wasm1" | "mvp" => { + if !enable { + bail!("cannot disable `{part}`, it can only be enabled"); + } + ret = WasmFeatures::wasm1(); + } + "wasm2" => { + if !enable { + bail!("cannot disable `{part}`, it can only be enabled"); + } + ret = WasmFeatures::wasm2(); + } name => { let flag = WasmFeatures::FLAGS