Bug 1831176: Update wast crate. r=yury,glandium,supply-chain-reviewers

Updating wast to the latest version in order to get the new binary encoding for cast instructions.

Differential Revision: https://phabricator.services.mozilla.com/D184022
This commit is contained in:
Ben Visness 2023-07-21 22:00:04 +00:00
parent b648995bf4
commit 67731fc42a
83 changed files with 2973 additions and 2141 deletions

55
Cargo.lock generated
View File

@ -2390,7 +2390,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
"indexmap",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
@ -2591,15 +2591,22 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.9.2"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
"serde",
]
[[package]]
name = "indexmap"
version = "2.999.999"
dependencies = [
"indexmap 1.9.3",
]
[[package]]
name = "inherent"
version = "1.0.7"
@ -2737,7 +2744,7 @@ version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=64ba08e24749616de2344112f226d1ef4ba893ae#64ba08e24749616de2344112f226d1ef4ba893ae"
dependencies = [
"bumpalo",
"indexmap",
"indexmap 1.9.3",
]
[[package]]
@ -2747,7 +2754,7 @@ source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=64ba08e24749
dependencies = [
"bumpalo",
"byteorder",
"indexmap",
"indexmap 1.9.3",
"jsparagus-ast",
"jsparagus-scope",
"jsparagus-stencil",
@ -2785,7 +2792,7 @@ name = "jsparagus-scope"
version = "0.1.0"
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=64ba08e24749616de2344112f226d1ef4ba893ae#64ba08e24749616de2344112f226d1ef4ba893ae"
dependencies = [
"indexmap",
"indexmap 1.9.3",
"jsparagus-ast",
"jsparagus-stencil",
]
@ -3460,7 +3467,7 @@ dependencies = [
"getrandom",
"hashbrown",
"hyper",
"indexmap",
"indexmap 1.9.3",
"libc",
"log",
"memchr",
@ -3581,7 +3588,7 @@ dependencies = [
"bitflags 2.999.999",
"codespan-reporting",
"hexf-parse",
"indexmap",
"indexmap 1.9.3",
"log",
"num-traits",
"rustc-hash",
@ -3656,7 +3663,7 @@ name = "neqo-transport"
version = "0.6.4"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.4#80db3a01f3273c7e742ba560fa99246fc8b30c4f"
dependencies = [
"indexmap",
"indexmap 1.9.3",
"lazy_static",
"log",
"neqo-common",
@ -4152,7 +4159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225"
dependencies = [
"base64 0.13.999",
"indexmap",
"indexmap 1.9.3",
"line-wrap",
"serde",
"time 0.3.17",
@ -4724,7 +4731,7 @@ version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"indexmap",
"indexmap 1.9.3",
"itoa",
"ryu",
"serde",
@ -4788,7 +4795,7 @@ version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
dependencies = [
"indexmap",
"indexmap 1.9.3",
"ryu",
"serde",
"yaml-rust",
@ -4808,7 +4815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f1641177943b4e6faf7622463ae6dfe0f143eb88799e91e2e2e68ede568af5"
dependencies = [
"data-encoding",
"indexmap",
"indexmap 1.9.3",
"rust_decimal",
]
@ -4999,7 +5006,7 @@ dependencies = [
"euclid",
"fxhash",
"gecko-profiler",
"indexmap",
"indexmap 1.9.3",
"itertools",
"itoa",
"lazy_static",
@ -5884,22 +5891,22 @@ version = "0.2.100"
[[package]]
name = "wasm-encoder"
version = "0.29.0"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"
checksum = "06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a"
dependencies = [
"leb128",
]
[[package]]
name = "wasm-smith"
version = "0.12.10"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "027ec1c470cd5d56c43b8e02040250b136ddb5975dd76a1c16915137f5f17e76"
checksum = "706fc2c6fb0af287ea9147d343485536b5857b72cd32b1d4091619583b334103"
dependencies = [
"arbitrary",
"flagset",
"indexmap",
"indexmap 2.999.999",
"leb128",
"wasm-encoder",
"wasmparser",
@ -5907,19 +5914,19 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.107.0"
version = "0.109.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb"
checksum = "8bf9564f29de2890ee34406af52d2a92dec6ef044c8ddfc5add5db8dcfd36e6c"
dependencies = [
"indexmap",
"indexmap 2.999.999",
"semver",
]
[[package]]
name = "wast"
version = "60.0.0"
version = "62.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd06cc744b536e30387e72a48fdd492105b9c938bb4f415c39c616a7a0a697ad"
checksum = "c7f7ee878019d69436895f019b65f62c33da63595d8e857cbdc87c13ecb29a32"
dependencies = [
"leb128",
"memchr",

View File

@ -147,6 +147,9 @@ ntapi = { path = "build/rust/ntapi" }
# Patch nix 0.24 to 0.26
nix = { path = "build/rust/nix" }
# Patch indexmap 2.0 to 1.0
indexmap = { path = "build/rust/indexmap" }
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
autocfg = { path = "third_party/rust/autocfg" }

View File

@ -0,0 +1,11 @@
[package]
name = "indexmap"
version = "2.999.999"
edition = "2021"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies.indexmap]
version = "1.9.3"

View File

@ -0,0 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub use indexmap::*;

View File

@ -5,6 +5,6 @@ authors = ["Christian Holler"]
license = "MPL-2.0"
[dependencies]
wasm-smith = "0.12.10"
wasm-smith = "0.12.12"
arbitrary = { version = "1.0.0", features = ["derive"] }
libc = "0.2"

View File

@ -2,7 +2,7 @@
wasmFullPass(`
(module
(func $f1)
(elem declare $f1)
(elem declare func $f1)
(elem declare funcref (ref.null func))
(func $run)
(export "run" (func $run))
@ -24,7 +24,7 @@ wasmFullPass(`
(module
(func $f1)
(table 1 1 funcref)
(elem $e1 declare $f1)
(elem $e1 declare func $f1)
(func (export "testfn") (table.init $e1 (i32.const 0) (i32.const 0) (i32.const 1)))
)
`);
@ -36,7 +36,7 @@ wasmEvalText(`
(module
(func $f1)
(table 1 1 funcref)
(elem $e1 declare $f1)
(elem $e1 declare func $f1)
(func $start (elem.drop $e1) (elem.drop $e1))
(start $start)
)
@ -47,7 +47,7 @@ wasmAssert(`
(module
(func $f1)
(table 1 1 funcref)
(elem declare $f1)
(elem declare func $f1)
(func $at (param i32) (result i32)
local.get 0
table.get 0

View File

@ -2,7 +2,7 @@
let { plusOne } = wasmEvalText(`(module
(; forward declaration so that ref.func works ;)
(elem declare $plusOneRef)
(elem declare func $plusOneRef)
(type $t (func (param i32) (result i32)))
(func $plusOneRef (param i32) (result i32)
@ -49,7 +49,7 @@ wasmFailValidateText(`(module
// signature mismatch
wasmFailValidateText(`(module
(type $t (func (param i32) (result i32)))
(elem declare $plusOneRef)
(elem declare func $plusOneRef)
(func $plusOneRef (param f32) (result f32)
(f32.add
local.get 0
@ -75,7 +75,7 @@ let { loadInt } = wasmEvalText(`(module
let { callLoadInt } = wasmEvalText(`(module
(type $t (func (result i32)))
(elem declare 0)
(elem declare func 0)
(import "" "loadInt" (func (result i32)))
(func (export "callLoadInt") (result i32)
ref.func 0

View File

@ -79,7 +79,7 @@ wasmValidateText(`(module
)
)`);
wasmFailValidateText(`(module
(elem declare 0)
(elem declare func 0)
(func
(local (ref func))
i32.const 0
@ -93,7 +93,7 @@ wasmFailValidateText(`(module
)
)`, /local\.get read from unset local/);
wasmValidateText(`(module
(elem declare 0)
(elem declare func 0)
(func (result funcref)
(local (ref func) (ref func))
i32.const 0
@ -154,7 +154,7 @@ assertErrorMessage(() => runMultiNullStack(), TypeError, /cannot pass null to no
// can have non-nullable globals
wasmEvalText(`(module
(func $f)
(elem declare $f)
(elem declare func $f)
(global (ref func) ref.func $f)
)`);
}

View File

@ -635,7 +635,7 @@ assertErrorMessage(() => wasmEvalText(`(module
// validation: array-type imm-operand needs to be "in range"
assertErrorMessage(() => wasmEvalText(`(module
(type $a (array funcref))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -650,7 +650,7 @@ assertErrorMessage(() => wasmEvalText(`(module
// validation: array-type imm-operand must refer to an array type
assertErrorMessage(() => wasmEvalText(`(module
(type $a (func (param i64) (result f64)))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -666,7 +666,7 @@ assertErrorMessage(() => wasmEvalText(`(module
// elements
assertErrorMessage(() => wasmEvalText(`(module
(type $a (array f32))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -681,7 +681,7 @@ assertErrorMessage(() => wasmEvalText(`(module
// validation: destination elem type must be a supertype of src elem type
assertErrorMessage(() => wasmEvalText(`(module
(type $a (array eqref))
(elem $e funcref $f1)
(elem $e func $f1)
(func $f1 (export "f1"))
;; The implied copy here is from elem-seg-of-funcrefs to
;; array-of-eqrefs, which must fail, because funcref isn't
@ -696,7 +696,7 @@ assertErrorMessage(() => wasmEvalText(`(module
// validation: segment index must be "in range"
assertErrorMessage(() => wasmEvalText(`(module
(type $a (array funcref))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -714,7 +714,7 @@ assertErrorMessage(() => wasmEvalText(`(module
let { newElem } = wasmEvalText(`(module
(table 4 funcref)
(type $a (array funcref))
(elem $e (offset (i32.const 0)) funcref $f1 $f2 $f3 $f4)
(elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -736,7 +736,7 @@ assertErrorMessage(() => wasmEvalText(`(module
let { newElem } = wasmEvalText(`(module
(table 4 funcref)
(type $a (array funcref))
(elem $e (offset (i32.const 0)) funcref $f1 $f2 $f3 $f4)
(elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -758,7 +758,7 @@ assertErrorMessage(() => wasmEvalText(`(module
let { newElem } = wasmEvalText(`(module
(table 4 funcref)
(type $a (array funcref))
(elem $e (offset (i32.const 0)) funcref $f1 $f2 $f3 $f4)
(elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -777,7 +777,7 @@ assertErrorMessage(() => wasmEvalText(`(module
{
let { newElem } = wasmEvalText(`(module
(type $a (array funcref))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))
@ -797,7 +797,7 @@ assertErrorMessage(() => wasmEvalText(`(module
{
let { newElem, f1, f2, f3, f4 } = wasmEvalText(`(module
(type $a (array funcref))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 (export "f1"))
(func $f2 (export "f2"))
(func $f3 (export "f3"))

View File

@ -452,16 +452,6 @@ assertErrorMessage(() => ins.pop(),
assertEq(ins.testg(10), 20);
}
// Test that field names must be unique in the module.
assertErrorMessage(() => wasmTextToBinary(
`(module
(type $s (struct (field $x i32)))
(type $t (struct (field $x i32)))
)`),
SyntaxError,
/duplicate identifier for field/);
// negative tests
// Wrong type passed as initializer

View File

@ -6,7 +6,7 @@ const v2vSigSection = sigSection([v2vSig]);
// 'ref.func' parses, validates and returns a non-null value
wasmFullPass(`
(module
(elem declare $run)
(elem declare func $run)
(func $run (result i32)
ref.func $run
ref.is_null
@ -19,7 +19,7 @@ wasmFullPass(`
{
let {f1} = wasmEvalText(`
(module
(elem declare $f1)
(elem declare func $f1)
(func $f1 (result funcref) ref.func $f1)
(export "f1" (func $f1))
)
@ -31,7 +31,7 @@ wasmFullPass(`
{
let {f1, f2} = wasmEvalText(`
(module
(elem declare $f1)
(elem declare func $f1)
(func $f1)
(func $f2 (result funcref) ref.func $f1)
(export "f1" (func $f1))
@ -45,7 +45,7 @@ wasmFullPass(`
{
let i1 = wasmEvalText(`
(module
(elem declare $f1)
(elem declare func $f1)
(func $f1)
(export "f1" (func $f1))
)
@ -53,7 +53,7 @@ wasmFullPass(`
let i2 = wasmEvalText(`
(module
(import "" "f1" (func $f1))
(elem declare $f1)
(elem declare func $f1)
(func $f2 (result funcref) ref.func $f1)
(export "f1" (func $f1))
(export "f2" (func $f2))
@ -91,7 +91,7 @@ assertErrorMessage(() => validFuncRefText('', 'funcref'), WebAssembly.CompileErr
// referenced function can be forward declared via segments
assertEq(validFuncRefText('(elem 0 (i32.const 0) func $referenced)', 'funcref') instanceof WebAssembly.Instance, true);
assertEq(validFuncRefText('(elem func $referenced)', 'funcref') instanceof WebAssembly.Instance, true);
assertEq(validFuncRefText('(elem declare $referenced)', 'funcref') instanceof WebAssembly.Instance, true);
assertEq(validFuncRefText('(elem declare func $referenced)', 'funcref') instanceof WebAssembly.Instance, true);
// also when the segment is passive or active 'funcref'
assertEq(validFuncRefText('(elem 0 (i32.const 0) funcref (ref.func $referenced))', 'funcref') instanceof WebAssembly.Instance, true);
@ -125,7 +125,7 @@ assertErrorMessage(() => new WebAssembly.Module(
var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
(module
(import "m" "f" (func $f (param i32) (result i32)))
(elem declare $f)
(elem declare func $f)
(table 1 funcref)
(func (export "f")
(table.set 0 (i32.const 0) (ref.func $f))))`)),

View File

@ -413,7 +413,7 @@ assertErrorMessage(() => wasmEvalText(
(func $f
(table.copy 0 (i32.const 0) (i32.const 0) (i32.const 2))))`), // target without source
SyntaxError,
/unexpected token, expected an identifier or u32/);
/unexpected token, expected an index or an identifier/);
// Make sure that dead code doesn't prevent compilation.
wasmEvalText(

View File

@ -6,7 +6,7 @@ function wasmEvalText(str, imports) {
}
let { newElem, f1, f2, f3, f4 } = wasmEvalText(`
(type $a (array funcref))
(elem $e funcref $f1 $f2 $f3 $f4)
(elem $e func $f1 $f2 $f3 $f4)
(func $f1 )
(func $f2 )
(func $f3 )

View File

@ -20,4 +20,4 @@ mozilla-central-workspace-hack = { version = "0.1", features = ["jsrust"], optio
jsrust_shared = { path = "./shared" }
# Workaround for https://github.com/rust-lang/rust/issues/58393
mozglue-static = { path = "../../../mozglue/static/rust" }
wast = "60.0.0"
wast = "62.0.0"

View File

@ -3950,12 +3950,24 @@ user-id = 3618 # David Tolnay (dtolnay)
start = "2019-05-02"
end = "2024-04-25"
[[trusted.equivalent]]
criteria = "safe-to-deploy"
user-id = 539 # Josh Stone (cuviper)
start = "2023-02-05"
end = "2024-07-17"
[[trusted.flate2]]
criteria = "safe-to-deploy"
user-id = 4333 # Josh Triplett (joshtriplett)
start = "2020-09-30"
end = "2024-05-05"
[[trusted.hashbrown]]
criteria = "safe-to-deploy"
user-id = 2915 # Amanieu d'Antras (Amanieu)
start = "2019-04-02"
end = "2024-07-17"
[[trusted.headers]]
criteria = "safe-to-deploy"
user-id = 359 # Sean McArthur (seanmonstar)

View File

@ -213,10 +213,6 @@ notes = "Upstream project which we pin."
[policy.wr_malloc_size_of]
audit-as-crates-io = false
[[exemptions.adler]]
version = "1.0.2"
criteria = "safe-to-deploy"
[[exemptions.ahash]]
version = "0.7.6"
criteria = "safe-to-deploy"
@ -645,10 +641,6 @@ criteria = "safe-to-deploy"
version = "0.10.0"
criteria = "safe-to-deploy"
[[exemptions.pin-project-lite]]
version = "0.2.9"
criteria = "safe-to-deploy"
[[exemptions.plain]]
version = "0.2.3"
criteria = "safe-to-deploy"

View File

@ -226,8 +226,8 @@ user-login = "seanmonstar"
user-name = "Sean McArthur"
[[publisher.indexmap]]
version = "1.9.2"
when = "2022-11-17"
version = "1.9.3"
when = "2023-03-24"
user-id = 539
user-login = "cuviper"
user-name = "Josh Stone"
@ -540,29 +540,29 @@ user-login = "alexcrichton"
user-name = "Alex Crichton"
[[publisher.wasm-encoder]]
version = "0.29.0"
when = "2023-05-26"
version = "0.31.0"
when = "2023-07-17"
user-id = 1
user-login = "alexcrichton"
user-name = "Alex Crichton"
[[publisher.wasm-smith]]
version = "0.12.10"
when = "2023-05-26"
version = "0.12.12"
when = "2023-07-17"
user-id = 1
user-login = "alexcrichton"
user-name = "Alex Crichton"
[[publisher.wasmparser]]
version = "0.107.0"
when = "2023-05-26"
version = "0.109.0"
when = "2023-07-17"
user-id = 1
user-login = "alexcrichton"
user-name = "Alex Crichton"
[[publisher.wast]]
version = "60.0.0"
when = "2023-05-26"
version = "62.0.0"
when = "2023-07-17"
user-id = 1
user-login = "alexcrichton"
user-name = "Alex Crichton"
@ -649,6 +649,12 @@ I am employed by a member of the Bytecode Alliance and plan to continue doing
so and will actively maintain this crate over time.
"""
[[audits.bytecode-alliance.audits.adler]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
version = "1.0.2"
notes = "This is a small crate which forbids unsafe code and is a straightforward implementation of the adler hashing algorithm."
[[audits.bytecode-alliance.audits.arrayref]]
who = "Nick Fitzgerald <fitzgen@gmail.com>"
criteria = "safe-to-deploy"
@ -881,30 +887,6 @@ throughout the ecosystem and skimming the crate shows no usage of `std::*` APIs
and nothing suspicious.
"""
[[audits.bytecode-alliance.audits.wasm-encoder]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
version = "0.25.0"
notes = "The Bytecode Alliance is the author of this crate."
[[audits.bytecode-alliance.audits.wasm-smith]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-run"
version = "0.12.5"
notes = "The Bytecode Alliance is the author of this crate."
[[audits.bytecode-alliance.audits.wasmparser]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
version = "0.102.0"
notes = "The Bytecode Alliance is the author of this crate."
[[audits.bytecode-alliance.audits.wast]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
version = "55.0.0"
notes = "The Bytecode Alliance is the author of this crate."
[[audits.embark-studios.audits.anyhow]]
who = "Johan Andersson <opensource@embark-studios.com>"
criteria = "safe-to-deploy"
@ -1027,6 +1009,13 @@ criteria = "safe-to-run"
version = "1.0.12"
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.google.audits.pin-project-lite]]
who = "David Koloski <dkoloski@google.com>"
criteria = "safe-to-deploy"
version = "0.2.9"
notes = "Reviewed on https://fxrev.dev/824504"
aggregated-from = "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT"
[[audits.google.audits.scoped-tls]]
who = "George Burgess IV <gbiv@google.com>"
criteria = "safe-to-run"

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"c77d3a8863367bbd5e9a6da5d8f100515da5e5a1441c293cbc09ffd947b7302b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.md":"f8b02aa7c20fc0f5bc13de9e9e78899ec8cdbc16c2db880a1d0bc14c25b07542","RELEASES.md":"38d29c78198505ec88702c1ba723d087a775fcda6559da1842b6f17a9cdf6a71","benches/bench.rs":"3b2900abbc9e8a60af78b0395222ee75e86bc68519a0f38477387d1572eed397","benches/faststring.rs":"5fdd6cdb19d0557ed58f241e809a240cf8939d9e5b87a72d5f127f81ab98380b","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/arbitrary.rs":"bb8bda10f686abe57eef1446d3fc3fc6fb251f95629b28c20e620a4838c43db8","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"ea2cbe4f6cc2c4a75f42c9fc936503e6bee0f136c60f6811a2a9907ed8886443","src/macros.rs":"80c22f630e7f81e6fa663ca4c9e50cf5f332c8905d72d1338bd16f24eb353c2a","src/map.rs":"2e9cbfa240865cfd6b6b972bdbdb39283e6302dd2d0d72b3c2bfce4414bf5729","src/map/core.rs":"8422cd774c5db7d83cdeb0c5836c10f29caa1bee8d95b0d674b01b32e7ce80d8","src/map/core/raw.rs":"4e5fac4fecccc352268351d8b1f82b345067b5c029bba7e6ab88e8f8bc799c6a","src/mutable_keys.rs":"a919065b59000286eb11c7d46f6896bf0a1d484c9dac5e61d80bb8990c9fbedb","src/rayon/map.rs":"1a508c7c95c5d56113b851f7ce140d62ad541f1c6129352a7ec62d5bea7af4a1","src/rayon/mod.rs":"019e9379ccab57a299ab5b5a2c0efc7561b77a715a5afe8f797c7e8330c6206c","src/rayon/set.rs":"ba00e88e90fb7ab803589f99f24b595d60309e541aae3d01fdde21bff3840194","src/rustc.rs":"fe7a348c5a10a66880cb6c737593fe79d3b6de40f44ba0d7b89204aa95e14a3a","src/serde.rs":"d45ec8fb9c02594ca6f2e9b20764778b2b4193a24a52f1e233160a33efc6e683","src/serde_seq.rs":"c54a52fa607b6ccddda1e76e829778ca304c49b5f434edc5e582a5386c35d662","src/set.rs":"0a57affb623fa6b28df18cc14841e4f076cbd1da5c809635d202f865640af1ee","src/util.rs":"ab712bce71b54cf2763e6010e64bb5944d1d59ce15e2f2beffa7ceed204d6a68","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"1addbc6cbcb1aae5b8bde0fb0e18197d947e8f13244e4ae7ebf97bdda00eafea","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"}
{"files":{"Cargo.toml":"1290d383adfdcd24f158a4619afb5547d633c83c0a1ab3b5c1ee0dabe4fb1f36","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.md":"f8b02aa7c20fc0f5bc13de9e9e78899ec8cdbc16c2db880a1d0bc14c25b07542","RELEASES.md":"85d9d9bc78e94df7ce90300bb94099b9ab2696d1b3f6b815c22761522878e679","benches/bench.rs":"3b2900abbc9e8a60af78b0395222ee75e86bc68519a0f38477387d1572eed397","benches/faststring.rs":"5fdd6cdb19d0557ed58f241e809a240cf8939d9e5b87a72d5f127f81ab98380b","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/arbitrary.rs":"bb8bda10f686abe57eef1446d3fc3fc6fb251f95629b28c20e620a4838c43db8","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"ea2cbe4f6cc2c4a75f42c9fc936503e6bee0f136c60f6811a2a9907ed8886443","src/macros.rs":"80c22f630e7f81e6fa663ca4c9e50cf5f332c8905d72d1338bd16f24eb353c2a","src/map.rs":"2e9cbfa240865cfd6b6b972bdbdb39283e6302dd2d0d72b3c2bfce4414bf5729","src/map/core.rs":"8422cd774c5db7d83cdeb0c5836c10f29caa1bee8d95b0d674b01b32e7ce80d8","src/map/core/raw.rs":"4e5fac4fecccc352268351d8b1f82b345067b5c029bba7e6ab88e8f8bc799c6a","src/mutable_keys.rs":"a919065b59000286eb11c7d46f6896bf0a1d484c9dac5e61d80bb8990c9fbedb","src/rayon/map.rs":"1a508c7c95c5d56113b851f7ce140d62ad541f1c6129352a7ec62d5bea7af4a1","src/rayon/mod.rs":"019e9379ccab57a299ab5b5a2c0efc7561b77a715a5afe8f797c7e8330c6206c","src/rayon/set.rs":"ba00e88e90fb7ab803589f99f24b595d60309e541aae3d01fdde21bff3840194","src/rustc.rs":"fe7a348c5a10a66880cb6c737593fe79d3b6de40f44ba0d7b89204aa95e14a3a","src/serde.rs":"d45ec8fb9c02594ca6f2e9b20764778b2b4193a24a52f1e233160a33efc6e683","src/serde_seq.rs":"c54a52fa607b6ccddda1e76e829778ca304c49b5f434edc5e582a5386c35d662","src/set.rs":"0a57affb623fa6b28df18cc14841e4f076cbd1da5c809635d202f865640af1ee","src/util.rs":"ab712bce71b54cf2763e6010e64bb5944d1d59ce15e2f2beffa7ceed204d6a68","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"1addbc6cbcb1aae5b8bde0fb0e18197d947e8f13244e4ae7ebf97bdda00eafea","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.56"
name = "indexmap"
version = "1.9.2"
version = "1.9.3"
description = "A hash table with consistent order and fast iteration."
documentation = "https://docs.rs/indexmap/"
readme = "README.md"
@ -66,8 +66,9 @@ version = "1.4.1"
optional = true
[dependencies.rustc-rayon]
version = "0.4"
version = "0.5"
optional = true
package = "rustc-rayon"
[dependencies.serde]
version = "1.0"

View File

@ -1,3 +1,7 @@
- 1.9.3
- Bump the `rustc-rayon` dependency, for compiler use only.
- 1.9.2
- `IndexMap` and `IndexSet` both implement `arbitrary::Arbitrary<'_>` and

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"017a8c6533b5524a7cc9c9c4f67c64fac705139e6690f792db35aa53a4060b3e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"469b853ac8bd9b034bc701f9fdf3da9c4c944b8a08438de1608d5d5d63e4765b","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/canonicals.rs":"9ab83dc38f01be083e4f4b391214232d5527eb81f6adb459c0719da9c8c7e168","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"25582534c0dec431c767c0e7f6cfb389cb597c24c8a80b72e81f08e25f13dadb","src/component/imports.rs":"c824ffeba530fe142655d3143b1c86e172485d46f05ea1c45fdb9f31ad22f00e","src/component/instances.rs":"4238b7cd93e987cbc3a7b57a397f82faea4cbc4b884cabb915f8f16ec9b02e20","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"f3b6691f822d53eb743b397a4e735786501cf000451753ae9a65031ae3249835","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"3d714f89e94293d285ad9347cc649788cdf45e4816f9ea9b91c5fb87084dbf44","src/core.rs":"a00656f82a623656c59a2d7230b40a5849a5083e117bc57061746f6e3022c7bb","src/core/code.rs":"ee841eab282781257f6d22f70d2061ffc106b93a0615aedd00f2b8d8feea0b50","src/core/custom.rs":"6883b79152f38ab902fa52a647098bcc64821ef3bc7b0f1cc9911e702b4f2856","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/dump.rs":"8feaa532e3851186277ec1f4906e7fdc82c6399b211b8c928b16e293db1205b0","src/core/elements.rs":"35e64746d1924f37a101969e289fe0049d967c9b5452516d78ced4e1a7858b4d","src/core/exports.rs":"f37351587cd0cfa7608f94e0fcbfa09d41c7df1d123c47825992c364d5d9ff11","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"560d8e8c818d968cd8a101ab3c639f723b1c754716aa1178d1c4570efd84d010","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"2f1053d9c2671e91a2b6e253dd38921bfc5f1b8a1a047b10c843033fe0f492de","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"80e93b756cdd1234cd088f98be8dd720fadede755ed5b884e6adacd7ef050072","src/core/producers.rs":"f4916c1cf61e26170cd10fe350de7dad18005461c362909b9557c16c507517bc","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"d5ae8c92c8707332eda6be6e5649f2f8042a1c6242494b0174cbee5e1971cace","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"3d7cbd703608aa8a49116685ab41d4f505507bb53dfaadaf41620be12dea582b","src/lib.rs":"e61325ab8de1b4c404f4ee7665eef404fca2d23322a9c8f94efec8426edc166b","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"}
{"files":{"Cargo.toml":"e50a4bb80d433cfa63a3e78b342afe04640eb400c686b2f48bfacc680f76ba71","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"222dd5da8d78696ebde282dacbf08a12a439f5f376d09870a2d4c1390ee99bf3","src/component/aliases.rs":"be5215154b872ed5664f3bfe2aa1391f36a2575aa9d53971ab61868a1c446e9d","src/component/canonicals.rs":"a4f9c7a2b8ac3783d7337a5579cf71df2f33b315b354965980bd2c483d3aa141","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"25582534c0dec431c767c0e7f6cfb389cb597c24c8a80b72e81f08e25f13dadb","src/component/imports.rs":"c824ffeba530fe142655d3143b1c86e172485d46f05ea1c45fdb9f31ad22f00e","src/component/instances.rs":"4238b7cd93e987cbc3a7b57a397f82faea4cbc4b884cabb915f8f16ec9b02e20","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/names.rs":"f3b6691f822d53eb743b397a4e735786501cf000451753ae9a65031ae3249835","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"cbc7a3dc0f3e23024cc82edfc9b8a3f49111faa44ef89fb06ca08c10794211e3","src/core.rs":"a00656f82a623656c59a2d7230b40a5849a5083e117bc57061746f6e3022c7bb","src/core/code.rs":"ee841eab282781257f6d22f70d2061ffc106b93a0615aedd00f2b8d8feea0b50","src/core/custom.rs":"4b9f07b701dc7b6990d92fb43016c28fb971411670bb6a48553b92b1c35eb9a3","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/dump.rs":"8feaa532e3851186277ec1f4906e7fdc82c6399b211b8c928b16e293db1205b0","src/core/elements.rs":"2df1ad85f683b5cf3ce43c8cfef3f08f74a17cec9171537e3f24205dc067b4f7","src/core/exports.rs":"f37351587cd0cfa7608f94e0fcbfa09d41c7df1d123c47825992c364d5d9ff11","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"560d8e8c818d968cd8a101ab3c639f723b1c754716aa1178d1c4570efd84d010","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"2f1053d9c2671e91a2b6e253dd38921bfc5f1b8a1a047b10c843033fe0f492de","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"80e93b756cdd1234cd088f98be8dd720fadede755ed5b884e6adacd7ef050072","src/core/producers.rs":"f4916c1cf61e26170cd10fe350de7dad18005461c362909b9557c16c507517bc","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"d5ae8c92c8707332eda6be6e5649f2f8042a1c6242494b0174cbee5e1971cace","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"507a100b4d30016aa7f718fd9bd1011e13a836f2d27974f66d50e9a9cbc41515","src/lib.rs":"e61325ab8de1b4c404f4ee7665eef404fca2d23322a9c8f94efec8426edc166b","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a"}

View File

@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "wasm-encoder"
version = "0.29.0"
version = "0.31.0"
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
description = """
A low-level WebAssembly encoder.

View File

@ -20,7 +20,7 @@ pub use self::names::*;
pub use self::start::*;
pub use self::types::*;
use crate::{CustomSection, Encode, ProducersSection};
use crate::{CustomSection, Encode, ProducersSection, RawCustomSection};
// Core sorts extended by the component model
const CORE_TYPE_SORT: u8 = 0x10;
@ -153,6 +153,12 @@ impl ComponentSection for CustomSection<'_> {
}
}
impl ComponentSection for RawCustomSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()
}
}
impl ComponentSection for ProducersSection {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()

View File

@ -1,4 +1,4 @@
use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentValType, Encode};
use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
/// Represents options for canonical function definitions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -129,9 +129,9 @@ impl CanonicalFunctionSection {
}
/// Defines a function which will drop the specified type of handle.
pub fn resource_drop(&mut self, ty: ComponentValType) -> &mut Self {
pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x03);
ty.encode(&mut self.bytes);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}

View File

@ -744,6 +744,12 @@ impl ComponentTypeSection {
pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> {
self.ty().defined_type()
}
/// Defines a new resource type.
pub fn resource(&mut self, rep: ValType, dtor: Option<u32>) -> &mut Self {
self.ty().resource(rep, dtor);
self
}
}
impl Encode for ComponentTypeSection {

View File

@ -26,6 +26,24 @@ impl Section for CustomSection<'_> {
}
}
/// A raw custom section where the bytes specified contain the leb-encoded
/// length of the custom section, the custom section's name, and the custom
/// section's data.
#[derive(Clone, Debug)]
pub struct RawCustomSection<'a>(pub &'a [u8]);
impl Encode for RawCustomSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
sink.extend(self.0);
}
}
impl Section for RawCustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -22,11 +22,10 @@ use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId};
/// let mut elements = ElementSection::new();
/// let table_index = 0;
/// let offset = ConstExpr::i32_const(42);
/// let element_type = RefType::FUNCREF;
/// let functions = Elements::Functions(&[
/// // Function indices...
/// ]);
/// elements.active(Some(table_index), &offset, element_type, functions);
/// elements.active(Some(table_index), &offset, functions);
///
/// let mut module = Module::new();
/// module
@ -47,7 +46,7 @@ pub enum Elements<'a> {
/// A sequences of references to functions by their indices.
Functions(&'a [u32]),
/// A sequence of reference expressions.
Expressions(&'a [ConstExpr]),
Expressions(RefType, &'a [ConstExpr]),
}
/// An element segment's mode.
@ -79,8 +78,6 @@ pub enum ElementMode<'a> {
pub struct ElementSegment<'a> {
/// The element segment's mode.
pub mode: ElementMode<'a>,
/// The element segment's type.
pub element_type: RefType,
/// This segment's elements.
pub elements: Elements<'a>,
}
@ -104,50 +101,53 @@ impl ElementSection {
/// Define an element segment.
pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
let expr_bit = match segment.elements {
Elements::Expressions(_) => 0b100u32,
Elements::Expressions(..) => 0b100u32,
Elements::Functions(_) => 0b000u32,
};
let mut encode_type = false;
match &segment.mode {
ElementMode::Active {
table: None,
offset,
} if segment.element_type == RefType::FUNCREF => {
(/* 0x00 | */expr_bit).encode(&mut self.bytes);
offset.encode(&mut self.bytes);
}
ElementMode::Passive => {
(0x01 | expr_bit).encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
segment.element_type.encode(&mut self.bytes);
}
encode_type = true;
}
ElementMode::Active { table, offset } => {
(0x02 | expr_bit).encode(&mut self.bytes);
table.unwrap_or(0).encode(&mut self.bytes);
offset.encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
segment.element_type.encode(&mut self.bytes);
match (table, &segment.elements) {
// If the `table` is not specified then the 0x00 encoding
// can be used with either function indices or expressions
// that have a `funcref` type.
(None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => {
(/* 0x00 | */expr_bit).encode(&mut self.bytes);
}
// ... otherwise fall through for all other expressions here
// with table 0 or an explicitly specified table to the 0x02
// encoding.
(None, Elements::Expressions(..)) | (Some(_), _) => {
(0x02 | expr_bit).encode(&mut self.bytes);
table.unwrap_or(0).encode(&mut self.bytes);
encode_type = true;
}
}
offset.encode(&mut self.bytes);
}
ElementMode::Declared => {
(0x03 | expr_bit).encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
segment.element_type.encode(&mut self.bytes);
}
encode_type = true;
}
}
match segment.elements {
Elements::Functions(fs) => {
if encode_type {
// elemkind == funcref
self.bytes.push(0x00);
}
fs.encode(&mut self.bytes);
}
Elements::Expressions(e) => {
Elements::Expressions(ty, e) => {
if encode_type {
ty.encode(&mut self.bytes);
}
e.len().encode(&mut self.bytes);
for expr in e {
expr.encode(&mut self.bytes);
@ -168,7 +168,6 @@ impl ElementSection {
&mut self,
table_index: Option<u32>,
offset: &ConstExpr,
element_type: RefType,
elements: Elements<'_>,
) -> &mut Self {
self.segment(ElementSegment {
@ -176,7 +175,6 @@ impl ElementSection {
table: table_index,
offset,
},
element_type,
elements,
})
}
@ -184,10 +182,9 @@ impl ElementSection {
/// Encode a passive element segment.
///
/// Passive segments are part of the bulk memory proposal.
pub fn passive<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self {
pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Passive,
element_type,
elements,
})
}
@ -195,10 +192,9 @@ impl ElementSection {
/// Encode a declared element segment.
///
/// Declared segments are part of the bulk memory proposal.
pub fn declared<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self {
pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Declared,
element_type,
elements,
})
}

View File

@ -1,6 +1,57 @@
use crate::{encode_section, Encode, Section, SectionId};
/// Array or struct field type.
/// Represents a subtype of possible other types in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct SubType {
/// Is the subtype final.
pub is_final: bool,
/// The list of supertype indexes. As of GC MVP, there can be at most one supertype.
pub supertype_idx: Option<u32>,
/// The structural type of the subtype.
pub structural_type: StructuralType,
}
/// Represents a structural type in a WebAssembly module.
#[derive(Debug, Clone)]
pub enum StructuralType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
/// The type is for a struct.
Struct(StructType),
}
/// Represents a type of a function in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FuncType {
/// The combined parameters and result types.
params_results: Box<[ValType]>,
/// The number of parameter types.
len_params: usize,
}
/// Represents a type of an array in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ArrayType(pub FieldType);
/// Represents a type of a struct in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructType {
/// Struct fields.
pub fields: Box<[FieldType]>,
}
/// Field type in structural types (structs, arrays).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct FieldType {
/// Storage type of the field.
pub element_type: StorageType,
/// Is the field mutable.
pub mutable: bool,
}
/// Storage type for structural type fields.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum StorageType {
/// The `i8` type.
@ -34,6 +85,35 @@ pub enum ValType {
Ref(RefType),
}
impl FuncType {
/// Creates a new [`FuncType`] from the given `params` and `results`.
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValType>,
R: IntoIterator<Item = ValType>,
{
let mut buffer = params.into_iter().collect::<Vec<_>>();
let len_params = buffer.len();
buffer.extend(results);
Self {
params_results: buffer.into(),
len_params,
}
}
/// Returns a shared slice to the parameter types of the [`FuncType`].
#[inline]
pub fn params(&self) -> &[ValType] {
&self.params_results[..self.len_params]
}
/// Returns a shared slice to the result types of the [`FuncType`].
#[inline]
pub fn results(&self) -> &[ValType] {
&self.params_results[self.len_params..]
}
}
impl ValType {
/// Alias for the `funcref` type in WebAssembly
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
@ -224,13 +304,59 @@ impl TypeSection {
}
/// Define an array type in this type section.
pub fn array(&mut self, ty: StorageType, mutable: bool) -> &mut Self {
pub fn array(&mut self, ty: &StorageType, mutable: bool) -> &mut Self {
self.bytes.push(0x5e);
self.field(ty, mutable);
self.num_added += 1;
self
}
fn field(&mut self, ty: &StorageType, mutable: bool) -> &mut Self {
ty.encode(&mut self.bytes);
self.bytes.push(mutable as u8);
self
}
/// Define a struct type in this type section.
pub fn struct_(&mut self, fields: Vec<FieldType>) -> &mut Self {
self.bytes.push(0x5f);
fields.len().encode(&mut self.bytes);
for f in fields.iter() {
self.field(&f.element_type, f.mutable);
}
self.num_added += 1;
self
}
/// Define an explicit subtype in this type section.
pub fn subtype(&mut self, ty: &SubType) -> &mut Self {
// In the GC spec, supertypes is a vector, not an option.
let st = match ty.supertype_idx {
Some(idx) => vec![idx],
None => vec![],
};
if ty.is_final {
self.bytes.push(0x4e);
st.encode(&mut self.bytes);
} else if !st.is_empty() {
self.bytes.push(0x50);
st.encode(&mut self.bytes);
}
match &ty.structural_type {
StructuralType::Func(ty) => {
self.function(ty.params().iter().copied(), ty.results().iter().copied());
}
StructuralType::Array(ArrayType(ty)) => {
self.array(&ty.element_type, ty.mutable);
}
StructuralType::Struct(ty) => {
self.struct_(ty.fields.to_vec());
}
}
self
}
}
impl Encode for TypeSection {

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"f896f021b268aca35dc7d09e988612fc7651c586e38a9b074f3532674eb4e341","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9202d01e78acf04e38e23e162a91c20ece8968f6172c87bfa6f18bf0b3f27d74","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"f11ed5adb46a746d875c15a7152e44e5ea1ba6bd270e160ce3b854e50d6ffc18","src/component/encode.rs":"b8625f9daa3eab0f405e6c4361b076e5ff7f2ebeb8beb6b7c22af35b8aadbf47","src/config.rs":"009364da9fb55ebe2625e2fa9a9fdc9033952f40304e353582e7bb22b10da4bf","src/core.rs":"cb38f2771d495f3af7d83e52750270bf781b49238821fb4a9e663d65fc8e35a5","src/core/code_builder.rs":"60e407a758ff58aafdcf4eb4e9141aca2ab7c7fe09d6644bc6e31043f88d0d69","src/core/code_builder/no_traps.rs":"e595dbde06551f5f8b23e03cfac0634beacab08e6243c66d6ffda95079212b24","src/core/encode.rs":"b4cc82895e3c3afe26e2e62bbdd63c44e7c1f091133e49f0eaf7e7ec22400e40","src/core/terminate.rs":"d24af5206a13aee7d6a6ea900ccdf088c09d053c36026cf1607cc38c972b3ba9","src/lib.rs":"07641b625f69b57e6e3275a6bdeb015fe68e5e1582cfd21c33395294caf0a84b","tests/component.rs":"44684e990e832590a0b348ce33fadf39ee55dec52fdfa9353570edcbf65325ee","tests/core.rs":"eafed78cccad968e64283505bb6d8ce905af5e1cabed3bd36abeba6eec2a0a9b"},"package":"027ec1c470cd5d56c43b8e02040250b136ddb5975dd76a1c16915137f5f17e76"}
{"files":{"Cargo.toml":"8588d7b930072bf0ac18ec62cd296f0eca3f8dab2c4cf261c14f6ac597e19236","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9202d01e78acf04e38e23e162a91c20ece8968f6172c87bfa6f18bf0b3f27d74","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"f11ed5adb46a746d875c15a7152e44e5ea1ba6bd270e160ce3b854e50d6ffc18","src/component/encode.rs":"b8625f9daa3eab0f405e6c4361b076e5ff7f2ebeb8beb6b7c22af35b8aadbf47","src/config.rs":"009364da9fb55ebe2625e2fa9a9fdc9033952f40304e353582e7bb22b10da4bf","src/core.rs":"d3717407f0982a2c1e20856874d347d3a2824b84bf0c5885d883a5e5cf165b5c","src/core/code_builder.rs":"60e407a758ff58aafdcf4eb4e9141aca2ab7c7fe09d6644bc6e31043f88d0d69","src/core/code_builder/no_traps.rs":"e595dbde06551f5f8b23e03cfac0634beacab08e6243c66d6ffda95079212b24","src/core/encode.rs":"1c3a76cb46511bfe91e01e5cd430fa145593f7986ff4f0041c854759b391d153","src/core/terminate.rs":"d24af5206a13aee7d6a6ea900ccdf088c09d053c36026cf1607cc38c972b3ba9","src/lib.rs":"07641b625f69b57e6e3275a6bdeb015fe68e5e1582cfd21c33395294caf0a84b","tests/component.rs":"44684e990e832590a0b348ce33fadf39ee55dec52fdfa9353570edcbf65325ee","tests/core.rs":"75e79b0ec56baa2fcb0e67ba61a3202f4265c99008ac2b4a52d882221c12048d"},"package":"706fc2c6fb0af287ea9147d343485536b5857b72cd32b1d4091619583b334103"}

View File

@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "wasm-smith"
version = "0.12.10"
version = "0.12.12"
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
exclude = ["/benches/corpus"]
description = "A WebAssembly test case generator"
@ -39,28 +39,25 @@ features = ["derive"]
version = "0.4"
[dependencies.indexmap]
version = "1.9.1"
version = "2.0.0"
[dependencies.leb128]
version = "0.2.4"
[dependencies.serde]
version = "1.0.137"
version = "1.0.166"
features = ["derive"]
optional = true
[dependencies.wasm-encoder]
version = "0.29.0"
version = "0.31.0"
[dependencies.wasmparser]
version = "0.107.0"
version = "0.109.0"
[dev-dependencies.criterion]
version = "0.3.3"
[dev-dependencies.libfuzzer-sys]
version = "0.4.0"
[dev-dependencies.rand]
version = "0.8.4"
features = ["small_rng"]
@ -70,3 +67,6 @@ _internal_cli = [
"serde",
"flagset/serde",
]
[target."cfg(not(target_family = \"wasm\"))".dev-dependencies.libfuzzer-sys]
version = "0.4.0"

View File

@ -547,14 +547,14 @@ impl Module {
// index in our newly generated module. Initially the option is `None` and will become a
// `Some` when we encounter an import that uses this signature in the next portion of this
// function. See also the `make_func_type` closure below.
let mut available_types = Vec::<(wasmparser::Type, Option<u32>)>::new();
let mut available_types = Vec::<(wasmparser::StructuralType, Option<u32>)>::new();
let mut available_imports = Vec::<wasmparser::Import>::new();
for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
match payload.expect("could not parse the available import payload") {
wasmparser::Payload::TypeSection(type_reader) => {
for ty in type_reader {
let ty = ty.expect("could not parse type section");
available_types.push((ty, None));
available_types.push((ty.structural_type, None));
}
}
wasmparser::Payload::ImportSection(import_reader) => {
@ -587,7 +587,7 @@ impl Module {
let serialized_sig_idx = match available_types.get_mut(parsed_sig_idx as usize) {
None => panic!("signature index refers to a type out of bounds"),
Some((_, Some(idx))) => *idx as usize,
Some((wasmparser::Type::Func(func_type), index_store)) => {
Some((wasmparser::StructuralType::Func(func_type), index_store)) => {
let multi_value_required = func_type.results().len() > 1;
let new_index = first_type_index + new_types.len();
if new_index >= max_types || (multi_value_required && !multi_value_enabled) {
@ -609,8 +609,11 @@ impl Module {
new_types.push(Type::Func(Rc::clone(&func_type)));
new_index
}
Some((wasmparser::Type::Array(_array_type), _index_store)) => {
unimplemented!("Array and struct types are not supported yet.");
Some((wasmparser::StructuralType::Array(_array_type), _index_store)) => {
unimplemented!("Array types are not supported yet.");
}
Some((wasmparser::StructuralType::Struct(_struct_type), _index_store)) => {
unimplemented!("Struct types are not supported yet.");
}
};
match &new_types[serialized_sig_idx - first_type_index] {

View File

@ -158,7 +158,7 @@ impl Module {
None => wasm_encoder::ConstExpr::ref_null(el.ty.heap_type),
}
}));
wasm_encoder::Elements::Expressions(&exps)
wasm_encoder::Elements::Expressions(el.ty, &exps)
}
Elements::Functions(fs) => wasm_encoder::Elements::Functions(fs),
};
@ -169,13 +169,13 @@ impl Module {
Offset::Const64(n) => ConstExpr::i64_const(n),
Offset::Global(g) => ConstExpr::global_get(g),
};
elems.active(*table, &offset, el.ty, elements);
elems.active(*table, &offset, elements);
}
ElementKind::Passive => {
elems.passive(el.ty, elements);
elems.passive(elements);
}
ElementKind::Declared => {
elems.declared(el.ty, elements);
elems.declared(elements);
}
}
}

View File

@ -130,10 +130,13 @@ fn smoke_test_imports_config() {
if let wasmparser::Payload::TypeSection(rdr) = payload {
// Gather the signature types to later check function types against.
for ty in rdr {
match ty.unwrap() {
wasmparser::Type::Func(ft) => sig_types.push(ft),
wasmparser::Type::Array(_) => {
unimplemented!("Array and struct types are not supported yet.")
match ty.unwrap().structural_type {
wasmparser::StructuralType::Func(ft) => sig_types.push(ft),
wasmparser::StructuralType::Array(_) => {
unimplemented!("Array types are not supported yet.")
}
wasmparser::StructuralType::Struct(_) => {
unimplemented!("Struct types are not supported yet.")
}
}
}

View File

@ -1 +1 @@
{"files":{"Cargo.lock":"0094a4caa360684ecf8dba191e832d04ea783f722bb3d7203a861ab5f1b6652b","Cargo.toml":"f9969ee73f9611dd62ba995630b919e1d81d2ba2af3cd2e9813d73778d734614","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"12b94c2a8ba04c5362b86ff36cdedb3596507a5606ce22a275cac2632f5d35ad","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/binary_reader.rs":"0c346c4248b39ab3d7c9908834442ef6f3aa5dc921804c3e89e7bf46d49dbe15","src/lib.rs":"b7fbf8cdd67033c61c1b3a3c25823ef4518458eda6cbfd44d1c80b20cf0c5076","src/limits.rs":"93b8ae6ce2f95c14b62e41fd6dc3ab3869a6879af46bd0c560b43193cea0b496","src/parser.rs":"c69c24f2308b05e0a5072bbd07084d2002e0ae291afd669361b5a4bb8c7fcad4","src/readers.rs":"406bf0cf694ed364c9c53cd25eb27a8e3fa97d099994f3e2a640747c49abf74b","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"72f3339cb452c1b055bd080281fe4923d132c280da112fcd1182594811b87494","src/readers/component/canonicals.rs":"45b8c54e842bc698d180b7396579b93e16fddb9a055c753482fc03bf5cd443b4","src/readers/component/exports.rs":"96cc2f65666da77b6230335378550d9b45a193795ee939d75808cc49cc1c06f4","src/readers/component/imports.rs":"5c6a0066adb143455b92b5ef1b773184ccf62923c8a35b26262e6a80058971d2","src/readers/component/instances.rs":"5f3ef2b8424a3beff2c34d118f1c9f168d1beee589c0e87dabab94ba726a8f1d","src/readers/component/names.rs":"3f5dac9db8668b18cd6721cd780e6aba9b223b404c9d1173d09efe4e6b4d3a8a","src/readers/component/start.rs":"8e1e5d8aa5ece26d42251449cadcce0546c4d995f1641941b8a31ed4bc6ac761","src/readers/component/types.rs":"6579bb3131570f35415fc47ab35efbfc2688b970052425741ad3a1aa89588b86","src/readers/core.rs":"c2536abe2a3305b4aa3d91f7fcea9c89e65a5c94af74e4f6a1b19bbe09f8fb2c","src/readers/core/code.rs":"53f49986febb27f4cb67f4495e7b369fc80e2f70908e1e831750698dd15fe37f","src/readers/core/coredumps.rs":"7cde14b700bdf2459fa57e2cbb5a520a4d1d8547f075c1440db74b19ecf74764","src/readers/core/custom.rs":"f80d3a994e8778a912319834228cbb772c65a4b6b1f25b41fe00d220d388831f","src/readers/core/data.rs":"c1fcda7b548b15be40b3dd1f667d97c30c543867f2dc4734b590846beefe3ae3","src/readers/core/elements.rs":"c7fdde45032eec293d69b8bce5519391db84117aa33a98dad35b12c68a532c9f","src/readers/core/exports.rs":"50dc1ee51b73f03f24077f7c290bca756966563cedbad9e49d735d60f60c91db","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"d23f99a3adc9593652a5efd4dc81e8f014f57e776b49717dabbdcd0a811a96b1","src/readers/core/imports.rs":"4d247e8cac0b3cef7425d93f7a7f2412b2ae8979da944080d565415499e27e87","src/readers/core/init.rs":"ec6717063b0b7f2e9aa17ae52083019cee52594bf5a8b6858f2d77b10d7a0639","src/readers/core/memories.rs":"351f816d663b7d17546dc3b19ce0e43f406ce743289219a3758f7c837903fa6d","src/readers/core/names.rs":"408ebf052170bf0dc874b3158bb31089a891c3735cb35df2976e0b1e9791febb","src/readers/core/operators.rs":"46e927f6db9db9097217c5485da3a7b89e638730def809d177897f39356f5f52","src/readers/core/producers.rs":"5b53d0979a68008f9aec0bb9bca64c071e49a6a1879d8459f1114fa666e661c5","src/readers/core/tables.rs":"cbe5b35893bd3929354b4487b344062ce6b540e6a70bde6eddf05a07a68574e9","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"e644d7fce8a8a4cab0b617d2d4000f2979375e5b0389b0511ad1aeff7eab6cd3","src/resources.rs":"e3bf138ef8fc94d2773fc6159bbd7f47611b5d9121c12e724cbbb824d8278411","src/validator.rs":"fda1d806231f3e714c538d0f23aab0c6e1f6790df591c11903a716514373eec3","src/validator/component.rs":"1920424f9dacf904ad6112ce5bc0d272e3aa60fd88895ae06b44294341ec904f","src/validator/core.rs":"268e88fed44d03c09cc2a500d292d676cc234748f64a00c95757a2349d24e91e","src/validator/func.rs":"63b66b7bb274be4115d8a26bce9b73128de0c079bd3318423288fadc1361fdb4","src/validator/names.rs":"0beae05cae3bf6d8fe2d0ebea1c5dd993fc8ce1116b454aca2a79a41a8e1c9d8","src/validator/operators.rs":"d488964a60fcb44c03b41b7f9fa3c7cafdfc30be2e2d9fef87aac73273056f8f","src/validator/types.rs":"e50497731c493205965e2f1cb8aee40287f00abff8f671034733960e81e42c03","tests/big-module.rs":"1f9241a4504d0421f6a5c759e3c688c87994fe04668b1d4e8912cedd98f2bd17"},"package":"29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb"}
{"files":{"Cargo.lock":"77ee2d9359018953cfd5bc20e037058aee2c38900f822a8f264fcaf2cee82368","Cargo.toml":"b1347320791d977fb2b3f173a3520117d1ee5e8f8ddcb8e8f8c9c98bdbd98979","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"dd6e7eb5f196d9ffe330873c8d68538a29a648075775f520678fc889f2bf8b4b","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/binary_reader.rs":"0c346c4248b39ab3d7c9908834442ef6f3aa5dc921804c3e89e7bf46d49dbe15","src/lib.rs":"b7fbf8cdd67033c61c1b3a3c25823ef4518458eda6cbfd44d1c80b20cf0c5076","src/limits.rs":"cda435bb60b635320d5890f02acd0889ff399712c234ffad2d2fda31080b6ed7","src/parser.rs":"c69c24f2308b05e0a5072bbd07084d2002e0ae291afd669361b5a4bb8c7fcad4","src/readers.rs":"406bf0cf694ed364c9c53cd25eb27a8e3fa97d099994f3e2a640747c49abf74b","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"72f3339cb452c1b055bd080281fe4923d132c280da112fcd1182594811b87494","src/readers/component/canonicals.rs":"d3b844d177be69c40644d924271588718685511fafcc46ee1d9d0f6942b9dccb","src/readers/component/exports.rs":"96cc2f65666da77b6230335378550d9b45a193795ee939d75808cc49cc1c06f4","src/readers/component/imports.rs":"5c6a0066adb143455b92b5ef1b773184ccf62923c8a35b26262e6a80058971d2","src/readers/component/instances.rs":"5f3ef2b8424a3beff2c34d118f1c9f168d1beee589c0e87dabab94ba726a8f1d","src/readers/component/names.rs":"3f5dac9db8668b18cd6721cd780e6aba9b223b404c9d1173d09efe4e6b4d3a8a","src/readers/component/start.rs":"8e1e5d8aa5ece26d42251449cadcce0546c4d995f1641941b8a31ed4bc6ac761","src/readers/component/types.rs":"bf511a8201af9e84e04e83041451a419520cd2d0f8024add18e36d78e985e065","src/readers/core.rs":"c2536abe2a3305b4aa3d91f7fcea9c89e65a5c94af74e4f6a1b19bbe09f8fb2c","src/readers/core/code.rs":"53f49986febb27f4cb67f4495e7b369fc80e2f70908e1e831750698dd15fe37f","src/readers/core/coredumps.rs":"7cde14b700bdf2459fa57e2cbb5a520a4d1d8547f075c1440db74b19ecf74764","src/readers/core/custom.rs":"f80d3a994e8778a912319834228cbb772c65a4b6b1f25b41fe00d220d388831f","src/readers/core/data.rs":"c1fcda7b548b15be40b3dd1f667d97c30c543867f2dc4734b590846beefe3ae3","src/readers/core/elements.rs":"7f05cbe94402bb2e591c8dd8f0be45309044c80f242568c66c1b2ea0011b7f50","src/readers/core/exports.rs":"50dc1ee51b73f03f24077f7c290bca756966563cedbad9e49d735d60f60c91db","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"d23f99a3adc9593652a5efd4dc81e8f014f57e776b49717dabbdcd0a811a96b1","src/readers/core/imports.rs":"4d247e8cac0b3cef7425d93f7a7f2412b2ae8979da944080d565415499e27e87","src/readers/core/init.rs":"ec6717063b0b7f2e9aa17ae52083019cee52594bf5a8b6858f2d77b10d7a0639","src/readers/core/memories.rs":"351f816d663b7d17546dc3b19ce0e43f406ce743289219a3758f7c837903fa6d","src/readers/core/names.rs":"408ebf052170bf0dc874b3158bb31089a891c3735cb35df2976e0b1e9791febb","src/readers/core/operators.rs":"46e927f6db9db9097217c5485da3a7b89e638730def809d177897f39356f5f52","src/readers/core/producers.rs":"5b53d0979a68008f9aec0bb9bca64c071e49a6a1879d8459f1114fa666e661c5","src/readers/core/tables.rs":"cbe5b35893bd3929354b4487b344062ce6b540e6a70bde6eddf05a07a68574e9","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"7d932e4939748cc856c8ae5b551336bb646c032253e4e03b2780dd57d7972cae","src/resources.rs":"e3bf138ef8fc94d2773fc6159bbd7f47611b5d9121c12e724cbbb824d8278411","src/validator.rs":"cab135ab8c4d32389fb38e514fc757fa440c3f8a82dda6e3d68ea5e83ce9a97d","src/validator/component.rs":"b771ab4604d895d0dc4b942cc9669b19b2a4aa07cfb5de3f0ce0c7f02df84dd2","src/validator/core.rs":"2b624b04176551dbf0af762376313a4dd941c9bca0e6f7b7760afb5b137d085d","src/validator/func.rs":"63b66b7bb274be4115d8a26bce9b73128de0c079bd3318423288fadc1361fdb4","src/validator/names.rs":"0beae05cae3bf6d8fe2d0ebea1c5dd993fc8ce1116b454aca2a79a41a8e1c9d8","src/validator/operators.rs":"a0cc09ba25b85f769647d0ecf2754f779648dbf86210b6d2a36ce8a9739f0423","src/validator/types.rs":"a7156e0bb5b59a53b08606d9ef2f1f67c01b94f159ceefbf909d31eab900e302","tests/big-module.rs":"2d956dedf1a9f0b1e976dd63c97d3707cd726da10166cad2f16ae33000ed13b3"},"package":"8bf9564f29de2890ee34406af52d2a92dec6ef044c8ddfc5add5db8dcfd36e6c"}

View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.71"
@ -33,9 +42,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.12.2"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cast"
@ -119,9 +128,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.14"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
@ -132,18 +141,18 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "csv"
version = "1.2.1"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad"
checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086"
dependencies = [
"csv-core",
"itoa",
@ -166,6 +175,12 @@ version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "half"
version = "1.8.2"
@ -174,9 +189,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.3"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "hermit-abi"
@ -189,20 +204,17 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.2.6"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "indexmap"
version = "1.9.3"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"autocfg",
"equivalent",
"hashbrown",
]
@ -217,15 +229,15 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
[[package]]
name = "js-sys"
version = "0.3.62"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
@ -244,18 +256,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "memchr"
@ -265,9 +274,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
@ -283,19 +292,19 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi 0.2.6",
"hermit-abi 0.3.2",
"libc",
]
[[package]]
name = "once_cell"
version = "1.17.1"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
@ -305,9 +314,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "plotters"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"num-traits",
"plotters-backend",
@ -318,33 +327,33 @@ dependencies = [
[[package]]
name = "plotters-backend"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-svg"
version = "0.3.3"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro2"
version = "1.0.57"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.27"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
dependencies = [
"proc-macro2",
]
@ -373,24 +382,38 @@ dependencies = [
[[package]]
name = "regex"
version = "1.8.1"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.1"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
[[package]]
name = "same-file"
@ -415,9 +438,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]]
name = "serde"
version = "1.0.163"
version = "1.0.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
[[package]]
name = "serde_cbor"
@ -431,9 +454,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.163"
version = "1.0.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
dependencies = [
"proc-macro2",
"quote",
@ -442,9 +465,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.96"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed"
dependencies = [
"itoa",
"ryu",
@ -453,9 +476,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.16"
version = "2.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2"
dependencies = [
"proc-macro2",
"quote",
@ -483,9 +506,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
[[package]]
name = "unicode-width"
@ -505,9 +528,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.85"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -515,9 +538,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.85"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
@ -530,9 +553,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.85"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -540,9 +563,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.85"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
@ -553,22 +576,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.85"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "wasm-encoder"
version = "0.29.0"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"
checksum = "06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a"
dependencies = [
"leb128",
]
[[package]]
name = "wasmparser"
version = "0.107.0"
version = "0.109.0"
dependencies = [
"anyhow",
"criterion",
@ -581,9 +604,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.62"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",

View File

@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "wasmparser"
version = "0.107.0"
version = "0.109.0"
authors = ["Yury Delendik <ydelendik@mozilla.com>"]
exclude = ["benches/*.wasm"]
description = """
@ -33,7 +33,7 @@ name = "benchmark"
harness = false
[dependencies.indexmap]
version = "1.9.1"
version = "2.0.0"
[dependencies.semver]
version = "1.0.0"
@ -51,4 +51,4 @@ version = "1.13.0"
version = "1.3"
[dev-dependencies.wasm-encoder]
version = "0.29.0"
version = "0.31.0"

View File

@ -4,10 +4,7 @@ use once_cell::unsync::Lazy;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use wasmparser::{
DataKind, ElementKind, HeapType, Parser, Payload, ValType, Validator, VisitOperator,
WasmFeatures,
};
use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures};
/// A benchmark input.
pub struct BenchmarkInput {
@ -139,7 +136,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
op?;
}
}
wasmparser::ElementItems::Expressions(r) => {
wasmparser::ElementItems::Expressions(_, r) => {
for op in r {
op?;
}

View File

@ -16,6 +16,7 @@
// The following limits are imposed by wasmparser on WebAssembly modules.
// The limits are agreed upon with other engines for consistency.
pub const MAX_WASM_TYPES: usize = 1_000_000;
pub const MAX_WASM_SUPERTYPES: usize = 1;
pub const MAX_WASM_FUNCTIONS: usize = 1_000_000;
pub const MAX_WASM_EXPORTS: usize = 100_000;
pub const MAX_WASM_GLOBALS: usize = 1_000_000;
@ -34,6 +35,7 @@ pub const MAX_WASM_TABLES: usize = 100;
pub const MAX_WASM_MEMORIES: usize = 100;
pub const MAX_WASM_TAGS: usize = 1_000_000;
pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
pub const MAX_WASM_STRUCT_FIELDS: usize = 10_000;
// Component-related limits
pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB

View File

@ -1,5 +1,5 @@
use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
use crate::{BinaryReader, ComponentValType, FromReader, Result, SectionLimited};
use crate::{BinaryReader, FromReader, Result, SectionLimited};
/// Represents options for component functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -50,9 +50,8 @@ pub enum CanonicalFunction {
},
/// A function which is used to drop resource handles of the specified type.
ResourceDrop {
/// The type of the resource that's being dropped, either an (own T) or
/// a (borrow T)
ty: ComponentValType,
/// The type index of the resource that's being dropped.
resource: u32,
},
/// A function which returns the underlying i32-based representation of the
/// specified resource.
@ -95,7 +94,9 @@ impl<'a> FromReader<'a> for CanonicalFunction {
0x02 => CanonicalFunction::ResourceNew {
resource: reader.read()?,
},
0x03 => CanonicalFunction::ResourceDrop { ty: reader.read()? },
0x03 => CanonicalFunction::ResourceDrop {
resource: reader.read()?,
},
0x04 => CanonicalFunction::ResourceRep {
resource: reader.read()?,
},

View File

@ -1,7 +1,7 @@
use crate::limits::*;
use crate::{
BinaryReader, ComponentAlias, ComponentExternName, ComponentImport, ComponentTypeRef,
FromReader, FuncType, Import, Result, SectionLimited, Type, TypeRef, ValType,
FromReader, FuncType, Import, Result, SectionLimited, SubType, TypeRef, ValType,
};
use std::fmt;
@ -39,7 +39,7 @@ impl<'a> FromReader<'a> for CoreType<'a> {
#[derive(Debug, Clone)]
pub enum ModuleTypeDeclaration<'a> {
/// The module type definition is for a type.
Type(Type),
Type(SubType),
/// The module type definition is for an export.
Export {
/// The name of the exported item.

View File

@ -26,8 +26,6 @@ pub struct Element<'a> {
pub kind: ElementKind<'a>,
/// The initial elements of the element segment.
pub items: ElementItems<'a>,
/// The type of the elements.
pub ty: RefType,
/// The range of the the element segment.
pub range: Range<usize>,
}
@ -54,7 +52,7 @@ pub enum ElementItems<'a> {
/// This element contains function indices.
Functions(SectionLimited<'a, u32>),
/// This element contains constant expressions used to initialize the table.
Expressions(SectionLimited<'a, ConstExpr<'a>>),
Expressions(RefType, SectionLimited<'a, ConstExpr<'a>>),
}
/// A reader for the element section of a WebAssembly module.
@ -104,10 +102,10 @@ impl<'a> FromReader<'a> for Element<'a> {
let exprs = flags & 0b100 != 0;
let ty = if flags & 0b011 != 0 {
if exprs {
reader.read()?
Some(reader.read()?)
} else {
match reader.read()? {
ExternalKind::Func => RefType::FUNCREF,
ExternalKind::Func => None,
_ => {
return Err(BinaryReaderError::new(
"only the function external type is supported in elem segment",
@ -117,7 +115,7 @@ impl<'a> FromReader<'a> for Element<'a> {
}
}
} else {
RefType::FUNCREF
None
};
// FIXME(#188) ideally wouldn't have to do skips here
let data = reader.skip(|reader| {
@ -134,11 +132,12 @@ impl<'a> FromReader<'a> for Element<'a> {
Ok(())
})?;
let items = if exprs {
ElementItems::Expressions(SectionLimited::new(
data.remaining_buffer(),
data.original_position(),
)?)
ElementItems::Expressions(
ty.unwrap_or(RefType::FUNCREF),
SectionLimited::new(data.remaining_buffer(), data.original_position())?,
)
} else {
assert!(ty.is_none());
ElementItems::Functions(SectionLimited::new(
data.remaining_buffer(),
data.original_position(),
@ -148,11 +147,6 @@ impl<'a> FromReader<'a> for Element<'a> {
let elem_end = reader.original_position();
let range = elem_start..elem_end;
Ok(Element {
kind,
items,
ty,
range,
})
Ok(Element { kind, items, range })
}
}

View File

@ -13,8 +13,11 @@
* limitations under the License.
*/
use crate::limits::{MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS};
use crate::{BinaryReader, FromReader, Result, SectionLimited};
use crate::limits::{
MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, MAX_WASM_STRUCT_FIELDS,
MAX_WASM_SUPERTYPES,
};
use crate::{BinaryReader, BinaryReaderError, FromReader, Result, SectionLimited};
use std::fmt::{self, Debug, Write};
/// Represents the types of values in a WebAssembly module.
@ -50,6 +53,12 @@ const _: () = {
assert!(std::mem::size_of::<ValType>() == 4);
};
pub(crate) trait Inherits {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType;
}
impl From<RefType> for ValType {
fn from(ty: RefType) -> ValType {
ValType::Ref(ty)
@ -89,6 +98,21 @@ impl ValType {
}
}
impl Inherits for ValType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
match (self, other) {
(Self::Ref(r1), Self::Ref(r2)) => r1.inherits(r2, type_at),
(
s @ (Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 | Self::Ref(_)),
o,
) => s == o,
}
}
}
impl<'a> FromReader<'a> for StorageType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
match reader.peek()? {
@ -510,6 +534,17 @@ impl RefType {
}
}
impl Inherits for RefType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
self == other
|| ((other.is_nullable() || !self.is_nullable())
&& self.heap_type().inherits(&other.heap_type(), type_at))
}
}
impl<'a> FromReader<'a> for RefType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
match reader.read()? {
@ -595,6 +630,69 @@ pub enum HeapType {
I31,
}
impl Inherits for HeapType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
match (self, other) {
(HeapType::Indexed(a), HeapType::Indexed(b)) => {
a == b || type_at(*a).inherits(type_at(*b), type_at)
}
(HeapType::Indexed(a), HeapType::Func) => match type_at(*a).structural_type {
StructuralType::Func(_) => true,
_ => false,
},
(HeapType::Indexed(a), HeapType::Array) => match type_at(*a).structural_type {
StructuralType::Array(_) => true,
_ => false,
},
(HeapType::Indexed(a), HeapType::Struct) => match type_at(*a).structural_type {
StructuralType::Struct(_) => true,
_ => false,
},
(HeapType::Indexed(a), HeapType::Eq | HeapType::Any) => {
match type_at(*a).structural_type {
StructuralType::Array(_) | StructuralType::Struct(_) => true,
_ => false,
}
}
(HeapType::Eq, HeapType::Any) => true,
(HeapType::I31 | HeapType::Array | HeapType::Struct, HeapType::Eq | HeapType::Any) => {
true
}
(HeapType::None, HeapType::Indexed(a)) => match type_at(*a).structural_type {
StructuralType::Array(_) | StructuralType::Struct(_) => true,
_ => false,
},
(
HeapType::None,
HeapType::I31 | HeapType::Eq | HeapType::Any | HeapType::Array | HeapType::Struct,
) => true,
(HeapType::NoExtern, HeapType::Extern) => true,
(HeapType::NoFunc, HeapType::Func) => true,
(HeapType::NoFunc, HeapType::Indexed(a)) => match type_at(*a).structural_type {
StructuralType::Func(_) => true,
_ => false,
},
(
a @ (HeapType::Func
| HeapType::Extern
| HeapType::Any
| HeapType::Indexed(_)
| HeapType::None
| HeapType::NoExtern
| HeapType::NoFunc
| HeapType::Eq
| HeapType::Struct
| HeapType::Array
| HeapType::I31),
b,
) => a == b,
}
}
}
impl<'a> FromReader<'a> for HeapType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
match reader.peek()? {
@ -651,14 +749,38 @@ impl<'a> FromReader<'a> for HeapType {
}
}
/// Represents a type in a WebAssembly module.
/// Represents a structural type in a WebAssembly module.
#[derive(Debug, Clone)]
pub enum Type {
pub enum StructuralType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
// Struct(StructType),
/// The type is for a struct.
Struct(StructType),
}
/// Represents a subtype of possible other types in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct SubType {
/// Is the subtype final.
pub is_final: bool,
/// The list of supertype indexes. As of GC MVP, there can be at most one supertype.
pub supertype_idx: Option<u32>,
/// The structural type of the subtype.
pub structural_type: StructuralType,
}
impl Inherits for SubType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
!other.is_final
&& self
.structural_type
.inherits(&other.structural_type, type_at)
}
}
/// Represents a type of a function in a WebAssembly module.
@ -672,13 +794,40 @@ pub struct FuncType {
/// Represents a type of an array in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ArrayType {
pub struct ArrayType(pub FieldType);
/// Represents a field type of an array or a struct.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FieldType {
/// Array element type.
pub element_type: StorageType,
/// Are elements mutable.
pub mutable: bool,
}
/// Represents a type of a struct in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructType {
/// Struct fields.
pub fields: Box<[FieldType]>,
}
impl Inherits for StructuralType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
match (self, other) {
(StructuralType::Func(a), StructuralType::Func(b)) => a.inherits(b, type_at),
(StructuralType::Array(a), StructuralType::Array(b)) => a.inherits(b, type_at),
(StructuralType::Struct(a), StructuralType::Struct(b)) => a.inherits(b, type_at),
(StructuralType::Func(_), _) => false,
(StructuralType::Array(_), _) => false,
(StructuralType::Struct(_), _) => false,
}
}
}
impl Debug for FuncType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuncType")
@ -750,6 +899,73 @@ impl FuncType {
}
}
impl Inherits for FuncType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
self.params().len() == other.params().len()
&& self.results().len() == other.results().len()
// Note: per GC spec, function subtypes are contravariant in their parameter types.
// Also see https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
&& self
.params()
.iter()
.zip(other.params())
.fold(true, |r, (a, b)| r && b.inherits(a, type_at))
&& self
.results()
.iter()
.zip(other.results())
.fold(true, |r, (a, b)| r && a.inherits(b, type_at))
}
}
impl Inherits for ArrayType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
self.0.inherits(&other.0, type_at)
}
}
impl Inherits for FieldType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
(other.mutable || !self.mutable) && self.element_type.inherits(&other.element_type, type_at)
}
}
impl Inherits for StorageType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
match (self, other) {
(Self::Val(a), Self::Val(b)) => a.inherits(b, type_at),
(a @ (Self::I8 | Self::I16 | Self::Val(_)), b) => a == b,
}
}
}
impl Inherits for StructType {
fn inherits<'a, F>(&self, other: &Self, type_at: &F) -> bool
where
F: Fn(u32) -> &'a SubType,
{
// Note: Structure types support width and depth subtyping.
self.fields.len() >= other.fields.len()
&& self
.fields
.iter()
.zip(other.fields.iter())
.fold(true, |r, (a, b)| r && a.inherits(b, type_at))
}
}
/// Represents a table's type.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TableType {
@ -828,14 +1044,50 @@ pub struct TagType {
}
/// A reader for the type section of a WebAssembly module.
pub type TypeSectionReader<'a> = SectionLimited<'a, Type>;
pub type TypeSectionReader<'a> = SectionLimited<'a, SubType>;
impl<'a> FromReader<'a> for Type {
impl<'a> FromReader<'a> for StructuralType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
read_structural_type(reader.read_u8()?, reader)
}
}
fn read_structural_type(
opcode: u8,
reader: &mut BinaryReader,
) -> Result<StructuralType, BinaryReaderError> {
Ok(match opcode {
0x60 => StructuralType::Func(reader.read()?),
0x5e => StructuralType::Array(reader.read()?),
0x5f => StructuralType::Struct(reader.read()?),
x => return reader.invalid_leading_byte(x, "type"),
})
}
impl<'a> FromReader<'a> for SubType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
let pos = reader.original_position();
Ok(match reader.read_u8()? {
0x60 => Type::Func(reader.read()?),
0x5e => Type::Array(reader.read()?),
x => return reader.invalid_leading_byte(x, "type"),
opcode @ (0x4e | 0x50) => {
let idx_iter = reader.read_iter(MAX_WASM_SUPERTYPES, "supertype idxs")?;
let idxs = idx_iter.collect::<Result<Vec<u32>>>()?;
if idxs.len() > 1 {
return Err(BinaryReaderError::new(
"multiple supertypes not supported",
pos,
));
}
SubType {
is_final: opcode == 0x4e,
supertype_idx: idxs.first().copied(),
structural_type: read_structural_type(reader.read_u8()?, reader)?,
}
}
opcode => SubType {
is_final: false,
supertype_idx: None,
structural_type: read_structural_type(opcode, reader)?,
},
})
}
}
@ -855,11 +1107,11 @@ impl<'a> FromReader<'a> for FuncType {
}
}
impl<'a> FromReader<'a> for ArrayType {
impl<'a> FromReader<'a> for FieldType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
let element_type = reader.read()?;
let mutable = reader.read_u8()?;
Ok(ArrayType {
Ok(FieldType {
element_type,
mutable: match mutable {
0 => false,
@ -872,3 +1124,18 @@ impl<'a> FromReader<'a> for ArrayType {
})
}
}
impl<'a> FromReader<'a> for ArrayType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(ArrayType(FieldType::from_reader(reader)?))
}
}
impl<'a> FromReader<'a> for StructType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
let fields = reader.read_iter(MAX_WASM_STRUCT_FIELDS, "struct fields")?;
Ok(StructType {
fields: fields.collect::<Result<_>>()?,
})
}
}

View File

@ -1156,8 +1156,8 @@ impl Validator {
crate::CanonicalFunction::ResourceNew { resource } => {
current.resource_new(resource, types, offset)
}
crate::CanonicalFunction::ResourceDrop { ty } => {
current.resource_drop(ty, types, offset)
crate::CanonicalFunction::ResourceDrop { resource } => {
current.resource_drop(resource, types, offset)
}
crate::CanonicalFunction::ResourceRep { resource } => {
current.resource_rep(resource, types, offset)
@ -1441,66 +1441,52 @@ mod tests {
assert_eq!(types.instance_count(), 0);
assert_eq!(types.value_count(), 0);
match types.func_type_at(0) {
Some(ty) => {
assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
assert_eq!(ty.results(), [ValType::I32]);
}
_ => unreachable!(),
}
let ty = types[types.core_type_at(0)].unwrap_func();
assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
assert_eq!(ty.results(), [ValType::I32]);
match types.func_type_at(1) {
Some(ty) => {
assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
assert_eq!(ty.results(), []);
}
_ => unreachable!(),
}
let ty = types[types.core_type_at(1)].unwrap_func();
assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
assert_eq!(ty.results(), []);
assert_eq!(
types.memory_at(0),
Some(MemoryType {
MemoryType {
memory64: false,
shared: false,
initial: 1,
maximum: Some(5)
})
}
);
assert_eq!(
types.table_at(0),
Some(TableType {
TableType {
initial: 10,
maximum: None,
element_type: RefType::FUNCREF,
})
}
);
assert_eq!(
types.global_at(0),
Some(GlobalType {
GlobalType {
content_type: ValType::I32,
mutable: true
})
}
);
match types.function_at(0) {
Some(ty) => {
assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
assert_eq!(ty.results(), [ValType::I32]);
}
_ => unreachable!(),
}
let id = types.function_at(0);
let ty = types[id].unwrap_func();
assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
assert_eq!(ty.results(), [ValType::I32]);
match types.tag_at(0) {
Some(ty) => {
assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
assert_eq!(ty.results(), []);
}
_ => unreachable!(),
}
let ty = types.tag_at(0);
let ty = types[ty].unwrap_func();
assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
assert_eq!(ty.results(), []);
assert_eq!(types.element_at(0), Some(RefType::FUNCREF));
assert_eq!(types.element_at(0), RefType::FUNCREF);
Ok(())
}
@ -1524,9 +1510,9 @@ mod tests {
let types = validator.validate_all(&bytes)?;
let t_id = types.id_from_type_index(0, false).unwrap();
let a1_id = types.id_from_type_index(1, false).unwrap();
let a2_id = types.id_from_type_index(2, false).unwrap();
let t_id = types.component_type_at(0);
let a1_id = types.component_type_at(1);
let a2_id = types.component_type_at(2);
// The ids should all be the same
assert!(t_id == a1_id);
@ -1534,14 +1520,8 @@ mod tests {
assert!(a1_id == a2_id);
// However, they should all point to the same type
assert!(std::ptr::eq(
types.type_from_id(t_id).unwrap(),
types.type_from_id(a1_id).unwrap()
));
assert!(std::ptr::eq(
types.type_from_id(t_id).unwrap(),
types.type_from_id(a2_id).unwrap()
));
assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
Ok(())
}
@ -1565,9 +1545,9 @@ mod tests {
let types = validator.validate_all(&bytes)?;
let t_id = types.id_from_type_index(0, false).unwrap();
let a1_id = types.id_from_type_index(1, false).unwrap();
let a2_id = types.id_from_type_index(2, false).unwrap();
let t_id = types.component_type_at(0);
let a1_id = types.component_type_at(1);
let a2_id = types.component_type_at(2);
// The ids should all be the same
assert!(t_id != a1_id);
@ -1575,14 +1555,8 @@ mod tests {
assert!(a1_id != a2_id);
// However, they should all point to the same type
assert!(std::ptr::eq(
types.type_from_id(t_id).unwrap(),
types.type_from_id(a1_id).unwrap()
));
assert!(std::ptr::eq(
types.type_from_id(t_id).unwrap(),
types.type_from_id(a2_id).unwrap()
));
assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
Ok(())
}

View File

@ -18,7 +18,8 @@ use crate::{
},
BinaryReaderError, CanonicalOption, ComponentExternName, ComponentExternalKind,
ComponentOuterAliasKind, ComponentTypeRef, ExternalKind, FuncType, GlobalType,
InstantiationArgKind, MemoryType, Result, TableType, TypeBounds, ValType, WasmFeatures,
InstantiationArgKind, MemoryType, Result, StructuralType, SubType, TableType, TypeBounds,
ValType, WasmFeatures,
};
use indexmap::{map::Entry, IndexMap, IndexSet};
use std::collections::{HashMap, HashSet};
@ -257,7 +258,11 @@ impl ComponentState {
check_limit: bool,
) -> Result<()> {
let ty = match ty {
crate::CoreType::Func(ty) => Type::Func(ty),
crate::CoreType::Func(ty) => Type::Sub(SubType {
is_final: false,
supertype_idx: None,
structural_type: StructuralType::Func(ty),
}),
crate::CoreType::Module(decls) => Type::Module(Box::new(Self::create_module_type(
components,
decls.into_vec(),
@ -371,7 +376,7 @@ impl ComponentState {
// function and has the correct signature.
if let Some(dtor) = dtor {
let ty = component.core_function_at(dtor, offset)?;
let ty = types[ty].as_func_type().unwrap();
let ty = types[ty].unwrap_func();
if ty.params() != [rep] || ty.results() != [] {
bail!(
offset,
@ -555,6 +560,21 @@ impl ComponentState {
ty: &ComponentEntityType,
types: &TypeAlloc,
) -> bool {
if let ComponentEntityType::Type { created, .. } = ty {
// If this is a top-level resource then register it in the
// appropriate context so later validation of method-like-names
// works out.
if let Some(name) = toplevel_name {
if let Type::Resource(_) = types[*created] {
let cx = match kind {
ExternKind::Import => &mut self.toplevel_imported_resources,
ExternKind::Export => &mut self.toplevel_exported_resources,
};
cx.register(name, *created);
}
}
}
match self.kind {
ComponentKind::Component | ComponentKind::ComponentType => {}
ComponentKind::InstanceType => return true,
@ -589,19 +609,6 @@ impl ComponentState {
}
}
// If this is a top-level resource then register it in the
// appropriate context so later validation of method-like-names
// works out.
if let Some(name) = toplevel_name {
if let Type::Resource(_) = types[*created] {
let cx = match kind {
ExternKind::Import => &mut self.toplevel_imported_resources,
ExternKind::Export => &mut self.toplevel_exported_resources,
};
cx.register(name, *created);
}
}
true
}
@ -618,7 +625,7 @@ impl ComponentState {
// captured, and everything is appropriately added to the right
// imported/exported set.
ComponentEntityType::Instance(i) => {
let ty = types[*i].as_component_instance_type().unwrap();
let ty = types[*i].unwrap_component_instance();
ty.exports
.values()
.all(|ty| self.validate_and_register_named_types(None, kind, ty, types))
@ -680,7 +687,7 @@ impl ComponentState {
// Core wasm constructs are always valid with respect to
// exported types, since they have none.
Type::Module(_) | Type::Instance(_) | Type::Func(_) | Type::Array(_) => true,
Type::Module(_) | Type::Instance(_) | Type::Sub(_) => true,
// Resource types, in isolation, are always valid to import
// or export since they're either attached to an import or
@ -733,7 +740,7 @@ impl ComponentState {
/// do not share resource types despite sharing the same original instance
/// type.
fn prepare_instance_import(&mut self, id: &mut TypeId, types: &mut TypeAlloc) {
let ty = types[*id].as_component_instance_type().unwrap();
let ty = types[*id].unwrap_component_instance();
// No special treatment for imports of instances which themselves have
// no defined resources
@ -767,7 +774,7 @@ impl ComponentState {
// path for where they're imported is updated as well with
// `self.next_import_index` as the import-to-be soon.
let mut mapping = Remapping::default();
let ty = types[*id].as_component_instance_type().unwrap();
let ty = types[*id].unwrap_component_instance();
for (old, new) in ty.defined_resources.iter().zip(&resources) {
let prev = mapping.resources.insert(*old, *new);
assert!(prev.is_none());
@ -804,7 +811,7 @@ impl ComponentState {
// encapsulates. This means that the instance type
// recorded for this export will itself have no
// defined resources.
let ty = types[*id].as_component_instance_type().unwrap();
let ty = types[*id].unwrap_component_instance();
// Check to see if `defined_resources` is non-empty, and if so then
// "freshen" all the resources and inherit them to our own defined
@ -837,9 +844,8 @@ impl ComponentState {
types.remap_component_entity(ty, &mut mapping);
}
for (id, path) in mem::take(&mut new_ty.explicit_resources) {
new_ty
.explicit_resources
.insert(mapping.resources[&id], path);
let id = mapping.resources.get(&id).copied().unwrap_or(id);
new_ty.explicit_resources.insert(id, path);
}
*id = types.push_ty(Type::ComponentInstance(Box::new(new_ty)));
}
@ -850,7 +856,7 @@ impl ComponentState {
// The path to each explicit resources gets one element prepended which
// is `self.next_export_index`, the index of the export about to be
// generated.
let ty = types[*id].as_component_instance_type().unwrap();
let ty = types[*id].unwrap_component_instance();
for (id, path) in ty.explicit_resources.iter() {
let mut new_path = vec![self.exports.len()];
new_path.extend(path);
@ -897,9 +903,7 @@ impl ComponentState {
offset: usize,
) -> Result<()> {
let ty = self.function_type_at(type_index, types, offset)?;
let core_ty = types[self.core_function_at(core_func_index, offset)?]
.as_func_type()
.unwrap();
let core_ty = types[self.core_function_at(core_func_index, offset)?].unwrap_func();
// Lifting a function is for an export, so match the expected canonical ABI
// export signature
@ -938,9 +942,7 @@ impl ComponentState {
types: &mut TypeAlloc,
offset: usize,
) -> Result<()> {
let ty = types[self.function_at(func_index, offset)?]
.as_component_func_type()
.unwrap();
let ty = types[self.function_at(func_index, offset)?].unwrap_component_func();
// Lowering a function is for an import, so use a function type that matches
// the expected canonical ABI import signature.
@ -948,7 +950,11 @@ impl ComponentState {
self.check_options(None, &info, &options, types, offset)?;
let lowered_ty = Type::Func(info.into_func_type());
let lowered_ty = Type::Sub(SubType {
is_final: false,
supertype_idx: None,
structural_type: StructuralType::Func(info.into_func_type()),
});
let id = types.push_ty(lowered_ty);
self.core_funcs.push(id);
@ -963,29 +969,27 @@ impl ComponentState {
offset: usize,
) -> Result<()> {
let rep = self.check_local_resource(resource, types, offset)?;
let core_ty = Type::Func(FuncType::new([rep], [ValType::I32]));
let core_ty = Type::Sub(SubType {
is_final: false,
supertype_idx: None,
structural_type: StructuralType::Func(FuncType::new([rep], [ValType::I32])),
});
self.core_funcs.push(types.push_ty(core_ty));
Ok(())
}
pub fn resource_drop(
&mut self,
ty: crate::ComponentValType,
resource: u32,
types: &mut TypeAlloc,
offset: usize,
) -> Result<()> {
let idx = match ty {
crate::ComponentValType::Primitive(_) => {
bail!(offset, "type-to-drop must be an own or borrow type")
}
crate::ComponentValType::Type(idx) => idx,
};
let ty = self.defined_type_at(idx, types, offset)?;
match types[ty].as_defined_type().unwrap() {
ComponentDefinedType::Own(_) | ComponentDefinedType::Borrow(_) => {}
_ => bail!(offset, "type-to-drop must be an own or borrow type"),
}
let core_ty = Type::Func(FuncType::new([ValType::I32], []));
self.resource_at(resource, types, offset)?;
let core_ty = Type::Sub(SubType {
is_final: false,
supertype_idx: None,
structural_type: StructuralType::Func(FuncType::new([ValType::I32], [])),
});
self.core_funcs.push(types.push_ty(core_ty));
Ok(())
}
@ -997,14 +1001,18 @@ impl ComponentState {
offset: usize,
) -> Result<()> {
let rep = self.check_local_resource(resource, types, offset)?;
let core_ty = Type::Func(FuncType::new([ValType::I32], [rep]));
let core_ty = Type::Sub(SubType {
is_final: false,
supertype_idx: None,
structural_type: StructuralType::Func(FuncType::new([ValType::I32], [rep])),
});
self.core_funcs.push(types.push_ty(core_ty));
Ok(())
}
fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result<ValType> {
let id = self.resource_at(idx, types, offset)?;
let resource = types[id].as_resource().unwrap();
let resource = types[id].unwrap_resource();
match self.defined_resources.get(&resource).and_then(|rep| *rep) {
Some(ty) => Ok(ty),
None => bail!(offset, "type {idx} is not a local resource"),
@ -1108,9 +1116,7 @@ impl ComponentState {
));
}
let ft = types[self.function_at(func_index, offset)?]
.as_component_func_type()
.unwrap();
let ft = types[self.function_at(func_index, offset)?].unwrap_component_func();
if ft.params.len() != args.len() {
bail!(
@ -1204,9 +1210,7 @@ impl ComponentState {
CanonicalOption::Realloc(idx) => {
realloc = match realloc {
None => {
let ty = types[self.core_function_at(*idx, offset)?]
.as_func_type()
.unwrap();
let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
if ty.params()
!= [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
|| ty.results() != [ValType::I32]
@ -1236,9 +1240,7 @@ impl ComponentState {
)
})?;
let ty = types[self.core_function_at(*idx, offset)?]
.as_func_type()
.unwrap();
let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
if ty.params() != core_ty.results() || !ty.results().is_empty() {
return Err(BinaryReaderError::new(
@ -1285,16 +1287,18 @@ impl ComponentState {
Ok(match ty {
ComponentTypeRef::Module(index) => {
let id = self.type_at(*index, true, offset)?;
types[id].as_module_type().ok_or_else(|| {
format_err!(offset, "core type index {index} is not a module type")
})?;
match &types[id] {
Type::Module(_) => {}
_ => bail!(offset, "core type index {index} is not a module type"),
}
ComponentEntityType::Module(id)
}
ComponentTypeRef::Func(index) => {
let id = self.type_at(*index, false, offset)?;
types[id].as_component_func_type().ok_or_else(|| {
format_err!(offset, "type index {index} is not a function type")
})?;
match &types[id] {
Type::ComponentFunc(_) => {}
_ => bail!(offset, "type index {index} is not a function type"),
}
ComponentEntityType::Func(id)
}
ComponentTypeRef::Value(ty) => {
@ -1324,16 +1328,18 @@ impl ComponentState {
}
ComponentTypeRef::Instance(index) => {
let id = self.type_at(*index, false, offset)?;
types[id].as_component_instance_type().ok_or_else(|| {
format_err!(offset, "type index {index} is not an instance type")
})?;
match &types[id] {
Type::ComponentInstance(_) => {}
_ => bail!(offset, "type index {index} is not an instance type"),
}
ComponentEntityType::Instance(id)
}
ComponentTypeRef::Component(index) => {
let id = self.type_at(*index, false, offset)?;
types[id].as_component_type().ok_or_else(|| {
format_err!(offset, "type index {index} is not a component type")
})?;
match &types[id] {
Type::Component(_) => {}
_ => bail!(offset, "type index {index} is not a component type"),
}
ComponentEntityType::Component(id)
}
})
@ -1632,16 +1638,15 @@ impl ComponentState {
for module_arg in module_args {
match module_arg.kind {
InstantiationArgKind::Instance => {
let instance_type = types[self.core_instance_at(module_arg.index, offset)?]
.as_instance_type()
.unwrap();
let instance_type =
types[self.core_instance_at(module_arg.index, offset)?].unwrap_instance();
insert_arg(module_arg.name, instance_type, &mut args, offset)?;
}
}
}
// Validate the arguments
let module_type = types[module_type_id].as_module_type().unwrap();
let module_type = types[module_type_id].unwrap_module();
let cx = SubtypeCx::new(types, types);
for ((module, name), expected) in module_type.imports.iter() {
let instance = args.get(module.as_str()).ok_or_else(|| {
@ -1811,7 +1816,7 @@ impl ComponentState {
// comments are hopefully enough when augmented with communication with
// the authors.
let component_type = types[component_type_id].as_component_type().unwrap();
let component_type = types[component_type_id].unwrap_component();
let mut exports = component_type.exports.clone();
let type_size = component_type
.exports
@ -1856,7 +1861,7 @@ impl ComponentState {
let fresh_defined_resources = (0..component_type.defined_resources.len())
.map(|_| types.alloc_resource_id())
.collect::<IndexSet<_>>();
let component_type = types[component_type_id].as_component_type().unwrap();
let component_type = types[component_type_id].unwrap_component();
for ((old, _path), new) in component_type
.defined_resources
.iter()
@ -1879,7 +1884,7 @@ impl ComponentState {
for entity in exports.values_mut() {
types.remap_component_entity(entity, &mut mapping);
}
let component_type = types[component_type_id].as_component_type().unwrap();
let component_type = types[component_type_id].unwrap_component();
let explicit_resources = component_type
.explicit_resources
.iter()
@ -1983,8 +1988,7 @@ impl ComponentState {
// instance, just with one more element in their path.
explicit_resources.extend(
types[ty]
.as_component_instance_type()
.unwrap()
.unwrap_component_instance()
.explicit_resources
.iter()
.map(|(id, path)| {
@ -2229,8 +2233,7 @@ impl ComponentState {
offset: usize,
) -> Result<()> {
let mut ty = match types[self.instance_at(instance_index, offset)?]
.as_component_instance_type()
.unwrap()
.unwrap_component_instance()
.exports
.get(name)
{
@ -2647,9 +2650,10 @@ impl ComponentState {
types: &'a TypeList,
offset: usize,
) -> Result<&'a ComponentFuncType> {
types[self.type_at(idx, false, offset)?]
.as_component_func_type()
.ok_or_else(|| format_err!(offset, "type index {idx} is not a function type"))
match &types[self.type_at(idx, false, offset)?] {
Type::ComponentFunc(f) => Ok(f),
_ => bail!(offset, "type index {idx} is not a function type"),
}
}
fn function_at(&self, idx: u32, offset: usize) -> Result<TypeId> {
@ -2733,8 +2737,7 @@ impl ComponentState {
offset: usize,
) -> Result<&'a EntityType> {
match types[self.core_instance_at(instance_index, offset)?]
.as_instance_type()
.unwrap()
.unwrap_instance()
.internal_exports(types)
.get(name)
{
@ -2944,7 +2947,7 @@ impl KebabNameContext {
ComponentEntityType::Func(id) => *id,
_ => bail!(offset, "item is not a func"),
};
Ok(types[id].as_component_func_type().unwrap())
Ok(types[id].unwrap_component_func())
};
match name.kind() {
// Normal kebab name or id? No validation necessary.

View File

@ -6,11 +6,12 @@ use super::{
types::{EntityType, Type, TypeAlloc, TypeId, TypeList},
};
use crate::limits::*;
use crate::readers::Inherits;
use crate::validator::core::arc::MaybeOwned;
use crate::{
BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FuncType,
Global, GlobalType, HeapType, MemoryType, RefType, Result, StorageType, Table, TableInit,
TableType, TagType, TypeRef, ValType, VisitOperator, WasmFeatures, WasmFuncType,
Global, GlobalType, HeapType, MemoryType, RefType, Result, StorageType, StructuralType,
SubType, Table, TableInit, TableType, TagType, TypeRef, ValType, VisitOperator, WasmFeatures,
WasmModuleResources,
};
use indexmap::IndexMap;
@ -198,24 +199,30 @@ impl ModuleState {
) -> Result<()> {
// the `funcref` value type is allowed all the way back to the MVP, so
// don't check it here
if e.ty != RefType::FUNCREF {
self.module
.check_value_type(ValType::Ref(e.ty), features, offset)?;
}
let element_ty = match &e.items {
crate::ElementItems::Functions(_) => RefType::FUNC,
crate::ElementItems::Expressions(ty, _) => {
self.module
.check_value_type(ValType::Ref(*ty), features, offset)?;
*ty
}
};
match e.kind {
ElementKind::Active {
table_index,
offset_expr,
} => {
let table = self.module.table_at(table_index.unwrap_or(0), offset)?;
if !self
.module
.matches(ValType::Ref(e.ty), ValType::Ref(table.element_type), types)
{
if !self.module.matches(
ValType::Ref(element_ty),
ValType::Ref(table.element_type),
types,
) {
return Err(BinaryReaderError::new(
format!(
"type mismatch: invalid element type `{}` for table type `{}`",
ty_to_str(e.ty.into()),
ty_to_str(element_ty.into()),
ty_to_str(table.element_type.into()),
),
offset,
@ -247,12 +254,6 @@ impl ModuleState {
match e.items {
crate::ElementItems::Functions(reader) => {
let count = reader.count();
if !e.ty.is_nullable() && count <= 0 {
return Err(BinaryReaderError::new(
"a non-nullable element must come with an initialization expression",
offset,
));
}
validate_count(count)?;
for f in reader.into_iter_with_offsets() {
let (offset, f) = f?;
@ -260,14 +261,14 @@ impl ModuleState {
self.module.assert_mut().function_references.insert(f);
}
}
crate::ElementItems::Expressions(reader) => {
crate::ElementItems::Expressions(ty, reader) => {
validate_count(reader.count())?;
for expr in reader {
self.check_const_expr(&expr?, ValType::Ref(e.ty), features, types)?;
self.check_const_expr(&expr?, ValType::Ref(ty), features, types)?;
}
}
}
self.module.assert_mut().element_types.push(e.ty);
self.module.assert_mut().element_types.push(element_ty);
Ok(())
}
@ -494,14 +495,79 @@ pub(crate) struct Module {
impl Module {
pub fn add_type(
&mut self,
ty: crate::Type,
ty: SubType,
features: &WasmFeatures,
types: &mut TypeAlloc,
offset: usize,
check_limit: bool,
) -> Result<()> {
let ty = match ty {
crate::Type::Func(t) => {
if check_limit {
check_max(self.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
}
let ty = self.check_subtype(ty, features, types, offset)?;
let id = types.push_ty(ty);
self.types.push(id);
Ok(())
}
fn check_subtype(
&mut self,
ty: SubType,
features: &WasmFeatures,
types: &mut TypeAlloc,
offset: usize,
) -> Result<Type> {
if !features.gc && (ty.is_final || ty.supertype_idx.is_some()) {
return Err(BinaryReaderError::new(
"gc proposal must be enabled to use subtypes",
offset,
));
}
self.check_structural_type(&ty.structural_type, features, offset)?;
if let Some(type_index) = ty.supertype_idx {
// Check the supertype exists, is not final, and the subtype matches it.
match self.type_at(types, type_index, offset)? {
Type::Sub(st) => {
if !&ty.inherits(st, &|idx| self.subtype_at(types, idx, offset).unwrap()) {
return Err(BinaryReaderError::new(
"subtype must match supertype",
offset,
));
}
}
_ => {
return Err(BinaryReaderError::new(
"supertype must be a non-final subtype itself",
offset,
));
}
};
}
Ok(Type::Sub(ty))
}
fn subtype_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a SubType> {
match self.type_at(types, idx, offset)? {
Type::Sub(ty) => Ok(ty),
_ => bail!(
offset,
"subtype with index {idx} not found, offset: {offset}"
),
}
}
fn check_structural_type(
&mut self,
ty: &StructuralType,
features: &WasmFeatures,
offset: usize,
) -> Result<()> {
match ty {
StructuralType::Func(t) => {
for ty in t.params().iter().chain(t.results()) {
self.check_value_type(*ty, features, offset)?;
}
@ -511,31 +577,33 @@ impl Module {
offset,
));
}
Type::Func(t)
}
crate::Type::Array(t) => {
StructuralType::Array(t) => {
if !features.gc {
return Err(BinaryReaderError::new(
"array indexed types not supported without the gc feature",
offset,
));
}
match t.element_type {
crate::StorageType::I8 | crate::StorageType::I16 => {}
crate::StorageType::Val(value_type) => {
match t.0.element_type {
StorageType::I8 | StorageType::I16 => {}
StorageType::Val(value_type) => {
self.check_value_type(value_type, features, offset)?;
}
};
Type::Array(t)
}
};
if check_limit {
check_max(self.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
StructuralType::Struct(t) => {
if !features.gc {
return Err(BinaryReaderError::new(
"struct indexed types not supported without the gc feature",
offset,
));
}
for ty in t.fields.iter() {
self.check_storage_type(ty.element_type, features, offset)?;
}
}
}
let id = types.push_ty(ty);
self.types.push(id);
Ok(())
}
@ -671,9 +739,13 @@ impl Module {
types: &'a TypeList,
offset: usize,
) -> Result<&'a FuncType> {
types[self.type_id_at(type_index, offset)?]
.as_func_type()
.ok_or_else(|| format_err!(offset, "type index {type_index} is not a function type"))
match &types[self.type_id_at(type_index, offset)?] {
Type::Sub(SubType {
structural_type: StructuralType::Func(f),
..
}) => Ok(f),
_ => bail!(offset, "type index {type_index} is not a function type"),
}
}
pub fn check_type_ref(
@ -798,6 +870,21 @@ impl Module {
.collect::<Result<_>>()
}
fn check_storage_type(
&self,
ty: StorageType,
features: &WasmFeatures,
offset: usize,
) -> Result<()> {
match ty {
StorageType::I8 | StorageType::I16 => {}
StorageType::Val(value_type) => {
self.check_value_type(value_type, features, offset)?;
}
}
Ok(())
}
fn check_value_type(&self, ty: ValType, features: &WasmFeatures, offset: usize) -> Result<()> {
match features.check_value_type(ty) {
Ok(()) => Ok(()),
@ -835,102 +922,11 @@ impl Module {
Ok(())
}
fn eq_valtypes(&self, ty1: ValType, ty2: ValType, types: &TypeList) -> bool {
match (ty1, ty2) {
(ValType::Ref(rt1), ValType::Ref(rt2)) => {
rt1.is_nullable() == rt2.is_nullable()
&& match (rt1.heap_type(), rt2.heap_type()) {
(HeapType::Indexed(n1), HeapType::Indexed(n2)) => {
self.eq_indexed_types(n1, n2, types)
}
(h1, h2) => h1 == h2,
}
}
_ => ty1 == ty2,
}
}
fn eq_indexed_types(&self, n1: u32, n2: u32, types: &TypeList) -> bool {
let n1 = self.type_at(types, n1.into(), 0).unwrap();
let n2 = self.type_at(types, n2.into(), 0).unwrap();
match (n1, n2) {
(Type::Func(f1), Type::Func(f2)) => self.eq_fns(f1, f2, types),
(Type::Array(a1), Type::Array(a2)) => {
a1.mutable == a2.mutable
&& match (a1.element_type, a2.element_type) {
(StorageType::Val(vt1), StorageType::Val(vt2)) => {
self.eq_valtypes(vt1, vt2, types)
}
(st1, st2) => st1 == st2,
}
}
_ => false,
}
}
fn eq_fns(&self, f1: &impl WasmFuncType, f2: &impl WasmFuncType, types: &TypeList) -> bool {
f1.len_inputs() == f2.len_inputs()
&& f2.len_outputs() == f2.len_outputs()
&& f1
.inputs()
.zip(f2.inputs())
.all(|(t1, t2)| self.eq_valtypes(t1, t2, types))
&& f1
.outputs()
.zip(f2.outputs())
.all(|(t1, t2)| self.eq_valtypes(t1, t2, types))
}
/// Check that a value of type ty1 is assignable to a variable / table element of type ty2.
/// E.g. a non-nullable reference can be assigned to a nullable reference, but not vice versa.
/// Or an indexed func ref is assignable to a generic func ref, but not vice versa.
pub(crate) fn matches(&self, ty1: ValType, ty2: ValType, types: &TypeList) -> bool {
fn matches_null(null1: bool, null2: bool) -> bool {
(null1 == null2) || null2
}
let matches_heap = |ty1: HeapType, ty2: HeapType, types: &TypeList| -> bool {
match (ty1, ty2) {
(HeapType::Indexed(n1), HeapType::Indexed(n2)) => {
// Check whether the defined types are (structurally) equivalent.
let n1 = self.type_at(types, n1.into(), 0);
let n2 = self.type_at(types, n2.into(), 0);
match (n1, n2) {
(Ok(Type::Func(n1)), Ok(Type::Func(n2))) => self.eq_fns(n1, n2, types),
(Ok(Type::Array(n1)), Ok(Type::Array(n2))) => {
(n1.mutable == n2.mutable || n2.mutable)
&& match (n1.element_type, n2.element_type) {
(StorageType::Val(vt1), StorageType::Val(vt2)) => {
self.matches(vt1, vt2, types)
}
(st1, st2) => st1 == st2,
}
}
_ => false,
}
}
(HeapType::Indexed(n1), HeapType::Func) => {
self.func_type_at(n1.into(), types, 0).is_ok()
}
(HeapType::Indexed(n1), HeapType::Array) => {
match self.type_at(types, n1.into(), 0) {
Ok(Type::Array(_)) => true,
_ => false,
}
}
(_, _) => ty1 == ty2,
}
};
let matches_ref = |ty1: RefType, ty2: RefType, types: &TypeList| -> bool {
matches_heap(ty1.heap_type(), ty2.heap_type(), types)
&& matches_null(ty1.is_nullable(), ty2.is_nullable())
};
match (ty1, ty2) {
(ValType::Ref(rt1), ValType::Ref(rt2)) => matches_ref(rt1, rt2, types),
(_, _) => ty1 == ty2,
}
ty1.inherits(&ty2, &|idx| self.subtype_at(types, idx, 0).unwrap())
}
fn check_tag_type(
@ -1122,11 +1118,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {
}
fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
Some(
self.types[*self.module.tags.get(at as usize)?]
.as_func_type()
.unwrap(),
)
Some(self.types[*self.module.tags.get(at as usize)?].unwrap_func())
}
fn global_at(&self, at: u32) -> Option<GlobalType> {
@ -1134,11 +1126,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {
}
fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
Some(
self.types[*self.module.types.get(at as usize)?]
.as_func_type()
.unwrap(),
)
Some(self.types[*self.module.types.get(at as usize)?].unwrap_func())
}
fn type_index_of_function(&self, at: u32) -> Option<u32> {
@ -1190,11 +1178,7 @@ impl WasmModuleResources for ValidatorResources {
}
fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
Some(
self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?]
.as_func_type()
.unwrap(),
)
Some(self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?].unwrap_func())
}
fn global_at(&self, at: u32) -> Option<GlobalType> {
@ -1202,11 +1186,7 @@ impl WasmModuleResources for ValidatorResources {
}
fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
Some(
self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?]
.as_func_type()
.unwrap(),
)
Some(self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?].unwrap_func())
}
fn type_index_of_function(&self, at: u32) -> Option<u32> {

View File

@ -3252,7 +3252,10 @@ where
segment
),
};
if segment_ty != table.element_type {
if !self
.resources
.matches(ValType::Ref(segment_ty), ValType::Ref(table.element_type))
{
bail!(self.offset, "type mismatch");
}
self.pop_operand(Some(ValType::I32))?;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
use wasm_encoder::*;
#[test]
fn big_type_indices() {
const N: u32 = 100_000;
@ -13,7 +14,7 @@ fn big_type_indices() {
module.section(&funcs);
let mut elems = ElementSection::new();
elems.declared(RefType::FUNCREF, Elements::Functions(&[0]));
elems.declared(Elements::Functions(&[0]));
module.section(&elems);
let mut code = CodeSection::new();

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "wast"
version = "60.0.0"
version = "62.0.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
description = """
Customizable Rust parsers for the WebAssembly Text formats WAT and WAST
@ -37,7 +37,7 @@ version = "2.4.1"
version = "0.1.9"
[dependencies.wasm-encoder]
version = "0.29.0"
version = "0.31.0"
[dev-dependencies.anyhow]
version = "1.0.58"

View File

@ -79,7 +79,7 @@ impl<'a> Parse<'a> for Alias<'a> {
let mut l = parser.lookahead1();
let (target, id, name) = if l.peek::<kw::outer>() {
let (target, id, name) = if l.peek::<kw::outer>()? {
parser.parse::<kw::outer>()?;
let outer = parser.parse()?;
let index = parser.parse()?;
@ -87,7 +87,7 @@ impl<'a> Parse<'a> for Alias<'a> {
parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?;
(AliasTarget::Outer { outer, index, kind }, id, name)
} else if l.peek::<kw::export>() {
} else if l.peek::<kw::export>()? {
parser.parse::<kw::export>()?;
let instance = parser.parse()?;
let export_name = parser.parse()?;
@ -103,7 +103,7 @@ impl<'a> Parse<'a> for Alias<'a> {
id,
name,
)
} else if l.peek::<kw::core>() {
} else if l.peek::<kw::core>()? {
parser.parse::<kw::core>()?;
parser.parse::<kw::export>()?;
let instance = parser.parse()?;
@ -155,28 +155,28 @@ pub enum ComponentExportAliasKind {
impl<'a> Parse<'a> for ComponentExportAliasKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::core>() {
if l.peek::<kw::core>()? {
parser.parse::<kw::core>()?;
let mut l = parser.lookahead1();
if l.peek::<kw::module>() {
if l.peek::<kw::module>()? {
parser.parse::<kw::module>()?;
Ok(Self::CoreModule)
} else {
Err(l.error())
}
} else if l.peek::<kw::func>() {
} else if l.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
Ok(Self::Func)
} else if l.peek::<kw::value>() {
} else if l.peek::<kw::value>()? {
parser.parse::<kw::value>()?;
Ok(Self::Value)
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
parser.parse::<kw::r#type>()?;
Ok(Self::Type)
} else if l.peek::<kw::component>() {
} else if l.peek::<kw::component>()? {
parser.parse::<kw::component>()?;
Ok(Self::Component)
} else if l.peek::<kw::instance>() {
} else if l.peek::<kw::instance>()? {
parser.parse::<kw::instance>()?;
Ok(Self::Instance)
} else {
@ -201,22 +201,22 @@ pub enum ComponentOuterAliasKind {
impl<'a> Parse<'a> for ComponentOuterAliasKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::core>() {
if l.peek::<kw::core>()? {
parser.parse::<kw::core>()?;
let mut l = parser.lookahead1();
if l.peek::<kw::module>() {
if l.peek::<kw::module>()? {
parser.parse::<kw::module>()?;
Ok(Self::CoreModule)
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
parser.parse::<kw::r#type>()?;
Ok(Self::CoreType)
} else {
Err(l.error())
}
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
parser.parse::<kw::r#type>()?;
Ok(Self::Type)
} else if l.peek::<kw::component>() {
} else if l.peek::<kw::component>()? {
parser.parse::<kw::component>()?;
Ok(Self::Component)
} else {

View File

@ -1,6 +1,6 @@
use crate::component::*;
use crate::core;
use crate::token::{Id, Index, NameAnnotation};
use crate::token::{Id, Index, NameAnnotation, Span};
use wasm_encoder::{
CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder,
ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentNameSection,
@ -43,6 +43,7 @@ fn encode_fields(
ComponentField::Import(i) => e.encode_import(i),
ComponentField::Export(ex) => e.encode_export(ex),
ComponentField::Custom(c) => e.encode_custom(c),
ComponentField::Producers(c) => e.encode_producers(c),
}
}
@ -179,6 +180,18 @@ impl<'a> Encoder<'a> {
self.component.section(custom);
}
fn encode_producers(&mut self, custom: &core::Producers) {
use crate::encode::Encode;
let mut data = Vec::new();
custom.encode(&mut data);
self.encode_custom(&Custom {
name: "producers",
span: Span::from_offset(0),
data: vec![&data],
})
}
fn encode_core_module(&mut self, module: &CoreModule<'a>) {
// Flush any in-progress section before encoding the module
self.flush(None);
@ -327,7 +340,7 @@ impl<'a> Encoder<'a> {
}
CanonicalFuncKind::ResourceDrop(info) => {
self.core_func_names.push(name);
self.funcs.resource_drop((&info.ty).into());
self.funcs.resource_drop(info.ty.into());
}
CanonicalFuncKind::ResourceRep(info) => {
self.core_func_names.push(name);

View File

@ -1,5 +1,6 @@
use crate::annotation;
use crate::component::*;
use crate::core::Producers;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::Index;
@ -108,12 +109,14 @@ impl<'a> Component<'a> {
impl<'a> Parse<'a> for Component<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let _r = parser.register_annotation("custom");
let _r = parser.register_annotation("producers");
let _r = parser.register_annotation("name");
let span = parser.parse::<kw::component>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let kind = if parser.peek::<kw::binary>() {
let kind = if parser.peek::<kw::binary>()? {
parser.parse::<kw::binary>()?;
let mut data = Vec::new();
while !parser.is_empty() {
@ -150,6 +153,7 @@ pub enum ComponentField<'a> {
Import(ComponentImport<'a>),
Export(ComponentExport<'a>),
Custom(Custom<'a>),
Producers(Producers<'a>),
}
impl<'a> ComponentField<'a> {
@ -164,47 +168,50 @@ impl<'a> ComponentField<'a> {
impl<'a> Parse<'a> for ComponentField<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::core>() {
if parser.peek2::<kw::module>() {
if parser.peek::<kw::core>()? {
if parser.peek2::<kw::module>()? {
return Ok(Self::CoreModule(parser.parse()?));
}
if parser.peek2::<kw::instance>() {
if parser.peek2::<kw::instance>()? {
return Ok(Self::CoreInstance(parser.parse()?));
}
if parser.peek2::<kw::r#type>() {
if parser.peek2::<kw::r#type>()? {
return Ok(Self::CoreType(parser.parse()?));
}
if parser.peek2::<kw::func>() {
if parser.peek2::<kw::func>()? {
return Ok(Self::CoreFunc(parser.parse()?));
}
} else {
if parser.peek::<kw::component>() {
if parser.peek::<kw::component>()? {
return Ok(Self::Component(parser.parse()?));
}
if parser.peek::<kw::instance>() {
if parser.peek::<kw::instance>()? {
return Ok(Self::Instance(parser.parse()?));
}
if parser.peek::<kw::alias>() {
if parser.peek::<kw::alias>()? {
return Ok(Self::Alias(parser.parse()?));
}
if parser.peek::<kw::r#type>() {
if parser.peek::<kw::r#type>()? {
return Ok(Self::Type(Type::parse_maybe_with_inline_exports(parser)?));
}
if parser.peek::<kw::import>() {
if parser.peek::<kw::import>()? {
return Ok(Self::Import(parser.parse()?));
}
if parser.peek::<kw::func>() {
if parser.peek::<kw::func>()? {
return Ok(Self::Func(parser.parse()?));
}
if parser.peek::<kw::export>() {
if parser.peek::<kw::export>()? {
return Ok(Self::Export(parser.parse()?));
}
if parser.peek::<kw::start>() {
if parser.peek::<kw::start>()? {
return Ok(Self::Start(parser.parse()?));
}
if parser.peek::<annotation::custom>() {
if parser.peek::<annotation::custom>()? {
return Ok(Self::Custom(parser.parse()?));
}
if parser.peek::<annotation::producers>()? {
return Ok(Self::Producers(parser.parse()?));
}
}
Err(parser.error("expected valid component field"))
}
@ -226,12 +233,12 @@ impl<'a> Parse<'a> for Start<'a> {
parser.parse::<kw::start>()?;
let func = parser.parse()?;
let mut args = Vec::new();
while !parser.is_empty() && !parser.peek2::<kw::result>() {
while !parser.is_empty() && !parser.peek2::<kw::result>()? {
args.push(parser.parens(|parser| parser.parse())?);
}
let mut results = Vec::new();
while !parser.is_empty() && parser.peek2::<kw::result>() {
while !parser.is_empty() && parser.peek2::<kw::result>()? {
results.push(parser.parens(|parser| {
parser.parse::<kw::result>()?;
parser.parens(|parser| {

View File

@ -127,7 +127,10 @@ impl<'a> Expander<'a> {
}
None
}
ComponentField::Start(_) | ComponentField::Alias(_) | ComponentField::Custom(_) => None,
ComponentField::Start(_)
| ComponentField::Alias(_)
| ComponentField::Custom(_)
| ComponentField::Producers(_) => None,
};
if let Some(expanded) = expanded {
@ -259,11 +262,8 @@ impl<'a> Expander<'a> {
}
CanonicalFuncKind::Lower(_)
| CanonicalFuncKind::ResourceNew(_)
| CanonicalFuncKind::ResourceRep(_) => {}
CanonicalFuncKind::ResourceDrop(info) => {
self.expand_component_val_ty(&mut info.ty);
}
| CanonicalFuncKind::ResourceRep(_)
| CanonicalFuncKind::ResourceDrop(_) => {}
}
}
@ -292,7 +292,6 @@ impl<'a> Expander<'a> {
kind: CanonicalFuncKind::ResourceNew(mem::take(info)),
})),
CoreFuncKind::ResourceDrop(info) => {
self.expand_component_val_ty(&mut info.ty);
Some(ComponentField::CanonicalFunc(CanonicalFunc {
span: func.span,
id: func.id,

View File

@ -119,19 +119,19 @@ impl<'a> Parse<'a> for ComponentExportKind<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::core>() {
if l.peek::<kw::core>()? {
// Remove core prefix
parser.parse::<kw::core>()?;
Ok(Self::CoreModule(parser.parse()?))
} else if l.peek::<kw::func>() {
} else if l.peek::<kw::func>()? {
Ok(Self::Func(parser.parse()?))
} else if l.peek::<kw::value>() {
} else if l.peek::<kw::value>()? {
Ok(Self::Value(parser.parse()?))
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
Ok(Self::Type(parser.parse()?))
} else if l.peek::<kw::component>() {
} else if l.peek::<kw::component>()? {
Ok(Self::Component(parser.parse()?))
} else if l.peek::<kw::instance>() {
} else if l.peek::<kw::instance>()? {
Ok(Self::Instance(parser.parse()?))
} else {
Err(l.error())
@ -141,23 +141,23 @@ impl<'a> Parse<'a> for ComponentExportKind<'a> {
}
impl Peek for ComponentExportKind<'_> {
fn peek(cursor: Cursor) -> bool {
let cursor = match cursor.lparen() {
fn peek(cursor: Cursor) -> Result<bool> {
let cursor = match cursor.lparen()? {
Some(c) => c,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
Some(("core", c)) => match c.keyword() {
let cursor = match cursor.keyword()? {
Some(("core", c)) => match c.keyword()? {
Some(("module", c)) => c,
_ => return false,
_ => return Ok(false),
},
Some(("func", c))
| Some(("value", c))
| Some(("type", c))
| Some(("component", c))
| Some(("instance", c)) => c,
_ => return false,
_ => return Ok(false),
};
Index::peek(cursor)
@ -179,7 +179,7 @@ pub struct InlineExport<'a> {
impl<'a> Parse<'a> for InlineExport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut names = Vec::new();
while parser.peek::<Self>() {
while parser.peek::<Self>()? {
names.push(parser.parens(|p| {
p.parse::<kw::export>()?;
p.parse()
@ -190,39 +190,39 @@ impl<'a> Parse<'a> for InlineExport<'a> {
}
impl Peek for InlineExport<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("export", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
// (export "foo")
if let Some((_, cursor)) = cursor.string() {
return cursor.rparen().is_some();
if let Some((_, cursor)) = cursor.string()? {
return Ok(cursor.rparen()?.is_some());
}
// (export (interface "foo"))
let cursor = match cursor.lparen() {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("interface", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.string() {
let cursor = match cursor.string()? {
Some((_, cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.rparen() {
let cursor = match cursor.rparen()? {
Some(cursor) => cursor,
_ => return false,
_ => return Ok(false),
};
cursor.rparen().is_some()
Ok(cursor.rparen()?.is_some())
}
fn display() -> &'static str {

View File

@ -57,21 +57,21 @@ impl<'a> Parse<'a> for CoreFuncKind<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::canon>() {
if l.peek::<kw::canon>()? {
parser.parse::<kw::canon>()?;
} else if l.peek::<kw::alias>() {
} else if l.peek::<kw::alias>()? {
return Ok(Self::Alias(parser.parse()?));
} else {
return Err(l.error());
}
let mut l = parser.lookahead1();
if l.peek::<kw::lower>() {
if l.peek::<kw::lower>()? {
Ok(CoreFuncKind::Lower(parser.parse()?))
} else if l.peek::<kw::resource_new>() {
} else if l.peek::<kw::resource_new>()? {
Ok(CoreFuncKind::ResourceNew(parser.parse()?))
} else if l.peek::<kw::resource_drop>() {
} else if l.peek::<kw::resource_drop>()? {
Ok(CoreFuncKind::ResourceDrop(parser.parse()?))
} else if l.peek::<kw::resource_rep>() {
} else if l.peek::<kw::resource_rep>()? {
Ok(CoreFuncKind::ResourceRep(parser.parse()?))
} else {
Err(l.error())
@ -153,7 +153,7 @@ impl<'a> Parse<'a> for FuncKind<'a> {
import,
ty: parser.parse()?,
})
} else if parser.peek::<LParen>() && parser.peek2::<kw::alias>() {
} else if parser.peek::<LParen>()? && parser.peek2::<kw::alias>()? {
parser.parens(|parser| Ok(Self::Alias(parser.parse()?)))
} else {
Ok(Self::Lift {
@ -187,7 +187,7 @@ impl<'a> Parse<'a> for CanonicalFunc<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::canon>()?.0;
if parser.peek::<kw::lift>() {
if parser.peek::<kw::lift>()? {
let info = parser.parse()?;
let (id, name, ty) = parser.parens(|parser| {
parser.parse::<kw::func>()?;
@ -203,13 +203,13 @@ impl<'a> Parse<'a> for CanonicalFunc<'a> {
name,
kind: CanonicalFuncKind::Lift { info, ty },
})
} else if parser.peek::<kw::lower>() {
} else if parser.peek::<kw::lower>()? {
Self::parse_core_func(span, parser, CanonicalFuncKind::Lower)
} else if parser.peek::<kw::resource_new>() {
} else if parser.peek::<kw::resource_new>()? {
Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceNew)
} else if parser.peek::<kw::resource_drop>() {
} else if parser.peek::<kw::resource_drop>()? {
Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceDrop)
} else if parser.peek::<kw::resource_rep>() {
} else if parser.peek::<kw::resource_rep>()? {
Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceRep)
} else {
Err(parser.error("expected `canon lift` or `canon lower`"))
@ -362,8 +362,8 @@ impl Default for CanonResourceNew<'_> {
/// Information relating to the `resource.drop` intrinsic.
#[derive(Debug)]
pub struct CanonResourceDrop<'a> {
/// The type that this intrinsic is dropping, either (borrow T) or (own T)
pub ty: ComponentValType<'a>,
/// The resource type that this intrinsic is dropping.
pub ty: Index<'a>,
}
impl<'a> Parse<'a> for CanonResourceDrop<'a> {
@ -379,7 +379,7 @@ impl<'a> Parse<'a> for CanonResourceDrop<'a> {
impl Default for CanonResourceDrop<'_> {
fn default() -> Self {
CanonResourceDrop {
ty: ComponentValType::Ref(Index::Num(0, Span::from_offset(0))),
ty: Index::Num(0, Span::from_offset(0)),
}
}
}
@ -429,30 +429,30 @@ pub enum CanonOpt<'a> {
impl<'a> Parse<'a> for CanonOpt<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::string_utf8>() {
if l.peek::<kw::string_utf8>()? {
parser.parse::<kw::string_utf8>()?;
Ok(Self::StringUtf8)
} else if l.peek::<kw::string_utf16>() {
} else if l.peek::<kw::string_utf16>()? {
parser.parse::<kw::string_utf16>()?;
Ok(Self::StringUtf16)
} else if l.peek::<kw::string_latin1_utf16>() {
} else if l.peek::<kw::string_latin1_utf16>()? {
parser.parse::<kw::string_latin1_utf16>()?;
Ok(Self::StringLatin1Utf16)
} else if l.peek::<LParen>() {
} else if l.peek::<LParen>()? {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::memory>() {
if l.peek::<kw::memory>()? {
let span = parser.parse::<kw::memory>()?.0;
Ok(CanonOpt::Memory(parse_trailing_item_ref(
kw::memory(span),
parser,
)?))
} else if l.peek::<kw::realloc>() {
} else if l.peek::<kw::realloc>()? {
parser.parse::<kw::realloc>()?;
Ok(CanonOpt::Realloc(
parser.parse::<IndexOrCoreRef<'_, _>>()?.0,
))
} else if l.peek::<kw::post_return>() {
} else if l.peek::<kw::post_return>()? {
parser.parse::<kw::post_return>()?;
Ok(CanonOpt::PostReturn(
parser.parse::<IndexOrCoreRef<'_, _>>()?.0,

View File

@ -34,7 +34,7 @@ pub enum ComponentExternName<'a> {
impl<'a> Parse<'a> for ComponentExternName<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() {
if parser.peek::<LParen>()? {
Ok(ComponentExternName::Interface(parser.parens(|p| {
p.parse::<kw::interface>()?;
p.parse()
@ -78,23 +78,23 @@ impl<'a> Parse<'a> for ItemSigNoName<'a> {
fn parse_item_sig<'a>(parser: Parser<'a>, name: bool) -> Result<ItemSig<'a>> {
let mut l = parser.lookahead1();
let (span, parse_kind): (_, fn(Parser<'a>) -> Result<ItemSigKind>) = if l.peek::<kw::core>() {
let (span, parse_kind): (_, fn(Parser<'a>) -> Result<ItemSigKind>) = if l.peek::<kw::core>()? {
let span = parser.parse::<kw::core>()?.0;
parser.parse::<kw::module>()?;
(span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?)))
} else if l.peek::<kw::func>() {
} else if l.peek::<kw::func>()? {
let span = parser.parse::<kw::func>()?.0;
(span, |parser| Ok(ItemSigKind::Func(parser.parse()?)))
} else if l.peek::<kw::component>() {
} else if l.peek::<kw::component>()? {
let span = parser.parse::<kw::component>()?.0;
(span, |parser| Ok(ItemSigKind::Component(parser.parse()?)))
} else if l.peek::<kw::instance>() {
} else if l.peek::<kw::instance>()? {
let span = parser.parse::<kw::instance>()?.0;
(span, |parser| Ok(ItemSigKind::Instance(parser.parse()?)))
} else if l.peek::<kw::value>() {
} else if l.peek::<kw::value>()? {
let span = parser.parse::<kw::value>()?.0;
(span, |parser| Ok(ItemSigKind::Value(parser.parse()?)))
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
let span = parser.parse::<kw::r#type>()?.0;
(span, |parser| {
Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?))
@ -139,10 +139,10 @@ pub enum TypeBounds<'a> {
impl<'a> Parse<'a> for TypeBounds<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::eq>() {
if l.peek::<kw::eq>()? {
parser.parse::<kw::eq>()?;
Ok(Self::Eq(parser.parse()?))
} else if l.peek::<kw::sub>() {
} else if l.peek::<kw::sub>()? {
parser.parse::<kw::sub>()?;
parser.parse::<kw::resource>()?;
Ok(Self::SubResource)
@ -172,39 +172,39 @@ impl<'a> Parse<'a> for InlineImport<'a> {
}
impl Peek for InlineImport<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("import", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
// (import "foo")
if let Some((_, cursor)) = cursor.string() {
return cursor.rparen().is_some();
if let Some((_, cursor)) = cursor.string()? {
return Ok(cursor.rparen()?.is_some());
}
// (import (interface "foo"))
let cursor = match cursor.lparen() {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("interface", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.string() {
let cursor = match cursor.string()? {
Some((_, cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.rparen() {
let cursor = match cursor.rparen()? {
Some(cursor) => cursor,
_ => return false,
_ => return Ok(false),
};
cursor.rparen().is_some()
Ok(cursor.rparen()?.is_some())
}
fn display() -> &'static str {

View File

@ -51,7 +51,7 @@ pub enum CoreInstanceKind<'a> {
impl<'a> Parse<'a> for CoreInstanceKind<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() && parser.peek2::<kw::instantiate>() {
if parser.peek::<LParen>()? && parser.peek2::<kw::instantiate>()? {
parser.parens(|parser| {
parser.parse::<kw::instantiate>()?;
Ok(Self::Instantiate {
@ -221,7 +221,7 @@ impl<'a> Parse<'a> for InstanceKind<'a> {
});
}
if parser.peek::<LParen>() && parser.peek2::<kw::instantiate>() {
if parser.peek::<LParen>()? && parser.peek2::<kw::instantiate>()? {
parser.parens(|parser| {
parser.parse::<kw::instantiate>()?;
Ok(Self::Instantiate {

View File

@ -1,7 +1,7 @@
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::Index;
fn peek<K: Peek>(cursor: Cursor) -> bool {
fn peek<K: Peek>(cursor: Cursor) -> Result<bool> {
// This is a little fancy because when parsing something like:
//
// (type (component (type $foo)))
@ -16,25 +16,25 @@ fn peek<K: Peek>(cursor: Cursor) -> bool {
// strings.
// Peek for the given keyword type
if !K::peek(cursor) {
return false;
if !K::peek(cursor)? {
return Ok(false);
}
// Move past the given keyword
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some((_, c)) => c,
_ => return false,
_ => return Ok(false),
};
// Peek an id or integer index, followed by `)` or string to disambiguate
match cursor
.id()
.map(|p| p.1)
.or_else(|| cursor.integer().map(|p| p.1))
{
Some(cursor) => cursor.rparen().is_some() || cursor.string().is_some(),
let cursor = match cursor.id()? {
Some((_, cursor)) => Some(cursor),
None => cursor.integer()?.map(|p| p.1),
};
Ok(match cursor {
Some(cursor) => cursor.rparen()?.is_some() || cursor.string()?.is_some(),
None => false,
}
})
}
/// Parses core item references.
@ -65,7 +65,7 @@ impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> {
}
impl<'a, K: Peek> Peek for CoreItemRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
peek::<K>(cursor)
}
@ -102,7 +102,7 @@ impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
}
impl<'a, K: Peek> Peek for ItemRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
peek::<K>(cursor)
}
@ -120,7 +120,7 @@ where
K: Parse<'a> + Default,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
if parser.peek::<Index<'_>>()? {
Ok(IndexOrRef(ItemRef {
kind: K::default(),
idx: parser.parse()?,
@ -141,7 +141,7 @@ where
K: Parse<'a> + Default,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
if parser.peek::<Index<'_>>()? {
Ok(IndexOrCoreRef(CoreItemRef {
kind: K::default(),
idx: parser.parse()?,

View File

@ -170,7 +170,7 @@ impl<'a> Resolver<'a> {
}
self.export(&mut e.kind)
}
ComponentField::Custom(_) => Ok(()),
ComponentField::Custom(_) | ComponentField::Producers(_) => Ok(()),
}
}
@ -375,7 +375,9 @@ impl<'a> Resolver<'a> {
}
CanonicalFuncKind::ResourceNew(info) => return self.resolve_ns(&mut info.ty, Ns::Type),
CanonicalFuncKind::ResourceRep(info) => return self.resolve_ns(&mut info.ty, Ns::Type),
CanonicalFuncKind::ResourceDrop(info) => return self.component_val_type(&mut info.ty),
CanonicalFuncKind::ResourceDrop(info) => {
return self.resolve_ns(&mut info.ty, Ns::Type)
}
};
for opt in opts {
@ -845,7 +847,7 @@ impl<'a> ComponentState<'a> {
ComponentExportKind::Component(_) => self.components.register(e.id, "component")?,
ComponentExportKind::Type(_) => self.types.register(e.id, "type")?,
},
ComponentField::Custom(_) => return Ok(()),
ComponentField::Custom(_) | ComponentField::Producers(_) => return Ok(()),
};
Ok(())

View File

@ -53,7 +53,7 @@ pub enum CoreTypeDef<'a> {
impl<'a> Parse<'a> for CoreTypeDef<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::module>() {
if parser.peek::<kw::module>()? {
parser.parse::<kw::module>()?;
Ok(Self::Module(parser.parse()?))
} else {
@ -94,13 +94,13 @@ pub enum ModuleTypeDecl<'a> {
impl<'a> Parse<'a> for ModuleTypeDecl<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::r#type>() {
if l.peek::<kw::r#type>()? {
Ok(Self::Type(parser.parse()?))
} else if l.peek::<kw::alias>() {
} else if l.peek::<kw::alias>()? {
Ok(Self::Alias(Alias::parse_outer_core_type_alias(parser)?))
} else if l.peek::<kw::import>() {
} else if l.peek::<kw::import>()? {
Ok(Self::Import(parser.parse()?))
} else if l.peek::<kw::export>() {
} else if l.peek::<kw::export>()? {
parser.parse::<kw::export>()?;
let name = parser.parse()?;
let et = parser.parens(|parser| parser.parse())?;
@ -187,19 +187,19 @@ pub enum TypeDef<'a> {
impl<'a> Parse<'a> for TypeDef<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() {
if parser.peek::<LParen>()? {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
if l.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
Ok(Self::Func(parser.parse()?))
} else if l.peek::<kw::component>() {
} else if l.peek::<kw::component>()? {
parser.parse::<kw::component>()?;
Ok(Self::Component(parser.parse()?))
} else if l.peek::<kw::instance>() {
} else if l.peek::<kw::instance>()? {
parser.parse::<kw::instance>()?;
Ok(Self::Instance(parser.parse()?))
} else if l.peek::<kw::resource>() {
} else if l.peek::<kw::resource>()? {
parser.parse::<kw::resource>()?;
Ok(Self::Resource(parser.parse()?))
} else {
@ -239,43 +239,43 @@ pub enum PrimitiveValType {
impl<'a> Parse<'a> for PrimitiveValType {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::bool_>() {
if l.peek::<kw::bool_>()? {
parser.parse::<kw::bool_>()?;
Ok(Self::Bool)
} else if l.peek::<kw::s8>() {
} else if l.peek::<kw::s8>()? {
parser.parse::<kw::s8>()?;
Ok(Self::S8)
} else if l.peek::<kw::u8>() {
} else if l.peek::<kw::u8>()? {
parser.parse::<kw::u8>()?;
Ok(Self::U8)
} else if l.peek::<kw::s16>() {
} else if l.peek::<kw::s16>()? {
parser.parse::<kw::s16>()?;
Ok(Self::S16)
} else if l.peek::<kw::u16>() {
} else if l.peek::<kw::u16>()? {
parser.parse::<kw::u16>()?;
Ok(Self::U16)
} else if l.peek::<kw::s32>() {
} else if l.peek::<kw::s32>()? {
parser.parse::<kw::s32>()?;
Ok(Self::S32)
} else if l.peek::<kw::u32>() {
} else if l.peek::<kw::u32>()? {
parser.parse::<kw::u32>()?;
Ok(Self::U32)
} else if l.peek::<kw::s64>() {
} else if l.peek::<kw::s64>()? {
parser.parse::<kw::s64>()?;
Ok(Self::S64)
} else if l.peek::<kw::u64>() {
} else if l.peek::<kw::u64>()? {
parser.parse::<kw::u64>()?;
Ok(Self::U64)
} else if l.peek::<kw::float32>() {
} else if l.peek::<kw::float32>()? {
parser.parse::<kw::float32>()?;
Ok(Self::Float32)
} else if l.peek::<kw::float64>() {
} else if l.peek::<kw::float64>()? {
parser.parse::<kw::float64>()?;
Ok(Self::Float64)
} else if l.peek::<kw::char>() {
} else if l.peek::<kw::char>()? {
parser.parse::<kw::char>()?;
Ok(Self::Char)
} else if l.peek::<kw::string>() {
} else if l.peek::<kw::string>()? {
parser.parse::<kw::string>()?;
Ok(Self::String)
} else {
@ -285,9 +285,9 @@ impl<'a> Parse<'a> for PrimitiveValType {
}
impl Peek for PrimitiveValType {
fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
matches!(
cursor.keyword(),
fn peek(cursor: crate::parser::Cursor<'_>) -> Result<bool> {
Ok(matches!(
cursor.keyword()?,
Some(("bool", _))
| Some(("s8", _))
| Some(("u8", _))
@ -301,7 +301,7 @@ impl Peek for PrimitiveValType {
| Some(("float64", _))
| Some(("char", _))
| Some(("string", _))
)
))
}
fn display() -> &'static str {
@ -321,7 +321,7 @@ pub enum ComponentValType<'a> {
impl<'a> Parse<'a> for ComponentValType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
if parser.peek::<Index<'_>>()? {
Ok(Self::Ref(parser.parse()?))
} else {
Ok(Self::Inline(InlineComponentValType::parse(parser)?.0))
@ -330,8 +330,8 @@ impl<'a> Parse<'a> for ComponentValType<'a> {
}
impl Peek for ComponentValType<'_> {
fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
Index::peek(cursor) || ComponentDefinedType::peek(cursor)
fn peek(cursor: crate::parser::Cursor<'_>) -> Result<bool> {
Ok(Index::peek(cursor)? || ComponentDefinedType::peek(cursor)?)
}
fn display() -> &'static str {
@ -348,7 +348,7 @@ pub struct InlineComponentValType<'a>(ComponentDefinedType<'a>);
impl<'a> Parse<'a> for InlineComponentValType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() {
if parser.peek::<LParen>()? {
parser.parens(|parser| {
Ok(Self(ComponentDefinedType::parse_non_primitive(
parser,
@ -382,28 +382,28 @@ pub enum ComponentDefinedType<'a> {
impl<'a> ComponentDefinedType<'a> {
fn parse_non_primitive(parser: Parser<'a>, mut l: Lookahead1<'a>) -> Result<Self> {
parser.depth_check()?;
if l.peek::<kw::record>() {
if l.peek::<kw::record>()? {
Ok(Self::Record(parser.parse()?))
} else if l.peek::<kw::variant>() {
} else if l.peek::<kw::variant>()? {
Ok(Self::Variant(parser.parse()?))
} else if l.peek::<kw::list>() {
} else if l.peek::<kw::list>()? {
Ok(Self::List(parser.parse()?))
} else if l.peek::<kw::tuple>() {
} else if l.peek::<kw::tuple>()? {
Ok(Self::Tuple(parser.parse()?))
} else if l.peek::<kw::flags>() {
} else if l.peek::<kw::flags>()? {
Ok(Self::Flags(parser.parse()?))
} else if l.peek::<kw::enum_>() {
} else if l.peek::<kw::enum_>()? {
Ok(Self::Enum(parser.parse()?))
} else if l.peek::<kw::union>() {
} else if l.peek::<kw::union>()? {
Ok(Self::Union(parser.parse()?))
} else if l.peek::<kw::option>() {
} else if l.peek::<kw::option>()? {
Ok(Self::Option(parser.parse()?))
} else if l.peek::<kw::result>() {
} else if l.peek::<kw::result>()? {
Ok(Self::Result(parser.parse()?))
} else if l.peek::<kw::own>() {
} else if l.peek::<kw::own>()? {
parser.parse::<kw::own>()?;
Ok(Self::Own(parser.parse()?))
} else if l.peek::<kw::borrow>() {
} else if l.peek::<kw::borrow>()? {
parser.parse::<kw::borrow>()?;
Ok(Self::Borrow(parser.parse()?))
} else {
@ -419,14 +419,14 @@ impl Default for ComponentDefinedType<'_> {
}
impl Peek for ComponentDefinedType<'_> {
fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
if PrimitiveValType::peek(cursor) {
return true;
fn peek(cursor: crate::parser::Cursor<'_>) -> Result<bool> {
if PrimitiveValType::peek(cursor)? {
return Ok(true);
}
match cursor.lparen() {
Ok(match cursor.lparen()? {
Some(cursor) => matches!(
cursor.keyword(),
cursor.keyword()?,
Some(("record", _))
| Some(("variant", _))
| Some(("list", _))
@ -440,7 +440,7 @@ impl Peek for ComponentDefinedType<'_> {
| Some(("borrow", _))
),
None => false,
}
})
}
fn display() -> &'static str {
@ -678,7 +678,7 @@ impl<'a> Parse<'a> for ResultType<'a> {
parser.parse::<kw::result>()?;
let ok: Option<ComponentValType> = parser.parse()?;
let err: Option<ComponentValType> = if parser.peek::<LParen>() {
let err: Option<ComponentValType> = if parser.peek::<LParen>()? {
Some(parser.parens(|parser| {
parser.parse::<kw::error>()?;
parser.parse()
@ -708,12 +708,12 @@ pub struct ComponentFunctionType<'a> {
impl<'a> Parse<'a> for ComponentFunctionType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut params: Vec<ComponentFunctionParam> = Vec::new();
while parser.peek2::<kw::param>() {
while parser.peek2::<kw::param>()? {
params.push(parser.parens(|p| p.parse())?);
}
let mut results: Vec<ComponentFunctionResult> = Vec::new();
while parser.peek2::<kw::result>() {
while parser.peek2::<kw::result>()? {
results.push(parser.parens(|p| p.parse())?);
}
@ -823,15 +823,15 @@ pub enum ComponentTypeDecl<'a> {
impl<'a> Parse<'a> for ComponentTypeDecl<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::core>() {
if l.peek::<kw::core>()? {
Ok(Self::CoreType(parser.parse()?))
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
Ok(Self::Type(Type::parse_no_inline_exports(parser)?))
} else if l.peek::<kw::alias>() {
} else if l.peek::<kw::alias>()? {
Ok(Self::Alias(parser.parse()?))
} else if l.peek::<kw::import>() {
} else if l.peek::<kw::import>()? {
Ok(Self::Import(parser.parse()?))
} else if l.peek::<kw::export>() {
} else if l.peek::<kw::export>()? {
Ok(Self::Export(parser.parse()?))
} else {
Err(l.error())
@ -881,13 +881,13 @@ pub enum InstanceTypeDecl<'a> {
impl<'a> Parse<'a> for InstanceTypeDecl<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::core>() {
if l.peek::<kw::core>()? {
Ok(Self::CoreType(parser.parse()?))
} else if l.peek::<kw::r#type>() {
} else if l.peek::<kw::r#type>()? {
Ok(Self::Type(Type::parse_no_inline_exports(parser)?))
} else if l.peek::<kw::alias>() {
} else if l.peek::<kw::alias>()? {
Ok(Self::Alias(parser.parse()?))
} else if l.peek::<kw::export>() {
} else if l.peek::<kw::export>()? {
Ok(Self::Export(parser.parse()?))
} else {
Err(l.error())
@ -960,7 +960,7 @@ pub enum CoreTypeUse<'a, T> {
impl<'a, T: Parse<'a>> Parse<'a> for CoreTypeUse<'a, T> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// Here the core context is assumed, so no core prefix is expected
if parser.peek::<LParen>() && parser.peek2::<CoreItemRef<'a, kw::r#type>>() {
if parser.peek::<LParen>()? && parser.peek2::<CoreItemRef<'a, kw::r#type>>()? {
Ok(Self::Ref(parser.parens(|parser| parser.parse())?))
} else {
Ok(Self::Inline(parser.parse()?))
@ -993,7 +993,7 @@ pub enum ComponentTypeUse<'a, T> {
impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() && parser.peek2::<ItemRef<'a, kw::r#type>>() {
if parser.peek::<LParen>()? && parser.peek2::<ItemRef<'a, kw::r#type>>()? {
Ok(Self::Ref(parser.parens(|parser| parser.parse())?))
} else {
Ok(Self::Inline(parser.parse()?))

View File

@ -36,10 +36,10 @@ static CASES: &[(&str, fn(Parser<'_>) -> Result<WastVal<'_>>)] = {
&[
("bool.const", |p| {
let mut l = p.lookahead1();
if l.peek::<kw::true_>() {
if l.peek::<kw::true_>()? {
p.parse::<kw::true_>()?;
Ok(Bool(true))
} else if l.peek::<kw::false_>() {
} else if l.peek::<kw::false_>()? {
p.parse::<kw::false_>()?;
Ok(Bool(false))
} else {
@ -140,7 +140,7 @@ impl<'a> Parse<'a> for WastVal<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.depth_check()?;
let parse = parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if let Some((kw, rest)) = c.keyword()? {
if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) {
return Ok((CASES[i].1, rest));
}
@ -152,12 +152,12 @@ impl<'a> Parse<'a> for WastVal<'a> {
}
impl Peek for WastVal<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let kw = match cursor.keyword() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let kw = match cursor.keyword()? {
Some((kw, _)) => kw,
None => return false,
None => return Ok(false),
};
CASES.iter().any(|(name, _)| *name == kw)
Ok(CASES.iter().any(|(name, _)| *name == kw))
}
fn display() -> &'static str {

View File

@ -545,6 +545,10 @@ impl Encode for Elem<'_> {
offset.encode(e);
e.push(0x00); // extern_kind
}
(ElemKind::Declared, ElemPayload::Indices(_)) => {
e.push(0x03); // flags
e.push(0x00); // extern_kind
}
(
ElemKind::Active {
table: Index::Num(0, _),
@ -572,10 +576,6 @@ impl Encode for Elem<'_> {
offset.encode(e);
ty.encode(e);
}
(ElemKind::Declared, ElemPayload::Indices(_)) => {
e.push(0x03); // flags
e.push(0x00); // extern_kind
}
(ElemKind::Declared, ElemPayload::Exprs { ty, .. }) => {
e.push(0x07); // flags
ty.encode(e);
@ -641,10 +641,10 @@ impl Encode for Func<'_> {
}
}
impl Encode for Vec<Local<'_>> {
impl Encode for Box<[Local<'_>]> {
fn encode(&self, e: &mut Vec<u8>) {
let mut locals_compressed = Vec::<(u32, ValType)>::new();
for local in self {
for local in self.iter() {
if let Some((cnt, prev)) = locals_compressed.last_mut() {
if *prev == local.ty {
*cnt += 1;
@ -919,7 +919,7 @@ fn find_names<'a>(
locals, expression, ..
} = &f.kind
{
for local in locals {
for local in locals.iter() {
if let Some(name) = get_name(&local.id, &local.name) {
local_names.push((local_idx, name));
}
@ -1173,7 +1173,7 @@ impl Encode for RefCast<'_> {
}
}
fn br_on_cast_flags(on_fail: bool, from_nullable: bool, to_nullable: bool) -> u8 {
fn br_on_cast_flags(from_nullable: bool, to_nullable: bool) -> u8 {
let mut flag = 0;
if from_nullable {
flag |= 1 << 0;
@ -1181,18 +1181,14 @@ fn br_on_cast_flags(on_fail: bool, from_nullable: bool, to_nullable: bool) -> u8
if to_nullable {
flag |= 1 << 1;
}
if on_fail {
flag |= 1 << 2;
}
flag
}
impl Encode for BrOnCast<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0xfb);
e.push(0x4f);
e.push(0x4e);
e.push(br_on_cast_flags(
false,
self.from_type.nullable,
self.to_type.nullable,
));
@ -1207,7 +1203,6 @@ impl Encode for BrOnCastFail<'_> {
e.push(0xfb);
e.push(0x4f);
e.push(br_on_cast_flags(
true,
self.from_type.nullable,
self.to_type.nullable,
));

View File

@ -31,7 +31,7 @@ impl Custom<'_> {
impl<'a> Parse<'a> for Custom<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<annotation::producers>() {
if parser.peek::<annotation::producers>()? {
Ok(Custom::Producers(parser.parse()?))
} else {
Ok(Custom::Raw(parser.parse()?))
@ -90,7 +90,7 @@ impl<'a> Parse<'a> for RawCustomSection<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<annotation::custom>()?.0;
let name = parser.parse()?;
let place = if parser.peek::<token::LParen>() {
let place = if parser.peek::<token::LParen>()? {
parser.parens(|p| p.parse())?
} else {
CustomPlace::AfterLast
@ -111,16 +111,16 @@ impl<'a> Parse<'a> for RawCustomSection<'a> {
impl<'a> Parse<'a> for CustomPlace {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
let ctor = if l.peek::<kw::before>() {
let ctor = if l.peek::<kw::before>()? {
parser.parse::<kw::before>()?;
if l.peek::<kw::first>() {
if l.peek::<kw::first>()? {
parser.parse::<kw::first>()?;
return Ok(CustomPlace::BeforeFirst);
}
CustomPlace::Before as fn(CustomPlaceAnchor) -> _
} else if l.peek::<kw::after>() {
} else if l.peek::<kw::after>()? {
parser.parse::<kw::after>()?;
if l.peek::<kw::last>() {
if l.peek::<kw::last>()? {
parser.parse::<kw::last>()?;
return Ok(CustomPlace::AfterLast);
}
@ -134,51 +134,51 @@ impl<'a> Parse<'a> for CustomPlace {
impl<'a> Parse<'a> for CustomPlaceAnchor {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::r#type>() {
if parser.peek::<kw::r#type>()? {
parser.parse::<kw::r#type>()?;
return Ok(CustomPlaceAnchor::Type);
}
if parser.peek::<kw::import>() {
if parser.peek::<kw::import>()? {
parser.parse::<kw::import>()?;
return Ok(CustomPlaceAnchor::Import);
}
if parser.peek::<kw::func>() {
if parser.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
return Ok(CustomPlaceAnchor::Func);
}
if parser.peek::<kw::table>() {
if parser.peek::<kw::table>()? {
parser.parse::<kw::table>()?;
return Ok(CustomPlaceAnchor::Table);
}
if parser.peek::<kw::memory>() {
if parser.peek::<kw::memory>()? {
parser.parse::<kw::memory>()?;
return Ok(CustomPlaceAnchor::Memory);
}
if parser.peek::<kw::global>() {
if parser.peek::<kw::global>()? {
parser.parse::<kw::global>()?;
return Ok(CustomPlaceAnchor::Global);
}
if parser.peek::<kw::export>() {
if parser.peek::<kw::export>()? {
parser.parse::<kw::export>()?;
return Ok(CustomPlaceAnchor::Export);
}
if parser.peek::<kw::start>() {
if parser.peek::<kw::start>()? {
parser.parse::<kw::start>()?;
return Ok(CustomPlaceAnchor::Start);
}
if parser.peek::<kw::elem>() {
if parser.peek::<kw::elem>()? {
parser.parse::<kw::elem>()?;
return Ok(CustomPlaceAnchor::Elem);
}
if parser.peek::<kw::code>() {
if parser.peek::<kw::code>()? {
parser.parse::<kw::code>()?;
return Ok(CustomPlaceAnchor::Code);
}
if parser.peek::<kw::data>() {
if parser.peek::<kw::data>()? {
parser.parse::<kw::data>()?;
return Ok(CustomPlaceAnchor::Data);
}
if parser.peek::<kw::tag>() {
if parser.peek::<kw::tag>()? {
parser.parse::<kw::tag>()?;
return Ok(CustomPlaceAnchor::Tag);
}
@ -203,13 +203,13 @@ impl<'a> Parse<'a> for Producers<'a> {
while !parser.is_empty() {
parser.parens(|parser| {
let mut l = parser.lookahead1();
let dst = if l.peek::<kw::language>() {
let dst = if l.peek::<kw::language>()? {
parser.parse::<kw::language>()?;
&mut languages
} else if l.peek::<kw::sdk>() {
} else if l.peek::<kw::sdk>()? {
parser.parse::<kw::sdk>()?;
&mut sdks
} else if l.peek::<kw::processed_by>() {
} else if l.peek::<kw::processed_by>()? {
parser.parse::<kw::processed_by>()?;
&mut processed_by
} else {

View File

@ -44,19 +44,19 @@ impl<'a> Parse<'a> for Export<'a> {
impl<'a> Parse<'a> for ExportKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
if l.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
Ok(ExportKind::Func)
} else if l.peek::<kw::table>() {
} else if l.peek::<kw::table>()? {
parser.parse::<kw::table>()?;
Ok(ExportKind::Table)
} else if l.peek::<kw::memory>() {
} else if l.peek::<kw::memory>()? {
parser.parse::<kw::memory>()?;
Ok(ExportKind::Memory)
} else if l.peek::<kw::global>() {
} else if l.peek::<kw::global>()? {
parser.parse::<kw::global>()?;
Ok(ExportKind::Global)
} else if l.peek::<kw::tag>() {
} else if l.peek::<kw::tag>()? {
parser.parse::<kw::tag>()?;
Ok(ExportKind::Tag)
} else {
@ -66,12 +66,12 @@ 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)
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(kw::func::peek(cursor)?
|| kw::table::peek(cursor)?
|| kw::memory::peek(cursor)?
|| kw::global::peek(cursor)?
|| kw::tag::peek(cursor)?)
}
fn display() -> &'static str {
"export kind"
@ -113,7 +113,7 @@ pub struct InlineExport<'a> {
impl<'a> Parse<'a> for InlineExport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut names = Vec::new();
while parser.peek::<Self>() {
while parser.peek::<Self>()? {
names.push(parser.parens(|p| {
p.parse::<kw::export>()?;
p.parse::<&str>()
@ -124,20 +124,20 @@ impl<'a> Parse<'a> for InlineExport<'a> {
}
impl Peek for InlineExport<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("export", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.string() {
let cursor = match cursor.string()? {
Some((_, cursor)) => cursor,
None => return false,
None => return Ok(false),
};
cursor.rparen().is_some()
Ok(cursor.rparen()?.is_some())
}
fn display() -> &'static str {

View File

@ -117,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::<LParen>() {
if !parser.is_empty() && !parser.peek::<LParen>()? {
return Err(parser.error("expected `(`"));
}
}
@ -220,10 +220,10 @@ impl<'a> ExpressionParser<'a> {
/// Parses either `(`, `)`, or nothing.
fn paren(&self, parser: Parser<'a>) -> Result<Paren> {
parser.step(|cursor| {
Ok(match cursor.lparen() {
Ok(match cursor.lparen()? {
Some(rest) => (Paren::Left, rest),
None if self.stack.is_empty() => (Paren::None, cursor),
None => match cursor.rparen() {
None => match cursor.rparen()? {
Some(rest) => (Paren::Right, rest),
None => (Paren::None, cursor),
},
@ -265,7 +265,7 @@ impl<'a> ExpressionParser<'a> {
if let If::Clause(if_instr) = i {
let instr = mem::replace(if_instr, Instruction::End(None));
*i = If::Then(instr);
if !parser.peek::<kw::then>() {
if !parser.peek::<kw::then>()? {
return Ok(false);
}
}
@ -426,7 +426,7 @@ macro_rules! instructions {
}
)*
let parse_remainder = parser.step(|c| {
let (kw, rest) = match c.keyword() {
let (kw, rest) = match c.keyword() ?{
Some(pair) => pair,
None => return Err(c.error("expected an instruction")),
};
@ -502,10 +502,10 @@ macro_rules! instructions {
instructions! {
pub enum Instruction<'a> {
Block(BlockType<'a>) : [0x02] : "block",
If(BlockType<'a>) : [0x04] : "if",
Block(Box<BlockType<'a>>) : [0x02] : "block",
If(Box<BlockType<'a>>) : [0x04] : "if",
Else(Option<Id<'a>>) : [0x05] : "else",
Loop(BlockType<'a>) : [0x03] : "loop",
Loop(Box<BlockType<'a>>) : [0x03] : "loop",
End(Option<Id<'a>>) : [0x0b] : "end",
Unreachable : [0x00] : "unreachable",
@ -515,11 +515,11 @@ instructions! {
BrTable(BrTableIndices<'a>) : [0x0e] : "br_table",
Return : [0x0f] : "return",
Call(Index<'a>) : [0x10] : "call",
CallIndirect(CallIndirect<'a>) : [0x11] : "call_indirect",
CallIndirect(Box<CallIndirect<'a>>) : [0x11] : "call_indirect",
// tail-call proposal
ReturnCall(Index<'a>) : [0x12] : "return_call",
ReturnCallIndirect(CallIndirect<'a>) : [0x13] : "return_call_indirect",
ReturnCallIndirect(Box<CallIndirect<'a>>) : [0x13] : "return_call_indirect",
// function-references proposal
CallRef(Index<'a>) : [0x14] : "call_ref",
@ -621,8 +621,8 @@ instructions! {
// gc proposal, concrete casting
RefTest(RefTest<'a>) : [] : "ref.test",
RefCast(RefCast<'a>) : [] : "ref.cast",
BrOnCast(BrOnCast<'a>) : [] : "br_on_cast",
BrOnCastFail(BrOnCastFail<'a>) : [] : "br_on_cast_fail",
BrOnCast(Box<BrOnCast<'a>>) : [] : "br_on_cast",
BrOnCastFail(Box<BrOnCastFail<'a>>) : [] : "br_on_cast_fail",
// gc proposal extern/any coercion operations
ExternInternalize : [0xfb, 0x70] : "extern.internalize",
@ -1118,7 +1118,7 @@ instructions! {
F64x2PromoteLowF32x4 : [0xfd, 95] : "f64x2.promote_low_f32x4",
// Exception handling proposal
Try(BlockType<'a>) : [0x06] : "try",
Try(Box<BlockType<'a>>) : [0x06] : "try",
Catch(Index<'a>) : [0x07] : "catch",
Throw(Index<'a>) : [0x08] : "throw",
Rethrow(Index<'a>) : [0x09] : "rethrow",
@ -1149,6 +1149,16 @@ instructions! {
}
}
// As shown in #1095 the size of this variant is somewhat performance-sensitive
// since big `*.wat` files will have a lot of these. This is a small ratchet to
// make sure that this enum doesn't become larger than it already is, although
// ideally it also wouldn't be as large as it is now.
const _: () = {
let size = std::mem::size_of::<Instruction<'_>>();
let pointer = std::mem::size_of::<u64>();
assert!(size <= pointer * 10);
};
impl<'a> Instruction<'a> {
pub(crate) fn needs_data_count(&self) -> bool {
match self {
@ -1205,15 +1215,15 @@ impl<'a> Parse<'a> for FuncBindType<'a> {
#[derive(Debug)]
#[allow(missing_docs)]
pub struct LetType<'a> {
pub block: BlockType<'a>,
pub locals: Vec<Local<'a>>,
pub block: Box<BlockType<'a>>,
pub locals: Box<[Local<'a>]>,
}
impl<'a> Parse<'a> for LetType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(LetType {
block: parser.parse()?,
locals: Local::parse_remainder(parser)?,
locals: Local::parse_remainder(parser)?.into(),
})
}
}
@ -1229,7 +1239,7 @@ pub struct BrTableIndices<'a> {
impl<'a> Parse<'a> for BrTableIndices<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut labels = vec![parser.parse()?];
while parser.peek::<Index>() {
while parser.peek::<Index>()? {
labels.push(parser.parse()?);
}
let default = labels.pop().unwrap();
@ -1247,7 +1257,7 @@ pub struct LaneArg {
impl<'a> Parse<'a> for LaneArg {
fn parse(parser: Parser<'a>) -> Result<Self> {
let lane = parser.step(|c| {
if let Some((i, rest)) = c.integer() {
if let Some((i, rest)) = c.integer()? {
if i.sign() == None {
let (src, radix) = i.val();
let val = u8::from_str_radix(src, radix)
@ -1287,7 +1297,7 @@ impl<'a> MemArg<'a> {
f: impl FnOnce(Cursor<'_>, &str, u32) -> Result<T>,
) -> Result<Option<T>> {
parser.step(|c| {
let (kw, rest) = match c.keyword() {
let (kw, rest) = match c.keyword()? {
Some(p) => p,
None => return Ok((None, c)),
};
@ -1354,17 +1364,17 @@ impl<'a> LoadOrStoreLane<'a> {
// This is sort of funky. The first integer we see could be the lane
// index, but it could also be the memory index. To determine what it is
// then if we see a second integer we need to look further.
let has_memarg = parser.step(|c| match c.integer() {
let has_memarg = parser.step(|c| match c.integer()? {
Some((_, after_int)) => {
// Two integers in a row? That means that the first one is the
// memory index and the second must be the lane index.
if after_int.integer().is_some() {
if after_int.integer()?.is_some() {
return Ok((true, c));
}
// If the first integer is trailed by `offset=...` or
// `align=...` then this is definitely a memarg.
if let Some((kw, _)) = after_int.keyword() {
if let Some((kw, _)) = after_int.keyword()? {
if kw.starts_with("offset=") || kw.starts_with("align=") {
return Ok((true, c));
}
@ -1427,7 +1437,7 @@ pub struct TableInit<'a> {
impl<'a> Parse<'a> for TableInit<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let prev_span = parser.prev_span();
let (elem, table) = if parser.peek2::<Index>() {
let (elem, table) = if parser.peek2::<Index>()? {
let table = parser.parse()?;
(parser.parse()?, table)
} else {
@ -1507,7 +1517,7 @@ pub struct MemoryInit<'a> {
impl<'a> Parse<'a> for MemoryInit<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let prev_span = parser.prev_span();
let (data, mem) = if parser.peek2::<Index>() {
let (data, mem) = if parser.peek2::<Index>()? {
let memory = parser.parse()?;
(parser.parse()?, memory)
} else {
@ -1840,7 +1850,7 @@ impl V128Const {
impl<'a> Parse<'a> for V128Const {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::i8x16>() {
if l.peek::<kw::i8x16>()? {
parser.parse::<kw::i8x16>()?;
Ok(V128Const::I8x16([
parser.parse()?,
@ -1860,7 +1870,7 @@ impl<'a> Parse<'a> for V128Const {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i16x8>() {
} else if l.peek::<kw::i16x8>()? {
parser.parse::<kw::i16x8>()?;
Ok(V128Const::I16x8([
parser.parse()?,
@ -1872,7 +1882,7 @@ impl<'a> Parse<'a> for V128Const {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i32x4>() {
} else if l.peek::<kw::i32x4>()? {
parser.parse::<kw::i32x4>()?;
Ok(V128Const::I32x4([
parser.parse()?,
@ -1880,10 +1890,10 @@ impl<'a> Parse<'a> for V128Const {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i64x2>() {
} else if l.peek::<kw::i64x2>()? {
parser.parse::<kw::i64x2>()?;
Ok(V128Const::I64x2([parser.parse()?, parser.parse()?]))
} else if l.peek::<kw::f32x4>() {
} else if l.peek::<kw::f32x4>()? {
parser.parse::<kw::f32x4>()?;
Ok(V128Const::F32x4([
parser.parse()?,
@ -1891,7 +1901,7 @@ impl<'a> Parse<'a> for V128Const {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::f64x2>() {
} else if l.peek::<kw::f64x2>()? {
parser.parse::<kw::f64x2>()?;
Ok(V128Const::F64x2([parser.parse()?, parser.parse()?]))
} else {
@ -1943,7 +1953,7 @@ impl<'a> Parse<'a> for SelectTypes<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut found = false;
let mut list = Vec::new();
while parser.peek2::<kw::result>() {
while parser.peek2::<kw::result>()? {
found = true;
parser.parens(|p| {
p.parse::<kw::result>()?;

View File

@ -38,7 +38,7 @@ pub enum FuncKind<'a> {
/// Almost all functions, those defined inline in a wasm module.
Inline {
/// The list of locals, if any, for this function.
locals: Vec<Local<'a>>,
locals: Box<[Local<'a>]>,
/// The instructions of the function.
expression: Expression<'a>,
@ -56,7 +56,7 @@ impl<'a> Parse<'a> for Func<'a> {
(parser.parse()?, FuncKind::Import(import))
} else {
let ty = parser.parse()?;
let locals = Local::parse_remainder(parser)?;
let locals = Local::parse_remainder(parser)?.into();
(
ty,
FuncKind::Inline {
@ -95,7 +95,7 @@ pub struct Local<'a> {
impl<'a> Local<'a> {
pub(crate) fn parse_remainder(parser: Parser<'a>) -> Result<Vec<Local<'a>>> {
let mut locals = Vec::new();
while parser.peek2::<kw::local>() {
while parser.peek2::<kw::local>()? {
parser.parens(|p| {
p.parse::<kw::local>()?;
if p.is_empty() {

View File

@ -59,7 +59,7 @@ pub enum ItemKind<'a> {
impl<'a> Parse<'a> for ItemSig<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
if l.peek::<kw::func>()? {
let span = parser.parse::<kw::func>()?.0;
Ok(ItemSig {
span,
@ -67,7 +67,7 @@ impl<'a> Parse<'a> for ItemSig<'a> {
name: parser.parse()?,
kind: ItemKind::Func(parser.parse()?),
})
} else if l.peek::<kw::table>() {
} else if l.peek::<kw::table>()? {
let span = parser.parse::<kw::table>()?.0;
Ok(ItemSig {
span,
@ -75,7 +75,7 @@ impl<'a> Parse<'a> for ItemSig<'a> {
name: None,
kind: ItemKind::Table(parser.parse()?),
})
} else if l.peek::<kw::memory>() {
} else if l.peek::<kw::memory>()? {
let span = parser.parse::<kw::memory>()?.0;
Ok(ItemSig {
span,
@ -83,7 +83,7 @@ impl<'a> Parse<'a> for ItemSig<'a> {
name: None,
kind: ItemKind::Memory(parser.parse()?),
})
} else if l.peek::<kw::global>() {
} else if l.peek::<kw::global>()? {
let span = parser.parse::<kw::global>()?.0;
Ok(ItemSig {
span,
@ -91,7 +91,7 @@ impl<'a> Parse<'a> for ItemSig<'a> {
name: None,
kind: ItemKind::Global(parser.parse()?),
})
} else if l.peek::<kw::tag>() {
} else if l.peek::<kw::tag>()? {
let span = parser.parse::<kw::tag>()?.0;
Ok(ItemSig {
span,
@ -131,25 +131,25 @@ impl<'a> Parse<'a> for InlineImport<'a> {
}
impl Peek for InlineImport<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let cursor = match cursor.lparen()? {
Some(cursor) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.keyword() {
let cursor = match cursor.keyword()? {
Some(("import", cursor)) => cursor,
_ => return false,
_ => return Ok(false),
};
let cursor = match cursor.string() {
let cursor = match cursor.string()? {
Some((_, cursor)) => cursor,
None => return false,
None => return Ok(false),
};
let cursor = match cursor.string() {
let cursor = match cursor.string()? {
Some((_, cursor)) => cursor,
None => return false,
None => return Ok(false),
};
cursor.rparen().is_some()
Ok(cursor.rparen()?.is_some())
}
fn display() -> &'static str {

View File

@ -59,7 +59,7 @@ impl<'a> Parse<'a> for Memory<'a> {
import,
ty: parser.parse()?,
}
} else if l.peek::<LParen>() || parser.peek2::<LParen>() {
} else if l.peek::<LParen>()? || parser.peek2::<LParen>()? {
let is_32 = if parser.parse::<Option<kw::i32>>()?.is_some() {
true
} else {
@ -74,7 +74,7 @@ impl<'a> Parse<'a> for Memory<'a> {
Ok(data)
})?;
MemoryKind::Inline { data, is_32 }
} else if l.peek::<u32>() || l.peek::<kw::i32>() || l.peek::<kw::i64>() {
} else if l.peek::<u32>()? || l.peek::<kw::i32>()? || l.peek::<kw::i64>()? {
MemoryKind::Normal(parser.parse()?)
} else {
return Err(l.error());
@ -133,19 +133,19 @@ impl<'a> Parse<'a> for Data<'a> {
let id = parser.parse()?;
let name = parser.parse()?;
let kind = 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 parser.peek::<u32>() {
let memory = if parser.peek::<u32>()? {
// 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::<kw::memory>() {
} else if parser.peek2::<kw::memory>()? {
parser.parens(|p| {
p.parse::<kw::memory>()?;
p.parse()
@ -154,7 +154,7 @@ impl<'a> Parse<'a> for Data<'a> {
Index::Num(0, span)
};
let offset = parser.parens(|parser| {
if parser.peek::<kw::offset>() {
if parser.peek::<kw::offset>()? {
parser.parse::<kw::offset>()?;
parser.parse()
} else {
@ -233,7 +233,7 @@ impl DataVal<'_> {
impl<'a> Parse<'a> for DataVal<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if !parser.peek::<LParen>() {
if !parser.peek::<LParen>()? {
return Ok(DataVal::String(parser.parse()?));
}
@ -265,7 +265,7 @@ impl<'a> Parse<'a> for DataVal<'a> {
where
F: Fn(U, &mut Vec<u8>),
{
if !lookahead.peek::<T>() {
if !lookahead.peek::<T>()? {
return Ok(false);
}
parser.parse::<T>()?;

View File

@ -110,11 +110,15 @@ impl<'a> Module<'a> {
impl<'a> Parse<'a> for Module<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let _r = parser.register_annotation("custom");
let _r = parser.register_annotation("producers");
let _r = parser.register_annotation("name");
let span = parser.parse::<kw::module>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let kind = if parser.peek::<kw::binary>() {
let kind = if parser.peek::<kw::binary>()? {
parser.parse::<kw::binary>()?;
let mut data = Vec::new();
while !parser.is_empty() {
@ -154,8 +158,6 @@ pub enum ModuleField<'a> {
impl<'a> ModuleField<'a> {
pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ModuleField>> {
let _r = parser.register_annotation("custom");
let _r = parser.register_annotation("producers");
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(ModuleField::parse)?);
@ -166,44 +168,44 @@ impl<'a> ModuleField<'a> {
impl<'a> Parse<'a> for ModuleField<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Type<'a>>() {
if parser.peek::<Type<'a>>()? {
return Ok(ModuleField::Type(parser.parse()?));
}
if parser.peek::<kw::rec>() {
if parser.peek::<kw::rec>()? {
return Ok(ModuleField::Rec(parser.parse()?));
}
if parser.peek::<kw::import>() {
if parser.peek::<kw::import>()? {
return Ok(ModuleField::Import(parser.parse()?));
}
if parser.peek::<kw::func>() {
if parser.peek::<kw::func>()? {
return Ok(ModuleField::Func(parser.parse()?));
}
if parser.peek::<kw::table>() {
if parser.peek::<kw::table>()? {
return Ok(ModuleField::Table(parser.parse()?));
}
if parser.peek::<kw::memory>() {
if parser.peek::<kw::memory>()? {
return Ok(ModuleField::Memory(parser.parse()?));
}
if parser.peek::<kw::global>() {
if parser.peek::<kw::global>()? {
return Ok(ModuleField::Global(parser.parse()?));
}
if parser.peek::<kw::export>() {
if parser.peek::<kw::export>()? {
return Ok(ModuleField::Export(parser.parse()?));
}
if parser.peek::<kw::start>() {
if parser.peek::<kw::start>()? {
parser.parse::<kw::start>()?;
return Ok(ModuleField::Start(parser.parse()?));
}
if parser.peek::<kw::elem>() {
if parser.peek::<kw::elem>()? {
return Ok(ModuleField::Elem(parser.parse()?));
}
if parser.peek::<kw::data>() {
if parser.peek::<kw::data>()? {
return Ok(ModuleField::Data(parser.parse()?));
}
if parser.peek::<kw::tag>() {
if parser.peek::<kw::tag>()? {
return Ok(ModuleField::Tag(parser.parse()?));
}
if parser.peek::<annotation::custom>() || parser.peek::<annotation::producers>() {
if parser.peek::<annotation::custom>()? || parser.peek::<annotation::producers>()? {
return Ok(ModuleField::Custom(parser.parse()?));
}
Err(parser.error("expected valid module field"))

View File

@ -3,6 +3,7 @@ use crate::core::*;
use crate::names::{resolve_error, Namespace};
use crate::token::{Id, Index};
use crate::Error;
use std::collections::HashMap;
pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Resolver<'a>, Error> {
let mut resolver = Resolver::default();
@ -25,7 +26,7 @@ pub struct Resolver<'a> {
tags: Namespace<'a>,
datas: Namespace<'a>,
elems: Namespace<'a>,
fields: Namespace<'a>,
fields: HashMap<u32, Namespace<'a>>,
type_info: Vec<TypeInfo<'a>>,
}
@ -46,16 +47,20 @@ impl<'a> Resolver<'a> {
}
fn register_type(&mut self, ty: &Type<'a>) -> Result<(), Error> {
let type_index = self.types.register(ty.id, "type")?;
match &ty.def {
// For GC structure types we need to be sure to populate the
// field namespace here as well.
//
// The field namespace is global, but the resolved indices
// are relative to the struct they are defined in
// The field namespace is relative to the struct fields are defined in
TypeDef::Struct(r#struct) => {
for (i, field) in r#struct.fields.iter().enumerate() {
if let Some(id) = field.id {
self.fields.register_specific(id, i as u32, "field")?;
self.fields
.entry(type_index)
.or_insert(Namespace::default())
.register_specific(id, i as u32, "field")?;
}
}
}
@ -75,7 +80,6 @@ impl<'a> Resolver<'a> {
_ => self.type_info.push(TypeInfo::Other),
}
self.types.register(ty.id, "type")?;
Ok(())
}
@ -176,7 +180,7 @@ impl<'a> Resolver<'a> {
}
// .. followed by locals themselves
for local in locals {
for local in locals.iter() {
scope.register(local.id, "local")?;
}
@ -492,13 +496,13 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
Let(t) => {
// Resolve (ref T) in locals
for local in &mut t.locals {
for local in t.locals.iter_mut() {
self.resolver.resolve_valtype(&mut local.ty)?;
}
// Register all locals defined in this let
let mut scope = Namespace::default();
for local in &t.locals {
for local in t.locals.iter() {
scope.register(local.id, "local")?;
}
self.scopes.push(scope);
@ -604,14 +608,20 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
self.resolver.resolve_reftype(&mut i.from_type)?;
}
StructNew(i) | StructNewDefault(i) | ArrayNew(i)
| ArrayNewDefault(i) | ArrayGet(i) | ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) => {
StructNew(i) | StructNewDefault(i) | ArrayNew(i) | ArrayNewDefault(i) | ArrayGet(i)
| ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) => {
self.resolver.resolve(i, Ns::Type)?;
}
StructSet(s) | StructGet(s) | StructGetS(s) | StructGetU(s) => {
self.resolver.resolve(&mut s.r#struct, Ns::Type)?;
self.resolver.fields.resolve(&mut s.field, "field")?;
let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?;
if let Index::Id(field_id) = s.field {
self.resolver
.fields
.get(&type_index)
.ok_or(Error::new(field_id.span(), format!("accessing a named field `{}` in a struct without named fields, type index {}", field_id.name(), type_index)))?
.resolve(&mut s.field, "field")?;
}
}
ArrayNewFixed(a) => {

View File

@ -1,6 +1,6 @@
use crate::core::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::parser::{Parse, Parser, Peek, Result};
use crate::token::{Id, Index, LParen, NameAnnotation, Span};
/// A WebAssembly `table` directive in a module.
@ -56,23 +56,22 @@ impl<'a> Parse<'a> for Table<'a> {
// Afterwards figure out which style this is, either:
//
// * `elemtype (elem ...)`
// * `(import "a" "b") limits`
// * `limits`
// * `elemtype (elem ...)`
// * `(import "a" "b") limits`
// * `limits`
let mut l = parser.lookahead1();
let kind = if l.peek::<RefType>() {
let kind = if l.peek::<RefType>()? {
let elem = parser.parse()?;
let payload = parser.parens(|p| {
p.parse::<kw::elem>()?;
let ty = if parser.peek::<LParen>() {
Some(elem)
if p.peek::<LParen>()? {
ElemPayload::parse_exprs(p, elem)
} else {
None
};
ElemPayload::parse_tail(parser, ty)
ElemPayload::parse_indices(p, Some(elem))
}
})?;
TableKind::Inline { elem, payload }
} else if l.peek::<u32>() {
} else if l.peek::<u32>()? {
TableKind::Normal {
ty: parser.parse()?,
init_expr: if !parser.is_empty() {
@ -156,26 +155,47 @@ impl<'a> Parse<'a> for Elem<'a> {
let id = parser.parse()?;
let name = parser.parse()?;
let kind = if parser.peek::<kw::declare>() {
// Element segments can start in a number of different ways:
//
// * `(elem ...`
// * `(elem declare ...`
// * `(elem (table ...`
// * `(elem (offset ...`
// * `(elem (<instr> ...`
let mut table_omitted = false;
let kind = if parser.peek::<kw::declare>()? {
parser.parse::<kw::declare>()?;
ElemKind::Declared
} else if parser.peek::<u32>() || (parser.peek::<LParen>() && !parser.peek::<RefType>()) {
let table = if parser.peek::<u32>() {
} else if parser.peek::<u32>()?
|| (parser.peek::<LParen>()? && !parser.peek::<RefType>()?)
{
let table = if parser.peek::<u32>()? {
// 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.
table_omitted = true;
Index::Num(parser.parse()?, span)
} else if parser.peek2::<kw::table>() {
} else if parser.peek2::<kw::table>()? {
parser.parens(|p| {
p.parse::<kw::table>()?;
p.parse()
})?
} else {
table_omitted = true;
Index::Num(0, span)
};
// NB: this is technically not spec-compliant where the spec says
// that `(instr)` is equivalent to `(offset instr)` for
// single-element offsets. The test suite, however, has offsets of
// the form `(instr (instr-arg))` which doesn't seem to follow this.
// I don't know whether the test is correct or the spec is correct
// so we're left with this for now.
//
// In theory though this should use `parse_expr_or_single_instr`.
let offset = parser.parens(|parser| {
if parser.peek::<kw::offset>() {
if parser.peek::<kw::offset>()? {
parser.parse::<kw::offset>()?;
}
parser.parse()
@ -184,7 +204,31 @@ impl<'a> Parse<'a> for Elem<'a> {
} else {
ElemKind::Passive
};
let payload = parser.parse()?;
// Element segments can have a number of ways to specify their element
// lists:
//
// * `func 0 1 ...` - list of indices
// * `<reftype> (ref.null func) ...` - list of expressions
// * `0 1 ...` - list of indices, only if the table was omitted for the
// legacy way tables were printed.
let indices = if parser.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
true
} else if parser.peek::<RefType>()? {
false
} else if table_omitted {
true
} else {
false // this will fall through to failing to parse a `RefType`
};
let payload = if indices {
ElemPayload::parse_indices(parser, None)?
} else {
let ty = parser.parse()?;
ElemPayload::parse_exprs(parser, ty)?
};
Ok(Elem {
span,
id,
@ -195,47 +239,67 @@ impl<'a> Parse<'a> for Elem<'a> {
}
}
impl<'a> Parse<'a> for ElemPayload<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
ElemPayload::parse_tail(parser, parser.parse()?)
}
}
impl<'a> ElemPayload<'a> {
fn parse_tail(parser: Parser<'a>, ty: Option<RefType<'a>>) -> Result<Self> {
let (must_use_indices, ty) = match ty {
None => {
parser.parse::<Option<kw::func>>()?;
(true, RefType::func())
}
Some(ty) => (false, ty),
fn parse_indices(parser: Parser<'a>, ty: Option<RefType<'a>>) -> Result<Self> {
let mut ret = match ty {
// If there is no requested type, then it's ok to parse a list of
// indices.
None => ElemPayload::Indices(Vec::new()),
// If the requested type is a `funcref` type then a list of indices
// can be parsed. This is because the list-of-indices encoding in
// the binary format can only accomodate the `funcref` type.
Some(ty) if ty == RefType::func() => ElemPayload::Indices(Vec::new()),
// Otherwise silently translate this list-of-indices into a
// list-of-expressions because that's the only way to accomodate a
// non-funcref type.
Some(ty) => ElemPayload::Exprs {
ty,
exprs: Vec::new(),
},
};
if let HeapType::Func = ty.heap {
if must_use_indices || parser.peek::<Index<'_>>() {
let mut elems = Vec::new();
while !parser.is_empty() {
elems.push(parser.parse()?);
while !parser.is_empty() {
let func = parser.parse()?;
match &mut ret {
ElemPayload::Indices(list) => list.push(func),
ElemPayload::Exprs { exprs, .. } => {
let expr = Expression {
instrs: [Instruction::RefFunc(func)].into(),
};
exprs.push(expr);
}
return Ok(ElemPayload::Indices(elems));
}
}
Ok(ret)
}
fn parse_exprs(parser: Parser<'a>, ty: RefType<'a>) -> Result<Self> {
let mut exprs = Vec::new();
while !parser.is_empty() {
let expr = parser.parens(|parser| {
if parser.peek::<kw::item>() {
parser.parse::<kw::item>()?;
parser.parse()
} else {
// Without `item` this is "sugar" for a single-instruction
// expression.
let insn = parser.parse()?;
Ok(Expression {
instrs: [insn].into(),
})
}
})?;
let expr = parse_expr_or_single_instr::<kw::item>(parser)?;
exprs.push(expr);
}
Ok(ElemPayload::Exprs { exprs, ty })
}
}
// Parses either `(T expr)` or `(instr)`, returning the resulting expression.
fn parse_expr_or_single_instr<'a, T>(parser: Parser<'a>) -> Result<Expression<'a>>
where
T: Parse<'a> + Peek,
{
parser.parens(|parser| {
if parser.peek::<T>()? {
parser.parse::<T>()?;
parser.parse()
} else {
// Without `item` this is "sugar" for a single-instruction
// expression.
let insn = parser.parse()?;
Ok(Expression {
instrs: [insn].into(),
})
}
})
}

View File

@ -19,22 +19,22 @@ pub enum ValType<'a> {
impl<'a> Parse<'a> for ValType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::i32>() {
if l.peek::<kw::i32>()? {
parser.parse::<kw::i32>()?;
Ok(ValType::I32)
} else if l.peek::<kw::i64>() {
} else if l.peek::<kw::i64>()? {
parser.parse::<kw::i64>()?;
Ok(ValType::I64)
} else if l.peek::<kw::f32>() {
} else if l.peek::<kw::f32>()? {
parser.parse::<kw::f32>()?;
Ok(ValType::F32)
} else if l.peek::<kw::f64>() {
} else if l.peek::<kw::f64>()? {
parser.parse::<kw::f64>()?;
Ok(ValType::F64)
} else if l.peek::<kw::v128>() {
} else if l.peek::<kw::v128>()? {
parser.parse::<kw::v128>()?;
Ok(ValType::V128)
} else if l.peek::<RefType>() {
} else if l.peek::<RefType>()? {
Ok(ValType::Ref(parser.parse()?))
} else {
Err(l.error())
@ -43,13 +43,13 @@ impl<'a> Parse<'a> for ValType<'a> {
}
impl<'a> Peek for ValType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
kw::i32::peek(cursor)
|| kw::i64::peek(cursor)
|| kw::f32::peek(cursor)
|| kw::f64::peek(cursor)
|| kw::v128::peek(cursor)
|| RefType::peek(cursor)
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(kw::i32::peek(cursor)?
|| kw::i64::peek(cursor)?
|| kw::f32::peek(cursor)?
|| kw::f64::peek(cursor)?
|| kw::v128::peek(cursor)?
|| RefType::peek(cursor)?)
}
fn display() -> &'static str {
"valtype"
@ -92,37 +92,37 @@ pub enum HeapType<'a> {
impl<'a> Parse<'a> for HeapType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
if l.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
Ok(HeapType::Func)
} else if l.peek::<kw::r#extern>() {
} else if l.peek::<kw::r#extern>()? {
parser.parse::<kw::r#extern>()?;
Ok(HeapType::Extern)
} else if l.peek::<kw::r#any>() {
} else if l.peek::<kw::r#any>()? {
parser.parse::<kw::r#any>()?;
Ok(HeapType::Any)
} else if l.peek::<kw::eq>() {
} else if l.peek::<kw::eq>()? {
parser.parse::<kw::eq>()?;
Ok(HeapType::Eq)
} else if l.peek::<kw::r#struct>() {
} else if l.peek::<kw::r#struct>()? {
parser.parse::<kw::r#struct>()?;
Ok(HeapType::Struct)
} else if l.peek::<kw::array>() {
} else if l.peek::<kw::array>()? {
parser.parse::<kw::array>()?;
Ok(HeapType::Array)
} else if l.peek::<kw::i31>() {
} else if l.peek::<kw::i31>()? {
parser.parse::<kw::i31>()?;
Ok(HeapType::I31)
} else if l.peek::<kw::nofunc>() {
} else if l.peek::<kw::nofunc>()? {
parser.parse::<kw::nofunc>()?;
Ok(HeapType::NoFunc)
} else if l.peek::<kw::noextern>() {
} else if l.peek::<kw::noextern>()? {
parser.parse::<kw::noextern>()?;
Ok(HeapType::NoExtern)
} else if l.peek::<kw::none>() {
} else if l.peek::<kw::none>()? {
parser.parse::<kw::none>()?;
Ok(HeapType::None)
} else if l.peek::<Index>() {
} else if l.peek::<Index>()? {
Ok(HeapType::Index(parser.parse()?))
} else {
Err(l.error())
@ -131,18 +131,18 @@ impl<'a> Parse<'a> for HeapType<'a> {
}
impl<'a> Peek for HeapType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
kw::func::peek(cursor)
|| kw::r#extern::peek(cursor)
|| kw::any::peek(cursor)
|| kw::eq::peek(cursor)
|| kw::r#struct::peek(cursor)
|| kw::array::peek(cursor)
|| kw::i31::peek(cursor)
|| kw::nofunc::peek(cursor)
|| kw::noextern::peek(cursor)
|| kw::none::peek(cursor)
|| (LParen::peek(cursor) && kw::r#type::peek2(cursor))
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(kw::func::peek(cursor)?
|| kw::r#extern::peek(cursor)?
|| kw::any::peek(cursor)?
|| kw::eq::peek(cursor)?
|| kw::r#struct::peek(cursor)?
|| kw::array::peek(cursor)?
|| kw::i31::peek(cursor)?
|| kw::nofunc::peek(cursor)?
|| kw::noextern::peek(cursor)?
|| kw::none::peek(cursor)?
|| (LParen::peek(cursor)? && kw::r#type::peek2(cursor)?))
}
fn display() -> &'static str {
"heaptype"
@ -242,47 +242,47 @@ impl<'a> RefType<'a> {
impl<'a> Parse<'a> for RefType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::funcref>() {
if l.peek::<kw::funcref>()? {
parser.parse::<kw::funcref>()?;
Ok(RefType::func())
} else if l.peek::<kw::anyfunc>() {
} else if l.peek::<kw::anyfunc>()? {
parser.parse::<kw::anyfunc>()?;
Ok(RefType::func())
} else if l.peek::<kw::externref>() {
} else if l.peek::<kw::externref>()? {
parser.parse::<kw::externref>()?;
Ok(RefType::r#extern())
} else if l.peek::<kw::anyref>() {
} else if l.peek::<kw::anyref>()? {
parser.parse::<kw::anyref>()?;
Ok(RefType::any())
} else if l.peek::<kw::eqref>() {
} else if l.peek::<kw::eqref>()? {
parser.parse::<kw::eqref>()?;
Ok(RefType::eq())
} else if l.peek::<kw::structref>() {
} else if l.peek::<kw::structref>()? {
parser.parse::<kw::structref>()?;
Ok(RefType::r#struct())
} else if l.peek::<kw::arrayref>() {
} else if l.peek::<kw::arrayref>()? {
parser.parse::<kw::arrayref>()?;
Ok(RefType::array())
} else if l.peek::<kw::i31ref>() {
} else if l.peek::<kw::i31ref>()? {
parser.parse::<kw::i31ref>()?;
Ok(RefType::i31())
} else if l.peek::<kw::nullfuncref>() {
} else if l.peek::<kw::nullfuncref>()? {
parser.parse::<kw::nullfuncref>()?;
Ok(RefType::nullfuncref())
} else if l.peek::<kw::nullexternref>() {
} else if l.peek::<kw::nullexternref>()? {
parser.parse::<kw::nullexternref>()?;
Ok(RefType::nullexternref())
} else if l.peek::<kw::nullref>() {
} else if l.peek::<kw::nullref>()? {
parser.parse::<kw::nullref>()?;
Ok(RefType::nullref())
} else if l.peek::<LParen>() {
} else if l.peek::<LParen>()? {
parser.parens(|p| {
let mut l = parser.lookahead1();
if l.peek::<kw::r#ref>() {
if l.peek::<kw::r#ref>()? {
p.parse::<kw::r#ref>()?;
let mut nullable = false;
if parser.peek::<kw::null>() {
if parser.peek::<kw::null>()? {
parser.parse::<kw::null>()?;
nullable = true;
}
@ -302,19 +302,19 @@ impl<'a> Parse<'a> for RefType<'a> {
}
impl<'a> Peek for RefType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
kw::funcref::peek(cursor)
|| /* legacy */ kw::anyfunc::peek(cursor)
|| kw::externref::peek(cursor)
|| kw::anyref::peek(cursor)
|| kw::eqref::peek(cursor)
|| kw::structref::peek(cursor)
|| kw::arrayref::peek(cursor)
|| kw::i31ref::peek(cursor)
|| kw::nullfuncref::peek(cursor)
|| kw::nullexternref::peek(cursor)
|| kw::nullref::peek(cursor)
|| (LParen::peek(cursor) && kw::r#ref::peek2(cursor))
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(kw::funcref::peek(cursor)?
|| /* legacy */ kw::anyfunc::peek(cursor)?
|| kw::externref::peek(cursor)?
|| kw::anyref::peek(cursor)?
|| kw::eqref::peek(cursor)?
|| kw::structref::peek(cursor)?
|| kw::arrayref::peek(cursor)?
|| kw::i31ref::peek(cursor)?
|| kw::nullfuncref::peek(cursor)?
|| kw::nullexternref::peek(cursor)?
|| kw::nullref::peek(cursor)?
|| (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?))
}
fn display() -> &'static str {
"reftype"
@ -333,13 +333,13 @@ pub enum StorageType<'a> {
impl<'a> Parse<'a> for StorageType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::i8>() {
if l.peek::<kw::i8>()? {
parser.parse::<kw::i8>()?;
Ok(StorageType::I8)
} else if l.peek::<kw::i16>() {
} else if l.peek::<kw::i16>()? {
parser.parse::<kw::i16>()?;
Ok(StorageType::I16)
} else if l.peek::<ValType>() {
} else if l.peek::<ValType>()? {
Ok(StorageType::Val(parser.parse()?))
} else {
Err(l.error())
@ -358,7 +358,7 @@ pub struct GlobalType<'a> {
impl<'a> Parse<'a> for GlobalType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek2::<kw::r#mut>() {
if parser.peek2::<kw::r#mut>()? {
parser.parens(|p| {
p.parse::<kw::r#mut>()?;
Ok(GlobalType {
@ -387,7 +387,7 @@ pub struct Limits {
impl<'a> Parse<'a> for Limits {
fn parse(parser: Parser<'a>) -> Result<Self> {
let min = parser.parse()?;
let max = if parser.peek::<u32>() {
let max = if parser.peek::<u32>()? {
Some(parser.parse()?)
} else {
None
@ -408,7 +408,7 @@ pub struct Limits64 {
impl<'a> Parse<'a> for Limits64 {
fn parse(parser: Parser<'a>) -> Result<Self> {
let min = parser.parse()?;
let max = if parser.peek::<u64>() {
let max = if parser.peek::<u64>()? {
Some(parser.parse()?)
} else {
None
@ -456,7 +456,7 @@ pub enum MemoryType {
impl<'a> Parse<'a> for MemoryType {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::i64>() {
if parser.peek::<kw::i64>()? {
parser.parse::<kw::i64>()?;
let limits = parser.parse()?;
let shared = parser.parse::<Option<kw::shared>>()?.is_some();
@ -484,10 +484,10 @@ impl<'a> FunctionType<'a> {
fn finish_parse(&mut self, allow_names: bool, parser: Parser<'a>) -> Result<()> {
let mut params = Vec::from(mem::take(&mut self.params));
let mut results = Vec::from(mem::take(&mut self.results));
while parser.peek2::<kw::param>() || parser.peek2::<kw::result>() {
while parser.peek2::<kw::param>()? || parser.peek2::<kw::result>()? {
parser.parens(|p| {
let mut l = p.lookahead1();
if l.peek::<kw::param>() {
if l.peek::<kw::param>()? {
if results.len() > 0 {
return Err(p.error(
"result before parameter (or unexpected token): \
@ -509,7 +509,7 @@ impl<'a> FunctionType<'a> {
while parse_more && !p.is_empty() {
params.push((None, None, p.parse()?));
}
} else if l.peek::<kw::result>() {
} else if l.peek::<kw::result>()? {
p.parse::<kw::result>()?;
while !p.is_empty() {
results.push(p.parse()?);
@ -538,15 +538,15 @@ impl<'a> Parse<'a> for FunctionType<'a> {
}
impl<'a> Peek for FunctionType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
if let Some(next) = cursor.lparen() {
match next.keyword() {
Some(("param", _)) | Some(("result", _)) => return true,
fn peek(cursor: Cursor<'_>) -> Result<bool> {
if let Some(next) = cursor.lparen()? {
match next.keyword()? {
Some(("param", _)) | Some(("result", _)) => return Ok(true),
_ => {}
}
}
false
Ok(false)
}
fn display() -> &'static str {
@ -570,7 +570,7 @@ impl<'a> Parse<'a> for FunctionTypeNoNames<'a> {
}
impl<'a> Peek for FunctionTypeNoNames<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
FunctionType::peek(cursor)
}
@ -596,7 +596,7 @@ impl<'a> Parse<'a> for StructType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut ret = StructType { fields: Vec::new() };
while !parser.is_empty() {
let field = if parser.peek2::<kw::field>() {
let field = if parser.peek2::<kw::field>()? {
parser.parens(|parser| {
parser.parse::<kw::field>()?;
StructField::parse(parser, true)
@ -624,7 +624,7 @@ pub struct StructField<'a> {
impl<'a> StructField<'a> {
fn parse(parser: Parser<'a>, with_id: bool) -> Result<Self> {
let id = if with_id { parser.parse()? } else { None };
let (ty, mutable) = if parser.peek2::<kw::r#mut>() {
let (ty, mutable) = if parser.peek2::<kw::r#mut>()? {
let ty = parser.parens(|parser| {
parser.parse::<kw::r#mut>()?;
parser.parse()
@ -648,7 +648,7 @@ pub struct ArrayType<'a> {
impl<'a> Parse<'a> for ArrayType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let (ty, mutable) = if parser.peek2::<kw::r#mut>() {
let (ty, mutable) = if parser.peek2::<kw::r#mut>()? {
let ty = parser.parens(|parser| {
parser.parse::<kw::r#mut>()?;
parser.parse()
@ -695,13 +695,13 @@ pub enum TypeDef<'a> {
impl<'a> Parse<'a> for TypeDef<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
if l.peek::<kw::func>()? {
parser.parse::<kw::func>()?;
Ok(TypeDef::Func(parser.parse()?))
} else if l.peek::<kw::r#struct>() {
} else if l.peek::<kw::r#struct>()? {
parser.parse::<kw::r#struct>()?;
Ok(TypeDef::Struct(parser.parse()?))
} else if l.peek::<kw::array>() {
} else if l.peek::<kw::array>()? {
parser.parse::<kw::array>()?;
Ok(TypeDef::Array(parser.parse()?))
} else {
@ -729,7 +729,7 @@ pub struct Type<'a> {
}
impl<'a> Peek for Type<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
kw::r#type::peek(cursor)
}
fn display() -> &'static str {
@ -743,19 +743,18 @@ impl<'a> Parse<'a> for Type<'a> {
let id = parser.parse()?;
let name = parser.parse()?;
let (parent, def, final_type) = if parser.peek2::<kw::sub>() {
let (parent, def, final_type) = if parser.peek2::<kw::sub>()? {
parser.parens(|parser| {
parser.parse::<kw::sub>()?;
let final_type: Option<bool> =
if parser.peek::<kw::r#final>() {
let final_type: Option<bool> = if parser.peek::<kw::r#final>()? {
parser.parse::<kw::r#final>()?;
Some(true)
} else {
Some(false)
};
let parent = if parser.peek::<Index<'a>>() {
let parent = if parser.peek::<Index<'a>>()? {
parser.parse()?
} else {
None
@ -791,7 +790,7 @@ impl<'a> Parse<'a> for Rec<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::r#rec>()?.0;
let mut types = Vec::new();
while parser.peek2::<Type<'a>>() {
while parser.peek2::<Type<'a>>()? {
types.push(parser.parens(|p| p.parse())?);
}
Ok(Rec { span, types })
@ -820,7 +819,7 @@ impl<'a, T> TypeUse<'a, T> {
impl<'a, T: Peek + Parse<'a>> Parse<'a> for TypeUse<'a, T> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let index = if parser.peek2::<kw::r#type>() {
let index = if parser.peek2::<kw::r#type>()? {
Some(parser.parens(|p| {
p.parse::<kw::r#type>()?;
p.parse()

View File

@ -33,7 +33,7 @@ static ARGS: &[(&str, fn(Parser<'_>) -> Result<WastArgCore<'_>>)] = {
impl<'a> Parse<'a> for WastArgCore<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let parse = parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if let Some((kw, rest)) = c.keyword()? {
if let Some(i) = ARGS.iter().position(|(name, _)| *name == kw) {
return Ok((ARGS[i].1, rest));
}
@ -45,12 +45,12 @@ impl<'a> Parse<'a> for WastArgCore<'a> {
}
impl Peek for WastArgCore<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let kw = match cursor.keyword() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let kw = match cursor.keyword()? {
Some((kw, _)) => kw,
None => return false,
None => return Ok(false),
};
ARGS.iter().find(|(name, _)| *name == kw).is_some()
Ok(ARGS.iter().find(|(name, _)| *name == kw).is_some())
}
fn display() -> &'static str {
@ -105,7 +105,7 @@ static RETS: &[(&str, fn(Parser<'_>) -> Result<WastRetCore<'_>>)] = {
impl<'a> Parse<'a> for WastRetCore<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let parse = parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if let Some((kw, rest)) = c.keyword()? {
if let Some(i) = RETS.iter().position(|(name, _)| *name == kw) {
return Ok((RETS[i].1, rest));
}
@ -117,12 +117,12 @@ impl<'a> Parse<'a> for WastRetCore<'a> {
}
impl Peek for WastRetCore<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let kw = match cursor.keyword() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let kw = match cursor.keyword()? {
Some((kw, _)) => kw,
None => return false,
None => return Ok(false),
};
RETS.iter().find(|(name, _)| *name == kw).is_some()
Ok(RETS.iter().find(|(name, _)| *name == kw).is_some())
}
fn display() -> &'static str {
@ -144,10 +144,10 @@ where
T: Parse<'a>,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::nan_canonical>() {
if parser.peek::<kw::nan_canonical>()? {
parser.parse::<kw::nan_canonical>()?;
Ok(NanPattern::CanonicalNan)
} else if parser.peek::<kw::nan_arithmetic>() {
} else if parser.peek::<kw::nan_arithmetic>()? {
parser.parse::<kw::nan_arithmetic>()?;
Ok(NanPattern::ArithmeticNan)
} else {
@ -175,7 +175,7 @@ pub enum V128Pattern {
impl<'a> Parse<'a> for V128Pattern {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::i8x16>() {
if l.peek::<kw::i8x16>()? {
parser.parse::<kw::i8x16>()?;
Ok(V128Pattern::I8x16([
parser.parse()?,
@ -195,7 +195,7 @@ impl<'a> Parse<'a> for V128Pattern {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i16x8>() {
} else if l.peek::<kw::i16x8>()? {
parser.parse::<kw::i16x8>()?;
Ok(V128Pattern::I16x8([
parser.parse()?,
@ -207,7 +207,7 @@ impl<'a> Parse<'a> for V128Pattern {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i32x4>() {
} else if l.peek::<kw::i32x4>()? {
parser.parse::<kw::i32x4>()?;
Ok(V128Pattern::I32x4([
parser.parse()?,
@ -215,10 +215,10 @@ impl<'a> Parse<'a> for V128Pattern {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::i64x2>() {
} else if l.peek::<kw::i64x2>()? {
parser.parse::<kw::i64x2>()?;
Ok(V128Pattern::I64x2([parser.parse()?, parser.parse()?]))
} else if l.peek::<kw::f32x4>() {
} else if l.peek::<kw::f32x4>()? {
parser.parse::<kw::f32x4>()?;
Ok(V128Pattern::F32x4([
parser.parse()?,
@ -226,7 +226,7 @@ impl<'a> Parse<'a> for V128Pattern {
parser.parse()?,
parser.parse()?,
]))
} else if l.peek::<kw::f64x2>() {
} else if l.peek::<kw::f64x2>()? {
parser.parse::<kw::f64x2>()?;
Ok(V128Pattern::F64x2([parser.parse()?, parser.parse()?]))
} else {

View File

@ -8,6 +8,12 @@ impl<T: Encode + ?Sized> Encode for &'_ T {
}
}
impl<T: Encode + ?Sized> Encode for Box<T> {
fn encode(&self, e: &mut Vec<u8>) {
T::encode(self, e)
}
}
impl<T: Encode> Encode for [T] {
fn encode(&self, e: &mut Vec<u8>) {
self.len().encode(e);

File diff suppressed because it is too large Load Diff

View File

@ -101,7 +101,7 @@ macro_rules! custom_keyword {
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if let Some((kw, rest)) = c.keyword()? {
if kw == $kw {
return Ok(($name(c.cur_span()), rest));
}
@ -112,12 +112,12 @@ macro_rules! custom_keyword {
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((kw, _rest)) = cursor.keyword() {
fn peek(cursor: $crate::parser::Cursor<'_>) -> $crate::parser::Result<bool> {
Ok(if let Some((kw, _rest)) = cursor.keyword()? {
kw == $kw
} else {
false
}
})
}
fn display() -> &'static str {
@ -168,7 +168,7 @@ macro_rules! custom_reserved {
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((rsv, rest)) = c.reserved() {
if let Some((rsv, rest)) = c.reserved()? {
if rsv == $rsv {
return Ok(($name(c.cur_span()), rest));
}
@ -179,11 +179,11 @@ macro_rules! custom_reserved {
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((rsv, _rest)) = cursor.reserved() {
rsv == $rsv
fn peek(cursor: $crate::parser::Cursor<'_>) -> Result<bool> {
if let Some((rsv, _rest)) = cursor.reserved()? {
Ok(rsv == $rsv)
} else {
false
Ok(false)
}
}
@ -290,7 +290,7 @@ macro_rules! custom_reserved {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// // and here `peek` works and our delegated parsing works because the
/// // annotation has been registered.
/// if parser.peek::<annotation::producer>() {
/// if parser.peek::<annotation::producer>()? {
/// return Ok(ModuleField::Producer(parser.parse()?));
/// }
///
@ -317,8 +317,8 @@ macro_rules! annotation {
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((a, rest)) = c.annotation() {
if a == $annotation {
if let Some((a, rest)) = c.reserved()? {
if a == concat!("@", $annotation) {
return Ok(($name(c.cur_span()), rest));
}
}
@ -328,12 +328,12 @@ macro_rules! annotation {
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((a, _rest)) = cursor.annotation() {
a == $annotation
fn peek(cursor: $crate::parser::Cursor<'_>) -> $crate::parser::Result<bool> {
Ok(if let Some((a, _rest)) = cursor.reserved()? {
a == concat!("@", $annotation)
} else {
false
}
})
}
fn display() -> &'static str {

View File

@ -54,7 +54,7 @@ impl<'a> Namespace<'a> {
if let Some(_prev) = self.names.insert(name, index) {
return Err(Error::new(
name.span(),
format!("duplicate identifier for {}", desc),
format!("duplicate identifier `{}` for {}", name.name(), desc),
));
}
Ok(())

View File

@ -42,7 +42,7 @@
//! // parentheses. The `parens` function here ensures that what we
//! // parse inside of it is surrounded by `(` and `)`.
//! let mut imports = Vec::new();
//! while parser.peek2::<kw::import>() {
//! while parser.peek2::<kw::import>()? {
//! let import = parser.parens(|p| p.parse())?;
//! imports.push(import);
//! }
@ -64,9 +64,10 @@
//! This module is heavily inspired by [`syn`](https://docs.rs/syn) so you can
//! likely also draw inspiration from the excellent examples in the `syn` crate.
use crate::lexer::{Float, Integer, Lexer, Token};
use crate::lexer::{Float, Integer, Lexer, Token, TokenKind};
use crate::token::Span;
use crate::Error;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
@ -120,7 +121,7 @@ pub(crate) const MAX_PARENS_DEPTH: usize = 100;
pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
let parser = buf.parser();
let result = parser.parse()?;
if parser.cursor().advance_token().is_none() {
if parser.cursor().token()?.is_none() {
Ok(result)
} else {
Err(parser.error("extra tokens remaining after parse"))
@ -202,7 +203,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
/// // parentheses. The `parens` function here ensures that what we
/// // parse inside of it is surrounded by `(` and `)`.
/// let mut imports = Vec::new();
/// while parser.peek2::<kw::import>() {
/// while parser.peek2::<kw::import>()? {
/// let import = parser.parens(|p| p.parse())?;
/// imports.push(import);
/// }
@ -243,6 +244,15 @@ pub trait Parse<'a>: Sized {
fn parse(parser: Parser<'a>) -> Result<Self>;
}
impl<'a, T> Parse<'a> for Box<T>
where
T: Parse<'a>,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(Box::new(parser.parse()?))
}
}
/// A trait for types which be used to "peek" to see if they're the next token
/// in an input stream of [`Parser`].
///
@ -264,16 +274,16 @@ pub trait Peek {
/// Returns `true` if [`Parse`] for this type is highly likely to succeed
/// failing no other error conditions happening (like an integer literal
/// being too big).
fn peek(cursor: Cursor<'_>) -> bool;
fn peek(cursor: Cursor<'_>) -> Result<bool>;
/// The same as `peek`, except it checks the token immediately following
/// the current token.
fn peek2(mut cursor: Cursor<'_>) -> bool {
if cursor.advance_token().is_some() {
Self::peek(cursor)
} else {
false
fn peek2(mut cursor: Cursor<'_>) -> Result<bool> {
match cursor.token()? {
Some(token) => cursor.advance_past(&token),
None => return Ok(false),
}
Self::peek(cursor)
}
/// Returns a human-readable name of this token to display when generating
@ -291,24 +301,30 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
/// tokens internally. A `ParseBuffer` only used to pass to the top-level
/// [`parse`] function.
pub struct ParseBuffer<'a> {
// list of tokens from the tokenized source (including whitespace and
// comments), and the second element is how to skip this token, if it can be
// skipped.
tokens: Box<[(Token<'a>, Cell<NextTokenAt>)]>,
input: &'a str,
cur: Cell<usize>,
lexer: Lexer<'a>,
cur: Cell<Position>,
known_annotations: RefCell<HashMap<String, usize>>,
depth: Cell<usize>,
strings: RefCell<Vec<Box<[u8]>>>,
}
#[derive(Copy, Clone, Debug)]
enum NextTokenAt {
/// Haven't computed where the next token is yet.
Unknown,
/// Previously computed the index of the next token.
Index(usize),
/// There is no next token, this is the last token.
Eof,
/// The current position within a `Lexer` that we're at. This simultaneously
/// stores the byte position that the lexer was last positioned at as well as
/// the next significant token.
///
/// Note that "significant" here does not mean that `token` is the next token
/// to be lexed at `offset`. Instead it's the next non-whitespace,
/// non-annotation, non-coment token. This simple cache-of-sorts avoids
/// re-parsing tokens the majority of the time, or at least that's the
/// intention.
///
/// If `token` is set to `None` then it means that either it hasn't been
/// calculated at or the lexer is at EOF. Basically it means go talk to the
/// lexer.
#[derive(Copy, Clone)]
struct Position {
offset: usize,
token: Option<Token>,
}
/// An in-progress parser for the tokens of a WebAssembly text file.
@ -341,7 +357,7 @@ pub struct Lookahead1<'a> {
#[derive(Copy, Clone)]
pub struct Cursor<'a> {
parser: Parser<'a>,
cur: usize,
pos: Position,
}
impl ParseBuffer<'_> {
@ -360,80 +376,100 @@ impl ParseBuffer<'_> {
///
/// Returns an error if `input` fails to lex.
pub fn new_with_lexer(lexer: Lexer<'_>) -> Result<ParseBuffer<'_>> {
let mut tokens = Vec::new();
let input = lexer.input();
for token in lexer {
tokens.push((token?, Cell::new(NextTokenAt::Unknown)));
}
let ret = ParseBuffer {
tokens: tokens.into_boxed_slice(),
cur: Cell::new(0),
Ok(ParseBuffer {
lexer,
depth: Cell::new(0),
input,
cur: Cell::new(Position {
offset: 0,
token: None,
}),
known_annotations: Default::default(),
};
ret.validate_annotations()?;
Ok(ret)
strings: Default::default(),
})
}
fn parser(&self) -> Parser<'_> {
Parser { buf: self }
}
// Validates that all annotations properly parse in that they have balanced
// delimiters. This is required since while parsing we generally skip
// annotations and there's no real opportunity to return a parse error.
fn validate_annotations(&self) -> Result<()> {
use crate::lexer::Token::*;
enum State {
None,
LParen,
Annotation { depth: usize, span: Span },
}
let mut state = State::None;
for token in self.tokens.iter() {
state = match (&token.0, state) {
// From nothing, a `(` starts the search for an annotation
(LParen(_), State::None) => State::LParen,
// ... otherwise in nothing we always preserve that state.
(_, State::None) => State::None,
// If the previous state was an `LParen`, we may have an
// annotation if the next keyword is reserved
(Reserved(s), State::LParen) if s.starts_with('@') && !s.is_empty() => {
let offset = self.input_pos(s);
State::Annotation {
span: Span { offset },
depth: 1,
}
}
// ... otherwise anything after an `LParen` kills the lparen
// state.
(_, State::LParen) => State::None,
// Once we're in an annotation we need to balance parentheses,
// so handle the depth changes.
(LParen(_), State::Annotation { span, depth }) => State::Annotation {
span,
depth: depth + 1,
},
(RParen(_), State::Annotation { depth: 1, .. }) => State::None,
(RParen(_), State::Annotation { span, depth }) => State::Annotation {
span,
depth: depth - 1,
},
// ... and otherwise all tokens are allowed in annotations.
(_, s @ State::Annotation { .. }) => s,
};
}
if let State::Annotation { span, .. } = state {
return Err(Error::new(span, "unclosed annotation".to_string()));
}
Ok(())
/// Stores an owned allocation in this `Parser` to attach the lifetime of
/// the vector to `self`.
///
/// This will return a reference to `s`, but one that's safely rooted in the
/// `Parser`.
fn push_str(&self, s: Vec<u8>) -> &[u8] {
let s = Box::from(s);
let ret = &*s as *const [u8];
self.strings.borrow_mut().push(s);
// This should be safe in that the address of `ret` isn't changing as
// it's on the heap itself. Additionally the lifetime of this return
// value is tied to the lifetime of `self` (nothing is deallocated
// early), so it should be safe to say the two have the same lifetime.
unsafe { &*ret }
}
fn input_pos(&self, src: &str) -> usize {
src.as_ptr() as usize - self.input.as_ptr() as usize
/// Lexes the next "significant" token from the `pos` specified.
///
/// This will skip irrelevant tokens such as whitespace, comments, and
/// unknown annotations.
fn advance_token(&self, mut pos: usize) -> Result<Option<Token>> {
let token = loop {
let token = match self.lexer.parse(&mut pos)? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
// Always skip whitespace and comments.
TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment => {
continue
}
// If an lparen is seen then this may be skipped if it's an
// annotation of the form `(@foo ...)`. In this situation
// everything up to and including the closing rparen is skipped.
//
// Note that the annotation is only skipped if it's an unknown
// annotation as known annotations are specifically registered
// as "someone's gonna parse this".
TokenKind::LParen => {
if let Some(annotation) = self.lexer.annotation(pos) {
match self.known_annotations.borrow().get(annotation) {
Some(0) | None => {
self.skip_annotation(&mut pos)?;
continue;
}
Some(_) => {}
}
}
break token;
}
_ => break token,
}
};
Ok(Some(token))
}
fn skip_annotation(&self, pos: &mut usize) -> Result<()> {
let mut depth = 1;
let span = Span { offset: *pos };
loop {
let token = match self.lexer.parse(pos)? {
Some(token) => token,
None => {
break Err(Error::new(span, "unclosed annotation".to_string()));
}
};
match token.kind {
TokenKind::LParen => depth += 1,
TokenKind::RParen => {
depth -= 1;
if depth == 0 {
break Ok(());
}
}
_ => {}
}
}
}
}
@ -448,18 +484,20 @@ impl<'a> Parser<'a> {
/// Note that if `false` is returned there *may* be more comments. Comments
/// and whitespace are not considered for whether this parser is empty.
pub fn is_empty(self) -> bool {
match self.cursor().advance_token() {
Some(Token::RParen(_)) | None => true,
Some(_) => false, // more tokens to parse!
match self.cursor().token() {
Ok(Some(token)) => matches!(token.kind, TokenKind::RParen),
Ok(None) => true,
Err(_) => false,
}
}
pub(crate) fn has_meaningful_tokens(self) -> bool {
self.buf.tokens[self.cursor().cur..].iter().any(|(t, _)| {
!matches!(
t,
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_)
)
self.buf.lexer.iter(0).any(|t| match t {
Ok(token) => !matches!(
token.kind,
TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment
),
Err(_) => true,
})
}
@ -555,7 +593,7 @@ impl<'a> Parser<'a> {
/// let min = parser.parse()?;
///
/// // ... and then test if there's a second number before parsing
/// let max = if parser.peek::<u32>() {
/// let max = if parser.peek::<u32>()? {
/// Some(parser.parse()?)
/// } else {
/// None
@ -568,30 +606,29 @@ impl<'a> Parser<'a> {
///
/// [spec]: https://webassembly.github.io/spec/core/text/types.html#limits
/// [`Limits`]: crate::core::Limits
pub fn peek<T: Peek>(self) -> bool {
pub fn peek<T: Peek>(self) -> Result<bool> {
T::peek(self.cursor())
}
/// Same as the [`Parser::peek`] method, except checks the next token, not
/// the current token.
pub fn peek2<T: Peek>(self) -> bool {
let mut cursor = self.cursor();
if cursor.advance_token().is_some() {
T::peek(cursor)
} else {
false
}
pub fn peek2<T: Peek>(self) -> Result<bool> {
T::peek2(self.cursor())
}
/// Same as the [`Parser::peek2`] method, except checks the next next token,
/// not the next token.
pub fn peek3<T: Peek>(self) -> bool {
pub fn peek3<T: Peek>(self) -> Result<bool> {
let mut cursor = self.cursor();
if cursor.advance_token().is_some() && cursor.advance_token().is_some() {
T::peek(cursor)
} else {
false
match cursor.token()? {
Some(token) => cursor.advance_past(&token),
None => return Ok(false),
}
match cursor.token()? {
Some(token) => cursor.advance_past(&token),
None => return Ok(false),
}
T::peek(cursor)
}
/// A helper structure to perform a sequence of `peek` operations and if
@ -628,9 +665,9 @@ impl<'a> Parser<'a> {
/// impl<'a> Parse<'a> for Index<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// let mut l = parser.lookahead1();
/// if l.peek::<Id>() {
/// if l.peek::<Id>()? {
/// Ok(Index::Id(parser.parse()?))
/// } else if l.peek::<u32>() {
/// } else if l.peek::<u32>()? {
/// Ok(Index::Num(parser.parse()?))
/// } else {
/// // produces error message of `expected identifier or u32`
@ -698,14 +735,18 @@ impl<'a> Parser<'a> {
self.buf.depth.set(self.buf.depth.get() + 1);
let before = self.buf.cur.get();
let res = self.step(|cursor| {
let mut cursor = match cursor.lparen() {
let mut cursor = match cursor.lparen()? {
Some(rest) => rest,
None => return Err(cursor.error("expected `(`")),
};
cursor.parser.buf.cur.set(cursor.cur);
cursor.parser.buf.cur.set(cursor.pos);
let result = f(cursor.parser)?;
cursor.cur = cursor.parser.buf.cur.get();
match cursor.rparen() {
// Reset our cursor's state to whatever the current state of the
// parser is.
cursor.pos = cursor.parser.buf.cur.get();
match cursor.rparen()? {
Some(rest) => Ok((result, rest)),
None => Err(cursor.error("expected `)`")),
}
@ -737,7 +778,7 @@ impl<'a> Parser<'a> {
fn cursor(self) -> Cursor<'a> {
Cursor {
parser: self,
cur: self.buf.cur.get(),
pos: self.buf.cur.get(),
}
}
@ -752,7 +793,7 @@ impl<'a> Parser<'a> {
F: FnOnce(Cursor<'a>) -> Result<(T, Cursor<'a>)>,
{
let (result, cursor) = f(self.cursor())?;
self.buf.cur.set(cursor.cur);
self.buf.cur.set(cursor.pos);
Ok(result)
}
@ -769,7 +810,7 @@ impl<'a> Parser<'a> {
/// Creates an error whose line/column information is pointing at the
/// given span.
pub fn error_at(self, span: Span, msg: impl fmt::Display) -> Error {
Error::parse(span, self.buf.input, msg.to_string())
Error::parse(span, self.buf.lexer.input(), msg.to_string())
}
/// Returns the span of the current token
@ -902,7 +943,7 @@ impl<'a> Parser<'a> {
/// // annotation with the parser we known that `peek` methods like
/// // this, working on the annotation token, are enabled to ever
/// // return `true`.
/// if parser.peek::<annotation::custom>() {
/// if parser.peek::<annotation::custom>()? {
/// return Ok(ModuleField::Custom(parser.parse()?));
/// }
///
@ -943,9 +984,10 @@ impl<'a> Cursor<'a> {
///
/// Does not take into account whitespace or comments.
pub fn cur_span(&self) -> Span {
let offset = match self.clone().advance_token() {
Some(t) => self.parser.buf.input_pos(t.src()),
None => self.parser.buf.input.len(),
let offset = match self.token() {
Ok(Some(t)) => t.offset,
Ok(None) => self.parser.buf.lexer.input().len(),
Err(_) => self.pos.offset,
};
Span { offset }
}
@ -954,10 +996,14 @@ impl<'a> Cursor<'a> {
///
/// Does not take into account whitespace or comments.
pub(crate) fn prev_span(&self) -> Option<Span> {
let (token, _) = self.parser.buf.tokens.get(self.cur.checked_sub(1)?)?;
// TODO
Some(Span {
offset: self.parser.buf.input_pos(token.src()),
offset: self.pos.offset,
})
// let (token, _) = self.parser.buf.tokens.get(self.cur.checked_sub(1)?)?;
// Some(Span {
// offset: token.offset,
// })
}
/// Same as [`Parser::error`], but works with the current token in this
@ -966,6 +1012,94 @@ impl<'a> Cursor<'a> {
self.parser.error_at(self.cur_span(), msg)
}
/// Tests whether the next token is an lparen
pub fn peek_lparen(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::LParen,
..
})
))
}
/// Tests whether the next token is an rparen
pub fn peek_rparen(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::RParen,
..
})
))
}
/// Tests whether the next token is an id
pub fn peek_id(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::Id,
..
})
))
}
/// Tests whether the next token is reserved
pub fn peek_reserved(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::Reserved,
..
})
))
}
/// Tests whether the next token is a keyword
pub fn peek_keyword(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::Keyword,
..
})
))
}
/// Tests whether the next token is an integer
pub fn peek_integer(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::Integer(_),
..
})
))
}
/// Tests whether the next token is a float
pub fn peek_float(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::Float(_),
..
})
))
}
/// Tests whether the next token is a string
pub fn peek_string(self) -> Result<bool> {
Ok(matches!(
self.token()?,
Some(Token {
kind: TokenKind::String,
..
})
))
}
/// Attempts to advance this cursor if the current token is a `(`.
///
/// If the current token is `(`, returns a new [`Cursor`] pointing at the
@ -973,11 +1107,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn lparen(mut self) -> Option<Self> {
match self.advance_token()? {
Token::LParen(_) => Some(self),
_ => None,
pub fn lparen(mut self) -> Result<Option<Self>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::LParen => {}
_ => return Ok(None),
}
self.advance_past(&token);
Ok(Some(self))
}
/// Attempts to advance this cursor if the current token is a `)`.
@ -987,11 +1127,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn rparen(mut self) -> Option<Self> {
match self.advance_token()? {
Token::RParen(_) => Some(self),
_ => None,
pub fn rparen(mut self) -> Result<Option<Self>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::RParen => {}
_ => return Ok(None),
}
self.advance_past(&token);
Ok(Some(self))
}
/// Attempts to advance this cursor if the current token is a
@ -1003,11 +1149,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn id(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Id(id) => Some((&id[1..], self)),
_ => None,
pub fn id(mut self) -> Result<Option<(&'a str, Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::Id => {}
_ => return Ok(None),
}
self.advance_past(&token);
Ok(Some((token.id(self.parser.buf.lexer.input()), self)))
}
/// Attempts to advance this cursor if the current token is a
@ -1019,11 +1171,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn keyword(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Keyword(id) => Some((id, self)),
_ => None,
pub fn keyword(mut self) -> Result<Option<(&'a str, Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::Keyword => {}
_ => return Ok(None),
}
self.advance_past(&token);
Ok(Some((token.keyword(self.parser.buf.lexer.input()), self)))
}
/// Attempts to advance this cursor if the current token is a
@ -1035,11 +1193,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn reserved(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Reserved(id) => Some((id, self)),
_ => None,
pub fn reserved(mut self) -> Result<Option<(&'a str, Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::Reserved => {}
_ => return Ok(None),
}
self.advance_past(&token);
Ok(Some((token.reserved(self.parser.buf.lexer.input()), self)))
}
/// Attempts to advance this cursor if the current token is a
@ -1051,11 +1215,20 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn integer(mut self) -> Option<(&'a Integer<'a>, Self)> {
match self.advance_token()? {
Token::Integer(i) => Some((i, self)),
_ => None,
}
pub fn integer(mut self) -> Result<Option<(Integer<'a>, Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
let i = match token.kind {
TokenKind::Integer(i) => i,
_ => return Ok(None),
};
self.advance_past(&token);
Ok(Some((
token.integer(self.parser.buf.lexer.input(), i),
self,
)))
}
/// Attempts to advance this cursor if the current token is a
@ -1067,11 +1240,17 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn float(mut self) -> Option<(&'a Float<'a>, Self)> {
match self.advance_token()? {
Token::Float(f) => Some((f, self)),
_ => None,
}
pub fn float(mut self) -> Result<Option<(Float<'a>, Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
let f = match token.kind {
TokenKind::Float(f) => f,
_ => return Ok(None),
};
self.advance_past(&token);
Ok(Some((token.float(self.parser.buf.lexer.input(), f), self)))
}
/// Attempts to advance this cursor if the current token is a
@ -1083,42 +1262,21 @@ impl<'a> Cursor<'a> {
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
pub fn string(mut self) -> Option<(&'a [u8], Self)> {
match self.advance_token()? {
Token::String(s) => Some((s.val(), self)),
_ => None,
}
}
/// Attempts to advance this cursor if the current token is a
/// [`Token::Reserved`](crate::lexer::Token) and looks like the start of an
/// annotation.
///
/// [Annotations][annotation] are a WebAssembly proposal for the text format
/// which allows placing structured text inside of a text file, for example
/// to specify the name section or other custom sections.
///
/// This function will attempt to see if the current token is the `@foo`
/// part of the annotation. This requires the previous token to be `(` and
/// the current token is `Reserved` which starts with `@` and has a nonzero
/// length for the following name.
///
/// Note that this will skip *unknown* annotations. Only pre-registered
/// annotations will be returned here.
///
/// This function will automatically skip over any comments, whitespace, or
/// unknown annotations.
///
/// [annotation]: https://github.com/WebAssembly/annotations
pub fn annotation(self) -> Option<(&'a str, Self)> {
let (token, cursor) = self.reserved()?;
if !token.starts_with('@') || token.len() <= 1 {
return None;
}
match &self.parser.buf.tokens.get(self.cur.wrapping_sub(1))?.0 {
Token::LParen(_) => Some((&token[1..], cursor)),
_ => None,
pub fn string(mut self) -> Result<Option<(&'a [u8], Self)>> {
let token = match self.token()? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::String => {}
_ => return Ok(None),
}
let string = match token.string(self.parser.buf.lexer.input()) {
Cow::Borrowed(s) => s,
Cow::Owned(s) => self.parser.buf.push_str(s),
};
self.advance_past(&token);
Ok(Some((string, self)))
}
/// Attempts to advance this cursor if the current token is a
@ -1126,133 +1284,42 @@ impl<'a> Cursor<'a> {
/// [`Token::BlockComment`](crate::lexer::Token)
///
/// This function will only skip whitespace, no other tokens.
pub fn comment(mut self) -> Option<(&'a str, Self)> {
pub fn comment(mut self) -> Result<Option<(&'a str, Self)>> {
let start = self.pos.offset;
self.pos.token = None;
let comment = loop {
match &self.parser.buf.tokens.get(self.cur)?.0 {
Token::LineComment(c) | Token::BlockComment(c) => {
self.cur += 1;
break c;
let token = match self.parser.buf.lexer.parse(&mut self.pos.offset)? {
Some(token) => token,
None => return Ok(None),
};
match token.kind {
TokenKind::LineComment | TokenKind::BlockComment => {
break token.src(self.parser.buf.lexer.input());
}
Token::Whitespace(_) => {
self.cur += 1;
TokenKind::Whitespace => {}
_ => {
self.pos.offset = start;
return Ok(None);
}
_ => return None,
}
};
Some((comment, self))
Ok(Some((comment, self)))
}
fn advance_token(&mut self) -> Option<&'a Token<'a>> {
let known_annotations = self.parser.buf.known_annotations.borrow();
let is_known_annotation = |name: &str| match known_annotations.get(name) {
Some(0) | None => false,
Some(_) => true,
};
loop {
let (token, next) = self.parser.buf.tokens.get(self.cur)?;
// If we're currently pointing at a token, and it's not the start
// of an annotation, then we return that token and advance
// ourselves to just after that token.
match token {
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => {}
_ => match self.annotation_start() {
Some(n) if !is_known_annotation(n) => {}
_ => {
self.cur += 1;
return Some(token);
}
},
}
// ... otherwise we need to skip the current token, and possibly
// more. Here we're skipping whitespace, comments, annotations, etc.
// Basically stuff that's intended to not be that relevant to the
// text format. This is a pretty common operation, though, and we
// may do it multiple times through peeks and such. As a result
// this is somewhat cached.
//
// The `next` field, if "unknown", means we haven't calculated the
// next token. Otherwise it's an index of where to resume searching
// for the next token.
//
// Note that this entire operation happens in a loop (hence the
// "somewhat cached") because the set of known annotations is
// dynamic and we can't cache which annotations are skipped. What we
// can do though is cache the number of tokens in the annotation so
// we know how to skip ahead of it.
match next.get() {
NextTokenAt::Unknown => match self.find_next() {
Some(i) => {
next.set(NextTokenAt::Index(i));
self.cur = i;
}
None => {
next.set(NextTokenAt::Eof);
return None;
}
},
NextTokenAt::Eof => return None,
NextTokenAt::Index(i) => self.cur = i,
}
fn token(&self) -> Result<Option<Token>> {
match self.pos.token {
Some(token) => Ok(Some(token)),
None => self.parser.buf.advance_token(self.pos.offset),
}
}
fn annotation_start(&self) -> Option<&'a str> {
match self.parser.buf.tokens.get(self.cur).map(|p| &p.0) {
Some(Token::LParen(_)) => {}
_ => return None,
}
let reserved = match self.parser.buf.tokens.get(self.cur + 1).map(|p| &p.0) {
Some(Token::Reserved(n)) => n,
_ => return None,
};
if reserved.starts_with('@') && reserved.len() > 1 {
Some(&reserved[1..])
} else {
None
}
}
/// Finds the next "real" token from the current position onwards.
///
/// This is a somewhat expensive operation to call quite a lot, so it's
/// cached in the token list. See the comment above in `advance_token` for
/// how this works.
///
/// Returns the index of the next relevant token to parse
fn find_next(mut self) -> Option<usize> {
// If we're pointing to the start of annotation we need to skip it
// in its entirety, so match the parentheses and figure out where
// the annotation ends.
if self.annotation_start().is_some() {
let mut depth = 1;
self.cur += 1;
while depth > 0 {
match &self.parser.buf.tokens.get(self.cur)?.0 {
Token::LParen(_) => depth += 1,
Token::RParen(_) => depth -= 1,
_ => {}
}
self.cur += 1;
}
return Some(self.cur);
}
// ... otherwise we're pointing at whitespace/comments, so we need to
// figure out how many of them we can skip.
loop {
let (token, _) = self.parser.buf.tokens.get(self.cur)?;
// and otherwise we skip all comments/whitespace and only
// get interested once a normal `Token` pops up.
match token {
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => {
self.cur += 1
}
_ => return Some(self.cur),
}
}
fn advance_past(&mut self, token: &Token) {
self.pos.offset = token.offset + (token.len as usize);
self.pos.token = self
.parser
.buf
.advance_token(self.pos.offset)
.unwrap_or(None);
}
}
@ -1261,13 +1328,13 @@ impl Lookahead1<'_> {
/// [`Lookahead1`] references.
///
/// For more information see [`Parser::lookahead1`] and [`Parser::peek`]
pub fn peek<T: Peek>(&mut self) -> bool {
if self.parser.peek::<T>() {
pub fn peek<T: Peek>(&mut self) -> Result<bool> {
Ok(if self.parser.peek::<T>()? {
true
} else {
self.attempts.push(T::display());
false
}
})
}
/// Generates an error message saying that one of the tokens passed to
@ -1306,7 +1373,7 @@ impl Lookahead1<'_> {
impl<'a, T: Peek + Parse<'a>> Parse<'a> for Option<T> {
fn parse(parser: Parser<'a>) -> Result<Option<T>> {
if parser.peek::<T>() {
if parser.peek::<T>()? {
Ok(Some(parser.parse()?))
} else {
Ok(None)

View File

@ -3,7 +3,7 @@
//! contexts too perhaps).
use crate::annotation;
use crate::lexer::FloatVal;
use crate::lexer::Float;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use std::fmt;
use std::hash::{Hash, Hasher};
@ -105,7 +105,7 @@ impl<'a> Eq for Id<'a> {}
impl<'a> Parse<'a> for Id<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.step(|c| {
if let Some((name, rest)) = c.id() {
if let Some((name, rest)) = c.id()? {
return Ok((Id::new(name, c.cur_span()), rest));
}
Err(c.error("expected an identifier"))
@ -124,8 +124,8 @@ impl fmt::Debug for Id<'_> {
}
impl Peek for Id<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.id().is_some()
fn peek(cursor: Cursor<'_>) -> Result<bool> {
cursor.peek_id()
}
fn display() -> &'static str {
@ -167,21 +167,22 @@ impl Index<'_> {
impl<'a> Parse<'a> for Index<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<Id>() {
if parser.peek::<Id>()? {
Ok(Index::Id(parser.parse()?))
} else if l.peek::<u32>() {
} else if parser.peek::<u32>()? {
let (val, span) = parser.parse()?;
Ok(Index::Num(val, span))
} else {
Err(l.error())
Err(parser.error(format!(
"unexpected token, expected an index or an identifier"
)))
}
}
}
impl Peek for Index<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
u32::peek(cursor) || Id::peek(cursor)
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(u32::peek(cursor)? || Id::peek(cursor)?)
}
fn display() -> &'static str {
@ -241,10 +242,10 @@ impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
}
impl<'a, K: Peek> Peek for ItemRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
match cursor.lparen() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
match cursor.lparen()? {
Some(remaining) => K::peek(remaining),
None => false,
None => Ok(false),
}
}
@ -270,8 +271,7 @@ impl<'a> Parse<'a> for NameAnnotation<'a> {
impl<'a> Parse<'a> for Option<NameAnnotation<'a>> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let _r = parser.register_annotation("name");
Ok(if parser.peek2::<annotation::name>() {
Ok(if parser.peek2::<annotation::name>()? {
Some(parser.parens(|p| p.parse())?)
} else {
None
@ -290,7 +290,7 @@ macro_rules! integers {
impl<'a> Parse<'a> for ($i, Span) {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.step(|c| {
if let Some((i, rest)) = c.integer() {
if let Some((i, rest)) = c.integer()? {
let (s, base) = i.val();
let val = $i::from_str_radix(s, base)
.or_else(|_| {
@ -311,8 +311,8 @@ macro_rules! integers {
}
impl Peek for $i {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.integer().is_some()
fn peek(cursor: Cursor<'_>) -> Result<bool> {
cursor.peek_integer()
}
fn display() -> &'static str {
@ -330,7 +330,7 @@ integers! {
impl<'a> Parse<'a> for &'a [u8] {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.step(|c| {
if let Some((i, rest)) = c.string() {
if let Some((i, rest)) = c.string()? {
return Ok((i, rest));
}
Err(c.error("expected a string"))
@ -339,8 +339,8 @@ impl<'a> Parse<'a> for &'a [u8] {
}
impl Peek for &'_ [u8] {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.string().is_some()
fn peek(cursor: Cursor<'_>) -> Result<bool> {
cursor.peek_string()
}
fn display() -> &'static str {
@ -362,7 +362,7 @@ impl Parse<'_> for String {
}
impl Peek for &'_ str {
fn peek(cursor: Cursor<'_>) -> bool {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
<&[u8]>::peek(cursor)
}
@ -388,12 +388,12 @@ macro_rules! float {
impl<'a> Parse<'a> for $name {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.step(|c| {
let (val, rest) = if let Some((f, rest)) = c.float() {
($parse(f.val()), rest)
} else if let Some((i, rest)) = c.integer() {
let (val, rest) = if let Some((f, rest)) = c.float()? {
($parse(&f), rest)
} else if let Some((i, rest)) = c.integer()? {
let (s, base) = i.val();
(
$parse(&FloatVal::Val {
$parse(&Float::Val {
hex: base == 16,
integral: s.into(),
decimal: None,
@ -412,7 +412,7 @@ macro_rules! float {
}
}
fn $parse(val: &FloatVal<'_>) -> Option<$int> {
fn $parse(val: &Float<'_>) -> Option<$int> {
// Compute a few well-known constants about the float representation
// given the parameters to the macro here.
let width = std::mem::size_of::<$int>() * 8;
@ -425,7 +425,7 @@ macro_rules! float {
let (hex, integral, decimal, exponent_str) = match val {
// Infinity is when the exponent bits are all set and
// the significand is zero.
FloatVal::Inf { negative } => {
Float::Inf { negative } => {
let exp_bits = (1 << $exp_bits) - 1;
let neg_bit = *negative as $int;
return Some(
@ -437,10 +437,13 @@ macro_rules! float {
// NaN is when the exponent bits are all set and
// the significand is nonzero. The default of NaN is
// when only the highest bit of the significand is set.
FloatVal::Nan { negative, val } => {
Float::Nan { negative, val } => {
let exp_bits = (1 << $exp_bits) - 1;
let neg_bit = *negative as $int;
let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int;
let signif = match val {
Some(val) => $int::from_str_radix(val,16).ok()?,
None => 1 << (signif_bits - 1),
};
// If the significand is zero then this is actually infinity
// so we fail to parse it.
if signif & signif_mask == 0 {
@ -454,7 +457,7 @@ macro_rules! float {
}
// This is trickier, handle this below
FloatVal::Val { hex, integral, decimal, exponent } => {
Float::Val { hex, integral, decimal, exponent } => {
(hex, integral, decimal, exponent)
}
};
@ -645,8 +648,8 @@ pub struct LParen {
}
impl Peek for LParen {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.lparen().is_some()
fn peek(cursor: Cursor<'_>) -> Result<bool> {
cursor.peek_lparen()
}
fn display() -> &'static str {
@ -663,7 +666,7 @@ mod tests {
($a:tt p $e:tt) => (f!(@mk $a, None, Some($e.into())));
($a:tt . $b:tt) => (f!(@mk $a, Some($b.into()), None));
($a:tt . $b:tt p $e:tt) => (f!(@mk $a, Some($b.into()), Some($e.into())));
(@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::FloatVal::Val {
(@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::Float::Val {
hex: true,
integral: $a.into(),
decimal: $b,

View File

@ -22,7 +22,7 @@ impl<'a> Parse<'a> for Wast<'a> {
// If it looks like a directive token is in the stream then we parse a
// bunch of directives, otherwise assume this is an inline module.
if parser.peek2::<WastDirectiveToken>() {
if parser.peek2::<WastDirectiveToken>()? {
while !parser.is_empty() {
directives.push(parser.parens(|p| p.parse())?);
}
@ -37,16 +37,16 @@ impl<'a> Parse<'a> for Wast<'a> {
struct WastDirectiveToken;
impl Peek for WastDirectiveToken {
fn peek(cursor: Cursor<'_>) -> bool {
let kw = match cursor.keyword() {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
let kw = match cursor.keyword()? {
Some((kw, _)) => kw,
None => return false,
None => return Ok(false),
};
kw.starts_with("assert_")
Ok(kw.starts_with("assert_")
|| kw == "module"
|| kw == "component"
|| kw == "register"
|| kw == "invoke"
|| kw == "invoke")
}
fn display() -> &'static str {
@ -128,39 +128,39 @@ impl WastDirective<'_> {
impl<'a> Parse<'a> for WastDirective<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::module>() || l.peek::<kw::component>() {
if l.peek::<kw::module>()? || l.peek::<kw::component>()? {
Ok(WastDirective::Wat(parser.parse()?))
} else if l.peek::<kw::assert_malformed>() {
} else if l.peek::<kw::assert_malformed>()? {
let span = parser.parse::<kw::assert_malformed>()?.0;
Ok(WastDirective::AssertMalformed {
span,
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_invalid>() {
} else if l.peek::<kw::assert_invalid>()? {
let span = parser.parse::<kw::assert_invalid>()?.0;
Ok(WastDirective::AssertInvalid {
span,
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::register>() {
} else if l.peek::<kw::register>()? {
let span = parser.parse::<kw::register>()?.0;
Ok(WastDirective::Register {
span,
name: parser.parse()?,
module: parser.parse()?,
})
} else if l.peek::<kw::invoke>() {
} else if l.peek::<kw::invoke>()? {
Ok(WastDirective::Invoke(parser.parse()?))
} else if l.peek::<kw::assert_trap>() {
} else if l.peek::<kw::assert_trap>()? {
let span = parser.parse::<kw::assert_trap>()?.0;
Ok(WastDirective::AssertTrap {
span,
exec: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_return>() {
} else if l.peek::<kw::assert_return>()? {
let span = parser.parse::<kw::assert_return>()?.0;
let exec = parser.parens(|p| p.parse())?;
let mut results = Vec::new();
@ -172,21 +172,21 @@ impl<'a> Parse<'a> for WastDirective<'a> {
exec,
results,
})
} else if l.peek::<kw::assert_exhaustion>() {
} else if l.peek::<kw::assert_exhaustion>()? {
let span = parser.parse::<kw::assert_exhaustion>()?.0;
Ok(WastDirective::AssertExhaustion {
span,
call: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_unlinkable>() {
} else if l.peek::<kw::assert_unlinkable>()? {
let span = parser.parse::<kw::assert_unlinkable>()?.0;
Ok(WastDirective::AssertUnlinkable {
span,
module: parser.parens(parse_wat)?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_exception>() {
} else if l.peek::<kw::assert_exception>()? {
let span = parser.parse::<kw::assert_exception>()?.0;
Ok(WastDirective::AssertException {
span,
@ -212,11 +212,11 @@ pub enum WastExecute<'a> {
impl<'a> Parse<'a> for WastExecute<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::invoke>() {
if l.peek::<kw::invoke>()? {
Ok(WastExecute::Invoke(parser.parse()?))
} else if l.peek::<kw::module>() || l.peek::<kw::component>() {
} else if l.peek::<kw::module>()? || l.peek::<kw::component>()? {
Ok(WastExecute::Wat(parse_wat(parser)?))
} else if l.peek::<kw::get>() {
} else if l.peek::<kw::get>()? {
parser.parse::<kw::get>()?;
Ok(WastExecute::Get {
module: parser.parse()?,
@ -235,7 +235,7 @@ fn parse_wat(parser: Parser) -> Result<Wat> {
// 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::<kw::component>() {
if parser.peek::<kw::component>()? {
Ok(Wat::Component(parser.parse()?))
} else {
Ok(Wat::Module(parser.parse()?))
@ -308,8 +308,8 @@ impl QuoteWat<'_> {
impl<'a> Parse<'a> for QuoteWat<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek2::<kw::quote>() {
let ctor = if parser.peek::<kw::component>() {
if parser.peek2::<kw::quote>()? {
let ctor = if parser.peek::<kw::component>()? {
parser.parse::<kw::component>()?;
QuoteWat::QuoteComponent
} else {
@ -339,7 +339,7 @@ pub enum WastArg<'a> {
impl<'a> Parse<'a> for WastArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<WastArgCore<'_>>() {
if parser.peek::<WastArgCore<'_>>()? {
Ok(WastArg::Core(parser.parse()?))
} else {
Ok(WastArg::Component(parser.parse()?))
@ -356,7 +356,7 @@ pub enum WastRet<'a> {
impl<'a> Parse<'a> for WastRet<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<WastRetCore<'_>>() {
if parser.peek::<WastRetCore<'_>>()? {
Ok(WastRet::Core(parser.parse()?))
} else {
Ok(WastRet::Component(parser.parse()?))

View File

@ -41,9 +41,11 @@ impl<'a> Parse<'a> for Wat<'a> {
}
let _r = parser.register_annotation("custom");
let wat = if parser.peek2::<kw::module>() {
let _r = parser.register_annotation("producers");
let _r = parser.register_annotation("name");
let wat = if parser.peek2::<kw::module>()? {
Wat::Module(parser.parens(|parser| parser.parse())?)
} else if parser.peek2::<kw::component>() {
} else if parser.peek2::<kw::component>()? {
Wat::Component(parser.parens(|parser| parser.parse())?)
} else {
let fields = ModuleField::parse_remaining(parser)?;

View File

@ -9,7 +9,7 @@ impl<'a> Parse<'a> for Comments<'a> {
let comments = parser.step(|mut cursor| {
let mut comments = Vec::new();
loop {
let (comment, c) = match cursor.comment() {
let (comment, c) = match cursor.comment()? {
Some(pair) => pair,
None => break,
};