diff --git a/Cargo.lock b/Cargo.lock index 6c20c9b90ad1..fb72b0664146 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5846,9 +5846,9 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wast" -version = "39.0.0" +version = "41.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9bbbd53432b267421186feee3e52436531fa69a7cfee9403f5204352df3dd05" +checksum = "f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870" dependencies = [ "leb128", "memchr", @@ -5857,9 +5857,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab98ed25494f97c69f28758617f27c3e92e5336040b5c3a14634f2dd3fe61830" +checksum = "48b3b9b3e39e66c7fd3f8be785e74444d216260f491e93369e317ed6482ff80f" dependencies = [ "wast", ] diff --git a/js/src/jit-test/tests/wasm/exceptions/memory.js b/js/src/jit-test/tests/wasm/exceptions/memory.js index 5e53a23c304e..fef249ddf5f6 100644 --- a/js/src/jit-test/tests/wasm/exceptions/memory.js +++ b/js/src/jit-test/tests/wasm/exceptions/memory.js @@ -26,6 +26,7 @@ `(module (import "m" "exn" (tag $exn)) (tag $localExn (param i32)) + (type $t (func)) (import "m" "tab" (table $importTable 2 funcref)) (import "m" "throwsExn" (func $importFuncThrowsExn)) (memory $mem (data "foo")) @@ -65,11 +66,11 @@ ["(call $anotherLocalFuncThrowsExn)", "(call $importFuncThrowsExn)", // Calls $localFuncThrowsExn. - "(call_indirect (table $localTable) (i32.const 0))", + "(call_indirect $localTable (type $t) (i32.const 0))", // Calls $importFuncThrowsExn. - "(call_indirect (table $localTable) (i32.const 1))", + "(call_indirect $localTable (type $t) (i32.const 1))", // Calls non exported function of the exports module $anotherThrowsExn. - "(call_indirect (table $importTable) (i32.const 0))"]; + "(call_indirect $importTable (type $t) (i32.const 0))"]; for (let callInstruction of callInstructions) { testMemoryAfterCall(callInstruction); diff --git a/js/src/jit-test/tests/wasm/large-memory.js b/js/src/jit-test/tests/wasm/large-memory.js index 295c0fc4c9e6..9f183b2e58c3 100644 --- a/js/src/jit-test/tests/wasm/large-memory.js +++ b/js/src/jit-test/tests/wasm/large-memory.js @@ -16,7 +16,7 @@ for ( let [pages,maxpages] of [[pages_vanilla, pages_vanilla+100], (memory (export "mem") ${pages} ${maxpages}) (data (i32.const ${(pages-5)*pagesz}) "yabbadabbado") - (data $flintstone passive "yabbadabbado") + (data $flintstone "yabbadabbado") (func (export "get_constaddr") (result i32) (i32.load (i32.const ${pages*pagesz-4}))) diff --git a/js/src/jit-test/tests/wasm/memory.js b/js/src/jit-test/tests/wasm/memory.js index 630643f03c3b..f5d7bb0a7d3c 100644 --- a/js/src/jit-test/tests/wasm/memory.js +++ b/js/src/jit-test/tests/wasm/memory.js @@ -498,7 +498,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(` assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(` (module - (data $d passive "01234") + (data $d "01234") (func (param i32 i32) (memory.init $d (local.get 0) (local.get 1))))`)), WebAssembly.CompileError, diff --git a/js/src/jit-test/tests/wasm/memory64/basic.js b/js/src/jit-test/tests/wasm/memory64/basic.js index 1e688de4ea2d..bf40707b9ff9 100644 --- a/js/src/jit-test/tests/wasm/memory64/basic.js +++ b/js/src/jit-test/tests/wasm/memory64/basic.js @@ -134,7 +134,7 @@ for (let [memType, ptrType] of memTypes ) { assertEq(WebAssembly.validate(wasmTextToBinary(` (module (memory ${memType} 1) - (data $seg passive "0123456789abcdef") + (data $seg "0123456789abcdef") (func (param $p ${ptrType}) (drop (${ptrType}.add (${ptrType}.const 1) (memory.size))) (drop (${ptrType}.add (${ptrType}.const 1) (memory.grow (${ptrType}.const 1)))) @@ -1435,7 +1435,7 @@ function makeModule(initial, maximum, shared) { (module (memory (export "mem") i64 ${initial} ${maximum} ${shared}) - (data $seg passive "0123456789") + (data $seg "0123456789") (func (export "size") (result i64) memory.size) diff --git a/js/src/jit-test/tests/wasm/memory64/memory-init.js b/js/src/jit-test/tests/wasm/memory64/memory-init.js index 3402b387892a..246fc3f2d403 100644 --- a/js/src/jit-test/tests/wasm/memory64/memory-init.js +++ b/js/src/jit-test/tests/wasm/memory64/memory-init.js @@ -12,7 +12,7 @@ for (let shared of ['', 'shared']) { var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(` (module (memory (export "mem") i64 65537 65537 ${shared}) - (data $d passive "${S}") + (data $d "${S}") (func (export "f") (param $p i64) (param $o i32) (param $n i32) (memory.init $d (local.get $p) (local.get $o) (local.get $n))))`))); } catch (e) { diff --git a/js/src/jit-test/tests/wasm/ref-types/tables-multiple.js b/js/src/jit-test/tests/wasm/ref-types/tables-multiple.js index e33cb0605c10..21130497ef1b 100644 --- a/js/src/jit-test/tests/wasm/ref-types/tables-multiple.js +++ b/js/src/jit-test/tests/wasm/ref-types/tables-multiple.js @@ -413,16 +413,7 @@ assertErrorMessage(() => wasmEvalText( (func $f (table.copy 0 (i32.const 0) (i32.const 0) (i32.const 2))))`), // target without source SyntaxError, - /expected keyword `table`/); - -assertErrorMessage(() => wasmEvalText( - `(module - (table $t0 2 funcref) - (table $t1 2 funcref) - (func $f - (table.copy (i32.const 0) 0 (i32.const 0) (i32.const 2))))`), // source without target - SyntaxError, - /wasm text error/); + /unexpected token, expected an identifier or u32/); // Make sure that dead code doesn't prevent compilation. wasmEvalText( diff --git a/js/src/jit-test/tests/wasm/widening-i32-after-call.js b/js/src/jit-test/tests/wasm/widening-i32-after-call.js index 461fccc83d0d..71dede01b121 100644 --- a/js/src/jit-test/tests/wasm/widening-i32-after-call.js +++ b/js/src/jit-test/tests/wasm/widening-i32-after-call.js @@ -27,7 +27,7 @@ var ins = wasmEvalText(` (func (export "wasm2import") (result i32) (call $g)) (func (export "wasmIndirect") (result i32) - (call_indirect (type $ty) $t (i32.const 0))) + (call_indirect $t (type $ty) (i32.const 0))) (func (export "instanceCall") (result i32) (memory.size)) )`, {'':{'wasm2import': function() {}}}); diff --git a/js/src/rust/Cargo.toml b/js/src/rust/Cargo.toml index 22681f79c678..d3f12c74ad4e 100644 --- a/js/src/rust/Cargo.toml +++ b/js/src/rust/Cargo.toml @@ -22,5 +22,5 @@ gluesmith = ['jsrust_shared/gluesmith'] jsrust_shared = { path = "./shared" } # Workaround for https://github.com/rust-lang/rust/issues/58393 mozglue-static = { path = "../../../mozglue/static/rust" } -wat = { version = "1.0.39" } +wat = { version = "1.0.43" } wasmparser = { version = "0.78.2" } diff --git a/third_party/rust/wast/.cargo-checksum.json b/third_party/rust/wast/.cargo-checksum.json index cbecc6adf35e..d5310e4cd393 100644 --- a/third_party/rust/wast/.cargo-checksum.json +++ b/third_party/rust/wast/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d733009b648137b9173d6cbfaccf5a05a9fe63973250de59f9829d88cff0c478","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"7fd991b3784666e241e704e669a67ca97ab91bbb621b6bd95c8e4eb299a2ff49","src/ast/alias.rs":"e3fda5f4b90a0b258cb8979b4fbb2e1461db6edc310323141f6591009f971c76","src/ast/assert_expr.rs":"f5a83d8fd33c2db4dc09885367bf33284a5510f6eda0e882da0c37324e23c97f","src/ast/custom.rs":"ab862dbb3dc10492ba2b9888f0ec27bd03168e17529b9e7f30c0333a1420aae1","src/ast/export.rs":"8de578adef537953f7ee4494cb5b156d162501e09a00cca41c3a20119b9281e8","src/ast/expr.rs":"695bee83e0929f6d923fcd353857f973f0f514b228bf97cd4beb7da890e1fc05","src/ast/func.rs":"be776bf25f4434006496b27d56d2e5472946e15079a4a832452c374789868d75","src/ast/global.rs":"d890ca3ee2dc5c34e09f512a49f0ecf52f5dfbbccef84ec4dcaff0fa96f74a29","src/ast/import.rs":"3ee2e2a3af1959c4c059bdf4ff900042a92142c1854efea6c0c2c83342a97bb2","src/ast/instance.rs":"4fce317029ff12b285c83ee5a60e83008b638ae3f4c43f6e98b02670e947f5c2","src/ast/memory.rs":"83eb0c0c70402c2791a8721e170fc126a5d7373e730bd7014216a29b9f5050e9","src/ast/mod.rs":"bbb78f8de26d731a37ccfc41f778cd38a30a3e0477ad393907bd9fcc302b797f","src/ast/module.rs":"dace07b31d10bb8dc3c7dd6b0e5400f8aa2c6c670958e57da5d1d43de2d99390","src/ast/nested_module.rs":"03453559f7fb6a187c33f715a4137ad972e7d9724eb908bda1c826437b9fd780","src/ast/table.rs":"e285da61ddd715d6275fb2d7177d2761bfd0a62589a6e053c804fce2bde568d8","src/ast/tag.rs":"81ffb7feeb7a02d6a44a2da732de3604f178b5d18a3734709106d5bef2201528","src/ast/token.rs":"9a18b7ff1d324b88d944890ade8816546993c42aae0b9574820aecdb45406dcd","src/ast/types.rs":"1c3bbd5cccf0d79431b57e06dd74107f58066c8a241f9267c0621918dc75d0a6","src/ast/wast.rs":"bc18bf48a6a2027fcd482e97a1d24038f22c5bc77e243d185d76a4192ec30b36","src/binary.rs":"6510f0c8c1e3486a2f95ed63b603ea68ef0e639bfe48a61817a229ee896f78b0","src/lexer.rs":"0daebd24a53ecc1cf2173205f94426854a443e43cf632e67286dd6390128ff82","src/lib.rs":"51f880f9eab5366237a5206ffcddf099d03a236c36d897aa8677ae5e0b7640a9","src/parser.rs":"c8c0346731d81245843f875ccb9990b65baf3ea63721616863e15e1135c8013c","src/resolve/aliases.rs":"e6924a496ea6d9151cf869a443fb966b06ed240cf5f26eae0c7ba8b9f92188c2","src/resolve/deinline_import_export.rs":"caf6197afa8e488f32971faf2f117009d45071af52c40aaebad29feb2068d6ae","src/resolve/gensym.rs":"252b82233c31d15a29a0d185db03d38fc94bbd7e995d26b06da72a5d088f4eb3","src/resolve/mod.rs":"e1b98c8d7a6b2450dd8006b90bc8e704dd7de674d99f18879fdd32b42917fe98","src/resolve/names.rs":"0750c01d8f88cde4231fecce0d661f1da3fdb11a36869007061e612b33bab38a","src/resolve/types.rs":"3221d249f71a436ea63395df3bcd93daf8be3f5df6dfb2e4aa43591fca66d1e5","tests/annotations.rs":"8000ecce44de048c35b0554643bb483fa06bdba92b38ba127ca1eafbac1cfec6","tests/comments.rs":"14104ab95b99f0402dcec15988c592aec760bfbccfedc9e532e4bf06afd0b836","tests/parse-fail.rs":"0f1d5dffd1e6145105571222096703c89c4f4a46e25c848faa730f731155ea1c","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"b66851e048a20240c3dc4c2a1a991436daf688a62fa94ff8f63a908fcaee8a9a","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"e9bbbd53432b267421186feee3e52436531fa69a7cfee9403f5204352df3dd05"} \ No newline at end of file +{"files":{"Cargo.toml":"4811bb1578ac21bea7c6b86d806a0da0435ecc3f7cbb28224d5f87596541b547","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"7fd991b3784666e241e704e669a67ca97ab91bbb621b6bd95c8e4eb299a2ff49","src/assert_expr.rs":"add54646ed45948a378e5ef53a2a0cc5e9ddb2d53cd67fefadadbf25490f8800","src/component/alias.rs":"66190812e2aee72e4b135ff81e960708d54123b3d6f198558c7b46f87d4bf2b9","src/component/binary.rs":"628a9fba680456e3ed00012e5866a0f3ca1bb0df0c7a204519e89306e8e932d0","src/component/component.rs":"b2bbb7f6da3e18f6d80d2e9f682d91e144a7cd7af9f9429f6bbd73960499441d","src/component/deftype.rs":"dee4b357c80866738ace860304129affcbcd9502a055874fb51e7fa2dbfdb39f","src/component/expand.rs":"58afbc22f32ddf04d4fbaf0737d8d4fd9394fd3052a96459eda17a18873e2593","src/component/export.rs":"eb9014bad577a9ad934b0bf8a6c3f2ce18a1f411744f06655bc5037bd10e2c9e","src/component/func.rs":"c087c3b14a87fe23f69d1e12a7cea20e43bb94f97851b432670fd6014f260220","src/component/import.rs":"8a95e289833970cc01fc97014e27e25c22c25c670266c2c59a258f74ca1d4337","src/component/instance.rs":"c95bd844c38185b4f3869fa67d5dd728f8183ff1ba7ba6929766223950a81813","src/component/intertype.rs":"716cb6f91cf7cac75f064328f43ca0c4261e2ab09b3292b7e5e6e39405583aa7","src/component/item_ref.rs":"d999beeb9d86906d5a16ec7428b6a44bc064c8090586c7c4b0545c0d01a80efe","src/component/mod.rs":"377402d683a92aa26f9f9473c983acf6416e008c72c679bc3c99e83a6f113ce6","src/component/module.rs":"0810e295b6f211a43cf5a18e59eebd6c0cc553273e4b567346b3814421e611c7","src/component/resolve.rs":"569033529a2e75521ebbe3a8bb43c02805bc73fe835a04c021492f67360e07ee","src/component/types.rs":"bdbc73ca258d8b7b2a6c741d71e11a18e8d9790b398beb029fffd6d731670ac2","src/core/binary.rs":"5d2adba1f396dac7dd55b34039a2d6cc205409a036c1948e5d6d7456ef17b929","src/core/custom.rs":"de9d79bae590af5fc150ae23d509407584123f930e3a87d97f6d13bf2ae8508b","src/core/export.rs":"f9001fd8e8cbb0ed7673995acc042ddd9a19cbbcdab0f8c9a7ce19d9a957e804","src/core/expr.rs":"af0b9a706fcaec1747c9599663c6ed97284bca042274614da08bbc1b2c465086","src/core/func.rs":"d7df909a0799f0d93071a5d55da53fdaa93dfcb0570b1e509705c557bb586dc8","src/core/global.rs":"dec0abecadd2fde9298acb729259deba1ef3c4733ae5afcb4fe8cd4a633f5349","src/core/import.rs":"fcf7affc0d55d16a90ed45cd87ebda6faaeee4b8af7c4abe34ff20b0cb58d8fb","src/core/memory.rs":"f2c85ecbd217f561eced97884df17c2cd22d3013606c43a925b19f81b1a49c59","src/core/mod.rs":"cd5349b371fdcfaa9377b0689edc6d9347e5b60ec46843c987585740ef5e1fdc","src/core/module.rs":"a08b1caacf399995b35734b4151f5178f5f92c8819168b80beae47faddfe8d40","src/core/resolve/deinline_import_export.rs":"67cfd3857c4b576c7f2c4bd04c218026d1d3026b95733d14c40cd1e1c10bccd2","src/core/resolve/mod.rs":"9b2680b00a1cafad2dbbfdac86aa1c135ea67203bbc4dee939302b27f4aff6d0","src/core/resolve/names.rs":"fc79fa8eac982722098d4c96a3af0c01c626473d3ba03d44399a297c34d8be9d","src/core/resolve/types.rs":"60189a11dcc62f20a606c19566c662065a7c4578c425c7c6762af48c4548c8ff","src/core/table.rs":"c6f64f987dafb9c3f6ea163544db84d10200635eccc08a64bf2454f0c071924a","src/core/tag.rs":"8a3d4fcdb86dedd68cdaf25abd930ef52a461cf2a0e9393bb9cb6f425afaaf2e","src/core/types.rs":"11b3c3b581d9eb7c8e202793703e4666931c30b6fc4b3275adcf423223c5a525","src/encode.rs":"7b21fa34cec14d8073ade8f5083a1575c736179860baa624682ad18ea054bb85","src/error.rs":"8592a920e2fd5360a24c0be8ff369db041579b6a48776ca696abddfcaa8ecd00","src/gensym.rs":"b5e02e34443085f01deb5b657e541be7dc5d6dc952304e434a0b08320ea6c185","src/lexer.rs":"6fb88d334bf8e901c2768b8d6581b6b07d16466f50ad4c9967bc3491486765f6","src/lib.rs":"ca963a9c6a1750fb8b6d1ce5435f930cd46d704cd3d3cdf63f86827e6d4ce0de","src/names.rs":"ee320bd2665b89f11173ffa491230824acf278d9034562ed59f7c8c3958feb49","src/parser.rs":"1b7666dbc9e4f39c3bed646cd214441821137a20d775497c7c76e2bb6d85ec8d","src/token.rs":"43e3312ef0682265c23e29dad4cfbd16049c10fb765bb85ced3e8c4c8e65dcb5","src/wast.rs":"41fa426b0239e3e4ca0f7e7f2b55a1611af2a7d95fac77fce6348966331ed378","src/wat.rs":"e8dbfad184a156c88ced3da82cbe8cddc4c0d4e5468cdd430110abc85415c14d","tests/annotations.rs":"60da35b7ab0b610a1cc15d4508fa172e9696ad02281177942bc48bef2ff5d871","tests/comments.rs":"2861aa6efb500b9b26633a151b27dddeca5b295a1f20d2f3892377889af60550","tests/parse-fail.rs":"0f1d5dffd1e6145105571222096703c89c4f4a46e25c848faa730f731155ea1c","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"b66851e048a20240c3dc4c2a1a991436daf688a62fa94ff8f63a908fcaee8a9a","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870"} \ No newline at end of file diff --git a/third_party/rust/wast/Cargo.toml b/third_party/rust/wast/Cargo.toml index 5a730e02491d..83c9a76040a1 100644 --- a/third_party/rust/wast/Cargo.toml +++ b/third_party/rust/wast/Cargo.toml @@ -10,20 +10,24 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" name = "wast" -version = "39.0.0" +version = "41.0.0" authors = ["Alex Crichton "] -description = "Customizable Rust parsers for the WebAssembly Text formats WAT and WAST\n" +description = """ +Customizable Rust parsers for the WebAssembly Text formats WAT and WAST +""" homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast" documentation = "https://docs.rs/wast" readme = "README.md" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast" +resolver = "2" [[test]] name = "parse-fail" harness = false + [dependencies.leb128] version = "0.2" @@ -32,6 +36,7 @@ version = "2.4.1" [dependencies.unicode-width] version = "0.1.9" + [dev-dependencies.anyhow] version = "1.0" diff --git a/third_party/rust/wast/src/ast/assert_expr.rs b/third_party/rust/wast/src/assert_expr.rs similarity index 94% rename from third_party/rust/wast/src/ast/assert_expr.rs rename to third_party/rust/wast/src/assert_expr.rs index f6fcc9cd1232..d7359c705cb2 100644 --- a/third_party/rust/wast/src/ast/assert_expr.rs +++ b/third_party/rust/wast/src/assert_expr.rs @@ -1,10 +1,13 @@ -use crate::ast::{kw, Float32, Float64, Index, HeapType}; +use crate::core::HeapType; +use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Float32, Float64, Index}; /// An expression that is valid inside an `assert_return` directive. /// -/// As of https://github.com/WebAssembly/spec/pull/1104, spec tests may include `assert_return` -/// directives that allow NaN patterns (`"nan:canonical"`, `"nan:arithmetic"`). Parsing an +/// As of , spec tests may +/// include `assert_return` directives that allow NaN patterns +/// (`"nan:canonical"`, `"nan:arithmetic"`). Parsing an /// `AssertExpression` means that: /// - only constant values (e.g. `i32.const 4`) are used in the `assert_return` directive /// - the NaN patterns are allowed (they are not allowed in regular `Expression`s). diff --git a/third_party/rust/wast/src/ast/alias.rs b/third_party/rust/wast/src/ast/alias.rs deleted file mode 100644 index 3c8d7358cf2b..000000000000 --- a/third_party/rust/wast/src/ast/alias.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::ast::{self, kw}; -use crate::parser::{Parse, Parser, Result}; - -/// An `alias` statement used to juggle indices with nested modules. -#[derive(Debug)] -pub struct Alias<'a> { - /// Where this `alias` was defined. - pub span: ast::Span, - /// An identifier that this alias is resolved with (optionally) for name - /// resolution. - pub id: Option>, - /// An optional name for this alias stored in the custom `name` section. - pub name: Option>, - /// The source of this alias. - pub source: AliasSource<'a>, - /// The kind of item that's being aliased. - pub kind: ast::ExportKind, -} - -#[derive(Debug)] -#[allow(missing_docs)] -pub enum AliasSource<'a> { - InstanceExport { - instance: ast::ItemRef<'a, kw::instance>, - export: &'a str, - }, - Outer { - /// The index of the module that this reference is referring to. - module: ast::Index<'a>, - /// The index of the item within `module` that this alias is referering - /// to. - index: ast::Index<'a>, - }, -} - -impl<'a> Parse<'a> for Alias<'a> { - fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let source = if parser.parse::>()?.is_some() { - AliasSource::Outer { - module: parser.parse()?, - index: parser.parse()?, - } - } else { - AliasSource::InstanceExport { - instance: parser.parse::>()?.0, - export: parser.parse()?, - } - }; - let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?; - - Ok(Alias { - span, - id, - name, - kind, - source, - }) - } -} diff --git a/third_party/rust/wast/src/ast/instance.rs b/third_party/rust/wast/src/ast/instance.rs deleted file mode 100644 index b0c9d021eac8..000000000000 --- a/third_party/rust/wast/src/ast/instance.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::ast::{self, kw}; -use crate::parser::{Parse, Parser, Result}; - -/// A nested WebAssembly instance to be created as part of a module. -#[derive(Debug)] -pub struct Instance<'a> { - /// Where this `instance` was defined. - pub span: ast::Span, - /// An identifier that this instance is resolved with (optionally) for name - /// resolution. - pub id: Option>, - /// An optional name for this function stored in the custom `name` section. - pub name: Option>, - /// If present, inline export annotations which indicate names this - /// definition should be exported under. - pub exports: ast::InlineExport<'a>, - /// What kind of instance this is, be it an inline-defined or imported one. - pub kind: InstanceKind<'a>, -} - -/// Possible ways to define a instance in the text format. -#[derive(Debug)] -pub enum InstanceKind<'a> { - /// An instance which is actually defined as an import, such as: - Import { - /// Where we're importing from - import: ast::InlineImport<'a>, - /// The type that this instance will have. - ty: ast::TypeUse<'a, ast::InstanceType<'a>>, - }, - - /// Instances whose instantiation is defined inline. - Inline { - /// Module that we're instantiating - module: ast::ItemRef<'a, kw::module>, - /// Arguments used to instantiate the instance - args: Vec>, - }, -} - -/// Arguments to the `instantiate` instruction -#[derive(Debug)] -#[allow(missing_docs)] -pub struct InstanceArg<'a> { - pub name: &'a str, - pub index: ast::ItemRef<'a, ast::ExportKind>, -} - -impl<'a> Parse<'a> for Instance<'a> { - fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let id = parser.parse()?; - let name = parser.parse()?; - let exports = parser.parse()?; - - let kind = if let Some(import) = parser.parse()? { - InstanceKind::Import { - import, - ty: parser.parse()?, - } - } else { - parser.parens(|p| { - p.parse::()?; - let module = p.parse::>()?.0; - let mut args = Vec::new(); - while !p.is_empty() { - args.push(p.parens(|p| p.parse())?); - } - Ok(InstanceKind::Inline { module, args }) - })? - }; - - Ok(Instance { - span, - id, - name, - exports, - kind, - }) - } -} - -impl<'a> Parse<'a> for InstanceArg<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(InstanceArg { - name: parser.parse()?, - index: parser.parse()?, - }) - } -} diff --git a/third_party/rust/wast/src/ast/mod.rs b/third_party/rust/wast/src/ast/mod.rs deleted file mode 100644 index d47f58be66dd..000000000000 --- a/third_party/rust/wast/src/ast/mod.rs +++ /dev/null @@ -1,430 +0,0 @@ -/// A macro to create a custom keyword parser. -/// -/// This macro is invoked in one of two forms: -/// -/// ``` -/// // keyword derived from the Rust identifier: -/// wast::custom_keyword!(foo); -/// -/// // or an explicitly specified string representation of the keyword: -/// wast::custom_keyword!(my_keyword = "the-wasm-keyword"); -/// ``` -/// -/// This can then be used to parse custom keyword for custom items, such as: -/// -/// ``` -/// use wast::parser::{Parser, Result, Parse}; -/// -/// struct InlineModule<'a> { -/// inline_text: &'a str, -/// } -/// -/// mod kw { -/// wast::custom_keyword!(inline); -/// } -/// -/// // Parse an inline string module of the form: -/// // -/// // (inline "(module (func))") -/// impl<'a> Parse<'a> for InlineModule<'a> { -/// fn parse(parser: Parser<'a>) -> Result { -/// parser.parse::()?; -/// Ok(InlineModule { -/// inline_text: parser.parse()?, -/// }) -/// } -/// } -/// ``` -/// -/// Note that the keyword name can only start with a lower-case letter, i.e. 'a'..'z'. -#[macro_export] -macro_rules! custom_keyword { - ($name:ident) => { - $crate::custom_keyword!($name = stringify!($name)); - }; - ($name:ident = $kw:expr) => { - #[allow(non_camel_case_types)] - #[allow(missing_docs)] - #[derive(Debug, Copy, Clone)] - pub struct $name(pub $crate::Span); - - impl<'a> $crate::parser::Parse<'a> for $name { - fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { - parser.step(|c| { - if let Some((kw, rest)) = c.keyword() { - if kw == $kw { - return Ok(($name(c.cur_span()), rest)); - } - } - Err(c.error(concat!("expected keyword `", $kw, "`"))) - }) - } - } - - impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((kw, _rest)) = cursor.keyword() { - kw == $kw - } else { - false - } - } - - fn display() -> &'static str { - concat!("`", $kw, "`") - } - } - }; -} - -/// A macro for defining custom reserved symbols. -/// -/// This is like `custom_keyword!` but for reserved symbols (`Token::Reserved`) -/// instead of keywords (`Token::Keyword`). -/// -/// ``` -/// use wast::parser::{Parser, Result, Parse}; -/// -/// // Define a custom reserved symbol, the "spaceship" operator: `<=>`. -/// wast::custom_reserved!(spaceship = "<=>"); -/// -/// /// A "three-way comparison" like `(<=> a b)` that returns -1 if `a` is less -/// /// than `b`, 0 if they're equal, and 1 if `a` is greater than `b`. -/// struct ThreeWayComparison<'a> { -/// lhs: wast::Expression<'a>, -/// rhs: wast::Expression<'a>, -/// } -/// -/// impl<'a> Parse<'a> for ThreeWayComparison<'a> { -/// fn parse(parser: Parser<'a>) -> Result { -/// parser.parse::()?; -/// let lhs = parser.parse()?; -/// let rhs = parser.parse()?; -/// Ok(ThreeWayComparison { lhs, rhs }) -/// } -/// } -/// ``` -#[macro_export] -macro_rules! custom_reserved { - ($name:ident) => { - $crate::custom_reserved!($name = stringify!($name)); - }; - ($name:ident = $rsv:expr) => { - #[allow(non_camel_case_types)] - #[allow(missing_docs)] - #[derive(Debug)] - pub struct $name(pub $crate::Span); - - impl<'a> $crate::parser::Parse<'a> for $name { - fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { - parser.step(|c| { - if let Some((rsv, rest)) = c.reserved() { - if rsv == $rsv { - return Ok(($name(c.cur_span()), rest)); - } - } - Err(c.error(concat!("expected reserved symbol `", $rsv, "`"))) - }) - } - } - - impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((rsv, _rest)) = cursor.reserved() { - rsv == $rsv - } else { - false - } - } - - fn display() -> &'static str { - concat!("`", $rsv, "`") - } - } - }; -} - -/// A macro, like [`custom_keyword`], to create a type which can be used to -/// parse/peek annotation directives. -/// -/// Note that when you're parsing custom annotations it can be somewhat tricky -/// due to the nature that most of them are skipped. You'll want to be sure to -/// consult the documentation of [`Parser::register_annotation`][register] when -/// using this macro. -/// -/// # Examples -/// -/// To see an example of how to use this macro, let's invent our own syntax for -/// the [producers section][section] which looks like: -/// -/// ```wat -/// (@producer "wat" "1.0.2") -/// ``` -/// -/// Here, for simplicity, we'll assume everything is a `processed-by` directive, -/// but you could get much more fancy with this as well. -/// -/// ``` -/// # use wast::*; -/// # use wast::parser::*; -/// -/// // First we define the custom annotation keyword we're using, and by -/// // convention we define it in an `annotation` module. -/// mod annotation { -/// wast::annotation!(producer); -/// } -/// -/// struct Producer<'a> { -/// name: &'a str, -/// version: &'a str, -/// } -/// -/// impl<'a> Parse<'a> for Producer<'a> { -/// fn parse(parser: Parser<'a>) -> Result { -/// // Remember that parser conventionally parse the *interior* of an -/// // s-expression, so we parse our `@producer` annotation and then we -/// // parse the payload of our annotation. -/// parser.parse::()?; -/// Ok(Producer { -/// name: parser.parse()?, -/// version: parser.parse()?, -/// }) -/// } -/// } -/// ``` -/// -/// Note though that this is only half of the parser for annotations. The other -/// half is calling the [`register_annotation`][register] method at the right -/// time to ensure the parser doesn't automatically skip our `@producer` -/// directive. Note that we *can't* call it inside the `Parse for Producer` -/// definition because that's too late and the annotation would already have -/// been skipped. -/// -/// Instead we'll need to call it from a higher level-parser before the -/// parenthesis have been parsed, like so: -/// -/// ``` -/// # use wast::*; -/// # use wast::parser::*; -/// struct Module<'a> { -/// fields: Vec>, -/// } -/// -/// impl<'a> Parse<'a> for Module<'a> { -/// fn parse(parser: Parser<'a>) -> Result { -/// // .. parse module header here ... -/// -/// // register our custom `@producer` annotation before we start -/// // parsing the parentheses of each field -/// let _r = parser.register_annotation("producer"); -/// -/// let mut fields = Vec::new(); -/// while !parser.is_empty() { -/// fields.push(parser.parens(|p| p.parse())?); -/// } -/// Ok(Module { fields }) -/// } -/// } -/// -/// enum ModuleField<'a> { -/// Producer(Producer<'a>), -/// // ... -/// } -/// # struct Producer<'a>(&'a str); -/// # impl<'a> Parse<'a> for Producer<'a> { -/// # fn parse(parser: Parser<'a>) -> Result { Ok(Producer(parser.parse()?)) } -/// # } -/// # mod annotation { wast::annotation!(producer); } -/// -/// impl<'a> Parse<'a> for ModuleField<'a> { -/// fn parse(parser: Parser<'a>) -> Result { -/// // and here `peek` works and our delegated parsing works because the -/// // annotation has been registered. -/// if parser.peek::() { -/// return Ok(ModuleField::Producer(parser.parse()?)); -/// } -/// -/// // .. typically we'd parse other module fields here... -/// -/// Err(parser.error("unknown module field")) -/// } -/// } -/// ``` -/// -/// [register]: crate::parser::Parser::register_annotation -/// [section]: https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md -#[macro_export] -macro_rules! annotation { - ($name:ident) => { - $crate::annotation!($name = stringify!($name)); - }; - ($name:ident = $annotation:expr) => { - #[allow(non_camel_case_types)] - #[allow(missing_docs)] - #[derive(Debug)] - pub struct $name(pub $crate::Span); - - impl<'a> $crate::parser::Parse<'a> for $name { - fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { - parser.step(|c| { - if let Some((a, rest)) = c.annotation() { - if a == $annotation { - return Ok(($name(c.cur_span()), rest)); - } - } - Err(c.error(concat!("expected annotation `@", $annotation, "`"))) - }) - } - } - - impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((a, _rest)) = cursor.annotation() { - a == $annotation - } else { - false - } - } - - fn display() -> &'static str { - concat!("`@", $annotation, "`") - } - } - }; -} - -macro_rules! reexport { - ($(mod $name:ident;)*) => ($(mod $name; pub use self::$name::*;)*); -} - -reexport! { - mod token; -} - -#[cfg(feature = "wasm-module")] -reexport! { - mod alias; - mod assert_expr; - mod custom; - mod tag; - mod export; - mod expr; - mod func; - mod global; - mod import; - mod instance; - mod memory; - mod module; - mod nested_module; - mod table; - mod types; - mod wast; -} - -/// Common keyword used to parse WebAssembly text files. -pub mod kw { - custom_keyword!(after); - custom_keyword!(alias); - custom_keyword!(any); - custom_keyword!(anyfunc); - custom_keyword!(anyref); - custom_keyword!(arg); - custom_keyword!(array); - custom_keyword!(assert_exception); - custom_keyword!(assert_exhaustion); - custom_keyword!(assert_invalid); - custom_keyword!(assert_malformed); - custom_keyword!(assert_return); - custom_keyword!(assert_return_arithmetic_nan); - custom_keyword!(assert_return_arithmetic_nan_f32x4); - custom_keyword!(assert_return_arithmetic_nan_f64x2); - custom_keyword!(assert_return_canonical_nan); - custom_keyword!(assert_return_canonical_nan_f32x4); - custom_keyword!(assert_return_canonical_nan_f64x2); - custom_keyword!(assert_return_func); - custom_keyword!(assert_trap); - custom_keyword!(assert_unlinkable); - custom_keyword!(before); - custom_keyword!(binary); - custom_keyword!(block); - custom_keyword!(catch); - custom_keyword!(catch_all); - custom_keyword!(code); - custom_keyword!(data); - custom_keyword!(dataref); - custom_keyword!(declare); - custom_keyword!(delegate); - custom_keyword!(r#do = "do"); - custom_keyword!(elem); - custom_keyword!(end); - custom_keyword!(tag); - custom_keyword!(export); - custom_keyword!(r#extern = "extern"); - custom_keyword!(externref); - custom_keyword!(eq); - custom_keyword!(eqref); - custom_keyword!(f32); - custom_keyword!(f32x4); - custom_keyword!(f64); - custom_keyword!(f64x2); - custom_keyword!(field); - custom_keyword!(first); - custom_keyword!(func); - custom_keyword!(funcref); - custom_keyword!(get); - custom_keyword!(global); - custom_keyword!(i16); - custom_keyword!(i16x8); - custom_keyword!(i31); - custom_keyword!(i31ref); - custom_keyword!(i32); - custom_keyword!(i32x4); - custom_keyword!(i64); - custom_keyword!(i64x2); - custom_keyword!(i8); - custom_keyword!(i8x16); - custom_keyword!(import); - custom_keyword!(instance); - custom_keyword!(instantiate); - custom_keyword!(invoke); - custom_keyword!(item); - custom_keyword!(last); - custom_keyword!(local); - custom_keyword!(memory); - custom_keyword!(module); - custom_keyword!(modulecode); - custom_keyword!(nan_arithmetic = "nan:arithmetic"); - custom_keyword!(nan_canonical = "nan:canonical"); - custom_keyword!(null); - custom_keyword!(nullref); - custom_keyword!(offset); - custom_keyword!(outer); - custom_keyword!(param); - custom_keyword!(parent); - custom_keyword!(passive); - custom_keyword!(quote); - custom_keyword!(r#else = "else"); - custom_keyword!(r#if = "if"); - custom_keyword!(r#loop = "loop"); - custom_keyword!(r#mut = "mut"); - custom_keyword!(r#type = "type"); - custom_keyword!(r#ref = "ref"); - custom_keyword!(ref_func = "ref.func"); - custom_keyword!(ref_null = "ref.null"); - custom_keyword!(register); - custom_keyword!(result); - custom_keyword!(rtt); - custom_keyword!(shared); - custom_keyword!(start); - custom_keyword!(r#struct = "struct"); - custom_keyword!(table); - custom_keyword!(then); - custom_keyword!(r#try = "try"); - custom_keyword!(v128); -} - -/// Common annotations used to parse WebAssembly text files. -pub mod annotation { - annotation!(custom); - annotation!(name); -} diff --git a/third_party/rust/wast/src/component/alias.rs b/third_party/rust/wast/src/component/alias.rs new file mode 100644 index 000000000000..b065cbf4d311 --- /dev/null +++ b/third_party/rust/wast/src/component/alias.rs @@ -0,0 +1,108 @@ +use crate::core; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, Index, NameAnnotation, Span}; + +/// An `alias` statement used to juggle indices with nested components. +#[derive(Debug, Clone)] +pub struct Alias<'a> { + /// Where this `alias` was defined. + pub span: Span, + /// An identifier that this alias is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this alias stored in the custom `name` section. + pub name: Option>, + /// The target of this alias. + pub target: AliasTarget<'a>, + /// The kind of item that's being aliased. + pub kind: AliasKind, +} + +/// aliaskind ::= (module ?) +/// | (component ?) +/// | (instance ?) +/// | (func ?) +/// | (value ?) +/// | (type ?) +/// | (table ?) +/// | (memory ?) +/// | (global ?) +/// | ... other Post-MVP Core definition kinds +#[derive(Debug, Clone)] +#[allow(missing_docs)] +pub enum AliasKind { + Module, + Component, + Instance, + Value, + ExportKind(core::ExportKind), +} + +impl<'a> Parse<'a> for AliasKind { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + let kind = parser.parse::()?; + Ok(AliasKind::ExportKind(kind)) + } else if l.peek::() { + parser.parse::()?; + Ok(AliasKind::Module) + } else if l.peek::() { + parser.parse::()?; + Ok(AliasKind::Component) + } else if l.peek::() { + parser.parse::()?; + Ok(AliasKind::Instance) + } else if l.peek::() { + parser.parse::()?; + Ok(AliasKind::Value) + } else { + Err(l.error()) + } + } +} + +/// aliastarget ::= export +/// | outer +#[derive(Debug, Clone)] +#[allow(missing_docs)] +pub enum AliasTarget<'a> { + Export { + instance: Index<'a>, + export: &'a str, + }, + Outer { + /// The number of enclosing components to skip. + outer: Index<'a>, + /// An index into the target component's `aliaskind` index space. + index: Index<'a>, + }, +} + +impl<'a> Parse<'a> for Alias<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let target = if parser.parse::>()?.is_some() { + AliasTarget::Outer { + outer: parser.parse()?, + index: parser.parse()?, + } + } else { + parser.parse::()?; + AliasTarget::Export { + instance: parser.parse::>()?, + export: parser.parse()?, + } + }; + let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?; + + Ok(Alias { + span, + id, + name, + kind, + target, + }) + } +} diff --git a/third_party/rust/wast/src/component/binary.rs b/third_party/rust/wast/src/component/binary.rs new file mode 100644 index 000000000000..590e4db73487 --- /dev/null +++ b/third_party/rust/wast/src/component/binary.rs @@ -0,0 +1,632 @@ +use crate::component::*; +use crate::core; +use crate::encode::Encode; +use crate::token::{Id, NameAnnotation}; + +pub fn encode(component: &Component<'_>) -> Vec { + match &component.kind { + ComponentKind::Text(fields) => encode_fields(&component.id, &component.name, fields), + ComponentKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().cloned()).collect(), + } +} + +fn encode_fields( + component_id: &Option>, + component_name: &Option>, + fields: &[ComponentField<'_>], +) -> Vec { + let mut e = Encoder { + wasm: Vec::new(), + tmp: Vec::new(), + last_section: None, + last_section_contents: Vec::new(), + last_section_count: 0, + }; + e.wasm.extend(b"\0asm"); + e.wasm.extend(b"\x0a\0\x01\0"); + + for field in fields { + match field { + ComponentField::Type(i) => e.append(1, i), + ComponentField::Import(i) => e.append(2, i), + ComponentField::Func(i) => e.append(3, i), + ComponentField::Module(i) => e.section(4, i), + ComponentField::Component(i) => e.section(5, i), + ComponentField::Instance(i) => e.append(6, i), + ComponentField::Export(i) => e.append(7, i), + ComponentField::Start(i) => e.section(8, i), + ComponentField::Alias(i) => e.append(9, i), + } + } + + // FIXME(WebAssembly/component-model#14): once a name section is defined it + // should be encoded here. + drop((component_id, component_name)); + + e.flush(); + + return e.wasm; +} + +struct Encoder { + wasm: Vec, + tmp: Vec, + + last_section: Option, + last_section_contents: Vec, + last_section_count: usize, +} + +impl Encoder { + /// Appends an entire section represented by the `section` provided + fn section(&mut self, id: u8, section: &dyn Encode) { + self.flush(); + self.tmp.truncate(0); + section.encode(&mut self.tmp); + self.wasm.push(id); + self.tmp.encode(&mut self.wasm); + } + + /// Appends an `item` specified within the section `id` specified. + fn append(&mut self, id: u8, item: &dyn Encode) { + // Flush if necessary to start a new section + if self.last_section != Some(id) { + self.flush(); + } + // ... and afterwards start building up this section incrementally + // in case the next item encoded is also part of this section. + item.encode(&mut self.last_section_contents); + self.last_section_count += 1; + self.last_section = Some(id); + } + + fn flush(&mut self) { + let id = match self.last_section.take() { + Some(id) => id, + None => return, + }; + self.wasm.push(id); + self.tmp.truncate(0); + self.last_section_count.encode(&mut self.tmp); + self.last_section_count = 0; + self.tmp.extend(self.last_section_contents.drain(..)); + self.tmp.encode(&mut self.wasm); + } +} + +impl Encode for NestedComponent<'_> { + fn encode(&self, e: &mut Vec) { + let fields = match &self.kind { + NestedComponentKind::Import { .. } => panic!("imports should be gone by now"), + NestedComponentKind::Inline(fields) => fields, + }; + e.extend(encode_fields(&self.id, &self.name, fields)); + } +} + +impl Encode for Module<'_> { + fn encode(&self, e: &mut Vec) { + match &self.kind { + ModuleKind::Import { .. } => panic!("imports should be gone by now"), + ModuleKind::Inline { fields } => { + e.extend(crate::core::binary::encode(&self.id, &self.name, fields)); + } + } + } +} + +impl Encode for Instance<'_> { + fn encode(&self, e: &mut Vec) { + match &self.kind { + InstanceKind::Module { module, args } => { + e.push(0x00); + e.push(0x00); + module.idx.encode(e); + args.encode(e); + } + InstanceKind::Component { component, args } => { + e.push(0x00); + e.push(0x01); + component.idx.encode(e); + args.encode(e); + } + InstanceKind::BundleOfComponentExports { args } => { + e.push(0x01); + args.encode(e); + } + InstanceKind::BundleOfExports { args } => { + e.push(0x02); + args.encode(e); + } + InstanceKind::Import { .. } => unreachable!("should be removed during expansion"), + } + } +} + +impl Encode for NamedModuleArg<'_> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + e.push(0x02); + self.arg.encode(e); + } +} + +impl Encode for ModuleArg<'_> { + fn encode(&self, e: &mut Vec) { + match self { + ModuleArg::Def(def) => { + def.idx.encode(e); + } + ModuleArg::BundleOfExports(..) => { + unreachable!("should be expanded already") + } + } + } +} + +impl Encode for NamedComponentArg<'_> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + self.arg.encode(e); + } +} + +impl Encode for ComponentArg<'_> { + fn encode(&self, e: &mut Vec) { + match self { + ComponentArg::Def(def) => { + match def.kind { + DefTypeKind::Module => e.push(0x00), + DefTypeKind::Component => e.push(0x01), + DefTypeKind::Instance => e.push(0x02), + DefTypeKind::Func => e.push(0x03), + DefTypeKind::Value => e.push(0x04), + } + def.idx.encode(e); + } + ComponentArg::BundleOfExports(..) => { + unreachable!("should be expanded already") + } + } + } +} + +impl Encode for Start<'_> { + fn encode(&self, e: &mut Vec) { + self.func.encode(e); + self.args.encode(e); + } +} + +impl Encode for Alias<'_> { + fn encode(&self, e: &mut Vec) { + match self.target { + AliasTarget::Export { instance, export } => { + match self.kind { + AliasKind::Module => { + e.push(0x00); + e.push(0x00); + } + AliasKind::Component => { + e.push(0x00); + e.push(0x01); + } + AliasKind::Instance => { + e.push(0x00); + e.push(0x02); + } + AliasKind::Value => { + e.push(0x00); + e.push(0x04); + } + AliasKind::ExportKind(export_kind) => { + e.push(0x01); + export_kind.encode(e); + } + } + instance.encode(e); + export.encode(e); + } + AliasTarget::Outer { outer, index } => { + e.push(0x02); + match self.kind { + AliasKind::Module => e.push(0x00), + AliasKind::Component => e.push(0x01), + AliasKind::ExportKind(core::ExportKind::Type) => e.push(0x05), + // FIXME(#590): this feels a bit odd but it's also weird to + // make this an explicit error somewhere else. Should + // revisit this when the encodings of aliases and such have + // all settled down. Hopefully #590 and + // WebAssembly/component-model#29 will help solve this. + _ => e.push(0xff), + } + outer.encode(e); + index.encode(e); + } + } + } +} + +impl Encode for CanonLower<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0x01); + self.opts.encode(e); + self.func.encode(e); + } +} + +impl Encode for CanonLift<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0x00); + self.type_.encode(e); + self.opts.encode(e); + self.func.encode(e); + } +} + +impl Encode for CanonOpt<'_> { + fn encode(&self, e: &mut Vec) { + match self { + CanonOpt::StringUtf8 => e.push(0x00), + CanonOpt::StringUtf16 => e.push(0x01), + CanonOpt::StringLatin1Utf16 => e.push(0x02), + CanonOpt::Into(index) => { + e.push(0x03); + index.encode(e); + } + } + } +} + +impl Encode for ModuleType<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0x4f); + self.defs.encode(e); + } +} + +impl Encode for ModuleTypeDef<'_> { + fn encode(&self, e: &mut Vec) { + match self { + ModuleTypeDef::Type(f) => { + e.push(0x01); + f.encode(e); + } + ModuleTypeDef::Import(i) => { + e.push(0x02); + i.encode(e); + } + ModuleTypeDef::Export(name, x) => { + e.push(0x07); + name.encode(e); + x.encode(e); + } + } + } +} + +impl Encode for ComponentType<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0x4e); + self.fields.encode(e); + } +} + +impl Encode for ComponentTypeField<'_> { + fn encode(&self, e: &mut Vec) { + match self { + ComponentTypeField::Type(ty_) => { + e.push(0x01); + ty_.encode(e); + } + ComponentTypeField::Alias(alias) => { + e.push(0x09); + alias.encode(e); + } + ComponentTypeField::Export(export) => { + e.push(0x07); + export.encode(e); + } + ComponentTypeField::Import(import) => { + e.push(0x02); + import.encode(e); + } + } + } +} + +impl Encode for InstanceType<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0x4d); + self.fields.encode(e); + } +} + +impl Encode for InstanceTypeField<'_> { + fn encode(&self, e: &mut Vec) { + match self { + InstanceTypeField::Type(ty_) => { + e.push(0x01); + ty_.encode(e); + } + InstanceTypeField::Alias(alias) => { + e.push(0x09); + alias.encode(e); + } + InstanceTypeField::Export(export) => { + e.push(0x07); + export.encode(e); + } + } + } +} + +impl Encode for ComponentExportType<'_> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + self.item.encode(e); + } +} +impl Encode for TypeField<'_> { + fn encode(&self, e: &mut Vec) { + match &self.def { + ComponentTypeDef::DefType(d) => d.encode(e), + ComponentTypeDef::InterType(i) => i.encode(e), + } + } +} + +impl Encode for Primitive { + fn encode(&self, e: &mut Vec) { + match self { + Primitive::Unit => e.push(0x7f), + Primitive::Bool => e.push(0x7e), + Primitive::S8 => e.push(0x7d), + Primitive::U8 => e.push(0x7c), + Primitive::S16 => e.push(0x7b), + Primitive::U16 => e.push(0x7a), + Primitive::S32 => e.push(0x79), + Primitive::U32 => e.push(0x78), + Primitive::S64 => e.push(0x77), + Primitive::U64 => e.push(0x76), + Primitive::Float32 => e.push(0x75), + Primitive::Float64 => e.push(0x74), + Primitive::Char => e.push(0x73), + Primitive::String => e.push(0x72), + } + } +} + +impl<'a> Encode for InterType<'a> { + fn encode(&self, e: &mut Vec) { + match self { + InterType::Primitive(p) => p.encode(e), + InterType::Record(r) => r.encode(e), + InterType::Variant(v) => v.encode(e), + InterType::List(l) => l.encode(e), + InterType::Tuple(t) => t.encode(e), + InterType::Flags(f) => f.encode(e), + InterType::Enum(n) => n.encode(e), + InterType::Union(u) => u.encode(e), + InterType::Option(o) => o.encode(e), + InterType::Expected(x) => x.encode(e), + } + } +} + +impl<'a> Encode for InterTypeRef<'a> { + fn encode(&self, e: &mut Vec) { + match self { + InterTypeRef::Primitive(p) => p.encode(e), + InterTypeRef::Ref(i) => i.encode(e), + InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), + } + } +} + +impl<'a> Encode for DefType<'a> { + fn encode(&self, e: &mut Vec) { + match self { + DefType::Func(f) => f.encode(e), + DefType::Module(m) => m.encode(e), + DefType::Component(c) => c.encode(e), + DefType::Instance(i) => i.encode(e), + DefType::Value(v) => v.encode(e), + } + } +} + +impl<'a> Encode for Record<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x71); + self.fields.encode(e); + } +} + +impl<'a> Encode for Field<'a> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + self.type_.encode(e); + } +} + +impl<'a> Encode for Variant<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x70); + self.cases.encode(e); + } +} + +impl<'a> Encode for Case<'a> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + self.type_.encode(e); + if let Some(defaults_to) = self.defaults_to { + e.push(0x01); + defaults_to.encode(e); + } else { + e.push(0x00); + } + } +} + +impl<'a> Encode for List<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6f); + self.element.encode(e); + } +} + +impl<'a> Encode for Tuple<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6e); + self.fields.encode(e); + } +} + +impl<'a> Encode for Flags<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6d); + self.flag_names.encode(e); + } +} + +impl<'a> Encode for Enum<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6c); + self.arms.encode(e); + } +} + +impl<'a> Encode for Union<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6b); + self.arms.encode(e); + } +} + +impl<'a> Encode for OptionType<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x6a); + self.element.encode(e); + } +} + +impl<'a> Encode for Expected<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x69); + self.ok.encode(e); + self.err.encode(e); + } +} + +impl<'a> Encode for ComponentFunctionType<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x4c); + self.params.encode(e); + self.result.encode(e); + } +} + +impl<'a> Encode for ComponentFunctionParam<'a> { + fn encode(&self, e: &mut Vec) { + if let Some(id) = self.name { + e.push(0x01); + id.encode(e); + } else { + e.push(0x00); + } + self.type_.encode(e); + } +} + +impl<'a> Encode for ValueType<'a> { + fn encode(&self, e: &mut Vec) { + e.push(0x4b); + self.value_type.encode(e) + } +} + +impl Encode for ComponentTypeUse<'_, T> { + fn encode(&self, e: &mut Vec) { + match self { + ComponentTypeUse::Inline(_) => unreachable!("should be expanded already"), + ComponentTypeUse::Ref(index) => index.encode(e), + } + } +} + +impl Encode for ComponentExport<'_> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + match &self.arg { + ComponentArg::Def(item_ref) => { + match item_ref.kind { + DefTypeKind::Module => e.push(0x00), + DefTypeKind::Component => e.push(0x01), + DefTypeKind::Instance => e.push(0x02), + DefTypeKind::Func => e.push(0x03), + DefTypeKind::Value => e.push(0x04), + } + item_ref.idx.encode(e); + } + ComponentArg::BundleOfExports(..) => { + unreachable!("should be expanded already") + } + } + } +} + +impl Encode for ComponentFunc<'_> { + fn encode(&self, e: &mut Vec) { + match &self.kind { + ComponentFuncKind::Import { .. } => unreachable!("should be expanded by now"), + ComponentFuncKind::Inline { body } => { + body.encode(e); + } + } + } +} + +impl Encode for ComponentFuncBody<'_> { + fn encode(&self, e: &mut Vec) { + match self { + ComponentFuncBody::CanonLift(lift) => lift.encode(e), + ComponentFuncBody::CanonLower(lower) => lower.encode(e), + } + } +} + +impl Encode for ComponentImport<'_> { + fn encode(&self, e: &mut Vec) { + self.name.encode(e); + self.item.encode(e); + } +} + +impl Encode for ItemSig<'_> { + fn encode(&self, e: &mut Vec) { + match &self.kind { + ItemKind::Component(t) => t.encode(e), + ItemKind::Module(t) => t.encode(e), + ItemKind::Func(t) => t.encode(e), + ItemKind::Instance(t) => t.encode(e), + ItemKind::Value(t) => t.encode(e), + } + } +} + +impl Encode for ItemRef<'_, K> { + fn encode(&self, dst: &mut Vec) { + assert!(self.export_names.is_empty()); + self.idx.encode(dst); + } +} + +impl Encode for CoreExport<'_> { + fn encode(&self, dst: &mut Vec) { + self.name.encode(dst); + self.index.kind.encode(dst); + self.index.encode(dst); + } +} diff --git a/third_party/rust/wast/src/component/component.rs b/third_party/rust/wast/src/component/component.rs new file mode 100644 index 000000000000..1ba469a884f0 --- /dev/null +++ b/third_party/rust/wast/src/component/component.rs @@ -0,0 +1,302 @@ +use crate::component::*; +use crate::core; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; + +/// A parsed WebAssembly component module. +#[derive(Debug)] +pub struct Component<'a> { + /// Where this `component` was defined + pub span: Span, + /// An optional identifier this component is known by + pub id: Option>, + /// An optional `@name` annotation for this component + pub name: Option>, + /// What kind of component this was parsed as. + pub kind: ComponentKind<'a>, +} + +/// The different kinds of ways to define a component. +#[derive(Debug)] +pub enum ComponentKind<'a> { + /// A component defined in the textual s-expression format. + Text(Vec>), + /// A component that had its raw binary bytes defined via the `binary` + /// directive. + Binary(Vec<&'a [u8]>), +} + +impl<'a> Component<'a> { + /// Performs a name resolution pass on this [`Component`], resolving all + /// symbolic names to indices. + /// + /// The WAT format contains a number of shorthands to make it easier to + /// write, such as inline exports, inline imports, inline type definitions, + /// etc. Additionally it allows using symbolic names such as `$foo` instead + /// of using indices. This module will postprocess an AST to remove all of + /// this syntactic sugar, preparing the AST for binary emission. This is + /// where expansion and name resolution happens. + /// + /// This function will mutate the AST of this [`Component`] and replace all + /// [`Index`](crate::token::Index) arguments with `Index::Num`. This will + /// also expand inline exports/imports listed on fields and handle various + /// other shorthands of the text format. + /// + /// If successful the AST was modified to be ready for binary encoding. + /// + /// # Errors + /// + /// If an error happens during resolution, such a name resolution error or + /// items are found in the wrong order, then an error is returned. + pub fn resolve(&mut self) -> std::result::Result<(), crate::Error> { + match &mut self.kind { + ComponentKind::Text(fields) => { + crate::component::expand::expand(fields); + } + ComponentKind::Binary(_) => {} + } + crate::component::resolve::resolve(self) + } + + /// Encodes this [`Component`] to its binary form. + /// + /// This function will take the textual representation in [`Component`] and + /// perform all steps necessary to convert it to a binary WebAssembly + /// component, suitable for writing to a `*.wasm` file. This function may + /// internally modify the [`Component`], for example: + /// + /// * Name resolution is performed to ensure that `Index::Id` isn't present + /// anywhere in the AST. + /// + /// * Inline shorthands such as imports/exports/types are all expanded to be + /// dedicated fields of the component. + /// + /// * Component fields may be shuffled around to preserve index ordering from + /// expansions. + /// + /// After all of this expansion has happened the component will be converted to + /// its binary form and returned as a `Vec`. This is then suitable to + /// hand off to other wasm runtimes and such. + /// + /// # Errors + /// + /// This function can return an error for name resolution errors and other + /// expansion-related errors. + pub fn encode(&mut self) -> std::result::Result, crate::Error> { + self.resolve()?; + Ok(crate::component::binary::encode(self)) + } + + pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> { + let mut starts = 0; + if let ComponentKind::Text(fields) = &self.kind { + for item in fields.iter() { + if let ComponentField::Start(_) = item { + starts += 1; + } + } + } + if starts > 1 { + return Err(parser.error("multiple start sections found")); + } + Ok(()) + } +} + +impl<'a> Parse<'a> for Component<'a> { + fn parse(parser: Parser<'a>) -> Result { + let _r = parser.register_annotation("custom"); + + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + + let kind = if parser.peek::() { + parser.parse::()?; + let mut data = Vec::new(); + while !parser.is_empty() { + data.push(parser.parse()?); + } + ComponentKind::Binary(data) + } else { + ComponentKind::Text(ComponentField::parse_remaining(parser)?) + }; + Ok(Component { + span, + id, + name, + kind, + }) + } +} + +/// A listing of all possible fields that can make up a WebAssembly component. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum ComponentField<'a> { + Type(TypeField<'a>), + Import(ComponentImport<'a>), + Func(ComponentFunc<'a>), + Export(ComponentExport<'a>), + Start(Start<'a>), + Instance(Instance<'a>), + Module(Module<'a>), + Component(NestedComponent<'a>), + Alias(Alias<'a>), +} + +impl<'a> ComponentField<'a> { + fn parse_remaining(parser: Parser<'a>) -> Result> { + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parens(ComponentField::parse)?); + } + Ok(fields) + } +} + +impl<'a> Parse<'a> for ComponentField<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + return Ok(ComponentField::Type(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Import(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Func(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Export(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Start(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Instance(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Module(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Component(parser.parse()?)); + } + if parser.peek::() { + return Ok(ComponentField::Alias(parser.parse()?)); + } + Err(parser.error("expected valid component field")) + } +} + +impl<'a> From> for ComponentField<'a> { + fn from(field: TypeField<'a>) -> ComponentField<'a> { + ComponentField::Type(field) + } +} + +impl<'a> From> for ComponentField<'a> { + fn from(field: Alias<'a>) -> ComponentField<'a> { + ComponentField::Alias(field) + } +} + +/// A function to call at instantiation time. +#[derive(Debug)] +pub struct Start<'a> { + /// The function to call. + pub func: ItemRef<'a, kw::func>, + /// The arguments to pass to the function. + pub args: Vec>, + /// Name of the result value. + pub result: Option>, +} + +impl<'a> Parse<'a> for Start<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let func = parser.parse::>()?.0; + let mut args = Vec::new(); + while !parser.is_empty() && !parser.peek2::() { + args.push(parser.parse()?); + } + let result = if !parser.is_empty() { + parser.parens(|parser| { + parser.parse::()?; + if !parser.is_empty() { + parser.parens(|parser| { + parser.parse::()?; + let id = parser.parse()?; + Ok(Some(id)) + }) + } else { + Ok(None) + } + })? + } else { + None + }; + Ok(Start { func, args, result }) + } +} + +/// A parsed WebAssembly component module. +#[derive(Debug)] +pub struct NestedComponent<'a> { + /// Where this `component` was defined + pub span: Span, + /// An optional identifier this component is known by + pub id: Option>, + /// An optional `@name` annotation for this component + pub name: Option>, + /// If present, inline export annotations which indicate names this + /// definition should be exported under. + pub exports: core::InlineExport<'a>, + /// What kind of component this was parsed as. + pub kind: NestedComponentKind<'a>, +} + +/// The different kinds of ways to define a nested component. +#[derive(Debug)] +pub enum NestedComponentKind<'a> { + /// This is actually an inline import of a component + Import { + /// The information about where this is being imported from. + import: InlineImport<'a>, + /// The type of component being imported. + ty: ComponentTypeUse<'a, ComponentType<'a>>, + }, + /// The component is defined inline as a local definition with its fields + /// listed here. + Inline(Vec>), +} + +impl<'a> Parse<'a> for NestedComponent<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let exports = parser.parse()?; + + let kind = if let Some(import) = parser.parse()? { + NestedComponentKind::Import { + import, + ty: parser.parse()?, + } + } else { + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parens(|p| p.parse())?); + } + NestedComponentKind::Inline(fields) + }; + + Ok(NestedComponent { + span, + id, + name, + exports, + kind, + }) + } +} diff --git a/third_party/rust/wast/src/component/deftype.rs b/third_party/rust/wast/src/component/deftype.rs new file mode 100644 index 000000000000..0aaf8e334779 --- /dev/null +++ b/third_party/rust/wast/src/component/deftype.rs @@ -0,0 +1,330 @@ +//! The `deftype` production in the component-model AST, and its children. + +use crate::component::*; +use crate::core; +use crate::kw; +use crate::parser::{Cursor, Parse, Parser, Peek, Result}; + +/// Different kinds of elements that can be exported from a WebAssembly component, +/// contained in a [`ComponentExport`]. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +#[allow(missing_docs)] +pub enum DefTypeKind { + Func, + Module, + Component, + Instance, + Value, +} + +impl<'a> Parse<'a> for DefTypeKind { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(DefTypeKind::Func) + } else if l.peek::() { + parser.parse::()?; + Ok(DefTypeKind::Module) + } else if l.peek::() { + parser.parse::()?; + Ok(DefTypeKind::Component) + } else if l.peek::() { + parser.parse::()?; + Ok(DefTypeKind::Instance) + } else if l.peek::() { + parser.parse::()?; + Ok(DefTypeKind::Value) + } else { + Err(l.error()) + } + } +} + +impl Peek for DefTypeKind { + fn peek(cursor: Cursor<'_>) -> bool { + kw::func::peek(cursor) + || kw::module::peek(cursor) + || kw::component::peek(cursor) + || kw::instance::peek(cursor) + || kw::value::peek(cursor) + } + fn display() -> &'static str { + "deftype kind" + } +} + +/// deftype ::= +/// | +/// | +/// | +/// | +#[derive(Debug)] +#[allow(missing_docs)] +pub enum DefType<'a> { + Func(ComponentFunctionType<'a>), + Module(ModuleType<'a>), + Component(ComponentType<'a>), + Instance(InstanceType<'a>), + Value(ValueType<'a>), +} + +impl<'a> Parse<'a> for DefType<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + parser.parse::()?; + Ok(DefType::Func(parser.parse()?)) + } else if parser.peek::() { + parser.parse::()?; + Ok(DefType::Module(parser.parse()?)) + } else if parser.peek::() { + parser.parse::()?; + Ok(DefType::Component(parser.parse()?)) + } else if parser.peek::() { + parser.parse::()?; + Ok(DefType::Instance(parser.parse()?)) + } else if parser.peek::() { + parser.parse::()?; + Ok(DefType::Value(parser.parse()?)) + } else { + Err(parser.error("expected a deftype")) + } + } +} + +/// A component function type with parameters and results. +/// +/// functype ::= (func ? (param ? )* (result )?) +#[derive(Debug)] +pub struct ComponentFunctionType<'a> { + /// The parameters of a function, optionally each having an identifier for + /// name resolution and a name for the custom `name` section. + pub params: Box<[ComponentFunctionParam<'a>]>, + /// The result type of a function. + pub result: InterTypeRef<'a>, +} + +impl<'a> Parse<'a> for ComponentFunctionType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut params = Vec::new(); + while parser.peek2::() { + parser.parens(|p| { + p.parse::()?; + params.push(ComponentFunctionParam { + name: p.parse()?, + type_: p.parse()?, + }); + Ok(()) + })?; + } + let result = if parser.peek2::() { + // Parse a `(result ...)`. + parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })? + } else { + // If the result is omitted, use `unit`. + InterTypeRef::Primitive(Primitive::Unit) + }; + Ok(Self { + params: params.into(), + result, + }) + } +} + +/// A parameter of a [`ComponentFunctionType`]. +#[derive(Clone, Debug)] +pub struct ComponentFunctionParam<'a> { + /// An optionally-specified name of this parameter + pub name: Option<&'a str>, + /// The type of the parameter. + pub type_: InterTypeRef<'a>, +} + +/// A type for a nested module +#[derive(Debug)] +pub struct ModuleType<'a> { + /// The fields of the module type. + pub defs: Vec>, +} + +impl<'a> Parse<'a> for ModuleType<'a> { + fn parse(parser: Parser<'a>) -> Result { + // See comments in `nested_module.rs` for why this is tested here. + if parser.parens_depth() > 100 { + return Err(parser.error("module type nesting too deep")); + } + + let mut defs = Vec::new(); + while !parser.is_empty() { + defs.push(parser.parens(|p| p.parse())?); + } + Ok(ModuleType { defs }) + } +} + +/// The contents of a [`ModuleType`]. +#[derive(Debug)] +pub enum ModuleTypeDef<'a> { + /// A function type. + Type(core::Type<'a>), + /// An import. + Import(core::Import<'a>), + /// An export. + Export(&'a str, core::ItemSig<'a>), +} + +impl<'a> Parse<'a> for ModuleTypeDef<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(ModuleTypeDef::Type(parser.parse()?)) + } else if l.peek::() { + Ok(ModuleTypeDef::Import(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + let name = parser.parse()?; + let et = parser.parens(|parser| parser.parse())?; + Ok(ModuleTypeDef::Export(name, et)) + } else { + Err(parser.error("Expected a moduletype-def")) + } + } +} + +/// A type for a nested component +#[derive(Debug, Default)] +pub struct ComponentType<'a> { + /// The fields of this `ComponentType`. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for ComponentType<'a> { + fn parse(parser: Parser<'a>) -> Result { + // See comments in `nested_module.rs` for why this is tested here. + if parser.parens_depth() > 100 { + return Err(parser.error("component type nesting too deep")); + } + + let mut fields = Vec::new(); + while !parser.is_empty() { + parser.parens(|parser| { + if parser.peek::() { + fields.push(ComponentTypeField::Import(parser.parse()?)); + } else if parser.peek::() { + fields.push(ComponentTypeField::Export(parser.parse()?)); + } else if parser.peek::() { + fields.push(ComponentTypeField::Type(parser.parse()?)); + } else if parser.peek::() { + fields.push(ComponentTypeField::Alias(parser.parse()?)); + } + Ok(()) + })?; + } + Ok(ComponentType { fields }) + } +} + +/// A field of a type for a nested component +#[derive(Debug)] +pub enum ComponentTypeField<'a> { + /// A public type for this component. + Type(TypeField<'a>), + + /// A public type relationships for this component. + Alias(Alias<'a>), + + /// An import expected for this component type. + Import(ComponentImport<'a>), + + /// An export this component type is expected to have. + Export(ComponentExportType<'a>), +} + +impl<'a> From> for ComponentTypeField<'a> { + fn from(field: TypeField<'a>) -> ComponentTypeField<'a> { + ComponentTypeField::Type(field) + } +} + +impl<'a> From> for ComponentTypeField<'a> { + fn from(field: Alias<'a>) -> ComponentTypeField<'a> { + ComponentTypeField::Alias(field) + } +} + +/// A type for a nested instance +#[derive(Debug)] +pub struct InstanceType<'a> { + /// The fields of this `InstanceType`. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for InstanceType<'a> { + fn parse(parser: Parser<'a>) -> Result { + // See comments in `nested_module.rs` for why this is tested here. + if parser.parens_depth() > 100 { + return Err(parser.error("instance type nesting too deep")); + } + + let mut fields = Vec::new(); + while !parser.is_empty() { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + fields.push(InstanceTypeField::Export(parser.parse()?)); + } else if l.peek::() { + fields.push(InstanceTypeField::Type(parser.parse()?)); + } else if l.peek::() { + fields.push(InstanceTypeField::Alias(parser.parse()?)); + } else { + return Err(l.error()); + } + Ok(()) + })?; + } + Ok(InstanceType { fields }) + } +} + +/// A field of a type for a nested instance +#[derive(Debug)] +pub enum InstanceTypeField<'a> { + /// A public type for this component. + Type(TypeField<'a>), + + /// A public type relationships for this component. + Alias(Alias<'a>), + + /// An export this component type is expected to have. + Export(ComponentExportType<'a>), +} + +impl<'a> From> for InstanceTypeField<'a> { + fn from(field: TypeField<'a>) -> InstanceTypeField<'a> { + InstanceTypeField::Type(field) + } +} + +impl<'a> From> for InstanceTypeField<'a> { + fn from(field: Alias<'a>) -> InstanceTypeField<'a> { + InstanceTypeField::Alias(field) + } +} + +/// A value type. +#[derive(Debug, Clone)] +pub struct ValueType<'a> { + /// The type of the value. + pub value_type: InterTypeRef<'a>, +} + +impl<'a> Parse<'a> for ValueType<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(ValueType { + value_type: parser.parse()?, + }) + } +} diff --git a/third_party/rust/wast/src/component/expand.rs b/third_party/rust/wast/src/component/expand.rs new file mode 100644 index 000000000000..8a01dd28d095 --- /dev/null +++ b/third_party/rust/wast/src/component/expand.rs @@ -0,0 +1,642 @@ +use crate::component::*; +use crate::core; +use crate::gensym; +use crate::kw; +use crate::token::{Id, Index, Span}; +use std::collections::HashMap; +use std::mem; + +/// Performs an AST "expansion" pass over the component fields provided. +/// +/// This expansion is intended to desugar the AST from various parsed constructs +/// to bits and bobs amenable for name resolution as well as binary encoding. +/// For example `(import "" (func))` is split into a type definition followed by +/// the import referencing that type definition. +/// +/// Most forms of AST expansion happen in this file and afterwards the AST will +/// be handed to the name resolution pass which will convert `Index::Id` to +/// `Index::Num` wherever it's found. +pub fn expand(fields: &mut Vec>) { + Expander::default().expand_component_fields(fields) +} + +#[derive(Default)] +struct Expander<'a> { + /// Fields, during processing, which should be prepended to the + /// currently-being-processed field. This should always be empty after + /// processing is complete. + to_prepend: Vec>, + component_fields_to_prepend: Vec>, + + /// Fields that are appended to the end of the module once everything has + /// finished. + component_fields_to_append: Vec>, +} + +impl<'a> Expander<'a> { + fn expand_component_fields(&mut self, fields: &mut Vec>) { + let mut cur = 0; + while cur < fields.len() { + self.expand_field(&mut fields[cur]); + let amt = self.to_prepend.len() + self.component_fields_to_prepend.len(); + fields.splice(cur..cur, self.component_fields_to_prepend.drain(..)); + fields.splice(cur..cur, self.to_prepend.drain(..).map(|f| f.into())); + cur += 1 + amt; + } + fields.extend(self.component_fields_to_append.drain(..)); + } + + fn expand_fields(&mut self, fields: &mut Vec, expand: fn(&mut Self, &mut T)) + where + T: From>, + { + let mut cur = 0; + while cur < fields.len() { + expand(self, &mut fields[cur]); + assert!(self.component_fields_to_prepend.is_empty()); + assert!(self.component_fields_to_append.is_empty()); + let amt = self.to_prepend.len(); + fields.splice(cur..cur, self.to_prepend.drain(..).map(T::from)); + cur += 1 + amt; + } + } + + fn expand_field(&mut self, item: &mut ComponentField<'a>) { + match item { + ComponentField::Type(t) => self.expand_type_field(t), + ComponentField::Import(t) => { + self.expand_item_sig(&mut t.item); + } + ComponentField::Component(c) => { + for name in c.exports.names.drain(..) { + self.component_fields_to_append.push(export( + c.span, + name, + DefTypeKind::Component, + &mut c.id, + )); + } + match &mut c.kind { + NestedComponentKind::Inline(fields) => expand(fields), + NestedComponentKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + *item = ComponentField::Import(ComponentImport { + span: c.span, + name: import.name, + item: ItemSig { + span: c.span, + id: c.id, + name: None, + kind: ItemKind::Component(ComponentTypeUse::Ref(idx)), + }, + }); + } + } + } + + ComponentField::Func(f) => { + for name in f.exports.names.drain(..) { + self.component_fields_to_append.push(export( + f.span, + name, + DefTypeKind::Func, + &mut f.id, + )); + } + match &mut f.kind { + ComponentFuncKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + *item = ComponentField::Import(ComponentImport { + span: f.span, + name: import.name, + item: ItemSig { + span: f.span, + id: f.id, + name: None, + kind: ItemKind::Func(ComponentTypeUse::Ref(idx)), + }, + }); + } + ComponentFuncKind::Inline { body } => match body { + ComponentFuncBody::CanonLift(lift) => { + self.expand_component_type_use(&mut lift.type_); + } + ComponentFuncBody::CanonLower(_) => {} + }, + } + } + + ComponentField::Module(m) => { + for name in m.exports.names.drain(..) { + self.component_fields_to_append.push(export( + m.span, + name, + DefTypeKind::Module, + &mut m.id, + )); + } + match &mut m.kind { + // inline modules are expanded later during resolution + ModuleKind::Inline { .. } => {} + ModuleKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + *item = ComponentField::Import(ComponentImport { + span: m.span, + name: import.name, + item: ItemSig { + span: m.span, + id: m.id, + name: None, + kind: ItemKind::Module(ComponentTypeUse::Ref(idx)), + }, + }); + } + } + } + + ComponentField::Instance(i) => { + for name in i.exports.names.drain(..) { + self.component_fields_to_append.push(export( + i.span, + name, + DefTypeKind::Instance, + &mut i.id, + )); + } + match &mut i.kind { + InstanceKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + *item = ComponentField::Import(ComponentImport { + span: i.span, + name: import.name, + item: ItemSig { + span: i.span, + id: i.id, + name: None, + kind: ItemKind::Instance(ComponentTypeUse::Ref(idx)), + }, + }); + } + InstanceKind::Module { args, .. } => { + for arg in args { + self.expand_module_arg(&mut arg.arg); + } + } + InstanceKind::Component { args, .. } => { + for arg in args { + self.expand_component_arg(&mut arg.arg); + } + } + InstanceKind::BundleOfExports { .. } + | InstanceKind::BundleOfComponentExports { .. } => {} + } + } + + ComponentField::Export(e) => { + self.expand_component_arg(&mut e.arg); + } + + ComponentField::Alias(_) | ComponentField::Start(_) => {} + } + + fn export<'a>( + span: Span, + name: &'a str, + kind: DefTypeKind, + id: &mut Option>, + ) -> ComponentField<'a> { + let id = gensym::fill(span, id); + ComponentField::Export(ComponentExport { + span, + name, + arg: ComponentArg::Def(ItemRef { + idx: Index::Id(id), + kind, + export_names: Vec::new(), + }), + }) + } + } + + fn expand_type_field(&mut self, field: &mut TypeField<'a>) { + match &mut field.def { + ComponentTypeDef::DefType(t) => self.expand_deftype(t), + ComponentTypeDef::InterType(t) => self.expand_intertype(t), + } + let name = gensym::fill(field.span, &mut field.id); + let name = Index::Id(name); + match &field.def { + ComponentTypeDef::DefType(DefType::Func(t)) => t.key().insert(self, name), + ComponentTypeDef::DefType(DefType::Module(t)) => t.key().insert(self, name), + ComponentTypeDef::DefType(DefType::Component(t)) => t.key().insert(self, name), + ComponentTypeDef::DefType(DefType::Instance(t)) => t.key().insert(self, name), + ComponentTypeDef::DefType(DefType::Value(t)) => t.key().insert(self, name), + ComponentTypeDef::InterType(t) => t.key().insert(self, name), + } + } + + fn expand_deftype(&mut self, ty: &mut DefType<'a>) { + match ty { + DefType::Func(t) => self.expand_func_ty(t), + DefType::Module(m) => self.expand_module_ty(m), + DefType::Component(c) => self.expand_component_ty(c), + DefType::Instance(i) => self.expand_instance_ty(i), + DefType::Value(v) => self.expand_value_ty(v), + } + } + + fn expand_func_ty(&mut self, ty: &mut ComponentFunctionType<'a>) { + for param in ty.params.iter_mut() { + self.expand_intertype_ref(&mut param.type_); + } + self.expand_intertype_ref(&mut ty.result); + } + + fn expand_module_ty(&mut self, ty: &mut ModuleType<'a>) { + use crate::core::resolve::types::{FuncKey, TypeKey, TypeReference}; + + // Note that this is a custom implementation from everything else in + // this file since this is using core wasm types instead of component + // types, so a small part of the core wasm expansion process is + // inlined here to handle the `TypeUse` from core wasm. + + let mut func_type_to_idx = HashMap::new(); + let mut to_prepend = Vec::new(); + let mut i = 0; + while i < ty.defs.len() { + match &mut ty.defs[i] { + ModuleTypeDef::Type(ty) => match &ty.def { + core::TypeDef::Func(f) => { + let id = gensym::fill(ty.span, &mut ty.id); + func_type_to_idx.insert(f.key(), Index::Id(id)); + } + core::TypeDef::Struct(_) => {} + core::TypeDef::Array(_) => {} + }, + ModuleTypeDef::Import(ty) => { + expand_sig(&mut ty.item, &mut to_prepend, &mut func_type_to_idx); + } + ModuleTypeDef::Export(_, item) => { + expand_sig(item, &mut to_prepend, &mut func_type_to_idx); + } + } + ty.defs.splice(i..i, to_prepend.drain(..)); + i += 1; + } + + fn expand_sig<'a>( + item: &mut core::ItemSig<'a>, + to_prepend: &mut Vec>, + func_type_to_idx: &mut HashMap, Index<'a>>, + ) { + match &mut item.kind { + core::ItemKind::Func(t) | core::ItemKind::Tag(core::TagType::Exception(t)) => { + // If the index is already filled in then this is skipped + if t.index.is_some() { + return; + } + + // Otherwise the inline type information is used to + // generate a type into this module if necessary. If the + // function type already exists we reuse the same key, + // otherwise a fresh type definition is created and we use + // that one instead. + let ty = t.inline.take().unwrap_or_default(); + let key = ty.key(); + if let Some(idx) = func_type_to_idx.get(&key) { + t.index = Some(idx.clone()); + return; + } + let id = gensym::gen(item.span); + to_prepend.push(ModuleTypeDef::Type(core::Type { + span: item.span, + id: Some(id), + name: None, + def: key.to_def(item.span), + })); + let idx = Index::Id(id); + t.index = Some(idx); + } + core::ItemKind::Global(_) + | core::ItemKind::Table(_) + | core::ItemKind::Memory(_) => {} + } + } + } + + fn expand_component_ty(&mut self, ty: &mut ComponentType<'a>) { + Expander::default().expand_fields(&mut ty.fields, |e, field| match field { + ComponentTypeField::Type(t) => e.expand_type_field(t), + ComponentTypeField::Alias(_) => {} + ComponentTypeField::Export(t) => e.expand_item_sig(&mut t.item), + ComponentTypeField::Import(t) => e.expand_item_sig(&mut t.item), + }) + } + + fn expand_instance_ty(&mut self, ty: &mut InstanceType<'a>) { + Expander::default().expand_fields(&mut ty.fields, |e, field| match field { + InstanceTypeField::Type(t) => e.expand_type_field(t), + InstanceTypeField::Alias(_) => {} + InstanceTypeField::Export(t) => e.expand_item_sig(&mut t.item), + }) + } + + fn expand_item_sig(&mut self, sig: &mut ItemSig<'a>) { + match &mut sig.kind { + ItemKind::Component(t) => self.expand_component_type_use(t), + ItemKind::Module(t) => self.expand_component_type_use(t), + ItemKind::Instance(t) => self.expand_component_type_use(t), + ItemKind::Value(t) => self.expand_component_type_use(t), + ItemKind::Func(t) => self.expand_component_type_use(t), + }; + } + + fn expand_value_ty(&mut self, ty: &mut ValueType<'a>) { + self.expand_intertype_ref(&mut ty.value_type); + } + + fn expand_intertype(&mut self, ty: &mut InterType<'a>) { + match ty { + InterType::Primitive(_) | InterType::Flags(_) | InterType::Enum(_) => {} + InterType::Record(r) => { + for field in r.fields.iter_mut() { + self.expand_intertype_ref(&mut field.type_); + } + } + InterType::Variant(v) => { + for case in v.cases.iter_mut() { + self.expand_intertype_ref(&mut case.type_); + } + } + InterType::List(t) => { + self.expand_intertype_ref(&mut t.element); + } + InterType::Tuple(t) => { + for field in t.fields.iter_mut() { + self.expand_intertype_ref(field); + } + } + InterType::Union(u) => { + for arm in u.arms.iter_mut() { + self.expand_intertype_ref(arm); + } + } + InterType::Option(t) => { + self.expand_intertype_ref(&mut t.element); + } + InterType::Expected(e) => { + self.expand_intertype_ref(&mut e.ok); + self.expand_intertype_ref(&mut e.err); + } + } + } + + fn expand_intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) { + let inline = match ty { + InterTypeRef::Primitive(_) | InterTypeRef::Ref(_) => return, + InterTypeRef::Inline(inline) => { + mem::replace(inline, InterType::Primitive(Primitive::Unit)) + } + }; + // If this inline type has already been defined within this context + // then reuse the previously defined type to avoid injecting too many + // types into the type index space. + if let Some(idx) = inline.key().lookup(self) { + *ty = InterTypeRef::Ref(idx); + return; + } + // And if this type isn't already defined we append it to the index + // space with a fresh and unique name. + let span = Span::from_offset(0); // FIXME(#613): don't manufacture + let id = gensym::gen(span); + self.to_prepend.push(TypeField { + span, + id: Some(id), + name: None, + def: inline.into_def(), + }); + let idx = Index::Id(id); + *ty = InterTypeRef::Ref(idx); + } + + fn expand_component_type_use( + &mut self, + item: &mut ComponentTypeUse<'a, T>, + ) -> ItemRef<'a, kw::r#type> + where + T: TypeReference<'a>, + { + let span = Span::from_offset(0); // FIXME(#613): don't manufacture + let dummy = ComponentTypeUse::Ref(ItemRef { + idx: Index::Num(0, span), + kind: kw::r#type(span), + export_names: Vec::new(), + }); + let mut inline = match mem::replace(item, dummy) { + // If this type-use was already a reference to an existing type + // then we put it back the way it was and return the corresponding + // index. + ComponentTypeUse::Ref(idx) => { + *item = ComponentTypeUse::Ref(idx.clone()); + return idx; + } + + // ... otherwise with an inline type definition we go into + // processing below. + ComponentTypeUse::Inline(inline) => inline, + }; + inline.expand(self); + + // If this inline type has already been defined within this context + // then reuse the previously defined type to avoid injecting too many + // types into the type index space. + if let Some(idx) = inline.key().lookup(self) { + let ret = ItemRef { + idx, + kind: kw::r#type(span), + export_names: Vec::new(), + }; + *item = ComponentTypeUse::Ref(ret.clone()); + return ret; + } + + // And if this type isn't already defined we append it to the index + // space with a fresh and unique name. + let id = gensym::gen(span); + self.to_prepend.push(TypeField { + span, + id: Some(id), + name: None, + def: inline.into_def(), + }); + let idx = Index::Id(id); + let ret = ItemRef { + idx, + kind: kw::r#type(span), + export_names: Vec::new(), + }; + *item = ComponentTypeUse::Ref(ret.clone()); + return ret; + } + + fn expand_module_arg(&mut self, arg: &mut ModuleArg<'a>) { + let (span, args) = match arg { + ModuleArg::Def(_) => return, + ModuleArg::BundleOfExports(span, exports) => (*span, mem::take(exports)), + }; + let id = gensym::gen(span); + self.component_fields_to_prepend + .push(ComponentField::Instance(Instance { + span, + id: Some(id), + name: None, + exports: Default::default(), + kind: InstanceKind::BundleOfExports { args }, + })); + *arg = ModuleArg::Def(ItemRef { + idx: Index::Id(id), + kind: kw::instance(span), + export_names: Vec::new(), + }); + } + + fn expand_component_arg(&mut self, arg: &mut ComponentArg<'a>) { + let (span, args) = match arg { + ComponentArg::Def(_) => return, + ComponentArg::BundleOfExports(span, exports) => (*span, mem::take(exports)), + }; + let id = gensym::gen(span); + self.component_fields_to_prepend + .push(ComponentField::Instance(Instance { + span, + id: Some(id), + name: None, + exports: Default::default(), + kind: InstanceKind::BundleOfComponentExports { args }, + })); + *arg = ComponentArg::Def(ItemRef { + idx: Index::Id(id), + kind: DefTypeKind::Instance, + export_names: Vec::new(), + }); + } +} + +trait TypeReference<'a> { + type Key: TypeKey<'a>; + fn key(&self) -> Self::Key; + fn expand(&mut self, cx: &mut Expander<'a>); + fn into_def(self) -> ComponentTypeDef<'a>; +} + +impl<'a> TypeReference<'a> for InterType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_intertype(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::InterType(self) + } +} + +impl<'a> TypeReference<'a> for ComponentType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_component_ty(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::DefType(DefType::Component(self)) + } +} + +impl<'a> TypeReference<'a> for ModuleType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_module_ty(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::DefType(DefType::Module(self)) + } +} + +impl<'a> TypeReference<'a> for InstanceType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_instance_ty(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::DefType(DefType::Instance(self)) + } +} + +impl<'a> TypeReference<'a> for ComponentFunctionType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_func_ty(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::DefType(DefType::Func(self)) + } +} + +impl<'a> TypeReference<'a> for ValueType<'a> { + type Key = Todo; // FIXME(#598): should implement this + + fn key(&self) -> Self::Key { + Todo + } + + fn expand(&mut self, cx: &mut Expander<'a>) { + cx.expand_value_ty(self) + } + + fn into_def(self) -> ComponentTypeDef<'a> { + ComponentTypeDef::DefType(DefType::Value(self)) + } +} + +trait TypeKey<'a> { + fn lookup(&self, cx: &Expander<'a>) -> Option>; + fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>); +} + +struct Todo; + +impl<'a> TypeKey<'a> for Todo { + fn lookup(&self, _cx: &Expander<'a>) -> Option> { + None + } + fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>) { + drop((cx, id)); + } +} diff --git a/third_party/rust/wast/src/component/export.rs b/third_party/rust/wast/src/component/export.rs new file mode 100644 index 000000000000..0539c41221b9 --- /dev/null +++ b/third_party/rust/wast/src/component/export.rs @@ -0,0 +1,26 @@ +use crate::component::ComponentArg; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::Span; + +/// A entry in a WebAssembly component's export section. +/// +/// export ::= (export ) +#[derive(Debug)] +pub struct ComponentExport<'a> { + /// Where this export was defined. + pub span: Span, + /// The name of this export from the component. + pub name: &'a str, + /// What's being exported from the component. + pub arg: ComponentArg<'a>, +} + +impl<'a> Parse<'a> for ComponentExport<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let arg = parser.parse()?; + Ok(ComponentExport { span, name, arg }) + } +} diff --git a/third_party/rust/wast/src/component/func.rs b/third_party/rust/wast/src/component/func.rs new file mode 100644 index 000000000000..0a675db08af6 --- /dev/null +++ b/third_party/rust/wast/src/component/func.rs @@ -0,0 +1,197 @@ +use crate::component::*; +use crate::core; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, LParen, NameAnnotation, Span}; + +/// A WebAssembly function to be inserted into a module. +/// +/// This is a member of both the function and code sections. +#[derive(Debug)] +pub struct ComponentFunc<'a> { + /// Where this `func` was defined. + pub span: Span, + /// An identifier that this function is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this function stored in the custom `name` section. + pub name: Option>, + /// If present, inline export annotations which indicate names this + /// definition should be exported under. + pub exports: core::InlineExport<'a>, + /// What kind of function this is, be it an inline-defined or imported + /// function. + pub kind: ComponentFuncKind<'a>, +} + +/// Possible ways to define a function in the text format. +#[derive(Debug)] +pub enum ComponentFuncKind<'a> { + /// A function which is actually defined as an import, such as: + /// + /// ```text + /// (func (import "foo") (type 3)) + /// ``` + Import { + /// The import name of this import + import: InlineImport<'a>, + /// The type that this function will have. + ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, + }, + + /// Almost all functions, those defined inline in a wasm module. + Inline { + /// The body of the function. + body: ComponentFuncBody<'a>, + }, +} + +impl<'a> Parse<'a> for ComponentFunc<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let exports = parser.parse()?; + + let kind = if let Some(import) = parser.parse()? { + ComponentFuncKind::Import { + import, + ty: parser.parse()?, + } + } else { + ComponentFuncKind::Inline { + body: parser.parens(|p| p.parse())?, + } + }; + + Ok(ComponentFunc { + span, + id, + name, + exports, + kind, + }) + } +} + +/// The body of a `ComponentFunc`. +#[derive(Debug)] +pub enum ComponentFuncBody<'a> { + /// A `canon.lift`. + CanonLift(CanonLift<'a>), + /// A `canon.lower`. + CanonLower(CanonLower<'a>), +} + +impl<'a> Parse<'a> for ComponentFuncBody<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + Ok(ComponentFuncBody::CanonLift(parser.parse()?)) + } else if parser.peek::() { + Ok(ComponentFuncBody::CanonLower(parser.parse()?)) + } else { + Err(parser.error("Expected canon.lift or canon.lower")) + } + } +} + +/// Extra information associated with canon.lift instructions. +#[derive(Debug)] +pub struct CanonLift<'a> { + /// The type exported to other components + pub type_: ComponentTypeUse<'a, ComponentFunctionType<'a>>, + /// Configuration options + pub opts: Vec>, + /// The function to wrap + pub func: ItemRef<'a, kw::func>, +} + +impl<'a> Parse<'a> for CanonLift<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let type_ = if parser.peek2::() { + ComponentTypeUse::Inline(parser.parens(|p| { + p.parse::()?; + p.parse() + })?) + } else { + ComponentTypeUse::Ref(parser.parse()?) + }; + let mut opts = Vec::new(); + while !parser.peek2::() { + opts.push(parser.parse()?); + } + let func = parser.parse()?; + Ok(CanonLift { type_, opts, func }) + } +} + +/// Extra information associated with canon.lower instructions. +#[derive(Debug)] +pub struct CanonLower<'a> { + /// Configuration options + pub opts: Vec>, + /// The function being wrapped + pub func: ItemRef<'a, kw::func>, +} + +impl<'a> Parse<'a> for CanonLower<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut opts = Vec::new(); + while !parser.is_empty() && (!parser.peek::() || !parser.peek2::()) { + opts.push(parser.parse()?); + } + let func = parser.parse()?; + Ok(CanonLower { opts, func }) + } +} + +#[derive(Debug)] +/// Canonical ABI options. +pub enum CanonOpt<'a> { + /// Encode strings as UTF-8. + StringUtf8, + /// Encode strings as UTF-16. + StringUtf16, + /// Encode strings as "compact UTF-16". + StringLatin1Utf16, + /// A target instance which supplies the memory that the canonical ABI + /// should operate on as well as functions that the canonical ABI can call + /// to allocate, reallocate and free linear memory + Into(ItemRef<'a, kw::instance>), +} + +impl<'a> Parse<'a> for CanonOpt<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::StringUtf8) + } else if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::StringUtf16) + } else if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::StringLatin1Utf16) + } else if l.peek::() { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::Into(parser.parse::>()?.0)) + } else { + Err(l.error()) + } + }) + } else { + Err(l.error()) + } + } +} + +impl Default for kw::instance { + fn default() -> kw::instance { + kw::instance(Span::from_offset(0)) + } +} diff --git a/third_party/rust/wast/src/component/import.rs b/third_party/rust/wast/src/component/import.rs new file mode 100644 index 000000000000..429d68fbcf70 --- /dev/null +++ b/third_party/rust/wast/src/component/import.rs @@ -0,0 +1,121 @@ +use crate::component::*; +use crate::kw; +use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::{Id, NameAnnotation, Span}; + +/// An `import` statement and entry in a WebAssembly component. +#[derive(Debug)] +pub struct ComponentImport<'a> { + /// Where this `import` was defined + pub span: Span, + /// The name of the item to import. + pub name: &'a str, + /// The item that's being imported. + pub item: ItemSig<'a>, +} + +impl<'a> Parse<'a> for ComponentImport<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let item = parser.parens(|p| p.parse())?; + Ok(ComponentImport { span, name, item }) + } +} + +#[derive(Debug)] +#[allow(missing_docs)] +pub struct ItemSig<'a> { + /// Where this item is defined in the source. + pub span: Span, + /// An optional identifier used during name resolution to refer to this item + /// from the rest of the component. + pub id: Option>, + /// An optional name which, for functions, will be stored in the + /// custom `name` section. + pub name: Option>, + /// What kind of item this is. + pub kind: ItemKind<'a>, +} + +#[derive(Debug)] +#[allow(missing_docs)] +pub enum ItemKind<'a> { + Component(ComponentTypeUse<'a, ComponentType<'a>>), + Module(ComponentTypeUse<'a, ModuleType<'a>>), + Instance(ComponentTypeUse<'a, InstanceType<'a>>), + Value(ComponentTypeUse<'a, ValueType<'a>>), + Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>), +} + +impl<'a> Parse<'a> for ItemSig<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = + if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemKind::Component(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemKind::Module(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemKind::Instance(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemKind::Func(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemKind::Value(parser.parse()?))) + } else { + return Err(l.error()); + }; + Ok(ItemSig { + span, + id: parser.parse()?, + name: parser.parse()?, + kind: parse_kind(parser)?, + }) + } +} + +/// A listing of a inline `(import "foo")` statement. +/// +/// This is the same as `core::InlineImport` except only one string import is +/// required. +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub struct InlineImport<'a> { + pub name: &'a str, +} + +impl<'a> Parse<'a> for InlineImport<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|p| { + p.parse::()?; + Ok(InlineImport { name: p.parse()? }) + }) + } +} + +impl Peek for InlineImport<'_> { + fn peek(cursor: Cursor<'_>) -> bool { + let cursor = match cursor.lparen() { + Some(cursor) => cursor, + None => return false, + }; + let cursor = match cursor.keyword() { + Some(("import", cursor)) => cursor, + _ => return false, + }; + let cursor = match cursor.string() { + Some((_, cursor)) => cursor, + None => return false, + }; + cursor.rparen().is_some() + } + + fn display() -> &'static str { + "inline import" + } +} diff --git a/third_party/rust/wast/src/component/instance.rs b/third_party/rust/wast/src/component/instance.rs new file mode 100644 index 000000000000..63d52eb7239b --- /dev/null +++ b/third_party/rust/wast/src/component/instance.rs @@ -0,0 +1,253 @@ +use crate::component::*; +use crate::core; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, Index, LParen, NameAnnotation, Span}; + +/// A nested WebAssembly instance to be created as part of a module. +#[derive(Debug)] +pub struct Instance<'a> { + /// Where this `instance` was defined. + pub span: Span, + /// An identifier that this instance is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this function stored in the custom `name` section. + pub name: Option>, + /// If present, inline export annotations which indicate names this + /// definition should be exported under. + pub exports: core::InlineExport<'a>, + /// What kind of instance this is, be it an inline-defined or imported one. + pub kind: InstanceKind<'a>, +} + +/// Possible ways to define a instance in the text format. +#[derive(Debug)] +pub enum InstanceKind<'a> { + /// The `(instance (import "x"))` sugar syntax + Import { + /// The name of the import + import: InlineImport<'a>, + /// The type of the instance being imported + ty: ComponentTypeUse<'a, InstanceType<'a>>, + }, + + /// Instantiate a core module. + Module { + /// Module that we're instantiating + module: ItemRef<'a, kw::module>, + /// Arguments used to instantiate the instance + args: Vec>, + }, + + /// Instantiate a component. + Component { + /// Component that we're instantiating + component: ItemRef<'a, kw::component>, + /// Arguments used to instantiate the instance + args: Vec>, + }, + + /// A bundle of module exports which isn't an instance, but can be used + /// in places that need an instance. + BundleOfExports { + /// Arguments used to create the anonymous instance + args: Vec>, + }, + + /// A bundle of component exports which isn't an instance, but can be used + /// in places that need an instance. + BundleOfComponentExports { + /// Arguments used to create the anonymous instance + args: Vec>, + }, +} + +/// Arguments to the module `instantiate` instruction +#[derive(Debug)] +#[allow(missing_docs)] +pub struct NamedModuleArg<'a> { + pub name: &'a str, + pub arg: ModuleArg<'a>, +} + +impl<'a> Parse<'a> for NamedModuleArg<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(NamedModuleArg { + name: parser.parse()?, + arg: parser.parse()?, + }) + } +} + +/// Arguments to the component `instantiate` instruction +#[derive(Debug)] +#[allow(missing_docs)] +pub struct NamedComponentArg<'a> { + pub name: &'a str, + pub arg: ComponentArg<'a>, +} + +impl<'a> Parse<'a> for NamedComponentArg<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(NamedComponentArg { + name: parser.parse()?, + arg: parser.parse()?, + }) + } +} + +/// ```text +/// modulearg ::= (instance ) +/// | (instance *) +/// ``` +#[derive(Debug)] +pub enum ModuleArg<'a> { + /// Core modules can reference instances. + Def(ItemRef<'a, kw::instance>), + /// `instance`, but it isn't actually an instance; it's a tuple of exports + /// which can be used in place of an instance. + BundleOfExports(Span, Vec>), +} + +/// ```text +/// componentarg ::= (module ) +/// | (component ) +/// | (instance ) +/// | (func ) +/// | (value ) +/// | (instance *) +/// ``` +#[derive(Debug)] +pub enum ComponentArg<'a> { + /// A reference to an item of one of the deftype kinds. + Def(ItemRef<'a, DefTypeKind>), + /// `instance`, but it isn't actually an instance; it's a tuple of exports + /// which can be used in place of an instance. + BundleOfExports(Span, Vec>), +} + +impl<'a> Parse<'a> for Instance<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let exports = parser.parse()?; + + let kind = if let Some(import) = parser.parse()? { + InstanceKind::Import { + import, + ty: parser.parse()?, + } + } else if parser.peek::() && parser.peek2::() { + parser.parens(|p| { + p.parse::()?; + if p.peek2::() { + let module = p.parse()?; + let mut args = Vec::new(); + while !p.is_empty() { + args.push(p.parens(|p| p.parse())?); + } + Ok(InstanceKind::Module { module, args }) + } else if p.peek2::() { + let component = p.parse()?; + let mut args = Vec::new(); + while !p.is_empty() { + args.push(p.parens(|p| p.parse())?); + } + Ok(InstanceKind::Component { component, args }) + } else { + return Err(parser.error("expected module or component")); + } + })? + } else if parser.peek::() { + parser.parse::()?; + let mut args = Vec::new(); + while !parser.is_empty() { + args.push(parser.parens(|p| p.parse())?); + } + InstanceKind::BundleOfExports { args } + } else { + let mut args = Vec::new(); + while !parser.is_empty() { + args.push(parser.parens(|p| p.parse())?); + } + InstanceKind::BundleOfComponentExports { args } + }; + + Ok(Instance { + span, + id, + name, + exports, + kind, + }) + } +} + +impl<'a> Parse<'a> for ModuleArg<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() && parser.peek3::() { + // `(instance )` + let def = parser.parse::>()?; + Ok(ModuleArg::Def(def)) + } else if parser.peek::() && parser.peek2::() { + let (span, exports) = parser.parens(|p| { + let span = p.parse::()?.0; + let mut exports = Vec::new(); + while !parser.is_empty() { + exports.push(parser.parens(|parser| parser.parse())?); + } + Ok((span, exports)) + })?; + Ok(ModuleArg::BundleOfExports(span, exports)) + } else { + Err(parser.error("expected an instance")) + } + } +} + +impl<'a> Parse<'a> for ComponentArg<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() && parser.peek3::() { + // `( )` + let def = parser.parse::>()?; + Ok(ComponentArg::Def(def)) + } else if parser.peek::() && parser.peek2::() { + let (span, exports) = parser.parens(|p| { + let span = p.parse::()?.0; + let mut exports = Vec::new(); + while !p.is_empty() { + exports.push(p.parens(|p| p.parse())?); + } + Ok((span, exports)) + })?; + Ok(ComponentArg::BundleOfExports(span, exports)) + } else { + Err(parser.error("expected def type, type, or instance")) + } + } +} + +/// A entry in a WebAssembly module's export section. +#[derive(Debug)] +pub struct CoreExport<'a> { + /// Where this export was defined. + pub span: Span, + /// The name of this export from the module. + pub name: &'a str, + /// What's being exported from the module. + pub index: ItemRef<'a, core::ExportKind>, +} + +impl<'a> Parse<'a> for CoreExport<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(CoreExport { + span: parser.parse::()?.0, + name: parser.parse()?, + index: parser.parse()?, + }) + } +} diff --git a/third_party/rust/wast/src/component/intertype.rs b/third_party/rust/wast/src/component/intertype.rs new file mode 100644 index 000000000000..0798984b4f0f --- /dev/null +++ b/third_party/rust/wast/src/component/intertype.rs @@ -0,0 +1,369 @@ +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::*; + +/// An interface-types type. +#[allow(missing_docs)] +#[derive(Debug, Clone)] +pub enum Primitive { + Unit, + Bool, + S8, + U8, + S16, + U16, + S32, + U32, + S64, + U64, + Float32, + Float64, + Char, + String, +} + +impl<'a> Parse<'a> for Primitive { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Primitive::Unit) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::Bool) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::S8) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::U8) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::S16) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::U16) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::S32) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::U32) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::S64) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::U64) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::Float32) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::Float64) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::Char) + } else if l.peek::() { + parser.parse::()?; + Ok(Primitive::String) + } else { + Err(l.error()) + } + } +} + +/// An interface-types type. +#[allow(missing_docs)] +#[derive(Debug, Clone)] +pub enum InterType<'a> { + Primitive(Primitive), + Record(Record<'a>), + Variant(Variant<'a>), + List(List<'a>), + Tuple(Tuple<'a>), + Flags(Flags<'a>), + Enum(Enum<'a>), + Union(Union<'a>), + Option(OptionType<'a>), + Expected(Expected<'a>), +} + +impl<'a> Parse<'a> for InterType<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + parser.parens(|parser| { + if parser.peek::() { + let record = parser.parse()?; + Ok(InterType::Record(record)) + } else if parser.peek::() { + let variant = parser.parse()?; + Ok(InterType::Variant(variant)) + } else if parser.peek::() { + let list = parser.parse()?; + Ok(InterType::List(list)) + } else if parser.peek::() { + let tuple = parser.parse()?; + Ok(InterType::Tuple(tuple)) + } else if parser.peek::() { + let flags = parser.parse()?; + Ok(InterType::Flags(flags)) + } else if parser.peek::() { + let enum_ = parser.parse()?; + Ok(InterType::Enum(enum_)) + } else if parser.peek::() { + let union = parser.parse()?; + Ok(InterType::Union(union)) + } else if parser.peek::() { + let optional = parser.parse()?; + Ok(InterType::Option(optional)) + } else if parser.peek::() { + let expected = parser.parse()?; + Ok(InterType::Expected(expected)) + } else { + Err(parser.error("expected derived intertype")) + } + }) + } else { + Ok(InterType::Primitive(parser.parse()?)) + } + } +} + +/// An interface-types type. +#[allow(missing_docs)] +#[derive(Debug, Clone)] +pub enum InterTypeRef<'a> { + Primitive(Primitive), + Inline(InterType<'a>), + Ref(Index<'a>), +} + +impl<'a> Parse<'a> for InterTypeRef<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() { + Ok(InterTypeRef::Ref(parser.parse()?)) + } else if parser.peek::() { + Ok(InterTypeRef::Inline(parser.parse()?)) + } else { + Ok(InterTypeRef::Primitive(parser.parse()?)) + } + } +} + +/// An interface-types record, aka a struct. +#[derive(Debug, Clone)] +pub struct Record<'a> { + /// The fields of the struct. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for Record<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parens(|p| p.parse())?); + } + Ok(Record { fields }) + } +} + +/// An interface-types record field. +#[derive(Debug, Clone)] +pub struct Field<'a> { + /// The name of the field. + pub name: &'a str, + /// The type of the field. + pub type_: InterTypeRef<'a>, +} + +impl<'a> Parse<'a> for Field<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Field { + name: parser.parse()?, + type_: parser.parse()?, + }) + } +} + +/// An interface-types variant, aka a discriminated union with named arms. +#[derive(Debug, Clone)] +pub struct Variant<'a> { + /// The cases of the variant type. + pub cases: Vec>, +} + +impl<'a> Parse<'a> for Variant<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut cases = Vec::new(); + while !parser.is_empty() { + cases.push(parser.parens(|p| p.parse())?); + } + Ok(Variant { cases }) + } +} + +/// An interface-types variant case. +#[derive(Debug, Clone)] +pub struct Case<'a> { + /// The name of the case. + pub name: &'a str, + /// Where this `component` was defined + pub span: Span, + /// The type of the case. + pub type_: InterTypeRef<'a>, + /// The optional defaults-to name. + pub defaults_to: Option<&'a str>, +} + +impl<'a> Parse<'a> for Case<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let type_ = parser.parse()?; + let defaults_to = if !parser.is_empty() { + Some(parser.parens(|parser| { + parser.parse::()?; + Ok(parser.parse()?) + })?) + } else { + None + }; + Ok(Case { + name, + span, + type_, + defaults_to, + }) + } +} + +/// An interface-types list, aka a fixed-size array. +#[derive(Debug, Clone)] +pub struct List<'a> { + /// The element type of the array. + pub element: Box>, +} + +impl<'a> Parse<'a> for List<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let ty = parser.parse()?; + Ok(List { + element: Box::new(ty), + }) + } +} + +/// An interface-types tuple, aka a record with anonymous fields. +#[derive(Debug, Clone)] +pub struct Tuple<'a> { + /// The types of the fields of the tuple. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for Tuple<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parse()?); + } + Ok(Tuple { fields }) + } +} + +/// An interface-types flags, aka a fixed-sized bitfield with named fields. +#[derive(Debug, Clone)] +pub struct Flags<'a> { + /// The names of the individual flags. + pub flag_names: Vec<&'a str>, +} + +impl<'a> Parse<'a> for Flags<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut flag_names = Vec::new(); + while !parser.is_empty() { + flag_names.push(parser.parse()?); + } + Ok(Flags { flag_names }) + } +} + +/// An interface-types enum, aka a discriminated union with unit arms. +#[derive(Debug, Clone)] +pub struct Enum<'a> { + /// The arms of the enum. + pub arms: Vec<&'a str>, +} + +impl<'a> Parse<'a> for Enum<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut arms = Vec::new(); + while !parser.is_empty() { + arms.push(parser.parse()?); + } + Ok(Enum { arms }) + } +} + +/// An interface-types union, aka a discriminated union with anonymous arms. +#[derive(Debug, Clone)] +pub struct Union<'a> { + /// The arms of the union. + pub arms: Vec>, +} + +impl<'a> Parse<'a> for Union<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut arms = Vec::new(); + while !parser.is_empty() { + arms.push(parser.parse()?); + } + Ok(Union { arms }) + } +} + +/// An interface-types optional, aka an option. +#[derive(Debug, Clone)] +pub struct OptionType<'a> { + /// The type of the value, when a value is present. + pub element: Box>, +} + +impl<'a> Parse<'a> for OptionType<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let ty = parser.parse()?; + Ok(OptionType { + element: Box::new(ty), + }) + } +} + +/// An interface-types expected, aka an result. +#[derive(Debug, Clone)] +pub struct Expected<'a> { + /// The type on success. + pub ok: Box>, + /// The type on failure. + pub err: Box>, +} + +impl<'a> Parse<'a> for Expected<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let ok = parser.parse()?; + let err = parser.parse()?; + Ok(Expected { + ok: Box::new(ok), + err: Box::new(err), + }) + } +} diff --git a/third_party/rust/wast/src/component/item_ref.rs b/third_party/rust/wast/src/component/item_ref.rs new file mode 100644 index 000000000000..b7745b75bed5 --- /dev/null +++ b/third_party/rust/wast/src/component/item_ref.rs @@ -0,0 +1,98 @@ +use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::Index; + +/// Parses `(func $foo)` +#[derive(Clone, Debug)] +#[allow(missing_docs)] +pub struct ItemRef<'a, K> { + pub kind: K, + pub idx: Index<'a>, + pub export_names: Vec<&'a str>, +} + +impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let kind = parser.parse::()?; + let idx = parser.parse()?; + let mut export_names = Vec::new(); + while !parser.is_empty() { + export_names.push(parser.parse()?); + } + Ok(ItemRef { + kind, + idx, + export_names, + }) + }) + } +} + +impl<'a, K: Peek> Peek for ItemRef<'a, K> { + fn peek(cursor: Cursor<'_>) -> bool { + match cursor.lparen() { + // This is a little fancy because when parsing something like: + // + // (type (component (type $foo))) + // + // we need to disambiguate that from + // + // (type (component (type $foo (func)))) + // + // where the first is a type reference and the second is an inline + // component type defining a type internally. The peek here not only + // peeks for `K` but also for the index and possibly trailing + // strings. + Some(remaining) if K::peek(remaining) => { + let remaining = match remaining.keyword() { + Some((_, remaining)) => remaining, + None => return false, + }; + match remaining + .id() + .map(|p| p.1) + .or_else(|| remaining.integer().map(|p| p.1)) + { + Some(remaining) => remaining.rparen().is_some() || remaining.string().is_some(), + None => false, + } + } + _ => false, + } + } + + fn display() -> &'static str { + "an item reference" + } +} + +/// Convenience structure to parse `$f` or `(item $f)`. +#[derive(Clone, Debug)] +pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); + +impl<'a, K> Parse<'a> for IndexOrRef<'a, K> +where + K: Parse<'a> + Default, +{ + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() { + Ok(IndexOrRef(ItemRef { + kind: K::default(), + idx: parser.parse()?, + export_names: Vec::new(), + })) + } else { + Ok(IndexOrRef(parser.parse()?)) + } + } +} + +impl<'a, K: Peek> Peek for IndexOrRef<'a, K> { + fn peek(cursor: Cursor<'_>) -> bool { + Index::peek(cursor) || ItemRef::::peek(cursor) + } + + fn display() -> &'static str { + "an item reference" + } +} diff --git a/third_party/rust/wast/src/component/mod.rs b/third_party/rust/wast/src/component/mod.rs new file mode 100644 index 000000000000..0e381148b1cc --- /dev/null +++ b/third_party/rust/wast/src/component/mod.rs @@ -0,0 +1,28 @@ +//! Types and support for parsing the component model text format. + +mod alias; +mod component; +mod deftype; +mod export; +mod func; +mod import; +mod instance; +mod intertype; +mod item_ref; +mod module; +mod types; +pub use self::alias::*; +pub use self::component::*; +pub use self::deftype::*; +pub use self::export::*; +pub use self::func::*; +pub use self::import::*; +pub use self::instance::*; +pub use self::intertype::*; +pub use self::item_ref::*; +pub use self::module::*; +pub use self::types::*; + +mod binary; +mod expand; +mod resolve; diff --git a/third_party/rust/wast/src/ast/nested_module.rs b/third_party/rust/wast/src/component/module.rs similarity index 54% rename from third_party/rust/wast/src/ast/nested_module.rs rename to third_party/rust/wast/src/component/module.rs index af3f1a95a4ba..3dd8ed14cd0e 100644 --- a/third_party/rust/wast/src/ast/nested_module.rs +++ b/third_party/rust/wast/src/component/module.rs @@ -1,42 +1,45 @@ -use crate::ast::{self, kw}; -use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::component::*; +use crate::core; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; -/// A nested WebAssembly nested module to be created as part of a module. +/// A nested WebAssembly module to be created as part of a component. #[derive(Debug)] -pub struct NestedModule<'a> { +pub struct Module<'a> { /// Where this `nested module` was defined. - pub span: ast::Span, + pub span: Span, /// An identifier that this nested module is resolved with (optionally) for name /// resolution. - pub id: Option>, + pub id: Option>, /// An optional name for this module stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: ast::InlineExport<'a>, + pub exports: core::InlineExport<'a>, /// What kind of nested module this is, be it an inline-defined or imported one. - pub kind: NestedModuleKind<'a>, + pub kind: ModuleKind<'a>, } /// Possible ways to define a nested module in the text format. #[derive(Debug)] -pub enum NestedModuleKind<'a> { +pub enum ModuleKind<'a> { /// An nested module which is actually defined as an import, such as: Import { /// Where this nested module is imported from - import: ast::InlineImport<'a>, + import: InlineImport<'a>, /// The type that this nested module will have. - ty: ast::TypeUse<'a, ast::ModuleType<'a>>, + ty: ComponentTypeUse<'a, ModuleType<'a>>, }, - /// Nested modules whose instantiation is defined inline. + /// modules whose instantiation is defined inline. Inline { /// Fields in the nested module. - fields: Vec>, + fields: Vec>, }, } -impl<'a> Parse<'a> for NestedModule<'a> { +impl<'a> Parse<'a> for Module<'a> { fn parse(parser: Parser<'a>) -> Result { // This is sort of a fundamental limitation of the way this crate is // designed. Everything is done through recursive descent parsing which @@ -57,7 +60,7 @@ impl<'a> Parse<'a> for NestedModule<'a> { let exports = parser.parse()?; let kind = if let Some(import) = parser.parse()? { - NestedModuleKind::Import { + ModuleKind::Import { import, ty: parser.parse()?, } @@ -66,10 +69,10 @@ impl<'a> Parse<'a> for NestedModule<'a> { while !parser.is_empty() { fields.push(parser.parens(|p| p.parse())?); } - NestedModuleKind::Inline { fields } + ModuleKind::Inline { fields } }; - Ok(NestedModule { + Ok(Module { span, id, name, @@ -78,38 +81,3 @@ impl<'a> Parse<'a> for NestedModule<'a> { }) } } - -// Note that this is a custom implementation to get multi-token lookahead to -// figure out how to parse `(type ...` when it's in an inline module. If this is -// `(type $x)` or `(type 0)` then it's an inline type annotation, otherwise it's -// probably a typedef like `(type $x (func))` or something like that. We only -// want to parse the two-token variant right now. -struct InlineType; - -impl Peek for InlineType { - fn peek(cursor: Cursor<'_>) -> bool { - let cursor = match cursor.lparen() { - Some(cursor) => cursor, - None => return false, - }; - let cursor = match cursor.keyword() { - Some(("type", cursor)) => cursor, - _ => return false, - }; - - // optional identifier - let cursor = match cursor.id() { - Some((_, cursor)) => cursor, - None => match cursor.integer() { - Some((_, cursor)) => cursor, - None => return false, - }, - }; - - cursor.rparen().is_some() - } - - fn display() -> &'static str { - "inline type" - } -} diff --git a/third_party/rust/wast/src/component/resolve.rs b/third_party/rust/wast/src/component/resolve.rs new file mode 100644 index 000000000000..ba9e673491db --- /dev/null +++ b/third_party/rust/wast/src/component/resolve.rs @@ -0,0 +1,726 @@ +use crate::component::*; +use crate::core; +use crate::kw; +use crate::names::Namespace; +use crate::token::{Id, Index}; +use crate::Error; + +/// Resolve the fields of a component and everything nested within it, changing +/// `Index::Id` to `Index::Num` and expanding alias syntax sugar. +pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> { + let fields = match &mut component.kind { + ComponentKind::Text(fields) => fields, + ComponentKind::Binary(_) => return Ok(()), + }; + let mut resolver = Resolver::default(); + resolver.fields(component.id, fields) +} + +#[derive(Default)] +struct Resolver<'a> { + stack: Vec>, + + // When a name refers to a definition in an outer scope, we'll need to + // insert an outer alias before it. This collects the aliases to be + // inserted during resolution. + aliases_to_insert: Vec>, +} + +/// Context structure used to perform name resolution. +#[derive(Default)] +struct ComponentState<'a> { + id: Option>, + + // Namespaces within each component. Note that each namespace carries + // with it information about the signature of the item in that namespace. + // The signature is later used to synthesize the type of a component and + // inject type annotations if necessary. + funcs: Namespace<'a>, + globals: Namespace<'a>, + tables: Namespace<'a>, + memories: Namespace<'a>, + types: Namespace<'a>, + tags: Namespace<'a>, + instances: Namespace<'a>, + modules: Namespace<'a>, + components: Namespace<'a>, + values: Namespace<'a>, +} + +impl<'a> ComponentState<'a> { + fn new(id: Option>) -> ComponentState<'a> { + ComponentState { + id, + ..ComponentState::default() + } + } +} + +impl<'a> Resolver<'a> { + fn current(&mut self) -> &mut ComponentState<'a> { + self.stack + .last_mut() + .expect("should have at least one component state") + } + + fn fields( + &mut self, + id: Option>, + fields: &mut Vec>, + ) -> Result<(), Error> { + self.stack.push(ComponentState::new(id)); + self.resolve_prepending_aliases(fields, Resolver::field, ComponentState::register)?; + self.stack.pop(); + Ok(()) + } + + fn resolve_prepending_aliases( + &mut self, + fields: &mut Vec, + resolve: fn(&mut Self, &mut T) -> Result<(), Error>, + register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>, + ) -> Result<(), Error> + where + T: From>, + { + assert!(self.aliases_to_insert.is_empty()); + + // Iterate through the fields of the component. We use an index + // instead of an iterator because we'll be inserting aliases + // as we go. + let mut i = 0; + while i < fields.len() { + // Resolve names within the field. + resolve(self, &mut fields[i])?; + + // Name resolution may have emitted some aliases. Insert them before + // the current definition. + let amt = self.aliases_to_insert.len(); + fields.splice(i..i, self.aliases_to_insert.drain(..).map(T::from)); + i += amt; + + // Definitions can't refer to themselves or to definitions that appear + // later in the format. Now that we're done resolving this field, + // assign it an index for later defintions to refer to. + register(self.current(), &fields[i])?; + + i += 1; + } + + Ok(()) + } + + fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> { + match field { + ComponentField::Import(i) => self.item_sig(&mut i.item), + + ComponentField::Type(t) => self.type_field(t), + + ComponentField::Func(f) => { + let body = match &mut f.kind { + ComponentFuncKind::Import { .. } => return Ok(()), + ComponentFuncKind::Inline { body } => body, + }; + let opts = match body { + ComponentFuncBody::CanonLift(lift) => { + self.type_use(&mut lift.type_)?; + self.item_ref(&mut lift.func)?; + &mut lift.opts + } + ComponentFuncBody::CanonLower(lower) => { + self.item_ref(&mut lower.func)?; + &mut lower.opts + } + }; + for opt in opts { + match opt { + CanonOpt::StringUtf8 + | CanonOpt::StringUtf16 + | CanonOpt::StringLatin1Utf16 => {} + CanonOpt::Into(instance) => { + self.item_ref(instance)?; + } + } + } + Ok(()) + } + + ComponentField::Instance(i) => match &mut i.kind { + InstanceKind::Module { module, args } => { + self.item_ref(module)?; + for arg in args { + match &mut arg.arg { + ModuleArg::Def(def) => { + self.item_ref(def)?; + } + ModuleArg::BundleOfExports(..) => { + unreachable!("should be expanded already"); + } + } + } + Ok(()) + } + InstanceKind::Component { component, args } => { + self.item_ref(component)?; + for arg in args { + match &mut arg.arg { + ComponentArg::Def(def) => { + self.item_ref(def)?; + } + ComponentArg::BundleOfExports(..) => { + unreachable!("should be expanded already") + } + } + } + Ok(()) + } + InstanceKind::BundleOfExports { args } => { + for arg in args { + self.item_ref(&mut arg.index)?; + } + Ok(()) + } + InstanceKind::BundleOfComponentExports { args } => { + for arg in args { + self.arg(&mut arg.arg)?; + } + Ok(()) + } + InstanceKind::Import { .. } => { + unreachable!("should be removed by expansion") + } + }, + ComponentField::Module(m) => { + match &mut m.kind { + ModuleKind::Inline { fields } => { + crate::core::resolve::resolve(fields)?; + } + + ModuleKind::Import { .. } => { + unreachable!("should be expanded already") + } + } + + Ok(()) + } + ComponentField::Component(c) => match &mut c.kind { + NestedComponentKind::Import { .. } => { + unreachable!("should be expanded already") + } + NestedComponentKind::Inline(fields) => self.fields(c.id, fields), + }, + ComponentField::Alias(a) => self.alias(a), + + ComponentField::Start(s) => { + self.item_ref(&mut s.func)?; + for arg in s.args.iter_mut() { + self.item_ref(arg)?; + } + Ok(()) + } + + ComponentField::Export(e) => { + self.arg(&mut e.arg)?; + Ok(()) + } + } + } + + fn item_sig(&mut self, sig: &mut ItemSig<'a>) -> Result<(), Error> { + match &mut sig.kind { + ItemKind::Component(t) => self.type_use(t), + ItemKind::Module(t) => self.type_use(t), + ItemKind::Instance(t) => self.type_use(t), + ItemKind::Func(t) => self.type_use(t), + ItemKind::Value(t) => self.type_use(t), + } + } + + fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> { + match &mut alias.target { + AliasTarget::Export { + instance, + export: _, + } => self.resolve_ns(instance, Ns::Instance), + AliasTarget::Outer { outer, index } => { + // Short-circuit when both indices are already resolved as this + // helps to write tests for invalid modules where wasmparser should + // be the one returning the error. + if let Index::Num(..) = outer { + if let Index::Num(..) = index { + return Ok(()); + } + } + + // Resolve `outer`, and compute the depth at which to look up + // `index`. + let depth = match outer { + Index::Id(id) => { + let mut depth = 0; + for resolver in self.stack.iter_mut().rev() { + if resolver.id == Some(*id) { + break; + } + depth += 1; + } + if depth as usize == self.stack.len() { + return Err(Error::new( + alias.span, + format!("outer component `{}` not found", id.name()), + )); + } + depth + } + Index::Num(n, _span) => *n, + }; + *outer = Index::Num(depth, alias.span); + if depth as usize >= self.stack.len() { + return Err(Error::new( + alias.span, + format!("component depth of `{}` is too large", depth), + )); + } + + // Resolve `index` within the computed scope depth. + let ns = match alias.kind { + AliasKind::Module => Ns::Module, + AliasKind::Component => Ns::Component, + AliasKind::Instance => Ns::Instance, + AliasKind::Value => Ns::Value, + AliasKind::ExportKind(kind) => kind.into(), + }; + let computed = self.stack.len() - 1 - depth as usize; + self.stack[computed].resolve(ns, index)?; + + Ok(()) + } + } + } + + fn arg(&mut self, arg: &mut ComponentArg<'a>) -> Result<(), Error> { + match arg { + ComponentArg::Def(item_ref) => { + self.item_ref(item_ref)?; + } + ComponentArg::BundleOfExports(..) => unreachable!("should be expanded already"), + } + Ok(()) + } + + fn type_use(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> { + let item = match ty { + ComponentTypeUse::Ref(r) => r, + ComponentTypeUse::Inline(_) => { + unreachable!("inline type-use should be expanded by now") + } + }; + self.item_ref(item) + } + + fn intertype(&mut self, ty: &mut InterType<'a>) -> Result<(), Error> { + match ty { + InterType::Primitive(_) => {} + InterType::Flags(_) => {} + InterType::Enum(_) => {} + InterType::Record(r) => { + for field in r.fields.iter_mut() { + self.intertype_ref(&mut field.type_)?; + } + } + InterType::Variant(v) => { + for case in v.cases.iter_mut() { + self.intertype_ref(&mut case.type_)?; + } + } + InterType::List(l) => { + self.intertype_ref(&mut *l.element)?; + } + InterType::Tuple(t) => { + for field in t.fields.iter_mut() { + self.intertype_ref(field)?; + } + } + InterType::Union(t) => { + for arm in t.arms.iter_mut() { + self.intertype_ref(arm)?; + } + } + InterType::Option(o) => { + self.intertype_ref(&mut *o.element)?; + } + InterType::Expected(r) => { + self.intertype_ref(&mut *r.ok)?; + self.intertype_ref(&mut *r.err)?; + } + } + Ok(()) + } + + fn intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) -> Result<(), Error> { + match ty { + InterTypeRef::Primitive(_) => Ok(()), + InterTypeRef::Ref(idx) => self.resolve_ns(idx, Ns::Type), + InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), + } + } + + fn type_field(&mut self, field: &mut TypeField<'a>) -> Result<(), Error> { + match &mut field.def { + ComponentTypeDef::DefType(DefType::Func(f)) => { + for param in f.params.iter_mut() { + self.intertype_ref(&mut param.type_)?; + } + self.intertype_ref(&mut f.result)?; + } + ComponentTypeDef::DefType(DefType::Module(m)) => { + self.stack.push(ComponentState::new(field.id)); + self.moduletype(m)?; + self.stack.pop(); + } + ComponentTypeDef::DefType(DefType::Component(c)) => { + self.stack.push(ComponentState::new(field.id)); + self.nested_component_type(c)?; + self.stack.pop(); + } + ComponentTypeDef::DefType(DefType::Instance(i)) => { + self.stack.push(ComponentState::new(field.id)); + self.instance_type(i)?; + self.stack.pop(); + } + ComponentTypeDef::DefType(DefType::Value(v)) => { + self.intertype_ref(&mut v.value_type)? + } + ComponentTypeDef::InterType(i) => self.intertype(i)?, + } + Ok(()) + } + + fn nested_component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> { + self.resolve_prepending_aliases( + &mut c.fields, + |resolver, field| match field { + ComponentTypeField::Alias(alias) => resolver.alias(alias), + ComponentTypeField::Type(ty) => resolver.type_field(ty), + ComponentTypeField::Import(import) => resolver.item_sig(&mut import.item), + ComponentTypeField::Export(export) => resolver.item_sig(&mut export.item), + }, + |state, field| { + match field { + ComponentTypeField::Alias(alias) => { + state.register_alias(alias)?; + } + ComponentTypeField::Type(ty) => { + state.types.register(ty.id, "type")?; + } + // Only the type namespace is populated within the component type + // namespace so these are ignored here. + ComponentTypeField::Import(_) | ComponentTypeField::Export(_) => {} + } + Ok(()) + }, + ) + } + + fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> { + self.resolve_prepending_aliases( + &mut c.fields, + |resolver, field| match field { + InstanceTypeField::Alias(alias) => resolver.alias(alias), + InstanceTypeField::Type(ty) => resolver.type_field(ty), + InstanceTypeField::Export(export) => resolver.item_sig(&mut export.item), + }, + |state, field| { + match field { + InstanceTypeField::Alias(alias) => { + state.register_alias(alias)?; + } + InstanceTypeField::Type(ty) => { + state.types.register(ty.id, "type")?; + } + InstanceTypeField::Export(_export) => {} + } + Ok(()) + }, + ) + } + + fn item_ref(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error> + where + K: Into + Copy, + { + let last_ns = item.kind.into(); + + // If there are no extra `export_names` listed then this is a reference to + // something defined within this component's index space, so resolve as + // necessary. + if item.export_names.is_empty() { + self.resolve_ns(&mut item.idx, last_ns)?; + return Ok(()); + } + + // ... otherwise the `index` of `item` refers to an intance and the + // `export_names` refer to recursive exports from this item. Resolve the + // instance locally and then process the export names one at a time, + // injecting aliases as necessary. + let mut index = item.idx.clone(); + self.resolve_ns(&mut index, Ns::Instance)?; + let span = item.idx.span(); + for (pos, export_name) in item.export_names.iter().enumerate() { + // The last name is in the namespace of the reference. All others are + // instances. + let ns = if pos == item.export_names.len() - 1 { + last_ns + } else { + Ns::Instance + }; + + // Record an outer alias to be inserted in front of the current + // definition. + let mut alias = Alias { + span, + id: None, + name: None, + target: AliasTarget::Export { + instance: index, + export: export_name, + }, + kind: match ns { + Ns::Module => AliasKind::Module, + Ns::Component => AliasKind::Component, + Ns::Instance => AliasKind::Instance, + Ns::Value => AliasKind::Value, + Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), + Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), + Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), + Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), + Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), + Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + }, + }; + + index = Index::Num(self.current().register_alias(&mut alias)?, span); + self.aliases_to_insert.push(alias); + } + item.idx = index; + item.export_names = Vec::new(); + + Ok(()) + } + + fn resolve_ns(&mut self, idx: &mut Index<'a>, ns: Ns) -> Result<(), Error> { + // Perform resolution on a local clone walking up the stack of components + // that we have. Note that a local clone is used since we don't want to use + // the parent's resolved index if a parent matches, instead we want to use + // the index of the alias that we will automatically insert. + let mut idx_clone = idx.clone(); + for (depth, resolver) in self.stack.iter_mut().rev().enumerate() { + let depth = depth as u32; + let found = match resolver.resolve(ns, &mut idx_clone) { + Ok(idx) => idx, + // Try the next parent + Err(_) => continue, + }; + + // If this is the current component then no extra alias is necessary, so + // return success. + if depth == 0 { + *idx = idx_clone; + return Ok(()); + } + let id = match idx { + Index::Id(id) => id.clone(), + Index::Num(..) => unreachable!(), + }; + + // When resolution succeeds in a parent then an outer alias is + // automatically inserted here in this component. + let span = idx.span(); + let mut alias = Alias { + span, + id: Some(id), + name: None, + target: AliasTarget::Outer { + outer: Index::Num(depth, span), + index: Index::Num(found, span), + }, + kind: match ns { + Ns::Module => AliasKind::Module, + Ns::Component => AliasKind::Component, + Ns::Instance => AliasKind::Instance, + Ns::Value => AliasKind::Value, + Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), + Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), + Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), + Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), + Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), + Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + }, + }; + let local_index = self.current().register_alias(&mut alias)?; + self.aliases_to_insert.push(alias); + *idx = Index::Num(local_index, span); + return Ok(()); + } + + // If resolution in any parent failed then simply return the error from our + // local namespace + self.current().resolve(ns, idx)?; + unreachable!() + } + + fn moduletype(&mut self, ty: &mut ModuleType<'_>) -> Result<(), Error> { + let mut types = Namespace::default(); + for def in ty.defs.iter_mut() { + match def { + ModuleTypeDef::Type(t) => { + types.register(t.id, "type")?; + } + ModuleTypeDef::Import(t) => resolve_item_sig(&mut t.item, &types)?, + ModuleTypeDef::Export(_, t) => resolve_item_sig(t, &types)?, + } + } + return Ok(()); + + fn resolve_item_sig<'a>( + sig: &mut core::ItemSig<'a>, + names: &Namespace<'a>, + ) -> Result<(), Error> { + match &mut sig.kind { + core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => { + let idx = ty.index.as_mut().expect("index should be filled in"); + names.resolve(idx, "type")?; + } + core::ItemKind::Memory(_) + | core::ItemKind::Global(_) + | core::ItemKind::Table(_) => {} + } + Ok(()) + } + } +} + +impl<'a> ComponentState<'a> { + fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result { + match ns { + Ns::Func => self.funcs.resolve(idx, "func"), + Ns::Table => self.tables.resolve(idx, "table"), + Ns::Global => self.globals.resolve(idx, "global"), + Ns::Memory => self.memories.resolve(idx, "memory"), + Ns::Tag => self.tags.resolve(idx, "tag"), + Ns::Type => self.types.resolve(idx, "type"), + Ns::Component => self.components.resolve(idx, "component"), + Ns::Module => self.modules.resolve(idx, "module"), + Ns::Instance => self.instances.resolve(idx, "instance"), + Ns::Value => self.values.resolve(idx, "instance"), + } + } + + /// Assign an index to the given field. + fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> { + match item { + ComponentField::Import(i) => match &i.item.kind { + ItemKind::Module(_) => self.modules.register(i.item.id, "module")?, + ItemKind::Component(_) => self.components.register(i.item.id, "component")?, + ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?, + ItemKind::Value(_) => self.values.register(i.item.id, "value")?, + ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, + }, + + ComponentField::Func(i) => self.funcs.register(i.id, "func")?, + ComponentField::Type(i) => self.types.register(i.id, "type")?, + ComponentField::Instance(i) => self.instances.register(i.id, "instance")?, + ComponentField::Module(m) => self.modules.register(m.id, "nested module")?, + ComponentField::Component(c) => self.components.register(c.id, "nested component")?, + ComponentField::Alias(a) => self.register_alias(a)?, + ComponentField::Start(s) => self.values.register(s.result, "value")?, + + // These fields don't define any items in any index space. + ComponentField::Export(_) => return Ok(()), + }; + + Ok(()) + } + + fn register_alias(&mut self, alias: &Alias<'a>) -> Result { + match alias.kind { + AliasKind::Module => self.modules.register(alias.id, "module"), + AliasKind::Component => self.components.register(alias.id, "component"), + AliasKind::Instance => self.instances.register(alias.id, "instance"), + AliasKind::Value => self.values.register(alias.id, "value"), + AliasKind::ExportKind(core::ExportKind::Func) => self.funcs.register(alias.id, "func"), + AliasKind::ExportKind(core::ExportKind::Table) => { + self.tables.register(alias.id, "table") + } + AliasKind::ExportKind(core::ExportKind::Memory) => { + self.memories.register(alias.id, "memory") + } + AliasKind::ExportKind(core::ExportKind::Global) => { + self.globals.register(alias.id, "global") + } + AliasKind::ExportKind(core::ExportKind::Tag) => self.tags.register(alias.id, "tag"), + AliasKind::ExportKind(core::ExportKind::Type) => self.types.register(alias.id, "type"), + } + } +} + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +enum Ns { + Func, + Table, + Global, + Memory, + Tag, + Type, + Component, + Module, + Instance, + Value, +} + +macro_rules! component_kw_conversions { + ($($kw:ident => $kind:ident)*) => ($( + impl From for Ns { + fn from(_: kw::$kw) -> Ns { + Ns::$kind + } + } + )*); +} + +component_kw_conversions! { + func => Func + module => Module + component => Component + instance => Instance + value => Value + table => Table + memory => Memory + global => Global + tag => Tag + r#type => Type +} + +impl From for Ns { + fn from(kind: DefTypeKind) -> Self { + match kind { + DefTypeKind::Module => Ns::Module, + DefTypeKind::Component => Ns::Component, + DefTypeKind::Instance => Ns::Instance, + DefTypeKind::Value => Ns::Value, + DefTypeKind::Func => Ns::Func, + } + } +} + +impl From for Ns { + fn from(kind: core::ExportKind) -> Self { + match kind { + core::ExportKind::Func => Ns::Func, + core::ExportKind::Table => Ns::Table, + core::ExportKind::Global => Ns::Global, + core::ExportKind::Memory => Ns::Memory, + core::ExportKind::Tag => Ns::Tag, + core::ExportKind::Type => Ns::Type, + } + } +} diff --git a/third_party/rust/wast/src/component/types.rs b/third_party/rust/wast/src/component/types.rs new file mode 100644 index 000000000000..ebc28a317c23 --- /dev/null +++ b/third_party/rust/wast/src/component/types.rs @@ -0,0 +1,91 @@ +use crate::component::*; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; + +/// A definition of a type. +/// +/// typeexpr ::= +/// | +#[derive(Debug)] +pub enum ComponentTypeDef<'a> { + /// The type of an entity. + DefType(DefType<'a>), + /// The type of a value. + InterType(InterType<'a>), +} + +/// The type of an exported item from an component or instance. +#[derive(Debug)] +pub struct ComponentExportType<'a> { + /// Where this export was defined. + pub span: Span, + /// The name of this export. + pub name: &'a str, + /// The signature of the item that's exported. + pub item: ItemSig<'a>, +} + +impl<'a> Parse<'a> for ComponentExportType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let item = parser.parens(|p| p.parse())?; + Ok(ComponentExportType { span, name, item }) + } +} +/// A type declaration in a component. +/// +/// type ::= (type ? ) +#[derive(Debug)] +pub struct TypeField<'a> { + /// Where this type was defined. + pub span: Span, + /// An optional identifer to refer to this `type` by as part of name + /// resolution. + pub id: Option>, + /// An optional name for this function stored in the custom `name` section. + pub name: Option>, + /// The type that we're declaring. + pub def: ComponentTypeDef<'a>, +} + +impl<'a> Parse<'a> for TypeField<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let def = if parser.peek2::() { + ComponentTypeDef::DefType(parser.parens(|p| p.parse())?) + } else { + ComponentTypeDef::InterType(parser.parse()?) + }; + Ok(TypeField { + span, + id, + name, + def, + }) + } +} +/// A reference to a type defined in this component. +/// +/// This is the same as `TypeUse`, but accepts `$T` as shorthand for +/// `(type $T)`. +#[derive(Debug, Clone)] +pub enum ComponentTypeUse<'a, T> { + /// The type that we're referencing. + Ref(ItemRef<'a, kw::r#type>), + /// The inline type. + Inline(T), +} + +impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() { + Ok(ComponentTypeUse::Ref(parser.parse()?)) + } else { + Ok(ComponentTypeUse::Inline(parser.parse()?)) + } + } +} diff --git a/third_party/rust/wast/src/binary.rs b/third_party/rust/wast/src/core/binary.rs similarity index 75% rename from third_party/rust/wast/src/binary.rs rename to third_party/rust/wast/src/core/binary.rs index d040f114ef3a..7d6d4feb4547 100644 --- a/third_party/rust/wast/src/binary.rs +++ b/third_party/rust/wast/src/core/binary.rs @@ -1,19 +1,14 @@ -use crate::ast::*; +use crate::core::*; +use crate::encode::Encode; +use crate::token::*; -pub fn encode(module: &Module<'_>) -> Vec { - match &module.kind { - ModuleKind::Text(fields) => encode_fields(&module.id, &module.name, fields), - ModuleKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().cloned()).collect(), - } -} - -fn encode_fields( +pub fn encode( module_id: &Option>, module_name: &Option>, fields: &[ModuleField<'_>], ) -> Vec { - use crate::ast::CustomPlace::*; - use crate::ast::CustomPlaceAnchor::*; + use CustomPlace::*; + use CustomPlaceAnchor::*; let mut types = Vec::new(); let mut imports = Vec::new(); @@ -27,9 +22,6 @@ fn encode_fields( let mut data = Vec::new(); let mut tags = Vec::new(); let mut customs = Vec::new(); - let mut instances = Vec::new(); - let mut modules = Vec::new(); - let mut aliases = Vec::new(); for field in fields { match field { ModuleField::Type(i) => types.push(i), @@ -44,9 +36,6 @@ fn encode_fields( ModuleField::Data(i) => data.push(i), ModuleField::Tag(i) => tags.push(i), ModuleField::Custom(i) => customs.push(i), - ModuleField::Instance(i) => instances.push(i), - ModuleField::NestedModule(i) => modules.push(i), - ModuleField::Alias(a) => aliases.push(a), } } @@ -60,47 +49,8 @@ fn encode_fields( e.custom_sections(BeforeFirst); - let mut items = fields - .iter() - .filter(|i| match i { - ModuleField::Alias(_) - | ModuleField::Type(_) - | ModuleField::Import(_) - | ModuleField::NestedModule(_) - | ModuleField::Instance(_) => true, - _ => false, - }) - .peekable(); - - // A special path is used for now to handle non-module-linking modules to - // work around WebAssembly/annotations#11 - if aliases.len() == 0 && modules.len() == 0 && instances.len() == 0 { - e.section_list(1, Type, &types); - e.section_list(2, Import, &imports); - } else { - while let Some(field) = items.next() { - macro_rules! list { - ($code:expr, $name:ident) => { - list!($code, $name, $name) - }; - ($code:expr, $field:ident, $custom:ident) => { - if let ModuleField::$field(f) = field { - let mut list = vec![f]; - while let Some(ModuleField::$field(f)) = items.peek() { - list.push(f); - items.next(); - } - e.section_list($code, $custom, &list); - } - }; - } - list!(1, Type); - list!(2, Import); - list!(14, NestedModule, Module); - list!(15, Instance); - list!(16, Alias); - } - } + e.section_list(1, Type, &types); + e.section_list(2, Import, &imports); let functys = funcs.iter().map(|f| &f.ty).collect::>(); e.section_list(3, Func, &functys); @@ -129,7 +79,7 @@ fn encode_fields( return e.wasm; - fn contains_bulk_memory(funcs: &[&crate::ast::Func<'_>]) -> bool { + fn contains_bulk_memory(funcs: &[&crate::core::Func<'_>]) -> bool { funcs .iter() .filter_map(|f| match &f.kind { @@ -175,75 +125,6 @@ impl Encoder<'_> { } } -pub(crate) trait Encode { - fn encode(&self, e: &mut Vec); -} - -impl Encode for &'_ T { - fn encode(&self, e: &mut Vec) { - T::encode(self, e) - } -} - -impl Encode for [T] { - fn encode(&self, e: &mut Vec) { - self.len().encode(e); - for item in self { - item.encode(e); - } - } -} - -impl Encode for Vec { - fn encode(&self, e: &mut Vec) { - <[T]>::encode(self, e) - } -} - -impl Encode for str { - fn encode(&self, e: &mut Vec) { - self.len().encode(e); - e.extend_from_slice(self.as_bytes()); - } -} - -impl Encode for usize { - fn encode(&self, e: &mut Vec) { - assert!(*self <= u32::max_value() as usize); - (*self as u32).encode(e) - } -} - -impl Encode for u8 { - fn encode(&self, e: &mut Vec) { - e.push(*self); - } -} - -impl Encode for u32 { - fn encode(&self, e: &mut Vec) { - leb128::write::unsigned(e, (*self).into()).unwrap(); - } -} - -impl Encode for i32 { - fn encode(&self, e: &mut Vec) { - leb128::write::signed(e, (*self).into()).unwrap(); - } -} - -impl Encode for u64 { - fn encode(&self, e: &mut Vec) { - leb128::write::unsigned(e, (*self).into()).unwrap(); - } -} - -impl Encode for i64 { - fn encode(&self, e: &mut Vec) { - leb128::write::signed(e, *self).unwrap(); - } -} - impl Encode for FunctionType<'_> { fn encode(&self, e: &mut Vec) { self.params.len().encode(e); @@ -271,19 +152,6 @@ impl Encode for ArrayType<'_> { } } -impl Encode for ModuleType<'_> { - fn encode(&self, e: &mut Vec) { - self.imports.encode(e); - self.exports.encode(e); - } -} - -impl Encode for InstanceType<'_> { - fn encode(&self, e: &mut Vec) { - self.exports.encode(e); - } -} - impl Encode for ExportType<'_> { fn encode(&self, e: &mut Vec) { self.name.encode(e); @@ -306,14 +174,6 @@ impl Encode for Type<'_> { e.push(0x5e); array.encode(e) } - TypeDef::Module(module) => { - e.push(0x61); - module.encode(e) - } - TypeDef::Instance(instance) => { - e.push(0x62); - instance.encode(e) - } } } } @@ -324,13 +184,6 @@ impl Encode for Option> { } } -impl Encode for (T, U) { - fn encode(&self, e: &mut Vec) { - self.0.encode(e); - self.1.encode(e); - } -} - impl<'a> Encode for ValType<'a> { fn encode(&self, e: &mut Vec) { match self { @@ -435,13 +288,7 @@ impl<'a> Encode for StorageType<'a> { impl Encode for Import<'_> { fn encode(&self, e: &mut Vec) { self.module.encode(e); - match self.field { - Some(s) => s.encode(e), - None => { - e.push(0x00); - e.push(0xff); - } - } + self.field.encode(e); self.item.encode(e); } } @@ -469,14 +316,6 @@ impl Encode for ItemSig<'_> { e.push(0x04); f.encode(e); } - ItemKind::Module(m) => { - e.push(0x05); - m.encode(e); - } - ItemKind::Instance(i) => { - e.push(0x06); - i.encode(e); - } } } } @@ -499,32 +338,6 @@ impl Encode for Index<'_> { } } -impl Encode for IndexOrRef<'_, T> { - fn encode(&self, e: &mut Vec) { - self.0.encode(e); - } -} - -impl Encode for ItemRef<'_, T> { - fn encode(&self, e: &mut Vec) { - match self { - ItemRef::Outer { .. } => panic!("should be expanded previously"), - ItemRef::Item { - idx, - exports, - #[cfg(wast_check_exhaustive)] - visited, - .. - } => { - #[cfg(wast_check_exhaustive)] - assert!(*visited); - assert!(exports.is_empty()); - idx.encode(e); - } - } - } -} - impl<'a> Encode for TableType<'a> { fn encode(&self, e: &mut Vec) { self.elem.encode(e); @@ -620,10 +433,8 @@ impl Encode for Global<'_> { impl Encode for Export<'_> { fn encode(&self, e: &mut Vec) { self.name.encode(e); - if let ItemRef::Item { kind, .. } = &self.index { - kind.encode(e); - } - self.index.encode(e); + self.kind.encode(e); + self.item.encode(e); } } @@ -635,8 +446,6 @@ impl Encode for ExportKind { ExportKind::Memory => e.push(0x02), ExportKind::Global => e.push(0x03), ExportKind::Tag => e.push(0x04), - ExportKind::Module => e.push(0x05), - ExportKind::Instance => e.push(0x06), ExportKind::Type => e.push(0x07), } } @@ -647,11 +456,7 @@ impl Encode for Elem<'_> { match (&self.kind, &self.payload) { ( ElemKind::Active { - table: - ItemRef::Item { - idx: Index::Num(0, _), - .. - }, + table: Index::Num(0, _), offset, }, ElemPayload::Indices(_), @@ -671,11 +476,7 @@ impl Encode for Elem<'_> { } ( ElemKind::Active { - table: - ItemRef::Item { - idx: Index::Num(0, _), - .. - }, + table: Index::Num(0, _), offset, }, ElemPayload::Exprs { @@ -732,17 +533,16 @@ impl Encode for Data<'_> { fn encode(&self, e: &mut Vec) { match &self.kind { DataKind::Passive => e.push(0x01), + DataKind::Active { + memory: Index::Num(0, _), + offset, + } => { + e.push(0x00); + offset.encode(e); + } DataKind::Active { memory, offset } => { - if let ItemRef::Item { - idx: Index::Num(0, _), - .. - } = memory - { - e.push(0x00); - } else { - e.push(0x02); - memory.encode(e); - } + e.push(0x02); + memory.encode(e); offset.encode(e); } } @@ -798,11 +598,7 @@ impl Encode for Expression<'_> { impl Encode for BlockType<'_> { fn encode(&self, e: &mut Vec) { // block types using an index are encoded as an sleb, not a uleb - if let Some(ItemRef::Item { - idx: Index::Num(n, _), - .. - }) = &self.ty.index - { + if let Some(Index::Num(n, _)) = &self.ty.index { return i64::from(*n).encode(e); } let ty = self @@ -842,17 +638,14 @@ impl Encode for LaneArg { impl Encode for MemArg<'_> { fn encode(&self, e: &mut Vec) { match &self.memory { - ItemRef::Item { - idx: Index::Num(0, _), - .. - } => { + Index::Num(0, _) => { self.align.trailing_zeros().encode(e); self.offset.encode(e); } - n => { + _ => { (self.align.trailing_zeros() | (1 << 6)).encode(e); self.offset.encode(e); - n.encode(e); + self.memory.encode(e); } } } @@ -946,10 +739,6 @@ struct Names<'a> { table_idx: u32, tags: Vec<(u32, &'a str)>, tag_idx: u32, - modules: Vec<(u32, &'a str)>, - module_idx: u32, - instances: Vec<(u32, &'a str)>, - instance_idx: u32, types: Vec<(u32, &'a str)>, type_idx: u32, data: Vec<(u32, &'a str)>, @@ -977,8 +766,6 @@ fn find_names<'a>( Type, Global, Func, - Module, - Instance, Memory, Table, Tag, @@ -998,8 +785,6 @@ fn find_names<'a>( ItemKind::Memory(_) => Name::Memory, ItemKind::Global(_) => Name::Global, ItemKind::Tag(_) => Name::Tag, - ItemKind::Instance(_) => Name::Instance, - ItemKind::Module(_) => Name::Module, }, &i.item.id, &i.item.name, @@ -1008,26 +793,10 @@ fn find_names<'a>( ModuleField::Table(t) => (Name::Table, &t.id, &t.name), ModuleField::Memory(m) => (Name::Memory, &m.id, &m.name), ModuleField::Tag(t) => (Name::Tag, &t.id, &t.name), - ModuleField::NestedModule(m) => (Name::Module, &m.id, &m.name), - ModuleField::Instance(i) => (Name::Instance, &i.id, &i.name), ModuleField::Type(t) => (Name::Type, &t.id, &t.name), ModuleField::Elem(e) => (Name::Elem, &e.id, &e.name), ModuleField::Data(d) => (Name::Data, &d.id, &d.name), ModuleField::Func(f) => (Name::Func, &f.id, &f.name), - ModuleField::Alias(a) => ( - match a.kind { - ExportKind::Func => Name::Func, - ExportKind::Table => Name::Table, - ExportKind::Memory => Name::Memory, - ExportKind::Global => Name::Global, - ExportKind::Module => Name::Module, - ExportKind::Instance => Name::Instance, - ExportKind::Tag => Name::Tag, - ExportKind::Type => Name::Type, - }, - &a.id, - &a.name, - ), ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => continue, }; @@ -1037,8 +806,6 @@ fn find_names<'a>( Name::Table => (&mut ret.tables, &mut ret.table_idx), Name::Memory => (&mut ret.memories, &mut ret.memory_idx), Name::Global => (&mut ret.globals, &mut ret.global_idx), - Name::Module => (&mut ret.modules, &mut ret.module_idx), - Name::Instance => (&mut ret.instances, &mut ret.instance_idx), Name::Tag => (&mut ret.tags, &mut ret.tag_idx), Name::Type => (&mut ret.types, &mut ret.type_idx), Name::Elem => (&mut ret.elems, &mut ret.elem_idx), @@ -1244,56 +1011,3 @@ impl Encode for StructAccess<'_> { self.field.encode(e); } } - -impl Encode for NestedModule<'_> { - fn encode(&self, e: &mut Vec) { - let fields = match &self.kind { - NestedModuleKind::Inline { fields, .. } => fields, - _ => panic!("should only have inline modules in emission"), - }; - - encode_fields(&self.id, &self.name, fields).encode(e); - } -} - -impl Encode for Instance<'_> { - fn encode(&self, e: &mut Vec) { - assert!(self.exports.names.is_empty()); - let (module, args) = match &self.kind { - InstanceKind::Inline { module, args } => (module, args), - _ => panic!("should only have inline instances in emission"), - }; - e.push(0x00); - module.encode(e); - args.encode(e); - } -} - -impl Encode for InstanceArg<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - if let ItemRef::Item { kind, .. } = &self.index { - kind.encode(e); - } - self.index.encode(e); - } -} - -impl Encode for Alias<'_> { - fn encode(&self, e: &mut Vec) { - match &self.source { - AliasSource::InstanceExport { instance, export } => { - e.push(0x00); - instance.encode(e); - self.kind.encode(e); - export.encode(e); - } - AliasSource::Outer { module, index } => { - e.push(0x01); - module.encode(e); - self.kind.encode(e); - index.encode(e); - } - } - } -} diff --git a/third_party/rust/wast/src/ast/custom.rs b/third_party/rust/wast/src/core/custom.rs similarity index 88% rename from third_party/rust/wast/src/ast/custom.rs rename to third_party/rust/wast/src/core/custom.rs index ae93301a79f5..ea2a60467088 100644 --- a/third_party/rust/wast/src/ast/custom.rs +++ b/third_party/rust/wast/src/core/custom.rs @@ -1,11 +1,12 @@ -use crate::ast::{self, annotation, kw}; use crate::parser::{Parse, Parser, Result}; +use crate::token::{self, Span}; +use crate::{annotation, kw}; /// A wasm custom section within a module. #[derive(Debug)] pub struct Custom<'a> { /// Where this `@custom` was defined. - pub span: ast::Span, + pub span: Span, /// Name of the custom section. pub name: &'a str, @@ -36,9 +37,6 @@ pub enum CustomPlace { pub enum CustomPlaceAnchor { Type, Import, - Module, - Instance, - Alias, Func, Table, Memory, @@ -55,7 +53,7 @@ impl<'a> Parse<'a> for Custom<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let name = parser.parse()?; - let place = if parser.peek::() { + let place = if parser.peek::() { parser.parens(|p| p.parse())? } else { CustomPlace::AfterLast @@ -147,18 +145,6 @@ impl<'a> Parse<'a> for CustomPlaceAnchor { parser.parse::()?; return Ok(CustomPlaceAnchor::Tag); } - if parser.peek::() { - parser.parse::()?; - return Ok(CustomPlaceAnchor::Instance); - } - if parser.peek::() { - parser.parse::()?; - return Ok(CustomPlaceAnchor::Module); - } - if parser.peek::() { - parser.parse::()?; - return Ok(CustomPlaceAnchor::Alias); - } Err(parser.error("expected a valid section name")) } diff --git a/third_party/rust/wast/src/ast/export.rs b/third_party/rust/wast/src/core/export.rs similarity index 79% rename from third_party/rust/wast/src/ast/export.rs rename to third_party/rust/wast/src/core/export.rs index f1f333b269e5..5ebe002f9706 100644 --- a/third_party/rust/wast/src/ast/export.rs +++ b/third_party/rust/wast/src/core/export.rs @@ -1,15 +1,18 @@ -use crate::ast::{self, kw}; +use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::{Index, Span}; /// A entry in a WebAssembly module's export section. #[derive(Debug)] pub struct Export<'a> { /// Where this export was defined. - pub span: ast::Span, + pub span: Span, /// The name of this export from the module. pub name: &'a str, + /// The kind of item being exported. + pub kind: ExportKind, /// What's being exported from the module. - pub index: ast::ItemRef<'a, ExportKind>, + pub item: Index<'a>, } /// Different kinds of elements that can be exported from a WebAssembly module, @@ -22,17 +25,19 @@ pub enum ExportKind { Memory, Global, Tag, - Module, - Instance, Type, } impl<'a> Parse<'a> for Export<'a> { fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let (kind, item) = parser.parens(|p| Ok((p.parse()?, p.parse()?)))?; Ok(Export { - span: parser.parse::()?.0, - name: parser.parse()?, - index: parser.parse()?, + span, + name, + kind, + item, }) } } @@ -55,12 +60,6 @@ impl<'a> Parse<'a> for ExportKind { } else if l.peek::() { parser.parse::()?; Ok(ExportKind::Tag) - } else if l.peek::() { - parser.parse::()?; - Ok(ExportKind::Module) - } else if l.peek::() { - parser.parse::()?; - Ok(ExportKind::Instance) } else if l.peek::() { parser.parse::()?; Ok(ExportKind::Type) @@ -70,6 +69,20 @@ impl<'a> Parse<'a> for ExportKind { } } +impl Peek for ExportKind { + fn peek(cursor: Cursor<'_>) -> bool { + kw::func::peek(cursor) + || kw::table::peek(cursor) + || kw::memory::peek(cursor) + || kw::global::peek(cursor) + || kw::tag::peek(cursor) + || kw::r#type::peek(cursor) + } + fn display() -> &'static str { + "export kind" + } +} + macro_rules! kw_conversions { ($($kw:ident => $kind:ident)*) => ($( impl From for ExportKind { @@ -80,15 +93,13 @@ macro_rules! kw_conversions { impl Default for kw::$kw { fn default() -> kw::$kw { - kw::$kw(ast::Span::from_offset(0)) + kw::$kw(Span::from_offset(0)) } } )*); } kw_conversions! { - instance => Instance - module => Module func => Func table => Table global => Global @@ -99,7 +110,7 @@ kw_conversions! { /// A listing of inline `(export "foo")` statements on a WebAssembly item in /// its textual format. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct InlineExport<'a> { /// The extra names to export an item as, if any. pub names: Vec<&'a str>, diff --git a/third_party/rust/wast/src/ast/expr.rs b/third_party/rust/wast/src/core/expr.rs similarity index 89% rename from third_party/rust/wast/src/ast/expr.rs rename to third_party/rust/wast/src/core/expr.rs index c062dcda7bee..0f1ee8a2ead4 100644 --- a/third_party/rust/wast/src/ast/expr.rs +++ b/third_party/rust/wast/src/core/expr.rs @@ -1,5 +1,8 @@ -use crate::ast::{self, kw, HeapType}; +use crate::core::*; +use crate::encode::Encode; +use crate::kw; use crate::parser::{Cursor, Parse, Parser, Result}; +use crate::token::*; use std::mem; /// An expression, or a list of instructions, in the WebAssembly text format. @@ -114,7 +117,7 @@ impl<'a> ExpressionParser<'a> { // of an `if block then we require that all sub-components are // s-expressions surrounded by `(` and `)`, so verify that here. if let Some(Level::If(_)) | Some(Level::Try(_)) = self.stack.last() { - if !parser.is_empty() && !parser.peek::() { + if !parser.is_empty() && !parser.peek::() { return Err(parser.error("expected `(`")); } } @@ -346,7 +349,7 @@ impl<'a> ExpressionParser<'a> { if let Try::CatchOrDelegate = i { // `catch` may be followed by more `catch`s or `catch_all`. if parser.parse::>()?.is_some() { - let evt = parser.parse::>()?; + let evt = parser.parse::>()?; self.instrs.push(Instruction::Catch(evt)); *i = Try::Catch; self.stack.push(Level::TryArm); @@ -361,7 +364,7 @@ impl<'a> ExpressionParser<'a> { } // `delegate` has an index, and also ends the block like `end`. if parser.parse::>()?.is_some() { - let depth = parser.parse::>()?; + let depth = parser.parse::>()?; self.instrs.push(Instruction::Delegate(depth)); *i = Try::Delegate; match self.paren(parser)? { @@ -374,7 +377,7 @@ impl<'a> ExpressionParser<'a> { if let Try::Catch = i { if parser.parse::>()?.is_some() { - let evt = parser.parse::>()?; + let evt = parser.parse::>()?; self.instrs.push(Instruction::Catch(evt)); *i = Try::Catch; self.stack.push(Level::TryArm); @@ -436,17 +439,17 @@ macro_rules! instructions { } } - impl crate::binary::Encode for Instruction<'_> { + impl Encode for Instruction<'_> { #[allow(non_snake_case)] fn encode(&self, v: &mut Vec) { match self { $( - Instruction::$name $((instructions!(@first $($arg)*)))? => { + Instruction::$name $((instructions!(@first x $($arg)*)))? => { fn encode<'a>($(arg: &instructions!(@ty $($arg)*),)? v: &mut Vec) { instructions!(@encode v $($binary)*); - $(::encode(arg, v);)? + $(::encode(arg, v);)? } - encode($( instructions!(@first $($arg)*), )? v) + encode($( instructions!(@first x $($arg)*), )? v) } )* } @@ -484,7 +487,7 @@ macro_rules! instructions { // simd opcodes prefixed with `0xfd` get a varuint32 encoding for their payload (@encode $dst:ident 0xfd, $simd:tt) => ({ $dst.push(0xfd); - ::encode(&$simd, $dst); + ::encode(&$simd, $dst); }); (@encode $dst:ident $($bytes:tt)*) => ($dst.extend_from_slice(&[$($bytes)*]);); @@ -501,21 +504,21 @@ instructions! { pub enum Instruction<'a> { Block(BlockType<'a>) : [0x02] : "block", If(BlockType<'a>) : [0x04] : "if", - Else(Option>) : [0x05] : "else", + Else(Option>) : [0x05] : "else", Loop(BlockType<'a>) : [0x03] : "loop", - End(Option>) : [0x0b] : "end", + End(Option>) : [0x0b] : "end", Unreachable : [0x00] : "unreachable", Nop : [0x01] : "nop", - Br(ast::Index<'a>) : [0x0c] : "br", - BrIf(ast::Index<'a>) : [0x0d] : "br_if", + Br(Index<'a>) : [0x0c] : "br", + BrIf(Index<'a>) : [0x0d] : "br_if", BrTable(BrTableIndices<'a>) : [0x0e] : "br_table", Return : [0x0f] : "return", - Call(ast::IndexOrRef<'a, kw::func>) : [0x10] : "call", + Call(Index<'a>) : [0x10] : "call", CallIndirect(CallIndirect<'a>) : [0x11] : "call_indirect", // tail-call proposal - ReturnCall(ast::IndexOrRef<'a, kw::func>) : [0x12] : "return_call", + ReturnCall(Index<'a>) : [0x12] : "return_call", ReturnCallIndirect(CallIndirect<'a>) : [0x13] : "return_call_indirect", // function-references proposal @@ -526,11 +529,11 @@ instructions! { Drop : [0x1a] : "drop", Select(SelectTypes<'a>) : [] : "select", - LocalGet(ast::Index<'a>) : [0x20] : "local.get" | "get_local", - LocalSet(ast::Index<'a>) : [0x21] : "local.set" | "set_local", - LocalTee(ast::Index<'a>) : [0x22] : "local.tee" | "tee_local", - GlobalGet(ast::IndexOrRef<'a, kw::global>) : [0x23] : "global.get" | "get_global", - GlobalSet(ast::IndexOrRef<'a, kw::global>) : [0x24] : "global.set" | "set_global", + LocalGet(Index<'a>) : [0x20] : "local.get" | "get_local", + LocalSet(Index<'a>) : [0x21] : "local.set" | "set_local", + LocalTee(Index<'a>) : [0x22] : "local.tee" | "tee_local", + GlobalGet(Index<'a>) : [0x23] : "global.get" | "get_global", + GlobalSet(Index<'a>) : [0x24] : "global.set" | "set_global", TableGet(TableArg<'a>) : [0x25] : "table.get", TableSet(TableArg<'a>) : [0x26] : "table.set", @@ -565,8 +568,8 @@ instructions! { MemoryInit(MemoryInit<'a>) : [0xfc, 0x08] : "memory.init", MemoryCopy(MemoryCopy<'a>) : [0xfc, 0x0a] : "memory.copy", MemoryFill(MemoryArg<'a>) : [0xfc, 0x0b] : "memory.fill", - DataDrop(ast::Index<'a>) : [0xfc, 0x09] : "data.drop", - ElemDrop(ast::Index<'a>) : [0xfc, 0x0d] : "elem.drop", + DataDrop(Index<'a>) : [0xfc, 0x09] : "data.drop", + ElemDrop(Index<'a>) : [0xfc, 0x0d] : "elem.drop", TableInit(TableInit<'a>) : [0xfc, 0x0c] : "table.init", TableCopy(TableCopy<'a>) : [0xfc, 0x0e] : "table.copy", TableFill(TableArg<'a>) : [0xfc, 0x11] : "table.fill", @@ -576,35 +579,35 @@ instructions! { RefNull(HeapType<'a>) : [0xd0] : "ref.null", RefIsNull : [0xd1] : "ref.is_null", RefExtern(u32) : [0xff] : "ref.extern", // only used in test harness - RefFunc(ast::IndexOrRef<'a, kw::func>) : [0xd2] : "ref.func", + RefFunc(Index<'a>) : [0xd2] : "ref.func", // function-references proposal RefAsNonNull : [0xd3] : "ref.as_non_null", - BrOnNull(ast::Index<'a>) : [0xd4] : "br_on_null", - BrOnNonNull(ast::Index<'a>) : [0xd6] : "br_on_non_null", + BrOnNull(Index<'a>) : [0xd4] : "br_on_null", + BrOnNonNull(Index<'a>) : [0xd6] : "br_on_non_null", // gc proposal: eqref RefEq : [0xd5] : "ref.eq", // gc proposal (moz specific, will be removed) - StructNew(ast::Index<'a>) : [0xfb, 0x0] : "struct.new", + StructNew(Index<'a>) : [0xfb, 0x0] : "struct.new", // gc proposal: struct - StructNewWithRtt(ast::Index<'a>) : [0xfb, 0x01] : "struct.new_with_rtt", - StructNewDefaultWithRtt(ast::Index<'a>) : [0xfb, 0x02] : "struct.new_default_with_rtt", + StructNewWithRtt(Index<'a>) : [0xfb, 0x01] : "struct.new_with_rtt", + StructNewDefaultWithRtt(Index<'a>) : [0xfb, 0x02] : "struct.new_default_with_rtt", StructGet(StructAccess<'a>) : [0xfb, 0x03] : "struct.get", StructGetS(StructAccess<'a>) : [0xfb, 0x04] : "struct.get_s", StructGetU(StructAccess<'a>) : [0xfb, 0x05] : "struct.get_u", StructSet(StructAccess<'a>) : [0xfb, 0x06] : "struct.set", // gc proposal: array - ArrayNewWithRtt(ast::Index<'a>) : [0xfb, 0x11] : "array.new_with_rtt", - ArrayNewDefaultWithRtt(ast::Index<'a>) : [0xfb, 0x12] : "array.new_default_with_rtt", - ArrayGet(ast::Index<'a>) : [0xfb, 0x13] : "array.get", - ArrayGetS(ast::Index<'a>) : [0xfb, 0x14] : "array.get_s", - ArrayGetU(ast::Index<'a>) : [0xfb, 0x15] : "array.get_u", - ArraySet(ast::Index<'a>) : [0xfb, 0x16] : "array.set", - ArrayLen(ast::Index<'a>) : [0xfb, 0x17] : "array.len", + ArrayNewWithRtt(Index<'a>) : [0xfb, 0x11] : "array.new_with_rtt", + ArrayNewDefaultWithRtt(Index<'a>) : [0xfb, 0x12] : "array.new_default_with_rtt", + ArrayGet(Index<'a>) : [0xfb, 0x13] : "array.get", + ArrayGetS(Index<'a>) : [0xfb, 0x14] : "array.get_s", + ArrayGetU(Index<'a>) : [0xfb, 0x15] : "array.get_u", + ArraySet(Index<'a>) : [0xfb, 0x16] : "array.set", + ArrayLen(Index<'a>) : [0xfb, 0x17] : "array.len", // gc proposal, i31 I31New : [0xfb, 0x20] : "i31.new", @@ -612,11 +615,11 @@ instructions! { I31GetU : [0xfb, 0x22] : "i31.get_u", // gc proposal, rtt casting - RTTCanon(ast::Index<'a>) : [0xfb, 0x30] : "rtt.canon", - RTTSub(ast::Index<'a>) : [0xfb, 0x31] : "rtt.sub", + RTTCanon(Index<'a>) : [0xfb, 0x30] : "rtt.canon", + RTTSub(Index<'a>) : [0xfb, 0x31] : "rtt.sub", RefTest : [0xfb, 0x40] : "ref.test", RefCast : [0xfb, 0x41] : "ref.cast", - BrOnCast(ast::Index<'a>) : [0xfb, 0x42] : "br_on_cast", + BrOnCast(Index<'a>) : [0xfb, 0x42] : "br_on_cast", // gc proposal, heap casting RefIsFunc : [0xfb, 0x50] : "ref.is_func", @@ -625,14 +628,14 @@ instructions! { RefAsFunc : [0xfb, 0x58] : "ref.as_func", RefAsData : [0xfb, 0x59] : "ref.as_data", RefAsI31 : [0xfb, 0x5a] : "ref.as_i31", - BrOnFunc(ast::Index<'a>) : [0xfb, 0x60] : "br_on_func", - BrOnData(ast::Index<'a>) : [0xfb, 0x61] : "br_on_data", - BrOnI31(ast::Index<'a>) : [0xfb, 0x62] : "br_on_i31", + BrOnFunc(Index<'a>) : [0xfb, 0x60] : "br_on_func", + BrOnData(Index<'a>) : [0xfb, 0x61] : "br_on_data", + BrOnI31(Index<'a>) : [0xfb, 0x62] : "br_on_i31", I32Const(i32) : [0x41] : "i32.const", I64Const(i64) : [0x42] : "i64.const", - F32Const(ast::Float32) : [0x43] : "f32.const", - F64Const(ast::Float64) : [0x44] : "f64.const", + F32Const(Float32) : [0x43] : "f32.const", + F64Const(Float64) : [0x44] : "f64.const", I32Clz : [0x67] : "i32.clz", I32Ctz : [0x68] : "i32.ctz", @@ -1120,30 +1123,30 @@ instructions! { // Exception handling proposal Try(BlockType<'a>) : [0x06] : "try", - Catch(ast::Index<'a>) : [0x07] : "catch", - Throw(ast::Index<'a>) : [0x08] : "throw", - Rethrow(ast::Index<'a>) : [0x09] : "rethrow", - Delegate(ast::Index<'a>) : [0x18] : "delegate", + Catch(Index<'a>) : [0x07] : "catch", + Throw(Index<'a>) : [0x08] : "throw", + Rethrow(Index<'a>) : [0x09] : "rethrow", + Delegate(Index<'a>) : [0x18] : "delegate", CatchAll : [0x19] : "catch_all", // Relaxed SIMD proposal - I8x16SwizzleRelaxed : [0xfd, 0xa2]: "i8x16.swizzle_relaxed", - I32x4TruncSatF32x4SRelaxed : [0xfd, 0xa5]: "i32x4.trunc_f32x4_s_relaxed", - I32x4TruncSatF32x4URelaxed : [0xfd, 0xa6]: "i32x4.trunc_f32x4_u_relaxed", - I32x4TruncSatF64x2SZeroRelaxed : [0xfd, 0xc5]: "i32x4.trunc_f64x2_s_zero_relaxed", - I32x4TruncSatF64x2UZeroRelaxed : [0xfd, 0xc6]: "i32x4.trunc_f64x2_u_zero_relaxed", - F32x4FmaRelaxed : [0xfd, 0xaf]: "f32x4.fma_relaxed", - F32x4FmsRelaxed : [0xfd, 0xb0]: "f32x4.fms_relaxed", - F64x4FmaRelaxed : [0xfd, 0xcf]: "f64x2.fma_relaxed", - F64x4FmsRelaxed : [0xfd, 0xd0]: "f64x2.fms_relaxed", + I8x16RelaxedSwizzle : [0xfd, 0xa2]: "i8x16.relaxed_swizzle", + I32x4RelaxedTruncSatF32x4S : [0xfd, 0xa5]: "i32x4.relaxed_trunc_f32x4_s", + I32x4RelaxedTruncSatF32x4U : [0xfd, 0xa6]: "i32x4.relaxed_trunc_f32x4_u", + I32x4RelaxedTruncSatF64x2SZero : [0xfd, 0xc5]: "i32x4.relaxed_trunc_f64x2_s_zero", + I32x4RelaxedTruncSatF64x2UZero : [0xfd, 0xc6]: "i32x4.relaxed_trunc_f64x2_u_zero", + F32x4Fma : [0xfd, 0xaf]: "f32x4.fma", + F32x4Fms : [0xfd, 0xb0]: "f32x4.fms", + F64x4Fma : [0xfd, 0xcf]: "f64x2.fma", + F64x4Fms : [0xfd, 0xd0]: "f64x2.fms", I8x16LaneSelect : [0xfd, 0xb2]: "i8x16.laneselect", I16x8LaneSelect : [0xfd, 0xb3]: "i16x8.laneselect", I32x4LaneSelect : [0xfd, 0xd2]: "i32x4.laneselect", I64x2LaneSelect : [0xfd, 0xd3]: "i64x2.laneselect", - F32x4MinRelaxed : [0xfd, 0xb4]: "f32x4.min_relaxed", - F32x4MaxRelaxed : [0xfd, 0xe2]: "f32x4.max_relaxed", - F64x2MinRelaxed : [0xfd, 0xd4]: "f64x2.min_relaxed", - F64x2MaxRelaxed : [0xfd, 0xee]: "f64x2.max_relaxed", + F32x4RelaxedMin : [0xfd, 0xb4]: "f32x4.relaxed_min", + F32x4RelaxedMax : [0xfd, 0xe2]: "f32x4.relaxed_max", + F64x2RelaxedMin : [0xfd, 0xd4]: "f64x2.relaxed_min", + F64x2RelaxedMax : [0xfd, 0xee]: "f64x2.relaxed_max", } } @@ -1154,9 +1157,9 @@ instructions! { #[derive(Debug)] #[allow(missing_docs)] pub struct BlockType<'a> { - pub label: Option>, - pub label_name: Option>, - pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>, + pub label: Option>, + pub label_name: Option>, + pub ty: TypeUse<'a, FunctionType<'a>>, } impl<'a> Parse<'a> for BlockType<'a> { @@ -1165,7 +1168,7 @@ impl<'a> Parse<'a> for BlockType<'a> { label: parser.parse()?, label_name: parser.parse()?, ty: parser - .parse::>>()? + .parse::>>()? .into(), }) } @@ -1175,14 +1178,14 @@ impl<'a> Parse<'a> for BlockType<'a> { #[derive(Debug)] #[allow(missing_docs)] pub struct FuncBindType<'a> { - pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>, + pub ty: TypeUse<'a, FunctionType<'a>>, } impl<'a> Parse<'a> for FuncBindType<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(FuncBindType { ty: parser - .parse::>>()? + .parse::>>()? .into(), }) } @@ -1193,14 +1196,14 @@ impl<'a> Parse<'a> for FuncBindType<'a> { #[allow(missing_docs)] pub struct LetType<'a> { pub block: BlockType<'a>, - pub locals: Vec>, + pub locals: Vec>, } impl<'a> Parse<'a> for LetType<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(LetType { block: parser.parse()?, - locals: ast::Local::parse_remainder(parser)?, + locals: Local::parse_remainder(parser)?, }) } } @@ -1209,15 +1212,15 @@ impl<'a> Parse<'a> for LetType<'a> { #[allow(missing_docs)] #[derive(Debug)] pub struct BrTableIndices<'a> { - pub labels: Vec>, - pub default: ast::Index<'a>, + pub labels: Vec>, + pub default: Index<'a>, } impl<'a> Parse<'a> for BrTableIndices<'a> { fn parse(parser: Parser<'a>) -> Result { let mut labels = Vec::new(); labels.push(parser.parse()?); - while parser.peek::() { + while parser.peek::() { labels.push(parser.parse()?); } let default = labels.pop().unwrap(); @@ -1264,7 +1267,7 @@ pub struct MemArg<'a> { /// The offset, in bytes of this access. pub offset: u64, /// The memory index we're accessing - pub memory: ast::ItemRef<'a, kw::memory>, + pub memory: Index<'a>, } impl<'a> MemArg<'a> { @@ -1287,8 +1290,8 @@ impl<'a> MemArg<'a> { return Ok((None, c)); } let num = &kw[1..]; - let num = if num.starts_with("0x") { - f(c, &num[2..], 16)? + let num = if let Some(stripped) = num.strip_prefix("0x") { + f(c, stripped, 16)? } else { f(c, num, 10)? }; @@ -1310,9 +1313,8 @@ impl<'a> MemArg<'a> { } let memory = parser - .parse::>>()? - .map(|i| i.0) - .unwrap_or(idx_zero(parser.prev_span(), kw::memory)); + .parse::>()? + .unwrap_or(Index::Num(0, parser.prev_span())); let offset = parse_u64("offset", parser)?.unwrap_or(0); let align = match parse_u32("align", parser)? { Some(n) if !n.is_power_of_two() => { @@ -1329,16 +1331,6 @@ impl<'a> MemArg<'a> { } } -fn idx_zero(span: ast::Span, mk_kind: fn(ast::Span) -> T) -> ast::ItemRef<'static, T> { - ast::ItemRef::Item { - kind: mk_kind(span), - idx: ast::Index::Num(0, span), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: false, - } -} - /// Extra data associated with the `loadN_lane` and `storeN_lane` instructions. #[derive(Debug)] pub struct LoadOrStoreLane<'a> { @@ -1385,7 +1377,7 @@ impl<'a> LoadOrStoreLane<'a> { MemArg { align: default_align, offset: 0, - memory: idx_zero(parser.prev_span(), kw::memory), + memory: Index::Num(0, parser.prev_span()), } }, lane: LaneArg::parse(parser)?, @@ -1397,24 +1389,18 @@ impl<'a> LoadOrStoreLane<'a> { #[derive(Debug)] pub struct CallIndirect<'a> { /// The table that this call is going to be indexing. - pub table: ast::ItemRef<'a, kw::table>, + pub table: Index<'a>, /// Type type signature that this `call_indirect` instruction is using. - pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>, + pub ty: TypeUse<'a, FunctionType<'a>>, } impl<'a> Parse<'a> for CallIndirect<'a> { fn parse(parser: Parser<'a>) -> Result { let prev_span = parser.prev_span(); - let mut table: Option> = parser.parse()?; - let ty = parser.parse::>>()?; - // Turns out the official test suite at this time thinks table - // identifiers comes first but wabt's test suites asserts differently - // putting them second. Let's just handle both. - if table.is_none() { - table = parser.parse()?; - } + let table: Option<_> = parser.parse()?; + let ty = parser.parse::>>()?; Ok(CallIndirect { - table: table.map(|i| i.0).unwrap_or(idx_zero(prev_span, kw::table)), + table: table.unwrap_or(Index::Num(0, prev_span)), ty: ty.into(), }) } @@ -1424,21 +1410,20 @@ impl<'a> Parse<'a> for CallIndirect<'a> { #[derive(Debug)] pub struct TableInit<'a> { /// The index of the table we're copying into. - pub table: ast::ItemRef<'a, kw::table>, + pub table: Index<'a>, /// The index of the element segment we're copying into a table. - pub elem: ast::Index<'a>, + pub elem: Index<'a>, } impl<'a> Parse<'a> for TableInit<'a> { fn parse(parser: Parser<'a>) -> Result { let prev_span = parser.prev_span(); - let (elem, table) = - if parser.peek::>() || parser.peek2::() { - let table = parser.parse::>()?.0; - (parser.parse()?, table) - } else { - (parser.parse()?, idx_zero(prev_span, kw::table)) - }; + let (elem, table) = if parser.peek2::() { + let table = parser.parse()?; + (parser.parse()?, table) + } else { + (parser.parse()?, Index::Num(0, prev_span)) + }; Ok(TableInit { table, elem }) } } @@ -1447,18 +1432,18 @@ impl<'a> Parse<'a> for TableInit<'a> { #[derive(Debug)] pub struct TableCopy<'a> { /// The index of the destination table to copy into. - pub dst: ast::ItemRef<'a, kw::table>, + pub dst: Index<'a>, /// The index of the source table to copy from. - pub src: ast::ItemRef<'a, kw::table>, + pub src: Index<'a>, } impl<'a> Parse<'a> for TableCopy<'a> { fn parse(parser: Parser<'a>) -> Result { - let (dst, src) = match parser.parse::>>()? { - Some(dst) => (dst.0, parser.parse::>()?.0), + let (dst, src) = match parser.parse::>()? { + Some(dst) => (dst, parser.parse()?), None => ( - idx_zero(parser.prev_span(), kw::table), - idx_zero(parser.prev_span(), kw::table), + Index::Num(0, parser.prev_span()), + Index::Num(0, parser.prev_span()), ), }; Ok(TableCopy { dst, src }) @@ -1469,15 +1454,15 @@ impl<'a> Parse<'a> for TableCopy<'a> { #[derive(Debug)] pub struct TableArg<'a> { /// The index of the table argument. - pub dst: ast::ItemRef<'a, kw::table>, + pub dst: Index<'a>, } impl<'a> Parse<'a> for TableArg<'a> { fn parse(parser: Parser<'a>) -> Result { - let dst = if let Some(dst) = parser.parse::>>()? { - dst.0 + let dst = if let Some(dst) = parser.parse()? { + dst } else { - idx_zero(parser.prev_span(), kw::table) + Index::Num(0, parser.prev_span()) }; Ok(TableArg { dst }) } @@ -1487,15 +1472,15 @@ impl<'a> Parse<'a> for TableArg<'a> { #[derive(Debug)] pub struct MemoryArg<'a> { /// The index of the memory space. - pub mem: ast::ItemRef<'a, kw::memory>, + pub mem: Index<'a>, } impl<'a> Parse<'a> for MemoryArg<'a> { fn parse(parser: Parser<'a>) -> Result { - let mem = if let Some(mem) = parser.parse::>>()? { - mem.0 + let mem = if let Some(mem) = parser.parse()? { + mem } else { - idx_zero(parser.prev_span(), kw::memory) + Index::Num(0, parser.prev_span()) }; Ok(MemoryArg { mem }) } @@ -1505,21 +1490,20 @@ impl<'a> Parse<'a> for MemoryArg<'a> { #[derive(Debug)] pub struct MemoryInit<'a> { /// The index of the data segment we're copying into memory. - pub data: ast::Index<'a>, + pub data: Index<'a>, /// The index of the memory we're copying into, - pub mem: ast::ItemRef<'a, kw::memory>, + pub mem: Index<'a>, } impl<'a> Parse<'a> for MemoryInit<'a> { fn parse(parser: Parser<'a>) -> Result { let prev_span = parser.prev_span(); - let (data, mem) = - if parser.peek::>() || parser.peek2::() { - let memory = parser.parse::>()?.0; - (parser.parse()?, memory) - } else { - (parser.parse()?, idx_zero(prev_span, kw::memory)) - }; + let (data, mem) = if parser.peek2::() { + let memory = parser.parse()?; + (parser.parse()?, memory) + } else { + (parser.parse()?, Index::Num(0, prev_span)) + }; Ok(MemoryInit { data, mem }) } } @@ -1528,18 +1512,18 @@ impl<'a> Parse<'a> for MemoryInit<'a> { #[derive(Debug)] pub struct MemoryCopy<'a> { /// The index of the memory we're copying from. - pub src: ast::ItemRef<'a, kw::memory>, + pub src: Index<'a>, /// The index of the memory we're copying to. - pub dst: ast::ItemRef<'a, kw::memory>, + pub dst: Index<'a>, } impl<'a> Parse<'a> for MemoryCopy<'a> { fn parse(parser: Parser<'a>) -> Result { - let (src, dst) = match parser.parse::>>()? { - Some(dst) => (parser.parse::>()?.0, dst.0), + let (src, dst) = match parser.parse()? { + Some(dst) => (parser.parse()?, dst), None => ( - idx_zero(parser.prev_span(), kw::memory), - idx_zero(parser.prev_span(), kw::memory), + Index::Num(0, parser.prev_span()), + Index::Num(0, parser.prev_span()), ), }; Ok(MemoryCopy { src, dst }) @@ -1550,9 +1534,9 @@ impl<'a> Parse<'a> for MemoryCopy<'a> { #[derive(Debug)] pub struct StructAccess<'a> { /// The index of the struct type we're accessing. - pub r#struct: ast::Index<'a>, + pub r#struct: Index<'a>, /// The index of the field of the struct we're accessing - pub field: ast::Index<'a>, + pub field: Index<'a>, } impl<'a> Parse<'a> for StructAccess<'a> { @@ -1573,8 +1557,8 @@ pub enum V128Const { I16x8([i16; 8]), I32x4([i32; 4]), I64x2([i64; 2]), - F32x4([ast::Float32; 4]), - F64x2([ast::Float64; 2]), + F32x4([Float32; 4]), + F64x2([Float64; 2]), } impl V128Const { @@ -1767,7 +1751,7 @@ impl<'a> Parse<'a> for I8x16Shuffle { #[derive(Debug)] pub struct SelectTypes<'a> { #[allow(missing_docs)] - pub tys: Option>>, + pub tys: Option>>, } impl<'a> Parse<'a> for SelectTypes<'a> { diff --git a/third_party/rust/wast/src/ast/func.rs b/third_party/rust/wast/src/core/func.rs similarity index 84% rename from third_party/rust/wast/src/ast/func.rs rename to third_party/rust/wast/src/core/func.rs index 6bc610555227..84abdf857857 100644 --- a/third_party/rust/wast/src/ast/func.rs +++ b/third_party/rust/wast/src/core/func.rs @@ -1,5 +1,7 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; /// A WebAssembly function to be inserted into a module. /// @@ -7,20 +9,20 @@ use crate::parser::{Parse, Parser, Result}; #[derive(Debug)] pub struct Func<'a> { /// Where this `func` was defined. - pub span: ast::Span, + pub span: Span, /// An identifier that this function is resolved with (optionally) for name /// resolution. - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: ast::InlineExport<'a>, + pub exports: InlineExport<'a>, /// What kind of function this is, be it an inline-defined or imported /// function. pub kind: FuncKind<'a>, /// The type that this function will have. - pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>, + pub ty: TypeUse<'a, FunctionType<'a>>, } /// Possible ways to define a function in the text format. @@ -31,7 +33,7 @@ pub enum FuncKind<'a> { /// ```text /// (func (type 3) (import "foo" "bar")) /// ``` - Import(ast::InlineImport<'a>), + Import(InlineImport<'a>), /// Almost all functions, those defined inline in a wasm module. Inline { @@ -39,7 +41,7 @@ pub enum FuncKind<'a> { locals: Vec>, /// The instructions of the function. - expression: ast::Expression<'a>, + expression: Expression<'a>, }, } @@ -83,11 +85,11 @@ impl<'a> Parse<'a> for Func<'a> { pub struct Local<'a> { /// An identifier that this local is resolved with (optionally) for name /// resolution. - pub id: Option>, + pub id: Option>, /// An optional name for this local stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// The value type of this local. - pub ty: ast::ValType<'a>, + pub ty: ValType<'a>, } impl<'a> Local<'a> { @@ -105,7 +107,11 @@ impl<'a> Local<'a> { let parse_more = id.is_none() && name.is_none(); locals.push(Local { id, name, ty }); while parse_more && !p.is_empty() { - locals.push(Local { id: None, name: None, ty: p.parse()? }); + locals.push(Local { + id: None, + name: None, + ty: p.parse()?, + }); } Ok(()) })?; diff --git a/third_party/rust/wast/src/ast/global.rs b/third_party/rust/wast/src/core/global.rs similarity index 83% rename from third_party/rust/wast/src/ast/global.rs rename to third_party/rust/wast/src/core/global.rs index b15ca521395c..b8ce287fd848 100644 --- a/third_party/rust/wast/src/ast/global.rs +++ b/third_party/rust/wast/src/core/global.rs @@ -1,20 +1,22 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; /// A WebAssembly global in a module #[derive(Debug)] pub struct Global<'a> { /// Where this `global` was defined. - pub span: ast::Span, + pub span: Span, /// An optional name to reference this global by - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: ast::InlineExport<'a>, + pub exports: InlineExport<'a>, /// The type of this global, both its value type and whether it's mutable. - pub ty: ast::GlobalType<'a>, + pub ty: GlobalType<'a>, /// What kind of global this defined as. pub kind: GlobalKind<'a>, } @@ -27,10 +29,10 @@ pub enum GlobalKind<'a> { /// ```text /// (global i32 (import "foo" "bar")) /// ``` - Import(ast::InlineImport<'a>), + Import(InlineImport<'a>), /// A global defined inline in the module itself - Inline(ast::Expression<'a>), + Inline(Expression<'a>), } impl<'a> Parse<'a> for Global<'a> { diff --git a/third_party/rust/wast/src/ast/import.rs b/third_party/rust/wast/src/core/import.rs similarity index 79% rename from third_party/rust/wast/src/ast/import.rs rename to third_party/rust/wast/src/core/import.rs index b13cf0a5bdfc..e44057f72fe7 100644 --- a/third_party/rust/wast/src/ast/import.rs +++ b/third_party/rust/wast/src/core/import.rs @@ -1,15 +1,17 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::{Id, NameAnnotation, Span}; /// An `import` statement and entry in a WebAssembly module. #[derive(Debug, Clone)] pub struct Import<'a> { /// Where this `import` was defined - pub span: ast::Span, + pub span: Span, /// The module that this statement is importing from pub module: &'a str, /// The name of the field in the module this statement imports from. - pub field: Option<&'a str>, + pub field: &'a str, /// The item that's being imported. pub item: ItemSig<'a>, } @@ -33,13 +35,13 @@ impl<'a> Parse<'a> for Import<'a> { #[allow(missing_docs)] pub struct ItemSig<'a> { /// Where this item is defined in the source. - pub span: ast::Span, + pub span: Span, /// An optional identifier used during name resolution to refer to this item /// from the rest of the module. - pub id: Option>, + pub id: Option>, /// An optional name which, for functions, will be stored in the /// custom `name` section. - pub name: Option>, + pub name: Option>, /// What kind of item this is. pub kind: ItemKind<'a>, } @@ -47,13 +49,11 @@ pub struct ItemSig<'a> { #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum ItemKind<'a> { - Func(ast::TypeUse<'a, ast::FunctionType<'a>>), - Table(ast::TableType<'a>), - Memory(ast::MemoryType), - Global(ast::GlobalType<'a>), - Tag(ast::TagType<'a>), - Module(ast::TypeUse<'a, ast::ModuleType<'a>>), - Instance(ast::TypeUse<'a, ast::InstanceType<'a>>), + Func(TypeUse<'a, FunctionType<'a>>), + Table(TableType<'a>), + Memory(MemoryType), + Global(GlobalType<'a>), + Tag(TagType<'a>), } impl<'a> Parse<'a> for ItemSig<'a> { @@ -99,22 +99,6 @@ impl<'a> Parse<'a> for ItemSig<'a> { name: None, kind: ItemKind::Tag(parser.parse()?), }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(ItemSig { - span, - id: parser.parse()?, - name: None, - kind: ItemKind::Module(parser.parse()?), - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(ItemSig { - span, - id: parser.parse()?, - name: None, - kind: ItemKind::Instance(parser.parse()?), - }) } else { Err(l.error()) } @@ -131,7 +115,7 @@ impl<'a> Parse<'a> for ItemSig<'a> { #[allow(missing_docs)] pub struct InlineImport<'a> { pub module: &'a str, - pub field: Option<&'a str>, + pub field: &'a str, } impl<'a> Parse<'a> for InlineImport<'a> { @@ -160,11 +144,9 @@ impl Peek for InlineImport<'_> { Some((_, cursor)) => cursor, None => return false, }; - - // optional field let cursor = match cursor.string() { Some((_, cursor)) => cursor, - None => cursor, + None => return false, }; cursor.rparen().is_some() diff --git a/third_party/rust/wast/src/ast/memory.rs b/third_party/rust/wast/src/core/memory.rs similarity index 80% rename from third_party/rust/wast/src/ast/memory.rs rename to third_party/rust/wast/src/core/memory.rs index adc5bded6ab5..20baf28a3cf7 100644 --- a/third_party/rust/wast/src/ast/memory.rs +++ b/third_party/rust/wast/src/core/memory.rs @@ -1,18 +1,20 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Lookahead1, Parse, Parser, Peek, Result}; +use crate::token::*; /// A defined WebAssembly memory instance inside of a module. #[derive(Debug)] pub struct Memory<'a> { /// Where this `memory` was defined - pub span: ast::Span, + pub span: Span, /// An optional name to refer to this memory by. - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: ast::InlineExport<'a>, + pub exports: InlineExport<'a>, /// How this memory is defined in the module. pub kind: MemoryKind<'a>, } @@ -23,12 +25,12 @@ pub enum MemoryKind<'a> { /// This memory is actually an inlined import definition. #[allow(missing_docs)] Import { - import: ast::InlineImport<'a>, - ty: ast::MemoryType, + import: InlineImport<'a>, + ty: MemoryType, }, /// A typical memory definition which simply says the limits of the memory - Normal(ast::MemoryType), + Normal(MemoryType), /// The data of this memory, starting from 0, explicitly listed Inline { @@ -57,7 +59,7 @@ impl<'a> Parse<'a> for Memory<'a> { import, ty: parser.parse()?, } - } else if l.peek::() || parser.peek2::() { + } else if l.peek::() || parser.peek2::() { let is_32 = if parser.parse::>()?.is_some() { true } else if parser.parse::>()?.is_some() { @@ -93,13 +95,13 @@ impl<'a> Parse<'a> for Memory<'a> { #[derive(Debug)] pub struct Data<'a> { /// Where this `data` was defined - pub span: ast::Span, + pub span: Span, /// The optional name of this data segment - pub id: Option>, + pub id: Option>, /// An optional name for this data stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// Whether this data segment is passive or active pub kind: DataKind<'a>, @@ -120,10 +122,10 @@ pub enum DataKind<'a> { /// memory on module instantiation. Active { /// The memory that this `Data` will be associated with. - memory: ast::ItemRef<'a, kw::memory>, + memory: Index<'a>, /// Initial offset to load this data segment at - offset: ast::Expression<'a>, + offset: Expression<'a>, }, } @@ -133,29 +135,25 @@ impl<'a> Parse<'a> for Data<'a> { let id = parser.parse()?; let name = parser.parse()?; - // The `passive` keyword is mentioned in the current spec but isn't - // mentioned in `wabt` tests, so consider it optional for now - let kind = if parser.peek::() { - parser.parse::()?; - DataKind::Passive - - // If data directly follows then assume this is a passive segment - } else if parser.peek::<&[u8]>() { + let kind = if parser.peek::<&[u8]>() { DataKind::Passive // ... and otherwise we must be attached to a particular memory as well // as having an initialization offset. } else { - let memory = if let Some(index) = parser.parse::>>()? { - index.0 + let memory = if parser.peek::() { + // FIXME: this is only here to accomodate + // proposals/threads/imports.wast at this current moment in + // time, this probably should get removed when the threads + // proposal is rebased on the current spec. + Index::Num(parser.parse()?, span) + } else if parser.peek2::() { + parser.parens(|p| { + p.parse::()?; + p.parse() + })? } else { - ast::ItemRef::Item { - kind: kw::memory(parser.prev_span()), - idx: ast::Index::Num(0, span), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: false, - } + Index::Num(0, span) }; let offset = parser.parens(|parser| { if parser.peek::() { @@ -167,7 +165,7 @@ impl<'a> Parse<'a> for Data<'a> { // single-instruction expression. let insn = parser.parse()?; if parser.is_empty() { - return Ok(ast::Expression { + return Ok(Expression { instrs: [insn].into(), }); } @@ -183,10 +181,10 @@ impl<'a> Parse<'a> for Data<'a> { // (data (offset ...)) // // but alas - let expr: ast::Expression = parser.parse()?; + let expr: Expression = parser.parse()?; let mut instrs = Vec::from(expr.instrs); instrs.push(insn); - Ok(ast::Expression { + Ok(Expression { instrs: instrs.into(), }) } @@ -237,7 +235,7 @@ impl DataVal<'_> { impl<'a> Parse<'a> for DataVal<'a> { fn parse(parser: Parser<'a>) -> Result { - if !parser.peek::() { + if !parser.peek::() { return Ok(DataVal::String(parser.parse()?)); } @@ -250,15 +248,9 @@ impl<'a> Parse<'a> for DataVal<'a> { || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? - || consume::(p, l, r, |u, v| { - v.extend(&u.bits.to_le_bytes()) - })? - || consume::(p, l, r, |u, v| { - v.extend(&u.bits.to_le_bytes()) - })? - || consume::(p, l, r, |u, v| { - v.extend(&u.to_le_bytes()) - })? + || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? + || consume::(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))? + || consume::(p, l, r, |u, v| v.extend(&u.to_le_bytes()))? { Ok(DataVal::Integral(result)) } else { diff --git a/third_party/rust/wast/src/core/mod.rs b/third_party/rust/wast/src/core/mod.rs new file mode 100644 index 000000000000..2369e988e302 --- /dev/null +++ b/third_party/rust/wast/src/core/mod.rs @@ -0,0 +1,27 @@ +//! Types and support for parsing the core wasm text format. + +mod custom; +mod export; +mod expr; +mod func; +mod global; +mod import; +mod memory; +mod module; +mod table; +mod tag; +mod types; +pub use self::custom::*; +pub use self::export::*; +pub use self::expr::*; +pub use self::func::*; +pub use self::global::*; +pub use self::import::*; +pub use self::memory::*; +pub use self::module::*; +pub use self::table::*; +pub use self::tag::*; +pub use self::types::*; + +pub(crate) mod binary; +pub(crate) mod resolve; diff --git a/third_party/rust/wast/src/ast/module.rs b/third_party/rust/wast/src/core/module.rs similarity index 69% rename from third_party/rust/wast/src/ast/module.rs rename to third_party/rust/wast/src/core/module.rs index 5330aaf00616..2dee10d350d8 100644 --- a/third_party/rust/wast/src/ast/module.rs +++ b/third_party/rust/wast/src/core/module.rs @@ -1,50 +1,19 @@ -use crate::ast::{self, annotation, kw}; +use crate::core::*; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, Index, NameAnnotation, Span}; +use crate::{annotation, kw}; -pub use crate::resolve::Names; +pub use crate::core::resolve::Names; -/// A `*.wat` file parser, or a parser for one parenthesized module. -/// -/// This is the top-level type which you'll frequently parse when working with -/// this crate. A `*.wat` file is either one `module` s-expression or a sequence -/// of s-expressions that are module fields. -#[derive(Debug)] -pub struct Wat<'a> { - #[allow(missing_docs)] - pub module: Module<'a>, -} - -impl<'a> Parse<'a> for Wat<'a> { - fn parse(parser: Parser<'a>) -> Result { - if !parser.has_meaningful_tokens() { - return Err(parser.error("expected at least one module field")); - } - let _r = parser.register_annotation("custom"); - let module = if !parser.peek2::() { - let fields = ModuleField::parse_remaining(parser)?; - Module { - span: ast::Span { offset: 0 }, - id: None, - name: None, - kind: ModuleKind::Text(fields), - } - } else { - parser.parens(|parser| parser.parse())? - }; - module.validate(parser)?; - Ok(Wat { module }) - } -} - -/// A parsed WebAssembly module. +/// A parsed WebAssembly core module. #[derive(Debug)] pub struct Module<'a> { /// Where this `module` was defined - pub span: ast::Span, + pub span: Span, /// An optional identifier this module is known by - pub id: Option>, + pub id: Option>, /// An optional `@name` annotation for this module - pub name: Option>, + pub name: Option>, /// What kind of module this was parsed as. pub kind: ModuleKind<'a>, } @@ -71,9 +40,9 @@ impl<'a> Module<'a> { /// where expansion and name resolution happens. /// /// This function will mutate the AST of this [`Module`] and replace all - /// [`super::Index`] arguments with `Index::Num`. This will also expand inline - /// exports/imports listed on fields and handle various other shorthands of - /// the text format. + /// [`Index`](crate::token::Index) arguments with `Index::Num`. This will + /// also expand inline exports/imports listed on fields and handle various + /// other shorthands of the text format. /// /// If successful the AST was modified to be ready for binary encoding. A /// [`Names`] structure is also returned so if you'd like to do your own @@ -84,7 +53,11 @@ impl<'a> Module<'a> { /// If an error happens during resolution, such a name resolution error or /// items are found in the wrong order, then an error is returned. pub fn resolve(&mut self) -> std::result::Result, crate::Error> { - crate::resolve::resolve(self) + let names = match &mut self.kind { + ModuleKind::Text(fields) => crate::core::resolve::resolve(fields)?, + ModuleKind::Binary(_blobs) => Default::default(), + }; + Ok(names) } /// Encodes this [`Module`] to its binary form. @@ -113,10 +86,13 @@ impl<'a> Module<'a> { /// expansion-related errors. pub fn encode(&mut self) -> std::result::Result, crate::Error> { self.resolve()?; - Ok(crate::binary::encode(self)) + Ok(match &self.kind { + ModuleKind::Text(fields) => crate::core::binary::encode(&self.id, &self.name, fields), + ModuleKind::Binary(blobs) => blobs.iter().flat_map(|b| b.iter().cloned()).collect(), + }) } - fn validate(&self, parser: Parser<'_>) -> Result<()> { + pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> { let mut starts = 0; if let ModuleKind::Text(fields) = &self.kind { for item in fields.iter() { @@ -162,25 +138,22 @@ impl<'a> Parse<'a> for Module<'a> { #[allow(missing_docs)] #[derive(Debug)] pub enum ModuleField<'a> { - Type(ast::Type<'a>), - Import(ast::Import<'a>), - Func(ast::Func<'a>), - Table(ast::Table<'a>), - Memory(ast::Memory<'a>), - Global(ast::Global<'a>), - Export(ast::Export<'a>), - Start(ast::ItemRef<'a, kw::func>), - Elem(ast::Elem<'a>), - Data(ast::Data<'a>), - Tag(ast::Tag<'a>), - Custom(ast::Custom<'a>), - Instance(ast::Instance<'a>), - NestedModule(ast::NestedModule<'a>), - Alias(ast::Alias<'a>), + Type(Type<'a>), + Import(Import<'a>), + Func(Func<'a>), + Table(Table<'a>), + Memory(Memory<'a>), + Global(Global<'a>), + Export(Export<'a>), + Start(Index<'a>), + Elem(Elem<'a>), + Data(Data<'a>), + Tag(Tag<'a>), + Custom(Custom<'a>), } impl<'a> ModuleField<'a> { - fn parse_remaining(parser: Parser<'a>) -> Result> { + pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result> { let mut fields = Vec::new(); while !parser.is_empty() { fields.push(parser.parens(ModuleField::parse)?); @@ -214,7 +187,7 @@ impl<'a> Parse<'a> for ModuleField<'a> { } if parser.peek::() { parser.parse::()?; - return Ok(ModuleField::Start(parser.parse::>()?.0)); + return Ok(ModuleField::Start(parser.parse()?)); } if parser.peek::() { return Ok(ModuleField::Elem(parser.parse()?)); @@ -228,15 +201,6 @@ impl<'a> Parse<'a> for ModuleField<'a> { if parser.peek::() { return Ok(ModuleField::Custom(parser.parse()?)); } - if parser.peek::() { - return Ok(ModuleField::Instance(parser.parse()?)); - } - if parser.peek::() { - return Ok(ModuleField::NestedModule(parser.parse()?)); - } - if parser.peek::() { - return Ok(ModuleField::Alias(parser.parse()?)); - } Err(parser.error("expected valid module field")) } } diff --git a/third_party/rust/wast/src/resolve/deinline_import_export.rs b/third_party/rust/wast/src/core/resolve/deinline_import_export.rs similarity index 76% rename from third_party/rust/wast/src/resolve/deinline_import_export.rs rename to third_party/rust/wast/src/core/resolve/deinline_import_export.rs index ba38bbd93c82..74e8d87a0186 100644 --- a/third_party/rust/wast/src/resolve/deinline_import_export.rs +++ b/third_party/rust/wast/src/core/resolve/deinline_import_export.rs @@ -1,5 +1,6 @@ -use crate::ast::*; -use crate::resolve::gensym; +use crate::core::*; +use crate::gensym; +use crate::token::{Id, Index, Span}; use std::mem; pub fn run(fields: &mut Vec) { @@ -80,7 +81,7 @@ pub fn run(fields: &mut Vec) { id: None, name: None, kind: DataKind::Active { - memory: item_ref(kw::memory(m.span), id), + memory: Index::Id(id), offset: Expression { instrs: Box::new([if is_32 { Instruction::I32Const(0) @@ -139,7 +140,7 @@ pub fn run(fields: &mut Vec) { id: None, name: None, kind: ElemKind::Active { - table: item_ref(kw::table(t.span), id), + table: Index::Id(id), offset: Expression { instrs: Box::new([Instruction::I32Const(0)]), }, @@ -196,62 +197,9 @@ pub fn run(fields: &mut Vec) { } } - ModuleField::Instance(i) => { - for name in i.exports.names.drain(..) { - to_append.push(export(i.span, name, ExportKind::Instance, &mut i.id)); - } - match &mut i.kind { - InstanceKind::Import { import, ty } => { - *item = ModuleField::Import(Import { - span: i.span, - module: import.module, - field: import.field, - item: ItemSig { - span: i.span, - id: i.id, - name: None, - kind: ItemKind::Instance(mem::replace( - ty, - TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))), - )), - }, - }); - } - InstanceKind::Inline { .. } => {} - } - } - - ModuleField::NestedModule(m) => { - for name in m.exports.names.drain(..) { - to_append.push(export(m.span, name, ExportKind::Module, &mut m.id)); - } - match &mut m.kind { - NestedModuleKind::Import { import, ty } => { - *item = ModuleField::Import(Import { - span: m.span, - module: import.module, - field: import.field, - item: ItemSig { - span: m.span, - id: m.id, - name: m.name, - kind: ItemKind::Module(mem::replace( - ty, - TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))), - )), - }, - }); - } - NestedModuleKind::Inline { fields, .. } => { - run(fields); - } - }; - } - ModuleField::Import(_) | ModuleField::Type(_) | ModuleField::Export(_) - | ModuleField::Alias(_) | ModuleField::Start(_) | ModuleField::Elem(_) | ModuleField::Data(_) @@ -279,16 +227,7 @@ fn export<'a>( ModuleField::Export(Export { span, name, - index: item_ref(kind, id), + kind, + item: Index::Id(id), }) } - -fn item_ref<'a, K>(kind: K, id: impl Into>) -> ItemRef<'a, K> { - ItemRef::Item { - kind, - idx: id.into(), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: false, - } -} diff --git a/third_party/rust/wast/src/resolve/mod.rs b/third_party/rust/wast/src/core/resolve/mod.rs similarity index 77% rename from third_party/rust/wast/src/resolve/mod.rs rename to third_party/rust/wast/src/core/resolve/mod.rs index b4e35bb0ad03..7b3ba2b1e33e 100644 --- a/third_party/rust/wast/src/resolve/mod.rs +++ b/third_party/rust/wast/src/core/resolve/mod.rs @@ -1,11 +1,10 @@ -use crate::ast::*; -use crate::Error; +use crate::core::*; +use crate::token::Index; +use crate::{gensym, Error}; -mod aliases; mod deinline_import_export; -mod gensym; mod names; -mod types; +pub(crate) mod types; #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub enum Ns { @@ -13,33 +12,11 @@ pub enum Ns { Table, Global, Memory, - Module, - Instance, Tag, Type, } -impl Ns { - fn from_export(kind: &ExportKind) -> Ns { - match kind { - ExportKind::Func => Ns::Func, - ExportKind::Table => Ns::Table, - ExportKind::Global => Ns::Global, - ExportKind::Memory => Ns::Memory, - ExportKind::Instance => Ns::Instance, - ExportKind::Module => Ns::Module, - ExportKind::Tag => Ns::Tag, - ExportKind::Type => Ns::Type, - } - } -} - -pub fn resolve<'a>(module: &mut Module<'a>) -> Result, Error> { - let fields = match &mut module.kind { - ModuleKind::Text(fields) => fields, - _ => return Ok(Default::default()), - }; - +pub fn resolve<'a>(fields: &mut Vec>) -> Result, Error> { // Ensure that each resolution of a module is deterministic in the names // that it generates by resetting our thread-local symbol generator. gensym::reset(); @@ -51,8 +28,6 @@ pub fn resolve<'a>(module: &mut Module<'a>) -> Result, Error> { // field. deinline_import_export::run(fields); - aliases::run(fields); - // With a canonical form of imports make sure that imports are all listed // first. let mut last = None; @@ -77,15 +52,15 @@ pub fn resolve<'a>(module: &mut Module<'a>) -> Result, Error> { // Perform name resolution over all `Index` items to resolve them all to // indices instead of symbolic names. - let resolver = names::resolve(module.id, fields)?; + let resolver = names::resolve(fields)?; Ok(Names { resolver }) } /// Representation of the results of name resolution for a module. /// /// This structure is returned from the -/// [`Module::resolve`](crate::Module::resolve) function and can be used to -/// resolve your own name arguments if you have any. +/// [`Module::resolve`](crate::core::Module::resolve) function and can be used +/// to resolve your own name arguments if you have any. #[derive(Default)] pub struct Names<'a> { resolver: names::Resolver<'a>, diff --git a/third_party/rust/wast/src/resolve/names.rs b/third_party/rust/wast/src/core/resolve/names.rs similarity index 62% rename from third_party/rust/wast/src/resolve/names.rs rename to third_party/rust/wast/src/core/resolve/names.rs index 982a1bb1ec2e..76abef83b201 100644 --- a/third_party/rust/wast/src/resolve/names.rs +++ b/third_party/rust/wast/src/core/resolve/names.rs @@ -1,21 +1,12 @@ -use crate::ast::*; -use crate::resolve::Ns; +use crate::core::resolve::Ns; +use crate::core::*; +use crate::names::{resolve_error, Namespace}; +use crate::token::{Id, Index}; use crate::Error; -use std::collections::{HashMap, HashSet}; -pub fn resolve<'a>( - id: Option>, - fields: &mut Vec>, -) -> Result, Error> { - let mut names = HashMap::new(); - let mut parents = Parents { - prev: None, - cur_id: id, - depth: 0, - names: &mut names, - }; +pub fn resolve<'a>(fields: &mut Vec>) -> Result, Error> { let mut resolver = Resolver::default(); - resolver.process(&mut parents, fields)?; + resolver.process(fields)?; Ok(resolver) } @@ -32,21 +23,14 @@ pub struct Resolver<'a> { memories: Namespace<'a>, types: Namespace<'a>, tags: Namespace<'a>, - modules: Namespace<'a>, - instances: Namespace<'a>, datas: Namespace<'a>, elems: Namespace<'a>, fields: Namespace<'a>, type_info: Vec>, - implicit_instances: HashSet<&'a str>, } impl<'a> Resolver<'a> { - fn process( - &mut self, - parents: &mut Parents<'a, '_>, - fields: &mut Vec>, - ) -> Result<(), Error> { + fn process(&mut self, fields: &mut Vec>) -> Result<(), Error> { // Number everything in the module, recording what names correspond to // what indices. for field in fields.iter_mut() { @@ -56,37 +40,24 @@ impl<'a> Resolver<'a> { // Then we can replace all our `Index::Id` instances with `Index::Num` // in the AST. Note that this also recurses into nested modules. for field in fields.iter_mut() { - self.resolve_field(field, parents)?; + self.resolve_field(field)?; } Ok(()) } fn register(&mut self, item: &ModuleField<'a>) -> Result<(), Error> { match item { - ModuleField::Import(i) => { - // Account for implicit instances created by two-level imports - // first. At this time they never have a name. - if i.field.is_some() { - if self.implicit_instances.insert(i.module) { - self.instances.register(None, "instance")?; - } - } - match &i.item.kind { - ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, - ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?, - ItemKind::Table(_) => self.tables.register(i.item.id, "table")?, - ItemKind::Global(_) => self.globals.register(i.item.id, "global")?, - ItemKind::Tag(_) => self.tags.register(i.item.id, "tag")?, - ItemKind::Module(_) => self.modules.register(i.item.id, "module")?, - ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?, - } - } + ModuleField::Import(i) => match &i.item.kind { + ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, + ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?, + ItemKind::Table(_) => self.tables.register(i.item.id, "table")?, + ItemKind::Global(_) => self.globals.register(i.item.id, "global")?, + ItemKind::Tag(_) => self.tags.register(i.item.id, "tag")?, + }, ModuleField::Global(i) => self.globals.register(i.id, "global")?, ModuleField::Memory(i) => self.memories.register(i.id, "memory")?, ModuleField::Func(i) => self.funcs.register(i.id, "func")?, ModuleField::Table(i) => self.tables.register(i.id, "table")?, - ModuleField::NestedModule(m) => self.modules.register(m.id, "module")?, - ModuleField::Instance(i) => self.instances.register(i.id, "instance")?, ModuleField::Type(i) => { match &i.def { @@ -103,10 +74,7 @@ impl<'a> Resolver<'a> { } } - TypeDef::Instance(_) - | TypeDef::Array(_) - | TypeDef::Func(_) - | TypeDef::Module(_) => {} + TypeDef::Array(_) | TypeDef::Func(_) => {} } // Record function signatures as we see them to so we can @@ -126,19 +94,6 @@ impl<'a> Resolver<'a> { ModuleField::Elem(e) => self.elems.register(e.id, "elem")?, ModuleField::Data(d) => self.datas.register(d.id, "data")?, ModuleField::Tag(t) => self.tags.register(t.id, "tag")?, - ModuleField::Alias(a) => match a.kind { - ExportKind::Func => self.funcs.register(a.id, "func")?, - ExportKind::Table => self.tables.register(a.id, "table")?, - ExportKind::Memory => self.memories.register(a.id, "memory")?, - ExportKind::Global => self.globals.register(a.id, "global")?, - ExportKind::Instance => self.instances.register(a.id, "instance")?, - ExportKind::Module => self.modules.register(a.id, "module")?, - ExportKind::Tag => self.tags.register(a.id, "tag")?, - ExportKind::Type => { - self.type_info.push(TypeInfo::Other); - self.types.register(a.id, "type")? - } - }, // These fields don't define any items in any index space. ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => { @@ -149,11 +104,7 @@ impl<'a> Resolver<'a> { Ok(()) } - fn resolve_field( - &self, - field: &mut ModuleField<'a>, - parents: &mut Parents<'a, '_>, - ) -> Result<(), Error> { + fn resolve_field(&self, field: &mut ModuleField<'a>) -> Result<(), Error> { match field { ModuleField::Import(i) => { self.resolve_item_sig(&mut i.item)?; @@ -169,8 +120,6 @@ impl<'a> Resolver<'a> { } } TypeDef::Array(array) => self.resolve_storagetype(&mut array.ty)?, - TypeDef::Module(m) => m.resolve(self)?, - TypeDef::Instance(i) => i.resolve(self)?, } Ok(()) } @@ -225,7 +174,7 @@ impl<'a> Resolver<'a> { ModuleField::Elem(e) => { match &mut e.kind { ElemKind::Active { table, offset } => { - self.resolve_item_ref(table)?; + self.resolve(table, Ns::Table)?; self.resolve_expr(offset)?; } ElemKind::Passive { .. } | ElemKind::Declared { .. } => {} @@ -233,7 +182,7 @@ impl<'a> Resolver<'a> { match &mut e.payload { ElemPayload::Indices(elems) => { for idx in elems { - self.resolve_item_ref(idx)?; + self.resolve(idx, Ns::Func)?; } } ElemPayload::Exprs { exprs, ty } => { @@ -248,19 +197,29 @@ impl<'a> Resolver<'a> { ModuleField::Data(d) => { if let DataKind::Active { memory, offset } = &mut d.kind { - self.resolve_item_ref(memory)?; + self.resolve(memory, Ns::Memory)?; self.resolve_expr(offset)?; } Ok(()) } ModuleField::Start(i) => { - self.resolve_item_ref(i)?; + self.resolve(i, Ns::Func)?; Ok(()) } ModuleField::Export(e) => { - self.resolve_item_ref(&mut e.index)?; + self.resolve( + &mut e.item, + match e.kind { + ExportKind::Func => Ns::Func, + ExportKind::Table => Ns::Table, + ExportKind::Memory => Ns::Memory, + ExportKind::Global => Ns::Global, + ExportKind::Tag => Ns::Tag, + ExportKind::Type => Ns::Type, + }, + )?; Ok(()) } @@ -281,25 +240,6 @@ impl<'a> Resolver<'a> { Ok(()) } - ModuleField::Instance(i) => { - if let InstanceKind::Inline { module, args } = &mut i.kind { - self.resolve_item_ref(module)?; - for arg in args { - self.resolve_item_ref(&mut arg.index)?; - } - } - Ok(()) - } - - ModuleField::NestedModule(m) => { - let fields = match &mut m.kind { - NestedModuleKind::Inline { fields } => fields, - NestedModuleKind::Import { .. } => panic!("should only be inline"), - }; - Resolver::default().process(&mut parents.push(self, m.id), fields)?; - Ok(()) - } - ModuleField::Table(t) => { if let TableKind::Normal(t) = &mut t.kind { self.resolve_heaptype(&mut t.elem.heap)?; @@ -307,29 +247,6 @@ impl<'a> Resolver<'a> { Ok(()) } - ModuleField::Alias(a) => { - match &mut a.source { - AliasSource::InstanceExport { instance, .. } => { - self.resolve_item_ref(instance)?; - } - AliasSource::Outer { module, index } => { - match (index, module) { - // If both indices are numeric then don't try to - // resolve anything since we could fail to walk up - // the parent chain, producing a wat2wasm error that - // should probably be a wasm validation error. - (Index::Num(..), Index::Num(..)) => {} - (index, module) => { - parents - .resolve(module)? - .resolve(index, Ns::from_export(&a.kind))?; - } - } - } - } - Ok(()) - } - ModuleField::Memory(_) | ModuleField::Custom(_) => Ok(()), } } @@ -369,12 +286,6 @@ impl<'a> Resolver<'a> { self.resolve_type_use(t)?; } ItemKind::Global(t) => self.resolve_valtype(&mut t.ty)?, - ItemKind::Instance(t) => { - self.resolve_type_use(t)?; - } - ItemKind::Module(m) => { - self.resolve_type_use(m)?; - } ItemKind::Table(t) => { self.resolve_heaptype(&mut t.elem.heap)?; } @@ -391,7 +302,7 @@ impl<'a> Resolver<'a> { T: TypeReference<'a>, { let idx = ty.index.as_mut().unwrap(); - let idx = self.resolve_item_ref(idx)?; + self.resolve(idx, Ns::Type)?; // If the type was listed inline *and* it was specified via a type index // we need to assert they're the same. @@ -416,137 +327,10 @@ impl<'a> Resolver<'a> { Ns::Table => self.tables.resolve(idx, "table"), Ns::Global => self.globals.resolve(idx, "global"), Ns::Memory => self.memories.resolve(idx, "memory"), - Ns::Instance => self.instances.resolve(idx, "instance"), - Ns::Module => self.modules.resolve(idx, "module"), Ns::Tag => self.tags.resolve(idx, "tag"), Ns::Type => self.types.resolve(idx, "type"), } } - - fn resolve_item_ref<'b, K>(&self, item: &'b mut ItemRef<'a, K>) -> Result<&'b Index<'a>, Error> - where - K: Into + Copy, - { - match item { - ItemRef::Item { - idx, - kind, - exports, - #[cfg(wast_check_exhaustive)] - visited, - } => { - #[cfg(wast_check_exhaustive)] - { - if !*visited { - return Err(Error::new( - idx.span(), - format!("BUG: this index wasn't visited"), - )); - } - } - debug_assert!(exports.len() == 0); - self.resolve( - idx, - match (*kind).into() { - ExportKind::Func => Ns::Func, - ExportKind::Table => Ns::Table, - ExportKind::Global => Ns::Global, - ExportKind::Memory => Ns::Memory, - ExportKind::Instance => Ns::Instance, - ExportKind::Module => Ns::Module, - ExportKind::Tag => Ns::Tag, - ExportKind::Type => Ns::Type, - }, - )?; - Ok(idx) - } - // should be expanded by now - ItemRef::Outer { .. } => unreachable!(), - } - } -} - -#[derive(Default)] -pub struct Namespace<'a> { - names: HashMap, u32>, - count: u32, -} - -impl<'a> Namespace<'a> { - fn register(&mut self, name: Option>, desc: &str) -> Result { - let index = self.alloc(); - if let Some(name) = name { - if let Some(_prev) = self.names.insert(name, index) { - // FIXME: temporarily allow duplicately-named data and element - // segments. This is a sort of dumb hack to get the spec test - // suite working (ironically). - // - // So as background, the text format disallows duplicate - // identifiers, causing a parse error if they're found. There - // are two tests currently upstream, however, data.wast and - // elem.wast, which *look* like they have duplicately named - // element and data segments. These tests, however, are using - // pre-bulk-memory syntax where a bare identifier was the - // table/memory being initialized. In post-bulk-memory this - // identifier is the name of the segment. Since we implement - // post-bulk-memory features that means that we're parsing the - // memory/table-to-initialize as the name of the segment. - // - // This is technically incorrect behavior but no one is - // hopefully relying on this too much. To get the spec tests - // passing we ignore errors for elem/data segments. Once the - // spec tests get updated enough we can remove this condition - // and return errors for them. - if desc != "elem" && desc != "data" { - return Err(Error::new( - name.span(), - format!("duplicate {} identifier", desc), - )); - } - } - } - Ok(index) - } - - fn alloc(&mut self) -> u32 { - let index = self.count; - self.count += 1; - return index; - } - - fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> { - if let Some(_prev) = self.names.insert(name, index) { - return Err(Error::new( - name.span(), - format!("duplicate identifier for {}", desc), - )); - } - Ok(()) - } - - fn resolve(&self, idx: &mut Index<'a>, desc: &str) -> Result { - let id = match idx { - Index::Num(n, _) => return Ok(*n), - Index::Id(id) => id, - }; - if let Some(&n) = self.names.get(id) { - *idx = Index::Num(n, id.span()); - return Ok(n); - } - Err(resolve_error(*id, desc)) - } -} - -fn resolve_error(id: Id<'_>, ns: &str) -> Error { - assert!( - !id.is_gensym(), - "symbol generated by `wast` itself cannot be resolved {:?}", - id - ); - Error::new( - id.span(), - format!("failed to find {} named `${}`", ns, id.name()), - ) } #[derive(Debug, Clone)] @@ -634,23 +418,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } fn resolve_instr(&mut self, instr: &mut Instruction<'a>) -> Result<(), Error> { - use crate::ast::Instruction::*; + use Instruction::*; if let Some(m) = instr.memarg_mut() { - self.resolver.resolve_item_ref(&mut m.memory)?; + self.resolver.resolve(&mut m.memory, Ns::Memory)?; } match instr { MemorySize(i) | MemoryGrow(i) | MemoryFill(i) => { - self.resolver.resolve_item_ref(&mut i.mem)?; + self.resolver.resolve(&mut i.mem, Ns::Memory)?; } MemoryInit(i) => { self.resolver.datas.resolve(&mut i.data, "data")?; - self.resolver.resolve_item_ref(&mut i.mem)?; + self.resolver.resolve(&mut i.mem, Ns::Memory)?; } MemoryCopy(i) => { - self.resolver.resolve_item_ref(&mut i.src)?; - self.resolver.resolve_item_ref(&mut i.dst)?; + self.resolver.resolve(&mut i.src, Ns::Memory)?; + self.resolver.resolve(&mut i.dst, Ns::Memory)?; } DataDrop(i) => { self.resolver.datas.resolve(i, "data")?; @@ -658,23 +442,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> { TableInit(i) => { self.resolver.elems.resolve(&mut i.elem, "elem")?; - self.resolver.resolve_item_ref(&mut i.table)?; + self.resolver.resolve(&mut i.table, Ns::Table)?; } ElemDrop(i) => { self.resolver.elems.resolve(i, "elem")?; } TableCopy(i) => { - self.resolver.resolve_item_ref(&mut i.dst)?; - self.resolver.resolve_item_ref(&mut i.src)?; + self.resolver.resolve(&mut i.dst, Ns::Table)?; + self.resolver.resolve(&mut i.src, Ns::Table)?; } TableFill(i) | TableSet(i) | TableGet(i) | TableSize(i) | TableGrow(i) => { - self.resolver.resolve_item_ref(&mut i.dst)?; + self.resolver.resolve(&mut i.dst, Ns::Table)?; } GlobalSet(i) | GlobalGet(i) => { - self.resolver.resolve_item_ref(&mut i.0)?; + self.resolver.resolve(i, Ns::Global)?; } LocalSet(i) | LocalGet(i) | LocalTee(i) => { @@ -698,11 +482,11 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } Call(i) | RefFunc(i) | ReturnCall(i) => { - self.resolver.resolve_item_ref(&mut i.0)?; + self.resolver.resolve(i, Ns::Func)?; } CallIndirect(c) | ReturnCallIndirect(c) => { - self.resolver.resolve_item_ref(&mut c.table)?; + self.resolver.resolve(&mut c.table, Ns::Table)?; self.resolver.resolve_type_use(&mut c.ty)?; } @@ -864,96 +648,6 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } } -struct Parents<'a, 'b> { - prev: Option>, - cur_id: Option>, - depth: usize, - names: &'b mut HashMap, usize>, -} - -struct ParentNode<'a, 'b> { - resolver: &'b Resolver<'a>, - id: Option>, - prev: Option<&'b ParentNode<'a, 'b>>, - prev_depth: Option, -} - -impl<'a, 'b> Parents<'a, 'b> { - fn push<'c>(&'c mut self, resolver: &'c Resolver<'a>, id: Option>) -> Parents<'a, 'c> - where - 'b: 'c, - { - let prev_depth = if let Some(id) = self.cur_id { - self.names.insert(id, self.depth) - } else { - None - }; - Parents { - prev: Some(ParentNode { - prev: self.prev.as_ref(), - resolver, - id: self.cur_id, - prev_depth, - }), - cur_id: id, - depth: self.depth + 1, - names: &mut *self.names, - } - } - - fn resolve(&self, index: &mut Index<'a>) -> Result<&'b Resolver<'a>, Error> { - let mut i = match *index { - Index::Num(n, _) => n, - Index::Id(id) => match self.names.get(&id) { - Some(idx) => (self.depth - *idx - 1) as u32, - None => return Err(resolve_error(id, "parent module")), - }, - }; - *index = Index::Num(i, index.span()); - let mut cur = match self.prev.as_ref() { - Some(n) => n, - None => { - return Err(Error::new( - index.span(), - "cannot use `outer` alias in root module".to_string(), - )) - } - }; - while i > 0 { - cur = match cur.prev { - Some(n) => n, - None => { - return Err(Error::new( - index.span(), - "alias to `outer` module index too large".to_string(), - )) - } - }; - i -= 1; - } - Ok(cur.resolver) - } -} - -impl<'a, 'b> Drop for Parents<'a, 'b> { - fn drop(&mut self) { - let (id, prev_depth) = match &self.prev { - Some(n) => (n.id, n.prev_depth), - None => return, - }; - if let Some(id) = id { - match prev_depth { - Some(i) => { - self.names.insert(id, i); - } - None => { - self.names.remove(&id); - } - } - } - } -} - enum TypeInfo<'a> { Func { params: Box<[ValType<'a>]>, @@ -1023,40 +717,3 @@ impl<'a> TypeReference<'a> for FunctionType<'a> { Ok(()) } } - -impl<'a> TypeReference<'a> for InstanceType<'a> { - fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> { - drop(cx); - Err(Error::new( - idx.span(), - format!("cannot specify instance type as a reference and inline"), - )) - } - - fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> { - for export in self.exports.iter_mut() { - cx.resolve_item_sig(&mut export.item)?; - } - Ok(()) - } -} - -impl<'a> TypeReference<'a> for ModuleType<'a> { - fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> { - drop(cx); - Err(Error::new( - idx.span(), - format!("cannot specify module type as a reference and inline"), - )) - } - - fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> { - for i in self.imports.iter_mut() { - cx.resolve_item_sig(&mut i.item)?; - } - for e in self.exports.iter_mut() { - cx.resolve_item_sig(&mut e.item)?; - } - Ok(()) - } -} diff --git a/third_party/rust/wast/src/resolve/types.rs b/third_party/rust/wast/src/core/resolve/types.rs similarity index 51% rename from third_party/rust/wast/src/resolve/types.rs rename to third_party/rust/wast/src/core/resolve/types.rs index 94c821572a28..6bf080e3b827 100644 --- a/third_party/rust/wast/src/resolve/types.rs +++ b/third_party/rust/wast/src/core/resolve/types.rs @@ -1,5 +1,6 @@ -use crate::ast::*; -use crate::resolve::gensym; +use crate::core::*; +use crate::gensym; +use crate::token::{Index, Span}; use std::collections::HashMap; pub fn expand<'a>(fields: &mut Vec>) { @@ -8,16 +9,11 @@ pub fn expand<'a>(fields: &mut Vec>) { } #[derive(Default)] -struct Expander<'a> { - // See the comment in `process` for why this exists. - process_imports_early: bool, - +pub(crate) struct Expander<'a> { // Maps used to "intern" types. These maps are populated as type annotations // are seen and inline type annotations use previously defined ones if // there's a match. func_type_to_idx: HashMap, Index<'a>>, - instance_type_to_idx: HashMap, Index<'a>>, - module_type_to_idx: HashMap, Index<'a>>, /// Fields, during processing, which should be prepended to the /// currently-being-processed field. This should always be empty after @@ -27,22 +23,6 @@ struct Expander<'a> { impl<'a> Expander<'a> { fn process(&mut self, fields: &mut Vec>) { - // For the given list of fields this determines whether imports are - // processed as part of `expand_header` or as part of `expand`. The - // reason for this distinction is that pre-module-linking types were - // always sorted to the front of the module so new types were always - // appended to the end. After module-linking, however, types are - // interspersed with imports and order matters. This means that imports - // can't use intern'd types which appear later. - // - // This is a bit of a hack and ideally something that needs to be - // addressed in the upstream spec. WebAssembly/module-linking#25 - // represents this issue. - self.process_imports_early = fields.iter().any(|f| match f { - ModuleField::Alias(_) | ModuleField::NestedModule(_) | ModuleField::Instance(_) => true, - _ => false, - }); - // Next we expand "header" fields which are those like types and // imports. In this context "header" is defined by the previous // `process_imports_early` annotation. @@ -75,20 +55,9 @@ impl<'a> Expander<'a> { TypeDef::Func(f) => { f.key().insert(self, Index::Id(id)); } - TypeDef::Instance(i) => { - i.expand(self); - i.key().insert(self, Index::Id(id)); - } - TypeDef::Module(m) => { - m.expand(self); - m.key().insert(self, Index::Id(id)); - } TypeDef::Array(_) | TypeDef::Struct(_) => {} } } - ModuleField::Import(i) if self.process_imports_early => { - self.expand_item_sig(&mut i.item); - } _ => {} } } @@ -99,10 +68,7 @@ impl<'a> Expander<'a> { ModuleField::Type(_) => {} ModuleField::Import(i) => { - // Only expand here if not expanded above - if !self.process_imports_early { - self.expand_item_sig(&mut i.item); - } + self.expand_item_sig(&mut i.item); } ModuleField::Func(f) => { self.expand_type_use(&mut f.ty); @@ -135,15 +101,8 @@ impl<'a> Expander<'a> { self.expand_type_use(ty); } }, - ModuleField::NestedModule(m) => { - if let NestedModuleKind::Inline { fields } = &mut m.kind { - Expander::default().process(fields); - } - } - ModuleField::Alias(_) - | ModuleField::Instance(_) - | ModuleField::Table(_) + ModuleField::Table(_) | ModuleField::Memory(_) | ModuleField::Start(_) | ModuleField::Export(_) @@ -156,14 +115,6 @@ impl<'a> Expander<'a> { ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => { self.expand_type_use(t); } - ItemKind::Instance(t) => { - self.expand_type_use(t); - t.inline.take(); - } - ItemKind::Module(m) => { - self.expand_type_use(m); - m.inline.take(); - } ItemKind::Global(_) | ItemKind::Table(_) | ItemKind::Memory(_) => {} } } @@ -228,13 +179,7 @@ impl<'a> Expander<'a> { T: TypeReference<'a>, { if let Some(idx) = &item.index { - match idx { - ItemRef::Item { idx, exports, .. } => { - debug_assert!(exports.len() == 0); - return idx.clone(); - } - ItemRef::Outer { .. } => unreachable!(), - } + return idx.clone(); } let key = match item.inline.as_mut() { Some(ty) => { @@ -243,15 +188,9 @@ impl<'a> Expander<'a> { } None => T::default().key(), }; - let span = Span::from_offset(0); // FIXME: don't manufacture + let span = Span::from_offset(0); // FIXME(#613): don't manufacture let idx = self.key_to_idx(span, key); - item.index = Some(ItemRef::Item { - idx, - kind: kw::r#type(span), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: true, - }); + item.index = Some(idx); return idx; } @@ -277,19 +216,19 @@ impl<'a> Expander<'a> { } } -trait TypeReference<'a>: Default { +pub(crate) trait TypeReference<'a>: Default { type Key: TypeKey<'a>; fn key(&self) -> Self::Key; fn expand(&mut self, cx: &mut Expander<'a>); } -trait TypeKey<'a> { +pub(crate) trait TypeKey<'a> { fn lookup(&self, cx: &Expander<'a>) -> Option>; fn to_def(&self, span: Span) -> TypeDef<'a>; fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>); } -type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>); +pub(crate) type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>); impl<'a> TypeReference<'a> for FunctionType<'a> { type Key = FuncKey<'a>; @@ -319,159 +258,3 @@ impl<'a> TypeKey<'a> for FuncKey<'a> { cx.func_type_to_idx.entry(self.clone()).or_insert(idx); } } - -// A list of the exports of a module as well as the signature they export. -type InstanceKey<'a> = Vec<(&'a str, Item<'a>)>; - -impl<'a> TypeReference<'a> for InstanceType<'a> { - type Key = InstanceKey<'a>; - - fn key(&self) -> Self::Key { - self.exports - .iter() - .map(|export| (export.name, Item::new(&export.item))) - .collect() - } - - fn expand(&mut self, cx: &mut Expander<'a>) { - for export in self.exports.iter_mut() { - cx.expand_item_sig(&mut export.item); - } - } -} - -impl<'a> TypeKey<'a> for InstanceKey<'a> { - fn lookup(&self, cx: &Expander<'a>) -> Option> { - cx.instance_type_to_idx.get(self).cloned() - } - - fn to_def(&self, span: Span) -> TypeDef<'a> { - let exports = self - .iter() - .map(|(name, item)| ExportType { - span, - name, - item: item.to_sig(span), - }) - .collect(); - TypeDef::Instance(InstanceType { exports }) - } - - fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) { - cx.instance_type_to_idx.entry(self.clone()).or_insert(idx); - } -} - -// The first element of this pair is the list of imports in the module, and the -// second element is the list of exports. -type ModuleKey<'a> = ( - Vec<(&'a str, Option<&'a str>, Item<'a>)>, - Vec<(&'a str, Item<'a>)>, -); - -impl<'a> TypeReference<'a> for ModuleType<'a> { - type Key = ModuleKey<'a>; - - fn key(&self) -> Self::Key { - let imports = self - .imports - .iter() - .map(|import| (import.module, import.field, Item::new(&import.item))) - .collect(); - let exports = self - .exports - .iter() - .map(|export| (export.name, Item::new(&export.item))) - .collect(); - (imports, exports) - } - - fn expand(&mut self, cx: &mut Expander<'a>) { - for export in self.exports.iter_mut() { - cx.expand_item_sig(&mut export.item); - } - for import in self.imports.iter_mut() { - cx.expand_item_sig(&mut import.item); - } - } -} - -impl<'a> TypeKey<'a> for ModuleKey<'a> { - fn lookup(&self, cx: &Expander<'a>) -> Option> { - cx.module_type_to_idx.get(self).cloned() - } - - fn to_def(&self, span: Span) -> TypeDef<'a> { - let imports = self - .0 - .iter() - .map(|(module, field, item)| Import { - span, - module, - field: *field, - item: item.to_sig(span), - }) - .collect(); - let exports = self - .1 - .iter() - .map(|(name, item)| ExportType { - span, - name, - item: item.to_sig(span), - }) - .collect(); - TypeDef::Module(ModuleType { imports, exports }) - } - - fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) { - cx.module_type_to_idx.entry(self.clone()).or_insert(idx); - } -} - -// A lookalike to `ItemKind` except without all non-relevant information for -// hashing. This is used as a hash key for instance/module type lookup. -#[derive(Clone, PartialEq, Eq, Hash)] -enum Item<'a> { - Func(Index<'a>), - Table(TableType<'a>), - Memory(MemoryType), - Global(GlobalType<'a>), - Tag(Index<'a>), - Module(Index<'a>), - Instance(Index<'a>), -} - -impl<'a> Item<'a> { - fn new(item: &ItemSig<'a>) -> Item<'a> { - match &item.kind { - ItemKind::Func(f) => Item::Func(*f.index.as_ref().unwrap().unwrap_index()), - ItemKind::Instance(f) => Item::Instance(*f.index.as_ref().unwrap().unwrap_index()), - ItemKind::Module(f) => Item::Module(*f.index.as_ref().unwrap().unwrap_index()), - ItemKind::Tag(TagType::Exception(f)) => { - Item::Tag(*f.index.as_ref().unwrap().unwrap_index()) - } - ItemKind::Table(t) => Item::Table(t.clone()), - ItemKind::Memory(t) => Item::Memory(t.clone()), - ItemKind::Global(t) => Item::Global(t.clone()), - } - } - - fn to_sig(&self, span: Span) -> ItemSig<'a> { - let kind = match self { - Item::Func(index) => ItemKind::Func(TypeUse::new_with_index(*index)), - Item::Tag(index) => ItemKind::Tag(TagType::Exception(TypeUse::new_with_index(*index))), - Item::Instance(index) => ItemKind::Instance(TypeUse::new_with_index(*index)), - Item::Module(index) => ItemKind::Module(TypeUse::new_with_index(*index)), - Item::Table(t) => ItemKind::Table(t.clone()), - Item::Memory(t) => ItemKind::Memory(t.clone()), - Item::Global(t) => ItemKind::Global(t.clone()), - }; - ItemSig { - span, - id: None, - name: None, - kind, - } - } -} diff --git a/third_party/rust/wast/src/ast/table.rs b/third_party/rust/wast/src/core/table.rs similarity index 77% rename from third_party/rust/wast/src/ast/table.rs rename to third_party/rust/wast/src/core/table.rs index d830ccf48a9b..005bfe2046c7 100644 --- a/third_party/rust/wast/src/ast/table.rs +++ b/third_party/rust/wast/src/core/table.rs @@ -1,18 +1,20 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, Index, LParen, NameAnnotation, Span}; /// A WebAssembly `table` directive in a module. #[derive(Debug)] pub struct Table<'a> { /// Where this table was defined. - pub span: ast::Span, + pub span: Span, /// An optional name to refer to this table by. - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: ast::InlineExport<'a>, + pub exports: InlineExport<'a>, /// How this table is textually defined in the module. pub kind: TableKind<'a>, } @@ -23,17 +25,17 @@ pub enum TableKind<'a> { /// This table is actually an inlined import definition. #[allow(missing_docs)] Import { - import: ast::InlineImport<'a>, - ty: ast::TableType<'a>, + import: InlineImport<'a>, + ty: TableType<'a>, }, /// A typical memory definition which simply says the limits of the table - Normal(ast::TableType<'a>), + Normal(TableType<'a>), /// The elem segments of this table, starting from 0, explicitly listed Inline { /// The element type of this table. - elem: ast::RefType<'a>, + elem: RefType<'a>, /// The element table entries to have, and the length of this list is /// the limits of the table as well. payload: ElemPayload<'a>, @@ -53,11 +55,11 @@ impl<'a> Parse<'a> for Table<'a> { // * `(import "a" "b") limits` // * `limits` let mut l = parser.lookahead1(); - let kind = if l.peek::() { + let kind = if l.peek::() { let elem = parser.parse()?; let payload = parser.parens(|p| { p.parse::()?; - let ty = if parser.peek::() { + let ty = if parser.peek::() { Some(elem) } else { None @@ -89,11 +91,11 @@ impl<'a> Parse<'a> for Table<'a> { #[derive(Debug)] pub struct Elem<'a> { /// Where this `elem` was defined. - pub span: ast::Span, + pub span: Span, /// An optional name by which to refer to this segment. - pub id: Option>, + pub id: Option>, /// An optional name for this element stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// The way this segment was defined in the module. pub kind: ElemKind<'a>, /// The payload of this element segment, typically a list of functions. @@ -114,9 +116,9 @@ pub enum ElemKind<'a> { /// An active segment associated with a table. Active { /// The table this `elem` is initializing. - table: ast::ItemRef<'a, kw::table>, + table: Index<'a>, /// The offset within `table` that we'll initialize at. - offset: ast::Expression<'a>, + offset: Expression<'a>, }, } @@ -124,15 +126,15 @@ pub enum ElemKind<'a> { #[derive(Debug)] pub enum ElemPayload<'a> { /// This element segment has a contiguous list of function indices - Indices(Vec>), + Indices(Vec>), /// This element segment has a list of optional function indices, /// represented as expressions using `ref.func` and `ref.null`. Exprs { /// The desired type of each expression below. - ty: ast::RefType<'a>, + ty: RefType<'a>, /// The expressions in this segment. - exprs: Vec>, + exprs: Vec>, }, } @@ -142,19 +144,23 @@ impl<'a> Parse<'a> for Elem<'a> { let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::() - || (parser.peek::() && !parser.peek::()) - { - let table = if let Some(index) = parser.parse::>>()? { - index.0 + let kind = if parser.peek::() { + parser.parse::()?; + ElemKind::Declared + } else if parser.peek::() || (parser.peek::() && !parser.peek::()) { + let table = if parser.peek::() { + // FIXME: this is only here to accomodate + // proposals/threads/imports.wast at this current moment in + // time, this probably should get removed when the threads + // proposal is rebased on the current spec. + Index::Num(parser.parse()?, span) + } else if parser.peek2::() { + parser.parens(|p| { + p.parse::()?; + p.parse() + })? } else { - ast::ItemRef::Item { - kind: kw::table(parser.prev_span()), - idx: ast::Index::Num(0, span), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: false, - } + Index::Num(0, span) }; let offset = parser.parens(|parser| { if parser.peek::() { @@ -163,9 +169,6 @@ impl<'a> Parse<'a> for Elem<'a> { parser.parse() })?; ElemKind::Active { table, offset } - } else if parser.peek::() { - parser.parse::()?; - ElemKind::Declared } else { ElemKind::Passive }; @@ -187,19 +190,19 @@ impl<'a> Parse<'a> for ElemPayload<'a> { } impl<'a> ElemPayload<'a> { - fn parse_tail(parser: Parser<'a>, ty: Option>) -> Result { + fn parse_tail(parser: Parser<'a>, ty: Option>) -> Result { let (must_use_indices, ty) = match ty { None => { parser.parse::>()?; - (true, ast::RefType::func()) + (true, RefType::func()) } Some(ty) => (false, ty), }; - if let ast::HeapType::Func = ty.heap { - if must_use_indices || parser.peek::>() { + if let HeapType::Func = ty.heap { + if must_use_indices || parser.peek::>() { let mut elems = Vec::new(); while !parser.is_empty() { - elems.push(parser.parse::>()?.0); + elems.push(parser.parse()?); } return Ok(ElemPayload::Indices(elems)); } @@ -214,7 +217,7 @@ impl<'a> ElemPayload<'a> { // Without `item` this is "sugar" for a single-instruction // expression. let insn = parser.parse()?; - Ok(ast::Expression { + Ok(Expression { instrs: [insn].into(), }) } diff --git a/third_party/rust/wast/src/ast/tag.rs b/third_party/rust/wast/src/core/tag.rs similarity index 86% rename from third_party/rust/wast/src/ast/tag.rs rename to third_party/rust/wast/src/core/tag.rs index 4d940c17a5f3..233b5e4cd0e3 100644 --- a/third_party/rust/wast/src/ast/tag.rs +++ b/third_party/rust/wast/src/core/tag.rs @@ -1,17 +1,19 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, NameAnnotation, Span}; /// A WebAssembly tag directive, part of the exception handling proposal. #[derive(Debug)] pub struct Tag<'a> { /// Where this tag was defined - pub span: ast::Span, + pub span: Span, /// An optional name by which to refer to this tag in name resolution. - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// Optional export directives for this tag. - pub exports: ast::InlineExport<'a>, + pub exports: InlineExport<'a>, /// The type of tag that is defined. pub ty: TagType<'a>, /// What kind of tag this is defined as. @@ -23,7 +25,7 @@ pub struct Tag<'a> { pub enum TagType<'a> { /// An exception tag, where the payload is the type signature of the tag /// (constructor parameters, etc). - Exception(ast::TypeUse<'a, ast::FunctionType<'a>>), + Exception(TypeUse<'a, FunctionType<'a>>), } /// Different kinds of tags that can be defined in a module. @@ -34,7 +36,7 @@ pub enum TagKind<'a> { /// ```text /// (tag (type 0) (import "foo" "bar")) /// ``` - Import(ast::InlineImport<'a>), + Import(InlineImport<'a>), /// A tag defined inline in the module itself Inline(), diff --git a/third_party/rust/wast/src/ast/types.rs b/third_party/rust/wast/src/core/types.rs similarity index 83% rename from third_party/rust/wast/src/ast/types.rs rename to third_party/rust/wast/src/core/types.rs index 5b209a261848..8f02b83fccac 100644 --- a/third_party/rust/wast/src/ast/types.rs +++ b/third_party/rust/wast/src/core/types.rs @@ -1,5 +1,7 @@ -use crate::ast::{self, kw}; +use crate::core::*; +use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::{Id, Index, LParen, NameAnnotation, Span}; use std::mem; /// The value types for a wasm module. @@ -12,7 +14,7 @@ pub enum ValType<'a> { F64, V128, Ref(RefType<'a>), - Rtt(Option, ast::Index<'a>), + Rtt(Option, Index<'a>), } impl<'a> Parse<'a> for ValType<'a> { @@ -35,7 +37,7 @@ impl<'a> Parse<'a> for ValType<'a> { Ok(ValType::V128) } else if l.peek::() { Ok(ValType::Ref(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::() { parser.parens(|p| { let mut l = p.lookahead1(); if l.peek::() { @@ -58,7 +60,7 @@ impl<'a> Peek for ValType<'a> { || kw::f32::peek(cursor) || kw::f64::peek(cursor) || kw::v128::peek(cursor) - || (ast::LParen::peek(cursor) && kw::rtt::peek2(cursor)) + || (LParen::peek(cursor) && kw::rtt::peek2(cursor)) || RefType::peek(cursor) } fn display() -> &'static str { @@ -89,7 +91,7 @@ pub enum HeapType<'a> { I31, /// A reference to a function, struct, or array: ref T. This is part of the /// GC proposal. - Index(ast::Index<'a>), + Index(Index<'a>), } impl<'a> Parse<'a> for HeapType<'a> { @@ -113,7 +115,7 @@ impl<'a> Parse<'a> for HeapType<'a> { } else if l.peek::() { parser.parse::()?; Ok(HeapType::I31) - } else if l.peek::() { + } else if l.peek::() { Ok(HeapType::Index(parser.parse()?)) } else { Err(l.error()) @@ -129,7 +131,7 @@ impl<'a> Peek for HeapType<'a> { || kw::eq::peek(cursor) || kw::data::peek(cursor) || kw::i31::peek(cursor) - || (ast::LParen::peek(cursor) && kw::r#type::peek2(cursor)) + || (LParen::peek(cursor) && kw::r#type::peek2(cursor)) } fn display() -> &'static str { "heaptype" @@ -218,7 +220,7 @@ impl<'a> Parse<'a> for RefType<'a> { } else if l.peek::() { parser.parse::()?; Ok(RefType::i31()) - } else if l.peek::() { + } else if l.peek::() { parser.parens(|p| { let mut l = parser.lookahead1(); if l.peek::() { @@ -253,7 +255,7 @@ impl<'a> Peek for RefType<'a> { || kw::eqref::peek(cursor) || kw::dataref::peek(cursor) || kw::i31ref::peek(cursor) - || (ast::LParen::peek(cursor) && kw::r#ref::peek2(cursor)) + || (LParen::peek(cursor) && kw::r#ref::peek2(cursor)) } fn display() -> &'static str { "reftype" @@ -414,13 +416,7 @@ impl<'a> Parse<'a> for MemoryType { pub struct FunctionType<'a> { /// The parameters of a function, optionally each having an identifier for /// name resolution and a name for the custom `name` section. - pub params: Box< - [( - Option>, - Option>, - ValType<'a>, - )], - >, + pub params: Box<[(Option>, Option>, ValType<'a>)]>, /// The results types of a function. pub results: Box<[ValType<'a>]>, } @@ -559,7 +555,7 @@ impl<'a> Parse<'a> for StructType<'a> { #[derive(Clone, Debug)] pub struct StructField<'a> { /// An optional identifier for name resolution. - pub id: Option>, + pub id: Option>, /// Whether this field may be mutated or not. pub mutable: bool, /// The storage type stored in this field. @@ -606,102 +602,15 @@ impl<'a> Parse<'a> for ArrayType<'a> { } } -/// A type for a nested module -#[derive(Clone, Debug, Default)] -pub struct ModuleType<'a> { - /// The imports that are expected for this module type. - pub imports: Vec>, - /// The exports that this module type is expected to have. - pub exports: Vec>, -} - -impl<'a> Parse<'a> for ModuleType<'a> { - fn parse(parser: Parser<'a>) -> Result { - // See comments in `nested_module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("module type nesting too deep")); - } - - let mut imports = Vec::new(); - while parser.peek2::() { - imports.push(parser.parens(|p| p.parse())?); - } - let mut exports = Vec::new(); - while parser.peek2::() { - parser.parens(|p| { - exports.push(p.parse()?); - Ok(()) - })?; - } - Ok(ModuleType { imports, exports }) - } -} - -impl<'a> Peek for ModuleType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - if let Some(next) = cursor.lparen() { - match next.keyword() { - Some(("import", _)) | Some(("export", _)) => return true, - _ => {} - } - } - - false - } - - fn display() -> &'static str { - "module type" - } -} - -/// A type for a nested instance -#[derive(Clone, Debug, Default)] -pub struct InstanceType<'a> { - /// The exported types from this instance - pub exports: Vec>, -} - -impl<'a> Parse<'a> for InstanceType<'a> { - fn parse(parser: Parser<'a>) -> Result { - // See comments in `nested_module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("instance type nesting too deep")); - } - - let mut exports = Vec::new(); - while !parser.is_empty() { - exports.push(parser.parens(|p| p.parse())?); - } - Ok(InstanceType { exports }) - } -} - -impl<'a> Peek for InstanceType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - if let Some(next) = cursor.lparen() { - match next.keyword() { - Some(("export", _)) => return true, - _ => {} - } - } - - false - } - - fn display() -> &'static str { - "instance type" - } -} - /// The type of an exported item from a module or instance. #[derive(Debug, Clone)] pub struct ExportType<'a> { /// Where this export was defined. - pub span: ast::Span, + pub span: Span, /// The name of this export. pub name: &'a str, /// The signature of the item that's exported. - pub item: ast::ItemSig<'a>, + pub item: ItemSig<'a>, } impl<'a> Parse<'a> for ExportType<'a> { @@ -722,22 +631,18 @@ pub enum TypeDef<'a> { Struct(StructType<'a>), /// An array type definition. Array(ArrayType<'a>), - /// A module type definition. - Module(ModuleType<'a>), - /// An instance type definition. - Instance(InstanceType<'a>), } /// A type declaration in a module #[derive(Debug)] pub struct Type<'a> { /// Where this type was defined. - pub span: ast::Span, + pub span: Span, /// An optional identifer to refer to this `type` by as part of name /// resolution. - pub id: Option>, + pub id: Option>, /// An optional name for this function stored in the custom `name` section. - pub name: Option>, + pub name: Option>, /// The type that we're declaring. pub def: TypeDef<'a>, } @@ -758,12 +663,6 @@ impl<'a> Parse<'a> for Type<'a> { } else if l.peek::() { parser.parse::()?; Ok(TypeDef::Array(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypeDef::Module(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypeDef::Instance(parser.parse()?)) } else { Err(l.error()) } @@ -781,7 +680,7 @@ impl<'a> Parse<'a> for Type<'a> { #[derive(Clone, Debug)] pub struct TypeUse<'a, T> { /// The type that we're referencing, if it was present. - pub index: Option>, + pub index: Option>, /// The inline type, if present. pub inline: Option, } @@ -789,15 +688,9 @@ pub struct TypeUse<'a, T> { impl<'a, T> TypeUse<'a, T> { /// Constructs a new instance of `TypeUse` without an inline definition but /// with an index specified. - pub fn new_with_index(idx: ast::Index<'a>) -> TypeUse<'a, T> { + pub fn new_with_index(idx: Index<'a>) -> TypeUse<'a, T> { TypeUse { - index: Some(ast::ItemRef::Item { - idx, - kind: kw::r#type::default(), - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: true, - }), + index: Some(idx), inline: None, } } @@ -806,7 +699,10 @@ impl<'a, T> TypeUse<'a, T> { impl<'a, T: Peek + Parse<'a>> Parse<'a> for TypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { let index = if parser.peek2::() { - Some(parser.parse()?) + Some(parser.parens(|p| { + p.parse::()?; + p.parse() + })?) } else { None }; diff --git a/third_party/rust/wast/src/encode.rs b/third_party/rust/wast/src/encode.rs new file mode 100644 index 000000000000..8e6d3ac7339e --- /dev/null +++ b/third_party/rust/wast/src/encode.rs @@ -0,0 +1,75 @@ +pub(crate) trait Encode { + fn encode(&self, e: &mut Vec); +} + +impl Encode for &'_ T { + fn encode(&self, e: &mut Vec) { + T::encode(self, e) + } +} + +impl Encode for [T] { + fn encode(&self, e: &mut Vec) { + self.len().encode(e); + for item in self { + item.encode(e); + } + } +} + +impl Encode for Vec { + fn encode(&self, e: &mut Vec) { + <[T]>::encode(self, e) + } +} + +impl Encode for str { + fn encode(&self, e: &mut Vec) { + self.len().encode(e); + e.extend_from_slice(self.as_bytes()); + } +} + +impl Encode for usize { + fn encode(&self, e: &mut Vec) { + assert!(*self <= u32::max_value() as usize); + (*self as u32).encode(e) + } +} + +impl Encode for u8 { + fn encode(&self, e: &mut Vec) { + e.push(*self); + } +} + +impl Encode for u32 { + fn encode(&self, e: &mut Vec) { + leb128::write::unsigned(e, (*self).into()).unwrap(); + } +} + +impl Encode for i32 { + fn encode(&self, e: &mut Vec) { + leb128::write::signed(e, (*self).into()).unwrap(); + } +} + +impl Encode for u64 { + fn encode(&self, e: &mut Vec) { + leb128::write::unsigned(e, (*self).into()).unwrap(); + } +} + +impl Encode for i64 { + fn encode(&self, e: &mut Vec) { + leb128::write::signed(e, *self).unwrap(); + } +} + +impl Encode for (T, U) { + fn encode(&self, e: &mut Vec) { + self.0.encode(e); + self.1.encode(e); + } +} diff --git a/third_party/rust/wast/src/error.rs b/third_party/rust/wast/src/error.rs new file mode 100644 index 000000000000..d2c40398111c --- /dev/null +++ b/third_party/rust/wast/src/error.rs @@ -0,0 +1,196 @@ +use crate::lexer::LexError; +use crate::token::Span; +use std::fmt; +use std::path::{Path, PathBuf}; +use unicode_width::UnicodeWidthStr; + +/// A convenience error type to tie together all the detailed errors produced by +/// this crate. +/// +/// This type can be created from a [`LexError`]. This also contains +/// storage for file/text information so a nice error can be rendered along the +/// same lines of rustc's own error messages (minus the color). +/// +/// This type is typically suitable for use in public APIs for consumers of this +/// crate. +#[derive(Debug)] +pub struct Error { + inner: Box, +} + +#[derive(Debug)] +struct ErrorInner { + text: Option, + file: Option, + span: Span, + kind: ErrorKind, +} + +#[derive(Debug)] +struct Text { + line: usize, + col: usize, + snippet: String, +} + +#[derive(Debug)] +enum ErrorKind { + Lex(LexError), + Custom(String), +} + +impl Error { + pub(crate) fn lex(span: Span, content: &str, kind: LexError) -> Error { + let mut ret = Error { + inner: Box::new(ErrorInner { + text: None, + file: None, + span, + kind: ErrorKind::Lex(kind), + }), + }; + ret.set_text(content); + return ret; + } + + pub(crate) fn parse(span: Span, content: &str, message: String) -> Error { + let mut ret = Error { + inner: Box::new(ErrorInner { + text: None, + file: None, + span, + kind: ErrorKind::Custom(message), + }), + }; + ret.set_text(content); + return ret; + } + + /// Creates a new error with the given `message` which is targeted at the + /// given `span` + /// + /// Note that you'll want to ensure that `set_text` or `set_path` is called + /// on the resulting error to improve the rendering of the error message. + pub fn new(span: Span, message: String) -> Error { + Error { + inner: Box::new(ErrorInner { + text: None, + file: None, + span, + kind: ErrorKind::Custom(message), + }), + } + } + + /// Return the `Span` for this error. + pub fn span(&self) -> Span { + self.inner.span + } + + /// To provide a more useful error this function can be used to extract + /// relevant textual information about this error into the error itself. + /// + /// The `contents` here should be the full text of the original file being + /// parsed, and this will extract a sub-slice as necessary to render in the + /// `Display` implementation later on. + pub fn set_text(&mut self, contents: &str) { + if self.inner.text.is_some() { + return; + } + self.inner.text = Some(Text::new(contents, self.inner.span)); + } + + /// To provide a more useful error this function can be used to set + /// the file name that this error is associated with. + /// + /// The `path` here will be stored in this error and later rendered in the + /// `Display` implementation. + pub fn set_path(&mut self, path: &Path) { + if self.inner.file.is_some() { + return; + } + self.inner.file = Some(path.to_path_buf()); + } + + /// Returns the underlying `LexError`, if any, that describes this error. + pub fn lex_error(&self) -> Option<&LexError> { + match &self.inner.kind { + ErrorKind::Lex(e) => Some(e), + _ => None, + } + } + + /// Returns the underlying message, if any, that describes this error. + pub fn message(&self) -> String { + match &self.inner.kind { + ErrorKind::Lex(e) => e.to_string(), + ErrorKind::Custom(e) => e.clone(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let err = match &self.inner.kind { + ErrorKind::Lex(e) => e as &dyn fmt::Display, + ErrorKind::Custom(e) => e as &dyn fmt::Display, + }; + let text = match &self.inner.text { + Some(text) => text, + None => { + return write!(f, "{} at byte offset {}", err, self.inner.span.offset); + } + }; + let file = self + .inner + .file + .as_ref() + .and_then(|p| p.to_str()) + .unwrap_or(""); + write!( + f, + "\ +{err} + --> {file}:{line}:{col} + | + {line:4} | {text} + | {marker:>0$}", + text.col + 1, + file = file, + line = text.line + 1, + col = text.col + 1, + err = err, + text = text.snippet, + marker = "^", + ) + } +} + +impl std::error::Error for Error {} + +impl Text { + fn new(content: &str, span: Span) -> Text { + let (line, col) = span.linecol_in(content); + let contents = content.lines().nth(line).unwrap_or(""); + let mut snippet = String::new(); + for ch in contents.chars() { + match ch { + // Replace tabs with spaces to render consistently + '\t' => { + snippet.push_str(" "); + } + // these codepoints change how text is rendered so for clarity + // in error messages they're dropped. + '\u{202a}' | '\u{202b}' | '\u{202d}' | '\u{202e}' | '\u{2066}' | '\u{2067}' + | '\u{2068}' | '\u{206c}' | '\u{2069}' => {} + + c => snippet.push(c), + } + } + // Use the `unicode-width` crate to figure out how wide the snippet, up + // to our "column", actually is. That'll tell us how many spaces to + // place before the `^` character that points at the problem + let col = snippet.get(..col).map(|s| s.width()).unwrap_or(col); + Text { line, col, snippet } + } +} diff --git a/third_party/rust/wast/src/resolve/gensym.rs b/third_party/rust/wast/src/gensym.rs similarity index 92% rename from third_party/rust/wast/src/resolve/gensym.rs rename to third_party/rust/wast/src/gensym.rs index 5f6d94133a1f..9f718f06d9b9 100644 --- a/third_party/rust/wast/src/resolve/gensym.rs +++ b/third_party/rust/wast/src/gensym.rs @@ -1,4 +1,4 @@ -use crate::ast::{Id, Span}; +use crate::token::{Id, Span}; use std::cell::Cell; thread_local!(static NEXT: Cell = Cell::new(0)); diff --git a/third_party/rust/wast/src/lexer.rs b/third_party/rust/wast/src/lexer.rs index afda80102775..5b6f577bfac9 100644 --- a/third_party/rust/wast/src/lexer.rs +++ b/third_party/rust/wast/src/lexer.rs @@ -24,7 +24,8 @@ //! //! [`Lexer`]: crate::lexer::Lexer -use crate::{Error, Span}; +use crate::token::Span; +use crate::Error; use std::borrow::Cow; use std::char; use std::fmt; @@ -32,7 +33,7 @@ use std::str; /// A structure used to lex the s-expression syntax of WAT files. /// -/// This structure is used to generate [`Source`] items, which should account for +/// This structure is used to generate [`Token`] items, which should account for /// every single byte of the input as we iterate over it. A [`LexError`] is /// returned for any non-lexable text. #[derive(Clone)] @@ -483,10 +484,10 @@ impl<'a> Lexer<'a> { } fn number(&self, src: &'a str) -> Option> { - let (sign, num) = if src.starts_with('+') { - (Some(SignToken::Plus), &src[1..]) - } else if src.starts_with('-') { - (Some(SignToken::Minus), &src[1..]) + let (sign, num) = if let Some(stripped) = src.strip_prefix('+') { + (Some(SignToken::Plus), stripped) + } else if let Some(stripped) = src.strip_prefix('-') { + (Some(SignToken::Minus), stripped) } else { (None, src) }; @@ -507,8 +508,8 @@ impl<'a> Lexer<'a> { negative, }, })))); - } else if num.starts_with("nan:0x") { - let mut it = num[6..].chars(); + } else if let Some(stripped) = num.strip_prefix("nan:0x") { + let mut it = stripped.chars(); let to_parse = skip_undescores(&mut it, false, char::is_ascii_hexdigit)?; if it.next().is_some() { return None; @@ -524,9 +525,9 @@ impl<'a> Lexer<'a> { } // Figure out if we're a hex number or not - let (mut it, hex, test_valid) = if num.starts_with("0x") { + let (mut it, hex, test_valid) = if let Some(stripped) = num.strip_prefix("0x") { ( - num[2..].chars(), + stripped.chars(), true, char::is_ascii_hexdigit as fn(&char) -> bool, ) diff --git a/third_party/rust/wast/src/lib.rs b/third_party/rust/wast/src/lib.rs index 57a0cf8d84ac..ce2b39216e7c 100644 --- a/third_party/rust/wast/src/lib.rs +++ b/third_party/rust/wast/src/lib.rs @@ -20,9 +20,10 @@ //! around working with a [`Parser`](`parser::Parser`) to parse streams of //! tokens. //! -//! * [`Module`] - this contains an Abstract Syntax Tree (AST) of the -//! WebAssembly Text format (WAT) as well as the unofficial WAST format. This -//! also has a [`Module::encode`] method to emit a module in its binary form. +//! * [`Module`](crate::core::Module) - this contains an Abstract Syntax Tree +//! (AST) of the WebAssembly Text format (WAT) as well as the unofficial WAST +//! format. This also has a [`Module::encode`](crate::core::Module::encode) +//! method to emit a module in its binary form. //! //! # Stability and WebAssembly Features //! @@ -47,209 +48,463 @@ #![deny(missing_docs, rustdoc::broken_intra_doc_links)] -use std::fmt; -use std::path::{Path, PathBuf}; -use unicode_width::UnicodeWidthStr; +/// A macro to create a custom keyword parser. +/// +/// This macro is invoked in one of two forms: +/// +/// ``` +/// // keyword derived from the Rust identifier: +/// wast::custom_keyword!(foo); +/// +/// // or an explicitly specified string representation of the keyword: +/// wast::custom_keyword!(my_keyword = "the-wasm-keyword"); +/// ``` +/// +/// This can then be used to parse custom keyword for custom items, such as: +/// +/// ``` +/// use wast::parser::{Parser, Result, Parse}; +/// +/// struct InlineModule<'a> { +/// inline_text: &'a str, +/// } +/// +/// mod kw { +/// wast::custom_keyword!(inline); +/// } +/// +/// // Parse an inline string module of the form: +/// // +/// // (inline "(module (func))") +/// impl<'a> Parse<'a> for InlineModule<'a> { +/// fn parse(parser: Parser<'a>) -> Result { +/// parser.parse::()?; +/// Ok(InlineModule { +/// inline_text: parser.parse()?, +/// }) +/// } +/// } +/// ``` +/// +/// Note that the keyword name can only start with a lower-case letter, i.e. 'a'..'z'. +#[macro_export] +macro_rules! custom_keyword { + ($name:ident) => { + $crate::custom_keyword!($name = stringify!($name)); + }; + ($name:ident = $kw:expr) => { + #[allow(non_camel_case_types)] + #[allow(missing_docs)] + #[derive(Debug, Copy, Clone)] + pub struct $name(pub $crate::token::Span); -#[cfg(feature = "wasm-module")] -mod binary; -#[cfg(feature = "wasm-module")] -mod resolve; + impl<'a> $crate::parser::Parse<'a> for $name { + fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { + parser.step(|c| { + if let Some((kw, rest)) = c.keyword() { + if kw == $kw { + return Ok(($name(c.cur_span()), rest)); + } + } + Err(c.error(concat!("expected keyword `", $kw, "`"))) + }) + } + } -mod ast; -pub use self::ast::*; + impl $crate::parser::Peek for $name { + fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { + if let Some((kw, _rest)) = cursor.keyword() { + kw == $kw + } else { + false + } + } + + fn display() -> &'static str { + concat!("`", $kw, "`") + } + } + }; +} + +/// A macro for defining custom reserved symbols. +/// +/// This is like `custom_keyword!` but for reserved symbols (`Token::Reserved`) +/// instead of keywords (`Token::Keyword`). +/// +/// ``` +/// use wast::parser::{Parser, Result, Parse}; +/// +/// // Define a custom reserved symbol, the "spaceship" operator: `<=>`. +/// wast::custom_reserved!(spaceship = "<=>"); +/// +/// /// A "three-way comparison" like `(<=> a b)` that returns -1 if `a` is less +/// /// than `b`, 0 if they're equal, and 1 if `a` is greater than `b`. +/// struct ThreeWayComparison<'a> { +/// lhs: wast::core::Expression<'a>, +/// rhs: wast::core::Expression<'a>, +/// } +/// +/// impl<'a> Parse<'a> for ThreeWayComparison<'a> { +/// fn parse(parser: Parser<'a>) -> Result { +/// parser.parse::()?; +/// let lhs = parser.parse()?; +/// let rhs = parser.parse()?; +/// Ok(ThreeWayComparison { lhs, rhs }) +/// } +/// } +/// ``` +#[macro_export] +macro_rules! custom_reserved { + ($name:ident) => { + $crate::custom_reserved!($name = stringify!($name)); + }; + ($name:ident = $rsv:expr) => { + #[allow(non_camel_case_types)] + #[allow(missing_docs)] + #[derive(Debug)] + pub struct $name(pub $crate::token::Span); + + impl<'a> $crate::parser::Parse<'a> for $name { + fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { + parser.step(|c| { + if let Some((rsv, rest)) = c.reserved() { + if rsv == $rsv { + return Ok(($name(c.cur_span()), rest)); + } + } + Err(c.error(concat!("expected reserved symbol `", $rsv, "`"))) + }) + } + } + + impl $crate::parser::Peek for $name { + fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { + if let Some((rsv, _rest)) = cursor.reserved() { + rsv == $rsv + } else { + false + } + } + + fn display() -> &'static str { + concat!("`", $rsv, "`") + } + } + }; +} + +/// A macro, like [`custom_keyword`], to create a type which can be used to +/// parse/peek annotation directives. +/// +/// Note that when you're parsing custom annotations it can be somewhat tricky +/// due to the nature that most of them are skipped. You'll want to be sure to +/// consult the documentation of [`Parser::register_annotation`][register] when +/// using this macro. +/// +/// # Examples +/// +/// To see an example of how to use this macro, let's invent our own syntax for +/// the [producers section][section] which looks like: +/// +/// ```wat +/// (@producer "wat" "1.0.2") +/// ``` +/// +/// Here, for simplicity, we'll assume everything is a `processed-by` directive, +/// but you could get much more fancy with this as well. +/// +/// ``` +/// # use wast::*; +/// # use wast::parser::*; +/// +/// // First we define the custom annotation keyword we're using, and by +/// // convention we define it in an `annotation` module. +/// mod annotation { +/// wast::annotation!(producer); +/// } +/// +/// struct Producer<'a> { +/// name: &'a str, +/// version: &'a str, +/// } +/// +/// impl<'a> Parse<'a> for Producer<'a> { +/// fn parse(parser: Parser<'a>) -> Result { +/// // Remember that parser conventionally parse the *interior* of an +/// // s-expression, so we parse our `@producer` annotation and then we +/// // parse the payload of our annotation. +/// parser.parse::()?; +/// Ok(Producer { +/// name: parser.parse()?, +/// version: parser.parse()?, +/// }) +/// } +/// } +/// ``` +/// +/// Note though that this is only half of the parser for annotations. The other +/// half is calling the [`register_annotation`][register] method at the right +/// time to ensure the parser doesn't automatically skip our `@producer` +/// directive. Note that we *can't* call it inside the `Parse for Producer` +/// definition because that's too late and the annotation would already have +/// been skipped. +/// +/// Instead we'll need to call it from a higher level-parser before the +/// parenthesis have been parsed, like so: +/// +/// ``` +/// # use wast::*; +/// # use wast::parser::*; +/// struct Module<'a> { +/// fields: Vec>, +/// } +/// +/// impl<'a> Parse<'a> for Module<'a> { +/// fn parse(parser: Parser<'a>) -> Result { +/// // .. parse module header here ... +/// +/// // register our custom `@producer` annotation before we start +/// // parsing the parentheses of each field +/// let _r = parser.register_annotation("producer"); +/// +/// let mut fields = Vec::new(); +/// while !parser.is_empty() { +/// fields.push(parser.parens(|p| p.parse())?); +/// } +/// Ok(Module { fields }) +/// } +/// } +/// +/// enum ModuleField<'a> { +/// Producer(Producer<'a>), +/// // ... +/// } +/// # struct Producer<'a>(&'a str); +/// # impl<'a> Parse<'a> for Producer<'a> { +/// # fn parse(parser: Parser<'a>) -> Result { Ok(Producer(parser.parse()?)) } +/// # } +/// # mod annotation { wast::annotation!(producer); } +/// +/// impl<'a> Parse<'a> for ModuleField<'a> { +/// fn parse(parser: Parser<'a>) -> Result { +/// // and here `peek` works and our delegated parsing works because the +/// // annotation has been registered. +/// if parser.peek::() { +/// return Ok(ModuleField::Producer(parser.parse()?)); +/// } +/// +/// // .. typically we'd parse other module fields here... +/// +/// Err(parser.error("unknown module field")) +/// } +/// } +/// ``` +/// +/// [register]: crate::parser::Parser::register_annotation +/// [section]: https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md +#[macro_export] +macro_rules! annotation { + ($name:ident) => { + $crate::annotation!($name = stringify!($name)); + }; + ($name:ident = $annotation:expr) => { + #[allow(non_camel_case_types)] + #[allow(missing_docs)] + #[derive(Debug)] + pub struct $name(pub $crate::token::Span); + + impl<'a> $crate::parser::Parse<'a> for $name { + fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { + parser.step(|c| { + if let Some((a, rest)) = c.annotation() { + if a == $annotation { + return Ok(($name(c.cur_span()), rest)); + } + } + Err(c.error(concat!("expected annotation `@", $annotation, "`"))) + }) + } + } + + impl $crate::parser::Peek for $name { + fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { + if let Some((a, _rest)) = cursor.annotation() { + a == $annotation + } else { + false + } + } + + fn display() -> &'static str { + concat!("`@", $annotation, "`") + } + } + }; +} pub mod lexer; pub mod parser; +pub mod token; -/// A convenience error type to tie together all the detailed errors produced by -/// this crate. -/// -/// This type can be created from a [`lexer::LexError`] or [`parser::Error`]. -/// This also contains storage for file/text information so a nice error can be -/// rendered along the same lines of rustc's own error messages (minus the -/// color). -/// -/// This type is typically suitable for use in public APIs for consumers of this -/// crate. -#[derive(Debug)] -pub struct Error { - inner: Box, +mod encode; +mod error; +mod gensym; +mod names; +pub use self::error::*; + +macro_rules! id { + ($($t:tt)*) => ($($t)*) } -#[derive(Debug)] -struct ErrorInner { - text: Option, - file: Option, - span: Span, - kind: ErrorKind, +#[cfg(feature = "wasm-module")] +id! { + mod assert_expr; + mod wast; + mod wat; + pub use self::assert_expr::*; + pub use self::wast::*; + pub use self::wat::*; + + // Support for core wasm parsing + pub mod core; + + // Support for component model parsing + pub mod component; } -#[derive(Debug)] -struct Text { - line: usize, - col: usize, - snippet: String, +/// Common keyword used to parse WebAssembly text files. +pub mod kw { + custom_keyword!(after); + custom_keyword!(alias); + custom_keyword!(any); + custom_keyword!(anyfunc); + custom_keyword!(anyref); + custom_keyword!(arg); + custom_keyword!(array); + custom_keyword!(assert_exception); + custom_keyword!(assert_exhaustion); + custom_keyword!(assert_invalid); + custom_keyword!(assert_malformed); + custom_keyword!(assert_return); + custom_keyword!(assert_trap); + custom_keyword!(assert_unlinkable); + custom_keyword!(before); + custom_keyword!(binary); + custom_keyword!(block); + custom_keyword!(catch); + custom_keyword!(catch_all); + custom_keyword!(code); + custom_keyword!(component); + custom_keyword!(data); + custom_keyword!(dataref); + custom_keyword!(declare); + custom_keyword!(delegate); + custom_keyword!(r#do = "do"); + custom_keyword!(elem); + custom_keyword!(end); + custom_keyword!(tag); + custom_keyword!(export); + custom_keyword!(r#extern = "extern"); + custom_keyword!(externref); + custom_keyword!(eq); + custom_keyword!(eqref); + custom_keyword!(f32); + custom_keyword!(f32x4); + custom_keyword!(f64); + custom_keyword!(f64x2); + custom_keyword!(field); + custom_keyword!(first); + custom_keyword!(func); + custom_keyword!(funcref); + custom_keyword!(get); + custom_keyword!(global); + custom_keyword!(i16); + custom_keyword!(i16x8); + custom_keyword!(i31); + custom_keyword!(i31ref); + custom_keyword!(i32); + custom_keyword!(i32x4); + custom_keyword!(i64); + custom_keyword!(i64x2); + custom_keyword!(i8); + custom_keyword!(i8x16); + custom_keyword!(import); + custom_keyword!(instance); + custom_keyword!(instantiate); + custom_keyword!(invoke); + custom_keyword!(item); + custom_keyword!(last); + custom_keyword!(local); + custom_keyword!(memory); + custom_keyword!(module); + custom_keyword!(modulecode); + custom_keyword!(nan_arithmetic = "nan:arithmetic"); + custom_keyword!(nan_canonical = "nan:canonical"); + custom_keyword!(null); + custom_keyword!(nullref); + custom_keyword!(offset); + custom_keyword!(outer); + custom_keyword!(param); + custom_keyword!(parent); + custom_keyword!(passive); + custom_keyword!(quote); + custom_keyword!(r#else = "else"); + custom_keyword!(r#if = "if"); + custom_keyword!(r#loop = "loop"); + custom_keyword!(r#mut = "mut"); + custom_keyword!(r#type = "type"); + custom_keyword!(r#ref = "ref"); + custom_keyword!(ref_func = "ref.func"); + custom_keyword!(ref_null = "ref.null"); + custom_keyword!(register); + custom_keyword!(result); + custom_keyword!(rtt); + custom_keyword!(shared); + custom_keyword!(start); + custom_keyword!(r#struct = "struct"); + custom_keyword!(table); + custom_keyword!(then); + custom_keyword!(r#try = "try"); + custom_keyword!(v128); + custom_keyword!(value); + custom_keyword!(s8); + custom_keyword!(s16); + custom_keyword!(s32); + custom_keyword!(s64); + custom_keyword!(u8); + custom_keyword!(u16); + custom_keyword!(u32); + custom_keyword!(u64); + custom_keyword!(char); + custom_keyword!(case); + custom_keyword!(defaults_to = "defaults-to"); + custom_keyword!(record); + custom_keyword!(string); + custom_keyword!(bool_ = "bool"); + custom_keyword!(float32); + custom_keyword!(float64); + custom_keyword!(variant); + custom_keyword!(unit); + custom_keyword!(flags); + custom_keyword!(option); + custom_keyword!(tuple); + custom_keyword!(list); + custom_keyword!(union); + custom_keyword!(expected); + custom_keyword!(canon_lift = "canon.lift"); + custom_keyword!(canon_lower = "canon.lower"); + custom_keyword!(enum_ = "enum"); + custom_keyword!(string_utf8 = "string=utf8"); + custom_keyword!(string_utf16 = "string=utf16"); + custom_keyword!(string_latin1_utf16 = "string=latin1+utf16"); + custom_keyword!(into); + custom_keyword!(with); + custom_keyword!(core); } -#[derive(Debug)] -enum ErrorKind { - Lex(lexer::LexError), - Custom(String), -} - -impl Error { - fn lex(span: Span, content: &str, kind: lexer::LexError) -> Error { - let mut ret = Error { - inner: Box::new(ErrorInner { - text: None, - file: None, - span, - kind: ErrorKind::Lex(kind), - }), - }; - ret.set_text(content); - return ret; - } - - fn parse(span: Span, content: &str, message: String) -> Error { - let mut ret = Error { - inner: Box::new(ErrorInner { - text: None, - file: None, - span, - kind: ErrorKind::Custom(message), - }), - }; - ret.set_text(content); - return ret; - } - - /// Creates a new error with the given `message` which is targeted at the - /// given `span` - /// - /// Note that you'll want to ensure that `set_text` or `set_path` is called - /// on the resulting error to improve the rendering of the error message. - pub fn new(span: Span, message: String) -> Error { - Error { - inner: Box::new(ErrorInner { - text: None, - file: None, - span, - kind: ErrorKind::Custom(message), - }), - } - } - - /// Return the `Span` for this error. - pub fn span(&self) -> Span { - self.inner.span - } - - /// To provide a more useful error this function can be used to extract - /// relevant textual information about this error into the error itself. - /// - /// The `contents` here should be the full text of the original file being - /// parsed, and this will extract a sub-slice as necessary to render in the - /// `Display` implementation later on. - pub fn set_text(&mut self, contents: &str) { - if self.inner.text.is_some() { - return; - } - self.inner.text = Some(Text::new(contents, self.inner.span)); - } - - /// To provide a more useful error this function can be used to set - /// the file name that this error is associated with. - /// - /// The `path` here will be stored in this error and later rendered in the - /// `Display` implementation. - pub fn set_path(&mut self, path: &Path) { - if self.inner.file.is_some() { - return; - } - self.inner.file = Some(path.to_path_buf()); - } - - /// Returns the underlying `LexError`, if any, that describes this error. - pub fn lex_error(&self) -> Option<&lexer::LexError> { - match &self.inner.kind { - ErrorKind::Lex(e) => Some(e), - _ => None, - } - } - - /// Returns the underlying message, if any, that describes this error. - pub fn message(&self) -> String { - match &self.inner.kind { - ErrorKind::Lex(e) => e.to_string(), - ErrorKind::Custom(e) => e.clone(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let err = match &self.inner.kind { - ErrorKind::Lex(e) => e as &dyn fmt::Display, - ErrorKind::Custom(e) => e as &dyn fmt::Display, - }; - let text = match &self.inner.text { - Some(text) => text, - None => { - return write!(f, "{} at byte offset {}", err, self.inner.span.offset); - } - }; - let file = self - .inner - .file - .as_ref() - .and_then(|p| p.to_str()) - .unwrap_or(""); - write!( - f, - "\ -{err} - --> {file}:{line}:{col} - | - {line:4} | {text} - | {marker:>0$}", - text.col + 1, - file = file, - line = text.line + 1, - col = text.col + 1, - err = err, - text = text.snippet, - marker = "^", - ) - } -} - -impl std::error::Error for Error {} - -impl Text { - fn new(content: &str, span: Span) -> Text { - let (line, col) = span.linecol_in(content); - let contents = content.lines().nth(line).unwrap_or(""); - let mut snippet = String::new(); - for ch in contents.chars() { - match ch { - // Replace tabs with spaces to render consistently - '\t' => { - snippet.push_str(" "); - } - // these codepoints change how text is rendered so for clarity - // in error messages they're dropped. - '\u{202a}' | '\u{202b}' | '\u{202d}' | '\u{202e}' | '\u{2066}' | '\u{2067}' - | '\u{2068}' | '\u{206c}' | '\u{2069}' => {} - - c => snippet.push(c), - } - } - // Use the `unicode-width` crate to figure out how wide the snippet, up - // to our "column", actually is. That'll tell us how many spaces to - // place before the `^` character that points at the problem - let col = snippet.get(..col).map(|s| s.width()).unwrap_or(col); - Text { line, col, snippet } - } +/// Common annotations used to parse WebAssembly text files. +pub mod annotation { + annotation!(custom); + annotation!(name); } diff --git a/third_party/rust/wast/src/names.rs b/third_party/rust/wast/src/names.rs new file mode 100644 index 000000000000..2605673d4df6 --- /dev/null +++ b/third_party/rust/wast/src/names.rs @@ -0,0 +1,86 @@ +use crate::token::{Id, Index}; +use crate::Error; +use std::collections::HashMap; + +#[derive(Default)] +pub struct Namespace<'a> { + names: HashMap, u32>, + count: u32, +} + +impl<'a> Namespace<'a> { + pub fn register(&mut self, name: Option>, desc: &str) -> Result { + let index = self.alloc(); + if let Some(name) = name { + if let Some(_prev) = self.names.insert(name, index) { + // FIXME: temporarily allow duplicately-named data and element + // segments. This is a sort of dumb hack to get the spec test + // suite working (ironically). + // + // So as background, the text format disallows duplicate + // identifiers, causing a parse error if they're found. There + // are two tests currently upstream, however, data.wast and + // elem.wast, which *look* like they have duplicately named + // element and data segments. These tests, however, are using + // pre-bulk-memory syntax where a bare identifier was the + // table/memory being initialized. In post-bulk-memory this + // identifier is the name of the segment. Since we implement + // post-bulk-memory features that means that we're parsing the + // memory/table-to-initialize as the name of the segment. + // + // This is technically incorrect behavior but no one is + // hopefully relying on this too much. To get the spec tests + // passing we ignore errors for elem/data segments. Once the + // spec tests get updated enough we can remove this condition + // and return errors for them. + if desc != "elem" && desc != "data" { + return Err(Error::new( + name.span(), + format!("duplicate {} identifier", desc), + )); + } + } + } + Ok(index) + } + + pub fn alloc(&mut self) -> u32 { + let index = self.count; + self.count += 1; + return index; + } + + pub fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> { + if let Some(_prev) = self.names.insert(name, index) { + return Err(Error::new( + name.span(), + format!("duplicate identifier for {}", desc), + )); + } + Ok(()) + } + + pub fn resolve(&self, idx: &mut Index<'a>, desc: &str) -> Result { + let id = match idx { + Index::Num(n, _) => return Ok(*n), + Index::Id(id) => id, + }; + if let Some(&n) = self.names.get(id) { + *idx = Index::Num(n, id.span()); + return Ok(n); + } + Err(resolve_error(*id, desc)) + } +} + +pub fn resolve_error(id: Id<'_>, ns: &str) -> Error { + assert!( + !id.is_gensym(), + "symbol generated by `wast` itself cannot be resolved {:?}", + id + ); + Error::new( + id.span(), + format!("failed to find {} named `${}`", ns, id.name()), + ) +} diff --git a/third_party/rust/wast/src/parser.rs b/third_party/rust/wast/src/parser.rs index e406b8e72ccb..2c30a4d1abfe 100644 --- a/third_party/rust/wast/src/parser.rs +++ b/third_party/rust/wast/src/parser.rs @@ -24,7 +24,8 @@ //! [`Parse`](crate::parser::Parse) trait: //! //! ``` -//! use wast::{kw, Import, Func}; +//! use wast::kw; +//! use wast::core::{Import, Func}; //! use wast::parser::{Parser, Parse, Result}; //! //! // Fields of a WebAssembly which only allow imports and functions, and all @@ -64,7 +65,8 @@ //! likely also draw inspiration from the excellent examples in the `syn` crate. use crate::lexer::{Float, Integer, Lexer, Token}; -use crate::{Error, Span}; +use crate::token::Span; +use crate::Error; use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::fmt; @@ -118,7 +120,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result { /// The [`Parse`] trait is main abstraction you'll be working with when defining /// custom parser or custom syntax for your WebAssembly text format (or when /// using the official format items). Almost all items in the -/// [`ast`](crate::ast) module implement the [`Parse`] trait, and you'll +/// [`core`](crate::core) module implement the [`Parse`] trait, and you'll /// commonly use this with: /// /// * The top-level [`parse`] function to parse an entire input. @@ -139,7 +141,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result { /// (import "foo" "bar" (func (type 0))) /// ``` /// -/// but the [`Import`](crate::ast::Import) type parser looks like: +/// but the [`Import`](crate::core::Import) type parser looks like: /// /// ``` /// # use wast::kw; @@ -170,7 +172,8 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result { /// before all functions. An example [`Parse`] implementation might look like: /// /// ``` -/// use wast::{Import, Func, kw}; +/// use wast::core::{Import, Func}; +/// use wast::kw; /// use wast::parser::{Parser, Parse, Result}; /// /// // Fields of a WebAssembly which only allow imports and functions, and all @@ -268,7 +271,7 @@ pub trait Peek { /// A convenience type definition for `Result` where the error is hardwired to /// [`Error`]. -pub type Result = std::result::Result; +pub type Result = std::result::Result; /// A low-level buffer of tokens which represents a completely lexed file. /// @@ -475,7 +478,7 @@ impl<'a> Parser<'a> { /// and a [`RefType`] /// /// ``` - /// # use wast::*; + /// # use wast::core::*; /// # use wast::parser::*; /// struct TableType<'a> { /// limits: Limits, @@ -493,9 +496,9 @@ impl<'a> Parser<'a> { /// } /// ``` /// - /// [`Limits`]: crate::ast::Limits - /// [`TableType`]: crate::ast::TableType - /// [`RefType`]: crate::ast::RefType + /// [`Limits`]: crate::core::Limits + /// [`TableType`]: crate::core::TableType + /// [`RefType`]: crate::core::RefType pub fn parse>(self) -> Result { T::parse(self) } @@ -552,7 +555,7 @@ impl<'a> Parser<'a> { /// ``` /// /// [spec]: https://webassembly.github.io/spec/core/text/types.html#limits - /// [`Limits`]: crate::ast::Limits + /// [`Limits`]: crate::core::Limits pub fn peek(self) -> bool { T::peek(self.cursor()) } @@ -568,6 +571,17 @@ impl<'a> Parser<'a> { } } + /// Same as the [`Parser::peek2`] method, except checks the next next token, + /// not the next token. + pub fn peek3(self) -> bool { + let mut cursor = self.cursor(); + if cursor.advance_token().is_some() && cursor.advance_token().is_some() { + T::peek(cursor) + } else { + false + } + } + /// A helper structure to perform a sequence of `peek` operations and if /// they all fail produce a nice error message. /// @@ -592,7 +606,7 @@ impl<'a> Parser<'a> { /// parsing an [`Index`] we can do: /// /// ``` - /// # use wast::*; + /// # use wast::token::*; /// # use wast::parser::*; /// enum Index<'a> { /// Num(u32), @@ -615,8 +629,8 @@ impl<'a> Parser<'a> { /// ``` /// /// [spec]: https://webassembly.github.io/spec/core/text/modules.html#indices - /// [`Index`]: crate::ast::Index - /// [`Id`]: crate::ast::Id + /// [`Index`]: crate::token::Index + /// [`Id`]: crate::token::Id pub fn lookahead1(self) -> Lookahead1<'a> { Lookahead1 { attempts: Vec::new(), @@ -646,7 +660,8 @@ impl<'a> Parser<'a> { /// the exact definition, but it's close enough! /// /// ``` - /// # use wast::*; + /// # use wast::kw; + /// # use wast::core::*; /// # use wast::parser::*; /// struct Module<'a> { /// fields: Vec>, @@ -708,7 +723,7 @@ impl<'a> Parser<'a> { /// A low-level parsing method you probably won't use. /// /// This is used to implement parsing of the most primitive types in the - /// [`ast`](crate::ast) module. You probably don't want to use this, but + /// [`core`](crate::core) module. You probably don't want to use this, but /// probably want to use something like [`Parser::parse`] or /// [`Parser::parens`]. pub fn step(self, f: F) -> Result @@ -793,7 +808,8 @@ impl<'a> Parser<'a> { /// to get an idea of how this works: /// /// ``` - /// # use wast::*; + /// # use wast::kw; + /// # use wast::token::NameAnnotation; /// # use wast::parser::*; /// struct Module<'a> { /// name: Option>, @@ -824,7 +840,8 @@ impl<'a> Parser<'a> { /// registered *before* we parse the parentheses of the annotation. /// /// ``` - /// # use wast::*; + /// # use wast::{kw, annotation}; + /// # use wast::core::Custom; /// # use wast::parser::*; /// struct Module<'a> { /// fields: Vec>, diff --git a/third_party/rust/wast/src/resolve/aliases.rs b/third_party/rust/wast/src/resolve/aliases.rs deleted file mode 100644 index 4875eec4c99f..000000000000 --- a/third_party/rust/wast/src/resolve/aliases.rs +++ /dev/null @@ -1,335 +0,0 @@ -use crate::ast::*; -use crate::resolve::gensym; -use std::collections::{hash_map::Entry, HashMap}; - -pub fn run(fields: &mut Vec) { - let mut cur = 0; - let mut cx = Expander::default(); - - // Note that insertion here is somewhat tricky. We're injecting aliases - // which will affect the index spaces for each kind of item being aliased. - // In the final binary aliases will come before all locally defined items, - // notably via the sorting in binary emission of this crate. To account for - // this index space behavior we need to ensure that aliases all appear at - // the right place in the module. - // - // The general algorithm here is that aliases discovered in the "header" of - // the module, e.g. imports/aliases/types/etc, are all inserted preceding - // the field that the alias is found within. After the header, however, the - // position of the header is recorded and all future aliases will be - // inserted at that location. - // - // This ends up meaning that aliases found in globals/functions/tables/etc - // will precede all of those definitions, being positioned at a point that - // should come after all the instances that are defined as well. Overall - // this isn't the cleanest algorithm and probably isn't the final form of - // those. It's hoped that discussion on WebAssembly/module-linking#25 might - // lead to a good solution. - let mut insertion_point = None; - while cur < fields.len() { - let field = &mut fields[cur]; - match field { - ModuleField::Alias(_) - | ModuleField::Type(_) - | ModuleField::Import(_) - | ModuleField::NestedModule(_) - | ModuleField::Instance(_) => {} - _ if insertion_point.is_none() => insertion_point = Some(cur), - _ => {} - } - cx.process(field); - if insertion_point.is_none() { - for item in cx.to_prepend.drain(..) { - fields.insert(cur, item); - cur += 1; - } - } - cur += 1; - } - if let Some(mut i) = insertion_point { - for item in cx.to_prepend.drain(..) { - fields.insert(i, item); - i += 1; - } - } - assert!(cx.to_prepend.is_empty()); -} - -#[derive(Default)] -struct Expander<'a> { - to_prepend: Vec>, - instances: HashMap<(Index<'a>, &'a str, ExportKind), Index<'a>>, - parents: HashMap<(Index<'a>, Index<'a>, ExportKind), Index<'a>>, -} - -impl<'a> Expander<'a> { - fn process(&mut self, field: &mut ModuleField<'a>) { - match field { - ModuleField::Alias(a) => { - let id = gensym::fill(a.span, &mut a.id); - match &mut a.source { - AliasSource::InstanceExport { instance, export } => { - self.expand(instance); - self.instances - .insert((*instance.unwrap_index(), export, a.kind), id.into()); - } - AliasSource::Outer { module, index } => { - self.parents.insert((*module, *index, a.kind), id.into()); - } - } - } - - ModuleField::Instance(i) => { - if let InstanceKind::Inline { module, args } = &mut i.kind { - self.expand(module); - for arg in args { - self.expand(&mut arg.index); - } - } - } - - ModuleField::Elem(e) => { - if let ElemKind::Active { table, offset, .. } = &mut e.kind { - self.expand(table); - self.expand_expr(offset); - } - match &mut e.payload { - ElemPayload::Indices(funcs) => { - for func in funcs { - self.expand(func); - } - } - ElemPayload::Exprs { exprs, .. } => { - for expr in exprs { - self.expand_expr(expr); - } - } - } - } - - ModuleField::Data(e) => { - if let DataKind::Active { memory, offset, .. } = &mut e.kind { - self.expand(memory); - self.expand_expr(offset); - } - } - - ModuleField::Export(e) => self.expand(&mut e.index), - - ModuleField::Func(f) => { - self.expand_type_use(&mut f.ty); - if let FuncKind::Inline { expression, .. } = &mut f.kind { - self.expand_expr(expression); - } - } - - ModuleField::Import(i) => self.expand_item_sig(&mut i.item), - - ModuleField::Global(g) => { - if let GlobalKind::Inline(expr) = &mut g.kind { - self.expand_expr(expr); - } - } - - ModuleField::Start(s) => self.expand(s), - - ModuleField::Tag(t) => match &mut t.ty { - TagType::Exception(t) => self.expand_type_use(t), - }, - - ModuleField::NestedModule(m) => match &mut m.kind { - NestedModuleKind::Import { ty, .. } => self.expand_type_use(ty), - NestedModuleKind::Inline { fields } => run(fields), - }, - - ModuleField::Type(t) => match &mut t.def { - TypeDef::Func(f) => f.expand(self), - TypeDef::Struct(_) => {} - TypeDef::Array(_) => {} - TypeDef::Module(m) => m.expand(self), - TypeDef::Instance(i) => i.expand(self), - }, - - ModuleField::Custom(_) | ModuleField::Memory(_) | ModuleField::Table(_) => {} - } - } - - fn expand_item_sig(&mut self, sig: &mut ItemSig<'a>) { - match &mut sig.kind { - ItemKind::Func(t) => self.expand_type_use(t), - ItemKind::Module(t) => self.expand_type_use(t), - ItemKind::Instance(t) => self.expand_type_use(t), - ItemKind::Table(_) => {} - ItemKind::Memory(_) => {} - ItemKind::Global(_) => {} - ItemKind::Tag(t) => match t { - TagType::Exception(t) => self.expand_type_use(t), - }, - } - } - - fn expand_type_use>(&mut self, ty: &mut TypeUse<'a, T>) { - if let Some(index) = &mut ty.index { - self.expand(index); - } - if let Some(inline) = &mut ty.inline { - inline.expand(self); - } - } - - fn expand_expr(&mut self, expr: &mut Expression<'a>) { - for instr in expr.instrs.iter_mut() { - self.expand_instr(instr); - } - } - - fn expand_instr(&mut self, instr: &mut Instruction<'a>) { - use Instruction::*; - - if let Some(m) = instr.memarg_mut() { - self.expand(&mut m.memory); - } - - match instr { - Call(i) | ReturnCall(i) | RefFunc(i) => self.expand(&mut i.0), - CallIndirect(i) | ReturnCallIndirect(i) => { - self.expand(&mut i.table); - self.expand_type_use(&mut i.ty); - } - TableInit(i) => self.expand(&mut i.table), - MemoryInit(i) => self.expand(&mut i.mem), - TableCopy(i) => { - self.expand(&mut i.src); - self.expand(&mut i.dst); - } - MemoryCopy(i) => { - self.expand(&mut i.src); - self.expand(&mut i.dst); - } - GlobalSet(g) | GlobalGet(g) => self.expand(&mut g.0), - TableGet(t) | TableSet(t) | TableFill(t) | TableSize(t) | TableGrow(t) => { - self.expand(&mut t.dst) - } - - MemorySize(m) | MemoryGrow(m) | MemoryFill(m) => self.expand(&mut m.mem), - - Let(t) => self.expand_type_use(&mut t.block.ty), - - Block(bt) | If(bt) | Loop(bt) | Try(bt) => self.expand_type_use(&mut bt.ty), - - FuncBind(t) => self.expand_type_use(&mut t.ty), - - _ => {} - } - } - - fn expand(&mut self, item: &mut ItemRef<'a, T>) - where - T: Into + Copy, - { - match item { - ItemRef::Outer { kind, module, idx } => { - let key = (*module, *idx, (*kind).into()); - let idx = match self.parents.entry(key) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(v) => { - let span = idx.span(); - let id = gensym::gen(span); - self.to_prepend.push(ModuleField::Alias(Alias { - span, - id: Some(id), - name: None, - source: AliasSource::Outer { - module: *module, - index: *idx, - }, - kind: (*kind).into(), - })); - *v.insert(Index::Id(id)) - } - }; - *item = ItemRef::Item { - kind: *kind, - idx, - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: true, - }; - } - ItemRef::Item { - kind, - idx, - exports, - #[cfg(wast_check_exhaustive)] - visited, - } => { - #[cfg(wast_check_exhaustive)] - { - *visited = true; - } - let mut cur = *idx; - let len = exports.len(); - for (i, export) in exports.drain(..).enumerate() { - let kind = if i < len - 1 { - ExportKind::Instance - } else { - (*kind).into() - }; - let key = (cur, export, kind); - cur = match self.instances.entry(key) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(v) => { - let span = idx.span(); - let id = gensym::gen(span); - self.to_prepend.push(ModuleField::Alias(Alias { - span, - id: Some(id), - name: None, - kind, - source: AliasSource::InstanceExport { - instance: ItemRef::Item { - kind: kw::instance(span), - idx: cur, - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: true, - }, - export, - }, - })); - *v.insert(Index::Id(id)) - } - }; - } - *idx = cur; - } - } - } -} - -trait Expand<'a> { - fn expand(&mut self, cx: &mut Expander<'a>); -} - -impl<'a> Expand<'a> for FunctionType<'a> { - fn expand(&mut self, _cx: &mut Expander<'a>) {} -} - -impl<'a> Expand<'a> for ModuleType<'a> { - fn expand(&mut self, cx: &mut Expander<'a>) { - for i in self.imports.iter_mut() { - cx.expand_item_sig(&mut i.item); - } - for e in self.exports.iter_mut() { - cx.expand_item_sig(&mut e.item); - } - } -} - -impl<'a> Expand<'a> for InstanceType<'a> { - fn expand(&mut self, cx: &mut Expander<'a>) { - for e in self.exports.iter_mut() { - cx.expand_item_sig(&mut e.item); - } - } -} diff --git a/third_party/rust/wast/src/ast/token.rs b/third_party/rust/wast/src/token.rs similarity index 90% rename from third_party/rust/wast/src/ast/token.rs rename to third_party/rust/wast/src/token.rs index 15b151b85770..bb3d3f12a615 100644 --- a/third_party/rust/wast/src/ast/token.rs +++ b/third_party/rust/wast/src/token.rs @@ -1,4 +1,8 @@ -use crate::ast::{annotation, kw}; +//! Common tokens that implement the [`Parse`] trait which are otherwise not +//! associated specifically with the wasm text format per se (useful in other +//! contexts too perhaps). + +use crate::annotation; use crate::lexer::FloatVal; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use std::fmt; @@ -217,65 +221,19 @@ impl Hash for Index<'_> { } /// Parses `(func $foo)` -/// -/// Optionally includes export strings for module-linking sugar syntax for alias -/// injection. #[derive(Clone, Debug)] #[allow(missing_docs)] -pub enum ItemRef<'a, K> { - Outer { - kind: K, - module: Index<'a>, - idx: Index<'a>, - }, - Item { - kind: K, - idx: Index<'a>, - exports: Vec<&'a str>, - #[cfg(wast_check_exhaustive)] - visited: bool, - }, -} - -impl<'a, K> ItemRef<'a, K> { - /// Unwraps the underlying `Index` for `ItemRef::Item`. - /// - /// Panics if this is `ItemRef::Outer` or if exports haven't been expanded - /// yet. - pub fn unwrap_index(&self) -> &Index<'a> { - match self { - ItemRef::Item { idx, exports, .. } => { - debug_assert!(exports.len() == 0); - idx - } - ItemRef::Outer { .. } => panic!("unwrap_index called on Parent"), - } - } +pub struct ItemRef<'a, K> { + pub kind: K, + pub idx: Index<'a>, } impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let kind = parser.parse::()?; - if parser.peek::() { - parser.parse::()?; - let module = parser.parse()?; - let idx = parser.parse()?; - Ok(ItemRef::Outer { kind, module, idx }) - } else { - let idx = parser.parse()?; - let mut exports = Vec::new(); - while !parser.is_empty() { - exports.push(parser.parse()?); - } - Ok(ItemRef::Item { - kind, - idx, - exports, - #[cfg(wast_check_exhaustive)] - visited: false, - }) - } + let idx = parser.parse()?; + Ok(ItemRef { kind, idx }) }) } } @@ -293,39 +251,6 @@ impl<'a, K: Peek> Peek for ItemRef<'a, K> { } } -/// Convenience structure to parse `$f` or `(item $f)`. -#[derive(Clone, Debug)] -pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); - -impl<'a, K> Parse<'a> for IndexOrRef<'a, K> -where - K: Parse<'a> + Default, -{ - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { - Ok(IndexOrRef(ItemRef::Item { - kind: K::default(), - idx: parser.parse()?, - exports: Vec::new(), - #[cfg(wast_check_exhaustive)] - visited: false, - })) - } else { - Ok(IndexOrRef(parser.parse()?)) - } - } -} - -impl<'a, K: Peek> Peek for IndexOrRef<'a, K> { - fn peek(cursor: Cursor<'_>) -> bool { - Index::peek(cursor) || ItemRef::::peek(cursor) - } - - fn display() -> &'static str { - "an item reference" - } -} - /// An `@name` annotation in source, currently of the form `@name "foo"` #[derive(Copy, Clone, PartialEq, Debug)] pub struct NameAnnotation<'a> { diff --git a/third_party/rust/wast/src/ast/wast.rs b/third_party/rust/wast/src/wast.rs similarity index 52% rename from third_party/rust/wast/src/ast/wast.rs rename to third_party/rust/wast/src/wast.rs index 49d245b41ac9..071161f101de 100644 --- a/third_party/rust/wast/src/ast/wast.rs +++ b/third_party/rust/wast/src/wast.rs @@ -1,6 +1,8 @@ -use crate::ast::{self, kw}; -use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::{AssertExpression, NanPattern, V128Pattern}; +use crate::core::Expression; +use crate::kw; +use crate::parser::{self, Cursor, Parse, ParseBuffer, Parser, Peek, Result}; +use crate::token::{Id, Span}; +use crate::{AssertExpression, Error, Wat}; /// A parsed representation of a `*.wast` file. /// @@ -24,8 +26,8 @@ impl<'a> Parse<'a> for Wast<'a> { directives.push(parser.parens(|p| p.parse())?); } } else { - let module = parser.parse::()?.module; - directives.push(WastDirective::Module(module)); + let module = parser.parse::()?; + directives.push(WastDirective::Wat(QuoteWat::Wat(module))); } Ok(Wast { directives }) } @@ -39,7 +41,11 @@ impl Peek for WastDirectiveToken { Some((kw, _)) => kw, None => return false, }; - kw.starts_with("assert_") || kw == "module" || kw == "register" || kw == "invoke" + kw.starts_with("assert_") + || kw == "module" + || kw == "component" + || kw == "register" + || kw == "invoke" } fn display() -> &'static str { @@ -54,61 +60,59 @@ impl Peek for WastDirectiveToken { #[allow(missing_docs)] #[derive(Debug)] pub enum WastDirective<'a> { - Module(ast::Module<'a>), - QuoteModule { - span: ast::Span, - source: Vec<&'a [u8]>, - }, + Wat(QuoteWat<'a>), AssertMalformed { - span: ast::Span, - module: QuoteModule<'a>, + span: Span, + module: QuoteWat<'a>, message: &'a str, }, AssertInvalid { - span: ast::Span, - module: QuoteModule<'a>, + span: Span, + module: QuoteWat<'a>, message: &'a str, }, Register { - span: ast::Span, + span: Span, name: &'a str, - module: Option>, + module: Option>, }, Invoke(WastInvoke<'a>), AssertTrap { - span: ast::Span, + span: Span, exec: WastExecute<'a>, message: &'a str, }, AssertReturn { - span: ast::Span, + span: Span, exec: WastExecute<'a>, - results: Vec>, + results: Vec>, }, AssertExhaustion { - span: ast::Span, + span: Span, call: WastInvoke<'a>, message: &'a str, }, AssertUnlinkable { - span: ast::Span, - module: ast::Module<'a>, + span: Span, + module: Wat<'a>, message: &'a str, }, AssertException { - span: ast::Span, + span: Span, exec: WastExecute<'a>, }, } impl WastDirective<'_> { /// Returns the location in the source that this directive was defined at - pub fn span(&self) -> ast::Span { + pub fn span(&self) -> Span { match self { - WastDirective::Module(m) => m.span, + WastDirective::Wat(QuoteWat::Wat(Wat::Module(m))) => m.span, + WastDirective::Wat(QuoteWat::Wat(Wat::Component(c))) => c.span, + WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span, + WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span, WastDirective::AssertMalformed { span, .. } | WastDirective::Register { span, .. } - | WastDirective::QuoteModule { span, .. } | WastDirective::AssertTrap { span, .. } | WastDirective::AssertReturn { span, .. } | WastDirective::AssertExhaustion { span, .. } @@ -123,18 +127,8 @@ impl WastDirective<'_> { impl<'a> Parse<'a> for WastDirective<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { - if parser.peek2::() { - parser.parse::()?; - let span = parser.parse::()?.0; - let mut source = Vec::new(); - while !parser.is_empty() { - source.push(parser.parse()?); - } - Ok(WastDirective::QuoteModule { span, source }) - } else { - Ok(WastDirective::Module(parser.parse()?)) - } + if l.peek::() || l.peek::() { + Ok(WastDirective::Wat(parser.parse()?)) } else if l.peek::() { let span = parser.parse::()?.0; Ok(WastDirective::AssertMalformed { @@ -177,69 +171,6 @@ impl<'a> Parse<'a> for WastDirective<'a> { exec, results, }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::LegacyCanonicalNaN], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - let pat = V128Pattern::F32x4([ - NanPattern::CanonicalNan, - NanPattern::CanonicalNan, - NanPattern::CanonicalNan, - NanPattern::CanonicalNan, - ]); - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::V128(pat)], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - let pat = V128Pattern::F64x2([NanPattern::CanonicalNan, NanPattern::CanonicalNan]); - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::V128(pat)], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::LegacyArithmeticNaN], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - let pat = V128Pattern::F32x4([ - NanPattern::ArithmeticNan, - NanPattern::ArithmeticNan, - NanPattern::ArithmeticNan, - NanPattern::ArithmeticNan, - ]); - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::V128(pat)], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - let pat = V128Pattern::F64x2([NanPattern::ArithmeticNan, NanPattern::ArithmeticNan]); - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::V128(pat)], - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WastDirective::AssertReturn { - span, - exec: parser.parens(|p| p.parse())?, - results: vec![AssertExpression::RefFunc(None)], - }) } else if l.peek::() { let span = parser.parse::()?.0; Ok(WastDirective::AssertExhaustion { @@ -251,7 +182,7 @@ impl<'a> Parse<'a> for WastDirective<'a> { let span = parser.parse::()?.0; Ok(WastDirective::AssertUnlinkable { span, - module: parser.parens(|p| p.parse())?, + module: parser.parens(parse_wat)?, message: parser.parse()?, }) } else if l.peek::() { @@ -270,9 +201,9 @@ impl<'a> Parse<'a> for WastDirective<'a> { #[derive(Debug)] pub enum WastExecute<'a> { Invoke(WastInvoke<'a>), - Module(ast::Module<'a>), + Wat(Wat<'a>), Get { - module: Option>, + module: Option>, global: &'a str, }, } @@ -282,8 +213,8 @@ impl<'a> Parse<'a> for WastExecute<'a> { let mut l = parser.lookahead1(); if l.peek::() { Ok(WastExecute::Invoke(parser.parse()?)) - } else if l.peek::() { - Ok(WastExecute::Module(parser.parse()?)) + } else if l.peek::() || l.peek::() { + Ok(WastExecute::Wat(parse_wat(parser)?)) } else if l.peek::() { parser.parse::()?; Ok(WastExecute::Get { @@ -296,13 +227,27 @@ impl<'a> Parse<'a> for WastExecute<'a> { } } +fn parse_wat<'a>(parser: Parser<'a>) -> Result> { + // Note that this doesn't use `Parse for Wat` since the `parser` provided + // has already peeled back the first layer of parentheses while `Parse for + // Wat` expects to be the top layer which means it also tries to peel off + // the parens. Instead we can skip the sugar that `Wat` has for simply a + // list of fields (no `(module ...)` container) and just parse the `Module` + // itself. + if parser.peek::() { + Ok(Wat::Component(parser.parse()?)) + } else { + Ok(Wat::Module(parser.parse()?)) + } +} + #[allow(missing_docs)] #[derive(Debug)] pub struct WastInvoke<'a> { - pub span: ast::Span, - pub module: Option>, + pub span: Span, + pub module: Option>, pub name: &'a str, - pub args: Vec>, + pub args: Vec>, } impl<'a> Parse<'a> for WastInvoke<'a> { @@ -325,60 +270,61 @@ impl<'a> Parse<'a> for WastInvoke<'a> { #[allow(missing_docs)] #[derive(Debug)] -pub enum QuoteModule<'a> { - Module(ast::Module<'a>), - Quote(Vec<&'a [u8]>), +pub enum QuoteWat<'a> { + Wat(Wat<'a>), + QuoteModule(Span, Vec<(Span, &'a [u8])>), + QuoteComponent(Span, Vec<(Span, &'a [u8])>), } -impl<'a> Parse<'a> for QuoteModule<'a> { +impl QuoteWat<'_> { + /// Encodes this module to bytes, either by encoding the module directly or + /// parsing the contents and then encoding it. + pub fn encode(&mut self) -> Result, Error> { + let (source, prefix) = match self { + QuoteWat::Wat(m) => return m.encode(), + QuoteWat::QuoteModule(_, source) => (source, None), + QuoteWat::QuoteComponent(_, source) => (source, Some("(component")), + }; + let mut ret = String::new(); + for (span, src) in source { + match std::str::from_utf8(src) { + Ok(s) => ret.push_str(s), + Err(_) => { + return Err(Error::new(*span, "malformed UTF-8 encoding".to_string())); + } + } + ret.push_str(" "); + } + if let Some(prefix) = prefix { + ret.insert_str(0, prefix); + ret.push_str(")"); + } + let buf = ParseBuffer::new(&ret)?; + let mut wat = parser::parse::>(&buf)?; + wat.encode() + } +} + +impl<'a> Parse<'a> for QuoteWat<'a> { fn parse(parser: Parser<'a>) -> Result { if parser.peek2::() { - parser.parse::()?; - parser.parse::()?; + let ctor = if parser.peek::() { + parser.parse::()?; + QuoteWat::QuoteComponent + } else { + parser.parse::()?; + QuoteWat::QuoteModule + }; + let span = parser.parse::()?.0; let mut src = Vec::new(); while !parser.is_empty() { - src.push(parser.parse()?); + let span = parser.cur_span(); + let string = parser.parse()?; + src.push((span, string)); } - Ok(QuoteModule::Quote(src)) + Ok(ctor(span, src)) } else { - Ok(QuoteModule::Module(parser.parse()?)) + Ok(QuoteWat::Wat(parse_wat(parser)?)) } } } - -#[cfg(test)] -mod tests { - use crate::ast::wast::WastDirective; - use crate::parser::{parse, ParseBuffer}; - - macro_rules! assert_parses_to_directive { - ($text:expr, $pattern:pat) => {{ - let buffer = ParseBuffer::new($text).unwrap(); - let directive: WastDirective = parse(&buffer).unwrap(); - if let $pattern = directive { - } else { - panic!("assertion failed") - } - }}; - } - - #[test] - fn assert_nan() { - assert_parses_to_directive!( - "assert_return_canonical_nan_f32x4 (invoke \"foo\" (f32.const 0))", - WastDirective::AssertReturn { .. } - ); - assert_parses_to_directive!( - "assert_return_canonical_nan_f64x2 (invoke \"foo\" (f32.const 0))", - WastDirective::AssertReturn { .. } - ); - assert_parses_to_directive!( - "assert_return_arithmetic_nan_f32x4 (invoke \"foo\" (f32.const 0))", - WastDirective::AssertReturn { .. } - ); - assert_parses_to_directive!( - "assert_return_arithmetic_nan_f64x2 (invoke \"foo\" (f32.const 0))", - WastDirective::AssertReturn { .. } - ); - } -} diff --git a/third_party/rust/wast/src/wat.rs b/third_party/rust/wast/src/wat.rs new file mode 100644 index 000000000000..631bc3d0ed44 --- /dev/null +++ b/third_party/rust/wast/src/wat.rs @@ -0,0 +1,60 @@ +use crate::component::Component; +use crate::core::{Module, ModuleField, ModuleKind}; +use crate::kw; +use crate::parser::{Parse, Parser, Result}; +use crate::token::Span; + +/// A `*.wat` file parser, or a parser for one parenthesized module. +/// +/// This is the top-level type which you'll frequently parse when working with +/// this crate. A `*.wat` file is either one `module` s-expression or a sequence +/// of s-expressions that are module fields. +#[derive(Debug)] +#[allow(missing_docs)] +pub enum Wat<'a> { + Module(Module<'a>), + Component(Component<'a>), +} + +impl Wat<'_> { + fn validate(&self, parser: Parser<'_>) -> Result<()> { + match self { + Wat::Module(m) => m.validate(parser), + Wat::Component(c) => c.validate(parser), + } + } + + /// Encodes this `Wat` to binary form. This calls either [`Module::encode`] + /// or [`Component::encode`]. + pub fn encode(&mut self) -> std::result::Result, crate::Error> { + match self { + Wat::Module(m) => m.encode(), + Wat::Component(c) => c.encode(), + } + } +} + +impl<'a> Parse<'a> for Wat<'a> { + fn parse(parser: Parser<'a>) -> Result { + if !parser.has_meaningful_tokens() { + return Err(parser.error("expected at least one module field")); + } + + let _r = parser.register_annotation("custom"); + let wat = if parser.peek2::() { + Wat::Module(parser.parens(|parser| parser.parse())?) + } else if parser.peek2::() { + Wat::Component(parser.parens(|parser| parser.parse())?) + } else { + let fields = ModuleField::parse_remaining(parser)?; + Wat::Module(Module { + span: Span { offset: 0 }, + id: None, + name: None, + kind: ModuleKind::Text(fields), + }) + }; + wat.validate(parser)?; + Ok(wat) + } +} diff --git a/third_party/rust/wast/tests/annotations.rs b/third_party/rust/wast/tests/annotations.rs index f6f04c48d847..b5ec89470738 100644 --- a/third_party/rust/wast/tests/annotations.rs +++ b/third_party/rust/wast/tests/annotations.rs @@ -95,14 +95,10 @@ fn assert_local_name(name: &str, wat: &str) -> anyhow::Result<()> { fn get_name_section(wasm: &[u8]) -> anyhow::Result> { for payload in Parser::new(0).parse_all(&wasm) { - if let Payload::CustomSection { - name: "name", - data, - data_offset, - range: _, - } = payload? - { - return Ok(NameSectionReader::new(data, data_offset)?); + if let Payload::CustomSection(c) = payload? { + if c.name() == "name" { + return Ok(NameSectionReader::new(c.data(), c.data_offset())?); + } } } panic!("no name section found"); @@ -110,7 +106,7 @@ fn get_name_section(wasm: &[u8]) -> anyhow::Result> { #[test] fn custom_section_order() -> anyhow::Result<()> { - let wasm = wat::parse_str( + let bytes = wat::parse_str( r#" (module (@custom "A" "aaa") @@ -131,33 +127,71 @@ fn custom_section_order() -> anyhow::Result<()> { "#, )?; macro_rules! assert_matches { - ($a:expr, $b:pat $(,)?) => { + ($a:expr, $b:pat $(if $cond:expr)? $(,)?) => { match &$a { - $b => {} + $b $(if $cond)? => {} a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)), } }; } let wasm = Parser::new(0) - .parse_all(&wasm) + .parse_all(&bytes) .collect::>>()?; assert_matches!(wasm[0], Payload::Version { .. }); - assert_matches!(wasm[1], Payload::CustomSection { name: "K", .. }); - assert_matches!(wasm[2], Payload::CustomSection { name: "F", .. }); + assert_matches!( + wasm[1], + Payload::CustomSection(c) if c.name() == "K" + ); + assert_matches!( + wasm[2], + Payload::CustomSection(c) if c.name() == "F" + ); assert_matches!(wasm[3], Payload::TypeSection(_)); - assert_matches!(wasm[4], Payload::CustomSection { name: "E", .. }); - assert_matches!(wasm[5], Payload::CustomSection { name: "C", .. }); - assert_matches!(wasm[6], Payload::CustomSection { name: "J", .. }); + assert_matches!( + wasm[4], + Payload::CustomSection(c) if c.name() == "E" + ); + assert_matches!( + wasm[5], + Payload::CustomSection(c) if c.name() == "C" + ); + assert_matches!( + wasm[6], + Payload::CustomSection(c) if c.name() == "J" + ); assert_matches!(wasm[7], Payload::FunctionSection(_)); - assert_matches!(wasm[8], Payload::CustomSection { name: "B", .. }); - assert_matches!(wasm[9], Payload::CustomSection { name: "I", .. }); + assert_matches!( + wasm[8], + Payload::CustomSection(c) if c.name() == "B" + ); + assert_matches!( + wasm[9], + Payload::CustomSection(c) if c.name() == "I" + ); assert_matches!(wasm[10], Payload::TableSection(_)); assert_matches!(wasm[11], Payload::CodeSectionStart { .. }); assert_matches!(wasm[12], Payload::CodeSectionEntry { .. }); - assert_matches!(wasm[13], Payload::CustomSection { name: "H", .. }); - assert_matches!(wasm[14], Payload::CustomSection { name: "G", .. }); - assert_matches!(wasm[15], Payload::CustomSection { name: "A", .. }); - assert_matches!(wasm[16], Payload::CustomSection { name: "D", .. }); - assert_matches!(wasm[17], Payload::End); + assert_matches!( + wasm[13], + Payload::CustomSection(c) if c.name() == "H" + ); + assert_matches!( + wasm[14], + Payload::CustomSection(c) if c.name() == "G" + ); + assert_matches!( + wasm[15], + Payload::CustomSection(c) if c.name() == "A" + ); + assert_matches!( + wasm[16], + Payload::CustomSection(c) if c.name() == "D" + ); + + match &wasm[17] { + Payload::End(x) if *x == bytes.len() => {} + p => panic!("`{:?}` doesn't match expected length of {}", p, bytes.len()), + } + Ok(()) } diff --git a/third_party/rust/wast/tests/comments.rs b/third_party/rust/wast/tests/comments.rs index 53a57ced3a5c..97252650be9d 100644 --- a/third_party/rust/wast/tests/comments.rs +++ b/third_party/rust/wast/tests/comments.rs @@ -49,7 +49,7 @@ fn parse_comments() -> anyhow::Result<()> { "#, )?; - let d: Documented = parser::parse(&buf)?; + let d: Documented = parser::parse(&buf)?; assert_eq!(d.comments.comments, vec![" hello", " again "]); drop(d.item); @@ -66,7 +66,7 @@ multiple;) "#, )?; - let d: Documented = parser::parse(&buf)?; + let d: Documented = parser::parse(&buf)?; assert_eq!( d.comments.comments, vec![" this", " is\non\nmultiple", " lines"] diff --git a/third_party/rust/wat/.cargo-checksum.json b/third_party/rust/wat/.cargo-checksum.json index 54340ae909d5..072add03044a 100644 --- a/third_party/rust/wat/.cargo-checksum.json +++ b/third_party/rust/wat/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"dec2dec4738c8ff5e0176744a1e16619ee371a8a1616e055eab15cd97ad26e83","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"86861dc59a785c0eb143e1798668e29076e25f69d7e802b5425054862c635be3","src/lib.rs":"b272ee59a5a1b713625cdf4443e5055d888966b9ec78014e01087895e9fc09bc"},"package":"ab98ed25494f97c69f28758617f27c3e92e5336040b5c3a14634f2dd3fe61830"} \ No newline at end of file +{"files":{"Cargo.toml":"2faa554ccc82ab2ffb485ac05f9738f3c6675e0b051f4b8ec3e92883fbd21f64","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"86861dc59a785c0eb143e1798668e29076e25f69d7e802b5425054862c635be3","src/lib.rs":"806f68f35b3c309b7dbdb24f14da254a9f7f5b14eef3b8015c95c3e9753e3bb0"},"package":"48b3b9b3e39e66c7fd3f8be785e74444d216260f491e93369e317ed6482ff80f"} \ No newline at end of file diff --git a/third_party/rust/wat/Cargo.toml b/third_party/rust/wat/Cargo.toml index 006aa02d5c0e..23eb25a8962d 100644 --- a/third_party/rust/wat/Cargo.toml +++ b/third_party/rust/wat/Cargo.toml @@ -10,15 +10,19 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" name = "wat" -version = "1.0.41" +version = "1.0.43" authors = ["Alex Crichton "] -description = "Rust parser for the WebAssembly Text format, WAT\n" +description = """ +Rust parser for the WebAssembly Text format, WAT +""" homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat" documentation = "https://docs.rs/wat" readme = "README.md" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat" +resolver = "2" + [dependencies.wast] -version = "39.0.0" +version = "41.0.0" diff --git a/third_party/rust/wat/src/lib.rs b/third_party/rust/wat/src/lib.rs index c6052bc63455..f48f0526f427 100644 --- a/third_party/rust/wat/src/lib.rs +++ b/third_party/rust/wat/src/lib.rs @@ -218,7 +218,7 @@ pub fn parse_str(wat: impl AsRef) -> Result> { fn _parse_str(wat: &str) -> Result> { let buf = ParseBuffer::new(&wat).map_err(|e| Error::cvt(e, wat))?; let mut ast = parser::parse::(&buf).map_err(|e| Error::cvt(e, wat))?; - Ok(ast.module.encode().map_err(|e| Error::cvt(e, wat))?) + Ok(ast.encode().map_err(|e| Error::cvt(e, wat))?) } /// A convenience type definition for `Result` where the error is [`Error`]