Bug 1770081 - Update wat/wast rust libraries. r=rhunt,glandium

wat syntax change/fixes:

    remove data "passive"
    fix table.copy
    misc call_indirect fixes

Differential Revision: https://phabricator.services.mozilla.com/D146863
This commit is contained in:
Yury Delendik 2022-06-07 20:29:20 +00:00
Родитель f42205257e
Коммит 94d55a2495
63 изменённых файлов: 5550 добавлений и 3053 удалений

8
Cargo.lock сгенерированный
Просмотреть файл

@ -5846,9 +5846,9 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65"
[[package]]
name = "wast"
version = "39.0.0"
version = "41.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9bbbd53432b267421186feee3e52436531fa69a7cfee9403f5204352df3dd05"
checksum = "f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870"
dependencies = [
"leb128",
"memchr",
@ -5857,9 +5857,9 @@ dependencies = [
[[package]]
name = "wat"
version = "1.0.41"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab98ed25494f97c69f28758617f27c3e92e5336040b5c3a14634f2dd3fe61830"
checksum = "48b3b9b3e39e66c7fd3f8be785e74444d216260f491e93369e317ed6482ff80f"
dependencies = [
"wast",
]

Просмотреть файл

@ -26,6 +26,7 @@
`(module
(import "m" "exn" (tag $exn))
(tag $localExn (param i32))
(type $t (func))
(import "m" "tab" (table $importTable 2 funcref))
(import "m" "throwsExn" (func $importFuncThrowsExn))
(memory $mem (data "foo"))
@ -65,11 +66,11 @@
["(call $anotherLocalFuncThrowsExn)",
"(call $importFuncThrowsExn)",
// Calls $localFuncThrowsExn.
"(call_indirect (table $localTable) (i32.const 0))",
"(call_indirect $localTable (type $t) (i32.const 0))",
// Calls $importFuncThrowsExn.
"(call_indirect (table $localTable) (i32.const 1))",
"(call_indirect $localTable (type $t) (i32.const 1))",
// Calls non exported function of the exports module $anotherThrowsExn.
"(call_indirect (table $importTable) (i32.const 0))"];
"(call_indirect $importTable (type $t) (i32.const 0))"];
for (let callInstruction of callInstructions) {
testMemoryAfterCall(callInstruction);

Просмотреть файл

@ -16,7 +16,7 @@ for ( let [pages,maxpages] of [[pages_vanilla, pages_vanilla+100],
(memory (export "mem") ${pages} ${maxpages})
(data (i32.const ${(pages-5)*pagesz}) "yabbadabbado")
(data $flintstone passive "yabbadabbado")
(data $flintstone "yabbadabbado")
(func (export "get_constaddr") (result i32)
(i32.load (i32.const ${pages*pagesz-4})))

Просмотреть файл

@ -498,7 +498,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
(module
(data $d passive "01234")
(data $d "01234")
(func (param i32 i32)
(memory.init $d (local.get 0) (local.get 1))))`)),
WebAssembly.CompileError,

Просмотреть файл

@ -134,7 +134,7 @@ for (let [memType, ptrType] of memTypes ) {
assertEq(WebAssembly.validate(wasmTextToBinary(`
(module
(memory ${memType} 1)
(data $seg passive "0123456789abcdef")
(data $seg "0123456789abcdef")
(func (param $p ${ptrType})
(drop (${ptrType}.add (${ptrType}.const 1) (memory.size)))
(drop (${ptrType}.add (${ptrType}.const 1) (memory.grow (${ptrType}.const 1))))
@ -1435,7 +1435,7 @@ function makeModule(initial, maximum, shared) {
(module
(memory (export "mem") i64 ${initial} ${maximum} ${shared})
(data $seg passive "0123456789")
(data $seg "0123456789")
(func (export "size") (result i64)
memory.size)

Просмотреть файл

@ -12,7 +12,7 @@ for (let shared of ['', 'shared']) {
var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
(module
(memory (export "mem") i64 65537 65537 ${shared})
(data $d passive "${S}")
(data $d "${S}")
(func (export "f") (param $p i64) (param $o i32) (param $n i32)
(memory.init $d (local.get $p) (local.get $o) (local.get $n))))`)));
} catch (e) {

Просмотреть файл

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

Просмотреть файл

@ -27,7 +27,7 @@ var ins = wasmEvalText(`
(func (export "wasm2import") (result i32)
(call $g))
(func (export "wasmIndirect") (result i32)
(call_indirect (type $ty) $t (i32.const 0)))
(call_indirect $t (type $ty) (i32.const 0)))
(func (export "instanceCall") (result i32)
(memory.size))
)`, {'':{'wasm2import': function() {}}});

Просмотреть файл

@ -22,5 +22,5 @@ gluesmith = ['jsrust_shared/gluesmith']
jsrust_shared = { path = "./shared" }
# Workaround for https://github.com/rust-lang/rust/issues/58393
mozglue-static = { path = "../../../mozglue/static/rust" }
wat = { version = "1.0.39" }
wat = { version = "1.0.43" }
wasmparser = { version = "0.78.2" }

2
third_party/rust/wast/.cargo-checksum.json поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

11
third_party/rust/wast/Cargo.toml поставляемый
Просмотреть файл

@ -10,20 +10,24 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
edition = "2021"
name = "wast"
version = "39.0.0"
version = "41.0.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
description = "Customizable Rust parsers for the WebAssembly Text formats WAT and WAST\n"
description = """
Customizable Rust parsers for the WebAssembly Text formats WAT and WAST
"""
homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast"
documentation = "https://docs.rs/wast"
readme = "README.md"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast"
resolver = "2"
[[test]]
name = "parse-fail"
harness = false
[dependencies.leb128]
version = "0.2"
@ -32,6 +36,7 @@ version = "2.4.1"
[dependencies.unicode-width]
version = "0.1.9"
[dev-dependencies.anyhow]
version = "1.0"

Просмотреть файл

@ -1,10 +1,13 @@
use crate::ast::{kw, Float32, Float64, Index, HeapType};
use crate::core::HeapType;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Float32, Float64, Index};
/// An expression that is valid inside an `assert_return` directive.
///
/// As of https://github.com/WebAssembly/spec/pull/1104, spec tests may include `assert_return`
/// directives that allow NaN patterns (`"nan:canonical"`, `"nan:arithmetic"`). Parsing an
/// As of <https://github.com/WebAssembly/spec/pull/1104>, spec tests may
/// include `assert_return` directives that allow NaN patterns
/// (`"nan:canonical"`, `"nan:arithmetic"`). Parsing an
/// `AssertExpression` means that:
/// - only constant values (e.g. `i32.const 4`) are used in the `assert_return` directive
/// - the NaN patterns are allowed (they are not allowed in regular `Expression`s).

60
third_party/rust/wast/src/ast/alias.rs поставляемый
Просмотреть файл

@ -1,60 +0,0 @@
use crate::ast::{self, kw};
use crate::parser::{Parse, Parser, Result};
/// An `alias` statement used to juggle indices with nested modules.
#[derive(Debug)]
pub struct Alias<'a> {
/// Where this `alias` was defined.
pub span: ast::Span,
/// An identifier that this alias is resolved with (optionally) for name
/// resolution.
pub id: Option<ast::Id<'a>>,
/// An optional name for this alias stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
/// The source of this alias.
pub source: AliasSource<'a>,
/// The kind of item that's being aliased.
pub kind: ast::ExportKind,
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum AliasSource<'a> {
InstanceExport {
instance: ast::ItemRef<'a, kw::instance>,
export: &'a str,
},
Outer {
/// The index of the module that this reference is referring to.
module: ast::Index<'a>,
/// The index of the item within `module` that this alias is referering
/// to.
index: ast::Index<'a>,
},
}
impl<'a> Parse<'a> for Alias<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::alias>()?.0;
let source = if parser.parse::<Option<kw::outer>>()?.is_some() {
AliasSource::Outer {
module: parser.parse()?,
index: parser.parse()?,
}
} else {
AliasSource::InstanceExport {
instance: parser.parse::<ast::IndexOrRef<_>>()?.0,
export: parser.parse()?,
}
};
let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?;
Ok(Alias {
span,
id,
name,
kind,
source,
})
}
}

91
third_party/rust/wast/src/ast/instance.rs поставляемый
Просмотреть файл

@ -1,91 +0,0 @@
use crate::ast::{self, kw};
use crate::parser::{Parse, Parser, Result};
/// A nested WebAssembly instance to be created as part of a module.
#[derive(Debug)]
pub struct Instance<'a> {
/// Where this `instance` was defined.
pub span: ast::Span,
/// An identifier that this instance is resolved with (optionally) for name
/// resolution.
pub id: Option<ast::Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
/// What kind of instance this is, be it an inline-defined or imported one.
pub kind: InstanceKind<'a>,
}
/// Possible ways to define a instance in the text format.
#[derive(Debug)]
pub enum InstanceKind<'a> {
/// An instance which is actually defined as an import, such as:
Import {
/// Where we're importing from
import: ast::InlineImport<'a>,
/// The type that this instance will have.
ty: ast::TypeUse<'a, ast::InstanceType<'a>>,
},
/// Instances whose instantiation is defined inline.
Inline {
/// Module that we're instantiating
module: ast::ItemRef<'a, kw::module>,
/// Arguments used to instantiate the instance
args: Vec<InstanceArg<'a>>,
},
}
/// Arguments to the `instantiate` instruction
#[derive(Debug)]
#[allow(missing_docs)]
pub struct InstanceArg<'a> {
pub name: &'a str,
pub index: ast::ItemRef<'a, ast::ExportKind>,
}
impl<'a> Parse<'a> for Instance<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::instance>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let exports = parser.parse()?;
let kind = if let Some(import) = parser.parse()? {
InstanceKind::Import {
import,
ty: parser.parse()?,
}
} else {
parser.parens(|p| {
p.parse::<kw::instantiate>()?;
let module = p.parse::<ast::IndexOrRef<_>>()?.0;
let mut args = Vec::new();
while !p.is_empty() {
args.push(p.parens(|p| p.parse())?);
}
Ok(InstanceKind::Inline { module, args })
})?
};
Ok(Instance {
span,
id,
name,
exports,
kind,
})
}
}
impl<'a> Parse<'a> for InstanceArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::import>()?;
Ok(InstanceArg {
name: parser.parse()?,
index: parser.parse()?,
})
}
}

430
third_party/rust/wast/src/ast/mod.rs поставляемый
Просмотреть файл

@ -1,430 +0,0 @@
/// A macro to create a custom keyword parser.
///
/// This macro is invoked in one of two forms:
///
/// ```
/// // keyword derived from the Rust identifier:
/// wast::custom_keyword!(foo);
///
/// // or an explicitly specified string representation of the keyword:
/// wast::custom_keyword!(my_keyword = "the-wasm-keyword");
/// ```
///
/// This can then be used to parse custom keyword for custom items, such as:
///
/// ```
/// use wast::parser::{Parser, Result, Parse};
///
/// struct InlineModule<'a> {
/// inline_text: &'a str,
/// }
///
/// mod kw {
/// wast::custom_keyword!(inline);
/// }
///
/// // Parse an inline string module of the form:
/// //
/// // (inline "(module (func))")
/// impl<'a> Parse<'a> for InlineModule<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// parser.parse::<kw::inline>()?;
/// Ok(InlineModule {
/// inline_text: parser.parse()?,
/// })
/// }
/// }
/// ```
///
/// Note that the keyword name can only start with a lower-case letter, i.e. 'a'..'z'.
#[macro_export]
macro_rules! custom_keyword {
($name:ident) => {
$crate::custom_keyword!($name = stringify!($name));
};
($name:ident = $kw:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone)]
pub struct $name(pub $crate::Span);
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if kw == $kw {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected keyword `", $kw, "`")))
})
}
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((kw, _rest)) = cursor.keyword() {
kw == $kw
} else {
false
}
}
fn display() -> &'static str {
concat!("`", $kw, "`")
}
}
};
}
/// A macro for defining custom reserved symbols.
///
/// This is like `custom_keyword!` but for reserved symbols (`Token::Reserved`)
/// instead of keywords (`Token::Keyword`).
///
/// ```
/// use wast::parser::{Parser, Result, Parse};
///
/// // Define a custom reserved symbol, the "spaceship" operator: `<=>`.
/// wast::custom_reserved!(spaceship = "<=>");
///
/// /// A "three-way comparison" like `(<=> a b)` that returns -1 if `a` is less
/// /// than `b`, 0 if they're equal, and 1 if `a` is greater than `b`.
/// struct ThreeWayComparison<'a> {
/// lhs: wast::Expression<'a>,
/// rhs: wast::Expression<'a>,
/// }
///
/// impl<'a> Parse<'a> for ThreeWayComparison<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// parser.parse::<spaceship>()?;
/// let lhs = parser.parse()?;
/// let rhs = parser.parse()?;
/// Ok(ThreeWayComparison { lhs, rhs })
/// }
/// }
/// ```
#[macro_export]
macro_rules! custom_reserved {
($name:ident) => {
$crate::custom_reserved!($name = stringify!($name));
};
($name:ident = $rsv:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug)]
pub struct $name(pub $crate::Span);
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((rsv, rest)) = c.reserved() {
if rsv == $rsv {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected reserved symbol `", $rsv, "`")))
})
}
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((rsv, _rest)) = cursor.reserved() {
rsv == $rsv
} else {
false
}
}
fn display() -> &'static str {
concat!("`", $rsv, "`")
}
}
};
}
/// A macro, like [`custom_keyword`], to create a type which can be used to
/// parse/peek annotation directives.
///
/// Note that when you're parsing custom annotations it can be somewhat tricky
/// due to the nature that most of them are skipped. You'll want to be sure to
/// consult the documentation of [`Parser::register_annotation`][register] when
/// using this macro.
///
/// # Examples
///
/// To see an example of how to use this macro, let's invent our own syntax for
/// the [producers section][section] which looks like:
///
/// ```wat
/// (@producer "wat" "1.0.2")
/// ```
///
/// Here, for simplicity, we'll assume everything is a `processed-by` directive,
/// but you could get much more fancy with this as well.
///
/// ```
/// # use wast::*;
/// # use wast::parser::*;
///
/// // First we define the custom annotation keyword we're using, and by
/// // convention we define it in an `annotation` module.
/// mod annotation {
/// wast::annotation!(producer);
/// }
///
/// struct Producer<'a> {
/// name: &'a str,
/// version: &'a str,
/// }
///
/// impl<'a> Parse<'a> for Producer<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// // Remember that parser conventionally parse the *interior* of an
/// // s-expression, so we parse our `@producer` annotation and then we
/// // parse the payload of our annotation.
/// parser.parse::<annotation::producer>()?;
/// Ok(Producer {
/// name: parser.parse()?,
/// version: parser.parse()?,
/// })
/// }
/// }
/// ```
///
/// Note though that this is only half of the parser for annotations. The other
/// half is calling the [`register_annotation`][register] method at the right
/// time to ensure the parser doesn't automatically skip our `@producer`
/// directive. Note that we *can't* call it inside the `Parse for Producer`
/// definition because that's too late and the annotation would already have
/// been skipped.
///
/// Instead we'll need to call it from a higher level-parser before the
/// parenthesis have been parsed, like so:
///
/// ```
/// # use wast::*;
/// # use wast::parser::*;
/// struct Module<'a> {
/// fields: Vec<ModuleField<'a>>,
/// }
///
/// impl<'a> Parse<'a> for Module<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// // .. parse module header here ...
///
/// // register our custom `@producer` annotation before we start
/// // parsing the parentheses of each field
/// let _r = parser.register_annotation("producer");
///
/// let mut fields = Vec::new();
/// while !parser.is_empty() {
/// fields.push(parser.parens(|p| p.parse())?);
/// }
/// Ok(Module { fields })
/// }
/// }
///
/// enum ModuleField<'a> {
/// Producer(Producer<'a>),
/// // ...
/// }
/// # struct Producer<'a>(&'a str);
/// # impl<'a> Parse<'a> for Producer<'a> {
/// # fn parse(parser: Parser<'a>) -> Result<Self> { Ok(Producer(parser.parse()?)) }
/// # }
/// # mod annotation { wast::annotation!(producer); }
///
/// impl<'a> Parse<'a> for ModuleField<'a> {
/// 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>() {
/// return Ok(ModuleField::Producer(parser.parse()?));
/// }
///
/// // .. typically we'd parse other module fields here...
///
/// Err(parser.error("unknown module field"))
/// }
/// }
/// ```
///
/// [register]: crate::parser::Parser::register_annotation
/// [section]: https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md
#[macro_export]
macro_rules! annotation {
($name:ident) => {
$crate::annotation!($name = stringify!($name));
};
($name:ident = $annotation:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug)]
pub struct $name(pub $crate::Span);
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((a, rest)) = c.annotation() {
if a == $annotation {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected annotation `@", $annotation, "`")))
})
}
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((a, _rest)) = cursor.annotation() {
a == $annotation
} else {
false
}
}
fn display() -> &'static str {
concat!("`@", $annotation, "`")
}
}
};
}
macro_rules! reexport {
($(mod $name:ident;)*) => ($(mod $name; pub use self::$name::*;)*);
}
reexport! {
mod token;
}
#[cfg(feature = "wasm-module")]
reexport! {
mod alias;
mod assert_expr;
mod custom;
mod tag;
mod export;
mod expr;
mod func;
mod global;
mod import;
mod instance;
mod memory;
mod module;
mod nested_module;
mod table;
mod types;
mod wast;
}
/// Common keyword used to parse WebAssembly text files.
pub mod kw {
custom_keyword!(after);
custom_keyword!(alias);
custom_keyword!(any);
custom_keyword!(anyfunc);
custom_keyword!(anyref);
custom_keyword!(arg);
custom_keyword!(array);
custom_keyword!(assert_exception);
custom_keyword!(assert_exhaustion);
custom_keyword!(assert_invalid);
custom_keyword!(assert_malformed);
custom_keyword!(assert_return);
custom_keyword!(assert_return_arithmetic_nan);
custom_keyword!(assert_return_arithmetic_nan_f32x4);
custom_keyword!(assert_return_arithmetic_nan_f64x2);
custom_keyword!(assert_return_canonical_nan);
custom_keyword!(assert_return_canonical_nan_f32x4);
custom_keyword!(assert_return_canonical_nan_f64x2);
custom_keyword!(assert_return_func);
custom_keyword!(assert_trap);
custom_keyword!(assert_unlinkable);
custom_keyword!(before);
custom_keyword!(binary);
custom_keyword!(block);
custom_keyword!(catch);
custom_keyword!(catch_all);
custom_keyword!(code);
custom_keyword!(data);
custom_keyword!(dataref);
custom_keyword!(declare);
custom_keyword!(delegate);
custom_keyword!(r#do = "do");
custom_keyword!(elem);
custom_keyword!(end);
custom_keyword!(tag);
custom_keyword!(export);
custom_keyword!(r#extern = "extern");
custom_keyword!(externref);
custom_keyword!(eq);
custom_keyword!(eqref);
custom_keyword!(f32);
custom_keyword!(f32x4);
custom_keyword!(f64);
custom_keyword!(f64x2);
custom_keyword!(field);
custom_keyword!(first);
custom_keyword!(func);
custom_keyword!(funcref);
custom_keyword!(get);
custom_keyword!(global);
custom_keyword!(i16);
custom_keyword!(i16x8);
custom_keyword!(i31);
custom_keyword!(i31ref);
custom_keyword!(i32);
custom_keyword!(i32x4);
custom_keyword!(i64);
custom_keyword!(i64x2);
custom_keyword!(i8);
custom_keyword!(i8x16);
custom_keyword!(import);
custom_keyword!(instance);
custom_keyword!(instantiate);
custom_keyword!(invoke);
custom_keyword!(item);
custom_keyword!(last);
custom_keyword!(local);
custom_keyword!(memory);
custom_keyword!(module);
custom_keyword!(modulecode);
custom_keyword!(nan_arithmetic = "nan:arithmetic");
custom_keyword!(nan_canonical = "nan:canonical");
custom_keyword!(null);
custom_keyword!(nullref);
custom_keyword!(offset);
custom_keyword!(outer);
custom_keyword!(param);
custom_keyword!(parent);
custom_keyword!(passive);
custom_keyword!(quote);
custom_keyword!(r#else = "else");
custom_keyword!(r#if = "if");
custom_keyword!(r#loop = "loop");
custom_keyword!(r#mut = "mut");
custom_keyword!(r#type = "type");
custom_keyword!(r#ref = "ref");
custom_keyword!(ref_func = "ref.func");
custom_keyword!(ref_null = "ref.null");
custom_keyword!(register);
custom_keyword!(result);
custom_keyword!(rtt);
custom_keyword!(shared);
custom_keyword!(start);
custom_keyword!(r#struct = "struct");
custom_keyword!(table);
custom_keyword!(then);
custom_keyword!(r#try = "try");
custom_keyword!(v128);
}
/// Common annotations used to parse WebAssembly text files.
pub mod annotation {
annotation!(custom);
annotation!(name);
}

108
third_party/rust/wast/src/component/alias.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,108 @@
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, Index, NameAnnotation, Span};
/// An `alias` statement used to juggle indices with nested components.
#[derive(Debug, Clone)]
pub struct Alias<'a> {
/// Where this `alias` was defined.
pub span: Span,
/// An identifier that this alias is resolved with (optionally) for name
/// resolution.
pub id: Option<Id<'a>>,
/// An optional name for this alias stored in the custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// The target of this alias.
pub target: AliasTarget<'a>,
/// The kind of item that's being aliased.
pub kind: AliasKind,
}
/// aliaskind ::= (module <id>?)
/// | (component <id>?)
/// | (instance <id>?)
/// | (func <id>?)
/// | (value <id>?)
/// | (type <id>?)
/// | (table <id>?)
/// | (memory <id>?)
/// | (global <id>?)
/// | ... other Post-MVP Core definition kinds
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum AliasKind {
Module,
Component,
Instance,
Value,
ExportKind(core::ExportKind),
}
impl<'a> Parse<'a> for AliasKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<core::ExportKind>() {
let kind = parser.parse::<core::ExportKind>()?;
Ok(AliasKind::ExportKind(kind))
} else if l.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(AliasKind::Module)
} else if l.peek::<kw::component>() {
parser.parse::<kw::component>()?;
Ok(AliasKind::Component)
} else if l.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(AliasKind::Instance)
} else if l.peek::<kw::value>() {
parser.parse::<kw::value>()?;
Ok(AliasKind::Value)
} else {
Err(l.error())
}
}
}
/// aliastarget ::= export <instanceidx> <name>
/// | outer <outeridx> <idx>
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum AliasTarget<'a> {
Export {
instance: Index<'a>,
export: &'a str,
},
Outer {
/// The number of enclosing components to skip.
outer: Index<'a>,
/// An index into the target component's `aliaskind` index space.
index: Index<'a>,
},
}
impl<'a> Parse<'a> for Alias<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::alias>()?.0;
let target = if parser.parse::<Option<kw::outer>>()?.is_some() {
AliasTarget::Outer {
outer: parser.parse()?,
index: parser.parse()?,
}
} else {
parser.parse::<kw::export>()?;
AliasTarget::Export {
instance: parser.parse::<Index<'a>>()?,
export: parser.parse()?,
}
};
let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?;
Ok(Alias {
span,
id,
name,
kind,
target,
})
}
}

632
third_party/rust/wast/src/component/binary.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,632 @@
use crate::component::*;
use crate::core;
use crate::encode::Encode;
use crate::token::{Id, NameAnnotation};
pub fn encode(component: &Component<'_>) -> Vec<u8> {
match &component.kind {
ComponentKind::Text(fields) => encode_fields(&component.id, &component.name, fields),
ComponentKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().cloned()).collect(),
}
}
fn encode_fields(
component_id: &Option<Id<'_>>,
component_name: &Option<NameAnnotation<'_>>,
fields: &[ComponentField<'_>],
) -> Vec<u8> {
let mut e = Encoder {
wasm: Vec::new(),
tmp: Vec::new(),
last_section: None,
last_section_contents: Vec::new(),
last_section_count: 0,
};
e.wasm.extend(b"\0asm");
e.wasm.extend(b"\x0a\0\x01\0");
for field in fields {
match field {
ComponentField::Type(i) => e.append(1, i),
ComponentField::Import(i) => e.append(2, i),
ComponentField::Func(i) => e.append(3, i),
ComponentField::Module(i) => e.section(4, i),
ComponentField::Component(i) => e.section(5, i),
ComponentField::Instance(i) => e.append(6, i),
ComponentField::Export(i) => e.append(7, i),
ComponentField::Start(i) => e.section(8, i),
ComponentField::Alias(i) => e.append(9, i),
}
}
// FIXME(WebAssembly/component-model#14): once a name section is defined it
// should be encoded here.
drop((component_id, component_name));
e.flush();
return e.wasm;
}
struct Encoder {
wasm: Vec<u8>,
tmp: Vec<u8>,
last_section: Option<u8>,
last_section_contents: Vec<u8>,
last_section_count: usize,
}
impl Encoder {
/// Appends an entire section represented by the `section` provided
fn section(&mut self, id: u8, section: &dyn Encode) {
self.flush();
self.tmp.truncate(0);
section.encode(&mut self.tmp);
self.wasm.push(id);
self.tmp.encode(&mut self.wasm);
}
/// Appends an `item` specified within the section `id` specified.
fn append(&mut self, id: u8, item: &dyn Encode) {
// Flush if necessary to start a new section
if self.last_section != Some(id) {
self.flush();
}
// ... and afterwards start building up this section incrementally
// in case the next item encoded is also part of this section.
item.encode(&mut self.last_section_contents);
self.last_section_count += 1;
self.last_section = Some(id);
}
fn flush(&mut self) {
let id = match self.last_section.take() {
Some(id) => id,
None => return,
};
self.wasm.push(id);
self.tmp.truncate(0);
self.last_section_count.encode(&mut self.tmp);
self.last_section_count = 0;
self.tmp.extend(self.last_section_contents.drain(..));
self.tmp.encode(&mut self.wasm);
}
}
impl Encode for NestedComponent<'_> {
fn encode(&self, e: &mut Vec<u8>) {
let fields = match &self.kind {
NestedComponentKind::Import { .. } => panic!("imports should be gone by now"),
NestedComponentKind::Inline(fields) => fields,
};
e.extend(encode_fields(&self.id, &self.name, fields));
}
}
impl Encode for Module<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.kind {
ModuleKind::Import { .. } => panic!("imports should be gone by now"),
ModuleKind::Inline { fields } => {
e.extend(crate::core::binary::encode(&self.id, &self.name, fields));
}
}
}
}
impl Encode for Instance<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.kind {
InstanceKind::Module { module, args } => {
e.push(0x00);
e.push(0x00);
module.idx.encode(e);
args.encode(e);
}
InstanceKind::Component { component, args } => {
e.push(0x00);
e.push(0x01);
component.idx.encode(e);
args.encode(e);
}
InstanceKind::BundleOfComponentExports { args } => {
e.push(0x01);
args.encode(e);
}
InstanceKind::BundleOfExports { args } => {
e.push(0x02);
args.encode(e);
}
InstanceKind::Import { .. } => unreachable!("should be removed during expansion"),
}
}
}
impl Encode for NamedModuleArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
e.push(0x02);
self.arg.encode(e);
}
}
impl Encode for ModuleArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ModuleArg::Def(def) => {
def.idx.encode(e);
}
ModuleArg::BundleOfExports(..) => {
unreachable!("should be expanded already")
}
}
}
}
impl Encode for NamedComponentArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
self.arg.encode(e);
}
}
impl Encode for ComponentArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ComponentArg::Def(def) => {
match def.kind {
DefTypeKind::Module => e.push(0x00),
DefTypeKind::Component => e.push(0x01),
DefTypeKind::Instance => e.push(0x02),
DefTypeKind::Func => e.push(0x03),
DefTypeKind::Value => e.push(0x04),
}
def.idx.encode(e);
}
ComponentArg::BundleOfExports(..) => {
unreachable!("should be expanded already")
}
}
}
}
impl Encode for Start<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.func.encode(e);
self.args.encode(e);
}
}
impl Encode for Alias<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self.target {
AliasTarget::Export { instance, export } => {
match self.kind {
AliasKind::Module => {
e.push(0x00);
e.push(0x00);
}
AliasKind::Component => {
e.push(0x00);
e.push(0x01);
}
AliasKind::Instance => {
e.push(0x00);
e.push(0x02);
}
AliasKind::Value => {
e.push(0x00);
e.push(0x04);
}
AliasKind::ExportKind(export_kind) => {
e.push(0x01);
export_kind.encode(e);
}
}
instance.encode(e);
export.encode(e);
}
AliasTarget::Outer { outer, index } => {
e.push(0x02);
match self.kind {
AliasKind::Module => e.push(0x00),
AliasKind::Component => e.push(0x01),
AliasKind::ExportKind(core::ExportKind::Type) => e.push(0x05),
// FIXME(#590): this feels a bit odd but it's also weird to
// make this an explicit error somewhere else. Should
// revisit this when the encodings of aliases and such have
// all settled down. Hopefully #590 and
// WebAssembly/component-model#29 will help solve this.
_ => e.push(0xff),
}
outer.encode(e);
index.encode(e);
}
}
}
}
impl Encode for CanonLower<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x01);
self.opts.encode(e);
self.func.encode(e);
}
}
impl Encode for CanonLift<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x00);
self.type_.encode(e);
self.opts.encode(e);
self.func.encode(e);
}
}
impl Encode for CanonOpt<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
CanonOpt::StringUtf8 => e.push(0x00),
CanonOpt::StringUtf16 => e.push(0x01),
CanonOpt::StringLatin1Utf16 => e.push(0x02),
CanonOpt::Into(index) => {
e.push(0x03);
index.encode(e);
}
}
}
}
impl Encode for ModuleType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x4f);
self.defs.encode(e);
}
}
impl Encode for ModuleTypeDef<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ModuleTypeDef::Type(f) => {
e.push(0x01);
f.encode(e);
}
ModuleTypeDef::Import(i) => {
e.push(0x02);
i.encode(e);
}
ModuleTypeDef::Export(name, x) => {
e.push(0x07);
name.encode(e);
x.encode(e);
}
}
}
}
impl Encode for ComponentType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x4e);
self.fields.encode(e);
}
}
impl Encode for ComponentTypeField<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ComponentTypeField::Type(ty_) => {
e.push(0x01);
ty_.encode(e);
}
ComponentTypeField::Alias(alias) => {
e.push(0x09);
alias.encode(e);
}
ComponentTypeField::Export(export) => {
e.push(0x07);
export.encode(e);
}
ComponentTypeField::Import(import) => {
e.push(0x02);
import.encode(e);
}
}
}
}
impl Encode for InstanceType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x4d);
self.fields.encode(e);
}
}
impl Encode for InstanceTypeField<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
InstanceTypeField::Type(ty_) => {
e.push(0x01);
ty_.encode(e);
}
InstanceTypeField::Alias(alias) => {
e.push(0x09);
alias.encode(e);
}
InstanceTypeField::Export(export) => {
e.push(0x07);
export.encode(e);
}
}
}
}
impl Encode for ComponentExportType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
self.item.encode(e);
}
}
impl Encode for TypeField<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.def {
ComponentTypeDef::DefType(d) => d.encode(e),
ComponentTypeDef::InterType(i) => i.encode(e),
}
}
}
impl Encode for Primitive {
fn encode(&self, e: &mut Vec<u8>) {
match self {
Primitive::Unit => e.push(0x7f),
Primitive::Bool => e.push(0x7e),
Primitive::S8 => e.push(0x7d),
Primitive::U8 => e.push(0x7c),
Primitive::S16 => e.push(0x7b),
Primitive::U16 => e.push(0x7a),
Primitive::S32 => e.push(0x79),
Primitive::U32 => e.push(0x78),
Primitive::S64 => e.push(0x77),
Primitive::U64 => e.push(0x76),
Primitive::Float32 => e.push(0x75),
Primitive::Float64 => e.push(0x74),
Primitive::Char => e.push(0x73),
Primitive::String => e.push(0x72),
}
}
}
impl<'a> Encode for InterType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
InterType::Primitive(p) => p.encode(e),
InterType::Record(r) => r.encode(e),
InterType::Variant(v) => v.encode(e),
InterType::List(l) => l.encode(e),
InterType::Tuple(t) => t.encode(e),
InterType::Flags(f) => f.encode(e),
InterType::Enum(n) => n.encode(e),
InterType::Union(u) => u.encode(e),
InterType::Option(o) => o.encode(e),
InterType::Expected(x) => x.encode(e),
}
}
}
impl<'a> Encode for InterTypeRef<'a> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
InterTypeRef::Primitive(p) => p.encode(e),
InterTypeRef::Ref(i) => i.encode(e),
InterTypeRef::Inline(_) => unreachable!("should be expanded by now"),
}
}
}
impl<'a> Encode for DefType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
DefType::Func(f) => f.encode(e),
DefType::Module(m) => m.encode(e),
DefType::Component(c) => c.encode(e),
DefType::Instance(i) => i.encode(e),
DefType::Value(v) => v.encode(e),
}
}
}
impl<'a> Encode for Record<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x71);
self.fields.encode(e);
}
}
impl<'a> Encode for Field<'a> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
self.type_.encode(e);
}
}
impl<'a> Encode for Variant<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x70);
self.cases.encode(e);
}
}
impl<'a> Encode for Case<'a> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
self.type_.encode(e);
if let Some(defaults_to) = self.defaults_to {
e.push(0x01);
defaults_to.encode(e);
} else {
e.push(0x00);
}
}
}
impl<'a> Encode for List<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6f);
self.element.encode(e);
}
}
impl<'a> Encode for Tuple<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6e);
self.fields.encode(e);
}
}
impl<'a> Encode for Flags<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6d);
self.flag_names.encode(e);
}
}
impl<'a> Encode for Enum<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6c);
self.arms.encode(e);
}
}
impl<'a> Encode for Union<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6b);
self.arms.encode(e);
}
}
impl<'a> Encode for OptionType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x6a);
self.element.encode(e);
}
}
impl<'a> Encode for Expected<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x69);
self.ok.encode(e);
self.err.encode(e);
}
}
impl<'a> Encode for ComponentFunctionType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x4c);
self.params.encode(e);
self.result.encode(e);
}
}
impl<'a> Encode for ComponentFunctionParam<'a> {
fn encode(&self, e: &mut Vec<u8>) {
if let Some(id) = self.name {
e.push(0x01);
id.encode(e);
} else {
e.push(0x00);
}
self.type_.encode(e);
}
}
impl<'a> Encode for ValueType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
e.push(0x4b);
self.value_type.encode(e)
}
}
impl<T> Encode for ComponentTypeUse<'_, T> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ComponentTypeUse::Inline(_) => unreachable!("should be expanded already"),
ComponentTypeUse::Ref(index) => index.encode(e),
}
}
}
impl Encode for ComponentExport<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
match &self.arg {
ComponentArg::Def(item_ref) => {
match item_ref.kind {
DefTypeKind::Module => e.push(0x00),
DefTypeKind::Component => e.push(0x01),
DefTypeKind::Instance => e.push(0x02),
DefTypeKind::Func => e.push(0x03),
DefTypeKind::Value => e.push(0x04),
}
item_ref.idx.encode(e);
}
ComponentArg::BundleOfExports(..) => {
unreachable!("should be expanded already")
}
}
}
}
impl Encode for ComponentFunc<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.kind {
ComponentFuncKind::Import { .. } => unreachable!("should be expanded by now"),
ComponentFuncKind::Inline { body } => {
body.encode(e);
}
}
}
}
impl Encode for ComponentFuncBody<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ComponentFuncBody::CanonLift(lift) => lift.encode(e),
ComponentFuncBody::CanonLower(lower) => lower.encode(e),
}
}
}
impl Encode for ComponentImport<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
self.item.encode(e);
}
}
impl Encode for ItemSig<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.kind {
ItemKind::Component(t) => t.encode(e),
ItemKind::Module(t) => t.encode(e),
ItemKind::Func(t) => t.encode(e),
ItemKind::Instance(t) => t.encode(e),
ItemKind::Value(t) => t.encode(e),
}
}
}
impl<K> Encode for ItemRef<'_, K> {
fn encode(&self, dst: &mut Vec<u8>) {
assert!(self.export_names.is_empty());
self.idx.encode(dst);
}
}
impl Encode for CoreExport<'_> {
fn encode(&self, dst: &mut Vec<u8>) {
self.name.encode(dst);
self.index.kind.encode(dst);
self.index.encode(dst);
}
}

302
third_party/rust/wast/src/component/component.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,302 @@
use crate::component::*;
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A parsed WebAssembly component module.
#[derive(Debug)]
pub struct Component<'a> {
/// Where this `component` was defined
pub span: Span,
/// An optional identifier this component is known by
pub id: Option<Id<'a>>,
/// An optional `@name` annotation for this component
pub name: Option<NameAnnotation<'a>>,
/// What kind of component this was parsed as.
pub kind: ComponentKind<'a>,
}
/// The different kinds of ways to define a component.
#[derive(Debug)]
pub enum ComponentKind<'a> {
/// A component defined in the textual s-expression format.
Text(Vec<ComponentField<'a>>),
/// A component that had its raw binary bytes defined via the `binary`
/// directive.
Binary(Vec<&'a [u8]>),
}
impl<'a> Component<'a> {
/// Performs a name resolution pass on this [`Component`], resolving all
/// symbolic names to indices.
///
/// The WAT format contains a number of shorthands to make it easier to
/// write, such as inline exports, inline imports, inline type definitions,
/// etc. Additionally it allows using symbolic names such as `$foo` instead
/// of using indices. This module will postprocess an AST to remove all of
/// this syntactic sugar, preparing the AST for binary emission. This is
/// where expansion and name resolution happens.
///
/// This function will mutate the AST of this [`Component`] and replace all
/// [`Index`](crate::token::Index) arguments with `Index::Num`. This will
/// also expand inline exports/imports listed on fields and handle various
/// other shorthands of the text format.
///
/// If successful the AST was modified to be ready for binary encoding.
///
/// # Errors
///
/// If an error happens during resolution, such a name resolution error or
/// items are found in the wrong order, then an error is returned.
pub fn resolve(&mut self) -> std::result::Result<(), crate::Error> {
match &mut self.kind {
ComponentKind::Text(fields) => {
crate::component::expand::expand(fields);
}
ComponentKind::Binary(_) => {}
}
crate::component::resolve::resolve(self)
}
/// Encodes this [`Component`] to its binary form.
///
/// This function will take the textual representation in [`Component`] and
/// perform all steps necessary to convert it to a binary WebAssembly
/// component, suitable for writing to a `*.wasm` file. This function may
/// internally modify the [`Component`], for example:
///
/// * Name resolution is performed to ensure that `Index::Id` isn't present
/// anywhere in the AST.
///
/// * Inline shorthands such as imports/exports/types are all expanded to be
/// dedicated fields of the component.
///
/// * Component fields may be shuffled around to preserve index ordering from
/// expansions.
///
/// After all of this expansion has happened the component will be converted to
/// its binary form and returned as a `Vec<u8>`. This is then suitable to
/// hand off to other wasm runtimes and such.
///
/// # Errors
///
/// This function can return an error for name resolution errors and other
/// expansion-related errors.
pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> {
self.resolve()?;
Ok(crate::component::binary::encode(self))
}
pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> {
let mut starts = 0;
if let ComponentKind::Text(fields) = &self.kind {
for item in fields.iter() {
if let ComponentField::Start(_) = item {
starts += 1;
}
}
}
if starts > 1 {
return Err(parser.error("multiple start sections found"));
}
Ok(())
}
}
impl<'a> Parse<'a> for Component<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let _r = parser.register_annotation("custom");
let span = parser.parse::<kw::component>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let kind = if parser.peek::<kw::binary>() {
parser.parse::<kw::binary>()?;
let mut data = Vec::new();
while !parser.is_empty() {
data.push(parser.parse()?);
}
ComponentKind::Binary(data)
} else {
ComponentKind::Text(ComponentField::parse_remaining(parser)?)
};
Ok(Component {
span,
id,
name,
kind,
})
}
}
/// A listing of all possible fields that can make up a WebAssembly component.
#[allow(missing_docs)]
#[derive(Debug)]
pub enum ComponentField<'a> {
Type(TypeField<'a>),
Import(ComponentImport<'a>),
Func(ComponentFunc<'a>),
Export(ComponentExport<'a>),
Start(Start<'a>),
Instance(Instance<'a>),
Module(Module<'a>),
Component(NestedComponent<'a>),
Alias(Alias<'a>),
}
impl<'a> ComponentField<'a> {
fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ComponentField>> {
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(ComponentField::parse)?);
}
Ok(fields)
}
}
impl<'a> Parse<'a> for ComponentField<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::r#type>() {
return Ok(ComponentField::Type(parser.parse()?));
}
if parser.peek::<kw::import>() {
return Ok(ComponentField::Import(parser.parse()?));
}
if parser.peek::<kw::func>() {
return Ok(ComponentField::Func(parser.parse()?));
}
if parser.peek::<kw::export>() {
return Ok(ComponentField::Export(parser.parse()?));
}
if parser.peek::<kw::start>() {
return Ok(ComponentField::Start(parser.parse()?));
}
if parser.peek::<kw::instance>() {
return Ok(ComponentField::Instance(parser.parse()?));
}
if parser.peek::<kw::module>() {
return Ok(ComponentField::Module(parser.parse()?));
}
if parser.peek::<kw::component>() {
return Ok(ComponentField::Component(parser.parse()?));
}
if parser.peek::<kw::alias>() {
return Ok(ComponentField::Alias(parser.parse()?));
}
Err(parser.error("expected valid component field"))
}
}
impl<'a> From<TypeField<'a>> for ComponentField<'a> {
fn from(field: TypeField<'a>) -> ComponentField<'a> {
ComponentField::Type(field)
}
}
impl<'a> From<Alias<'a>> for ComponentField<'a> {
fn from(field: Alias<'a>) -> ComponentField<'a> {
ComponentField::Alias(field)
}
}
/// A function to call at instantiation time.
#[derive(Debug)]
pub struct Start<'a> {
/// The function to call.
pub func: ItemRef<'a, kw::func>,
/// The arguments to pass to the function.
pub args: Vec<ItemRef<'a, kw::value>>,
/// Name of the result value.
pub result: Option<Id<'a>>,
}
impl<'a> Parse<'a> for Start<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::start>()?;
let func = parser.parse::<IndexOrRef<_>>()?.0;
let mut args = Vec::new();
while !parser.is_empty() && !parser.peek2::<kw::result>() {
args.push(parser.parse()?);
}
let result = if !parser.is_empty() {
parser.parens(|parser| {
parser.parse::<kw::result>()?;
if !parser.is_empty() {
parser.parens(|parser| {
parser.parse::<kw::value>()?;
let id = parser.parse()?;
Ok(Some(id))
})
} else {
Ok(None)
}
})?
} else {
None
};
Ok(Start { func, args, result })
}
}
/// A parsed WebAssembly component module.
#[derive(Debug)]
pub struct NestedComponent<'a> {
/// Where this `component` was defined
pub span: Span,
/// An optional identifier this component is known by
pub id: Option<Id<'a>>,
/// An optional `@name` annotation for this component
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: core::InlineExport<'a>,
/// What kind of component this was parsed as.
pub kind: NestedComponentKind<'a>,
}
/// The different kinds of ways to define a nested component.
#[derive(Debug)]
pub enum NestedComponentKind<'a> {
/// This is actually an inline import of a component
Import {
/// The information about where this is being imported from.
import: InlineImport<'a>,
/// The type of component being imported.
ty: ComponentTypeUse<'a, ComponentType<'a>>,
},
/// The component is defined inline as a local definition with its fields
/// listed here.
Inline(Vec<ComponentField<'a>>),
}
impl<'a> Parse<'a> for NestedComponent<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::component>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let exports = parser.parse()?;
let kind = if let Some(import) = parser.parse()? {
NestedComponentKind::Import {
import,
ty: parser.parse()?,
}
} else {
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(|p| p.parse())?);
}
NestedComponentKind::Inline(fields)
};
Ok(NestedComponent {
span,
id,
name,
exports,
kind,
})
}
}

330
third_party/rust/wast/src/component/deftype.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,330 @@
//! The `deftype` production in the component-model AST, and its children.
use crate::component::*;
use crate::core;
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
/// Different kinds of elements that can be exported from a WebAssembly component,
/// contained in a [`ComponentExport`].
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum DefTypeKind {
Func,
Module,
Component,
Instance,
Value,
}
impl<'a> Parse<'a> for DefTypeKind {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
parser.parse::<kw::func>()?;
Ok(DefTypeKind::Func)
} else if l.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(DefTypeKind::Module)
} else if l.peek::<kw::component>() {
parser.parse::<kw::component>()?;
Ok(DefTypeKind::Component)
} else if l.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(DefTypeKind::Instance)
} else if l.peek::<kw::value>() {
parser.parse::<kw::value>()?;
Ok(DefTypeKind::Value)
} else {
Err(l.error())
}
}
}
impl Peek for DefTypeKind {
fn peek(cursor: Cursor<'_>) -> bool {
kw::func::peek(cursor)
|| kw::module::peek(cursor)
|| kw::component::peek(cursor)
|| kw::instance::peek(cursor)
|| kw::value::peek(cursor)
}
fn display() -> &'static str {
"deftype kind"
}
}
/// deftype ::= <moduletype>
/// | <componenttype>
/// | <instancetype>
/// | <functype>
/// | <valuetype>
#[derive(Debug)]
#[allow(missing_docs)]
pub enum DefType<'a> {
Func(ComponentFunctionType<'a>),
Module(ModuleType<'a>),
Component(ComponentType<'a>),
Instance(InstanceType<'a>),
Value(ValueType<'a>),
}
impl<'a> Parse<'a> for DefType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::func>() {
parser.parse::<kw::func>()?;
Ok(DefType::Func(parser.parse()?))
} else if parser.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(DefType::Module(parser.parse()?))
} else if parser.peek::<kw::component>() {
parser.parse::<kw::component>()?;
Ok(DefType::Component(parser.parse()?))
} else if parser.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(DefType::Instance(parser.parse()?))
} else if parser.peek::<kw::value>() {
parser.parse::<kw::value>()?;
Ok(DefType::Value(parser.parse()?))
} else {
Err(parser.error("expected a deftype"))
}
}
}
/// A component function type with parameters and results.
///
/// functype ::= (func <id>? (param <name>? <intertype>)* (result <intertype>)?)
#[derive(Debug)]
pub struct ComponentFunctionType<'a> {
/// The parameters of a function, optionally each having an identifier for
/// name resolution and a name for the custom `name` section.
pub params: Box<[ComponentFunctionParam<'a>]>,
/// The result type of a function.
pub result: InterTypeRef<'a>,
}
impl<'a> Parse<'a> for ComponentFunctionType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut params = Vec::new();
while parser.peek2::<kw::param>() {
parser.parens(|p| {
p.parse::<kw::param>()?;
params.push(ComponentFunctionParam {
name: p.parse()?,
type_: p.parse()?,
});
Ok(())
})?;
}
let result = if parser.peek2::<kw::result>() {
// Parse a `(result ...)`.
parser.parens(|parser| {
parser.parse::<kw::result>()?;
parser.parse()
})?
} else {
// If the result is omitted, use `unit`.
InterTypeRef::Primitive(Primitive::Unit)
};
Ok(Self {
params: params.into(),
result,
})
}
}
/// A parameter of a [`ComponentFunctionType`].
#[derive(Clone, Debug)]
pub struct ComponentFunctionParam<'a> {
/// An optionally-specified name of this parameter
pub name: Option<&'a str>,
/// The type of the parameter.
pub type_: InterTypeRef<'a>,
}
/// A type for a nested module
#[derive(Debug)]
pub struct ModuleType<'a> {
/// The fields of the module type.
pub defs: Vec<ModuleTypeDef<'a>>,
}
impl<'a> Parse<'a> for ModuleType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// See comments in `nested_module.rs` for why this is tested here.
if parser.parens_depth() > 100 {
return Err(parser.error("module type nesting too deep"));
}
let mut defs = Vec::new();
while !parser.is_empty() {
defs.push(parser.parens(|p| p.parse())?);
}
Ok(ModuleType { defs })
}
}
/// The contents of a [`ModuleType`].
#[derive(Debug)]
pub enum ModuleTypeDef<'a> {
/// A function type.
Type(core::Type<'a>),
/// An import.
Import(core::Import<'a>),
/// An export.
Export(&'a str, core::ItemSig<'a>),
}
impl<'a> Parse<'a> for ModuleTypeDef<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::r#type>() {
Ok(ModuleTypeDef::Type(parser.parse()?))
} else if l.peek::<kw::import>() {
Ok(ModuleTypeDef::Import(parser.parse()?))
} else if l.peek::<kw::export>() {
parser.parse::<kw::export>()?;
let name = parser.parse()?;
let et = parser.parens(|parser| parser.parse())?;
Ok(ModuleTypeDef::Export(name, et))
} else {
Err(parser.error("Expected a moduletype-def"))
}
}
}
/// A type for a nested component
#[derive(Debug, Default)]
pub struct ComponentType<'a> {
/// The fields of this `ComponentType`.
pub fields: Vec<ComponentTypeField<'a>>,
}
impl<'a> Parse<'a> for ComponentType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// See comments in `nested_module.rs` for why this is tested here.
if parser.parens_depth() > 100 {
return Err(parser.error("component type nesting too deep"));
}
let mut fields = Vec::new();
while !parser.is_empty() {
parser.parens(|parser| {
if parser.peek::<kw::import>() {
fields.push(ComponentTypeField::Import(parser.parse()?));
} else if parser.peek::<kw::export>() {
fields.push(ComponentTypeField::Export(parser.parse()?));
} else if parser.peek::<kw::r#type>() {
fields.push(ComponentTypeField::Type(parser.parse()?));
} else if parser.peek::<kw::alias>() {
fields.push(ComponentTypeField::Alias(parser.parse()?));
}
Ok(())
})?;
}
Ok(ComponentType { fields })
}
}
/// A field of a type for a nested component
#[derive(Debug)]
pub enum ComponentTypeField<'a> {
/// A public type for this component.
Type(TypeField<'a>),
/// A public type relationships for this component.
Alias(Alias<'a>),
/// An import expected for this component type.
Import(ComponentImport<'a>),
/// An export this component type is expected to have.
Export(ComponentExportType<'a>),
}
impl<'a> From<TypeField<'a>> for ComponentTypeField<'a> {
fn from(field: TypeField<'a>) -> ComponentTypeField<'a> {
ComponentTypeField::Type(field)
}
}
impl<'a> From<Alias<'a>> for ComponentTypeField<'a> {
fn from(field: Alias<'a>) -> ComponentTypeField<'a> {
ComponentTypeField::Alias(field)
}
}
/// A type for a nested instance
#[derive(Debug)]
pub struct InstanceType<'a> {
/// The fields of this `InstanceType`.
pub fields: Vec<InstanceTypeField<'a>>,
}
impl<'a> Parse<'a> for InstanceType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// See comments in `nested_module.rs` for why this is tested here.
if parser.parens_depth() > 100 {
return Err(parser.error("instance type nesting too deep"));
}
let mut fields = Vec::new();
while !parser.is_empty() {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::export>() {
fields.push(InstanceTypeField::Export(parser.parse()?));
} else if l.peek::<kw::r#type>() {
fields.push(InstanceTypeField::Type(parser.parse()?));
} else if l.peek::<kw::alias>() {
fields.push(InstanceTypeField::Alias(parser.parse()?));
} else {
return Err(l.error());
}
Ok(())
})?;
}
Ok(InstanceType { fields })
}
}
/// A field of a type for a nested instance
#[derive(Debug)]
pub enum InstanceTypeField<'a> {
/// A public type for this component.
Type(TypeField<'a>),
/// A public type relationships for this component.
Alias(Alias<'a>),
/// An export this component type is expected to have.
Export(ComponentExportType<'a>),
}
impl<'a> From<TypeField<'a>> for InstanceTypeField<'a> {
fn from(field: TypeField<'a>) -> InstanceTypeField<'a> {
InstanceTypeField::Type(field)
}
}
impl<'a> From<Alias<'a>> for InstanceTypeField<'a> {
fn from(field: Alias<'a>) -> InstanceTypeField<'a> {
InstanceTypeField::Alias(field)
}
}
/// A value type.
#[derive(Debug, Clone)]
pub struct ValueType<'a> {
/// The type of the value.
pub value_type: InterTypeRef<'a>,
}
impl<'a> Parse<'a> for ValueType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(ValueType {
value_type: parser.parse()?,
})
}
}

642
third_party/rust/wast/src/component/expand.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,642 @@
use crate::component::*;
use crate::core;
use crate::gensym;
use crate::kw;
use crate::token::{Id, Index, Span};
use std::collections::HashMap;
use std::mem;
/// Performs an AST "expansion" pass over the component fields provided.
///
/// This expansion is intended to desugar the AST from various parsed constructs
/// to bits and bobs amenable for name resolution as well as binary encoding.
/// For example `(import "" (func))` is split into a type definition followed by
/// the import referencing that type definition.
///
/// Most forms of AST expansion happen in this file and afterwards the AST will
/// be handed to the name resolution pass which will convert `Index::Id` to
/// `Index::Num` wherever it's found.
pub fn expand(fields: &mut Vec<ComponentField<'_>>) {
Expander::default().expand_component_fields(fields)
}
#[derive(Default)]
struct Expander<'a> {
/// Fields, during processing, which should be prepended to the
/// currently-being-processed field. This should always be empty after
/// processing is complete.
to_prepend: Vec<TypeField<'a>>,
component_fields_to_prepend: Vec<ComponentField<'a>>,
/// Fields that are appended to the end of the module once everything has
/// finished.
component_fields_to_append: Vec<ComponentField<'a>>,
}
impl<'a> Expander<'a> {
fn expand_component_fields(&mut self, fields: &mut Vec<ComponentField<'a>>) {
let mut cur = 0;
while cur < fields.len() {
self.expand_field(&mut fields[cur]);
let amt = self.to_prepend.len() + self.component_fields_to_prepend.len();
fields.splice(cur..cur, self.component_fields_to_prepend.drain(..));
fields.splice(cur..cur, self.to_prepend.drain(..).map(|f| f.into()));
cur += 1 + amt;
}
fields.extend(self.component_fields_to_append.drain(..));
}
fn expand_fields<T>(&mut self, fields: &mut Vec<T>, expand: fn(&mut Self, &mut T))
where
T: From<TypeField<'a>>,
{
let mut cur = 0;
while cur < fields.len() {
expand(self, &mut fields[cur]);
assert!(self.component_fields_to_prepend.is_empty());
assert!(self.component_fields_to_append.is_empty());
let amt = self.to_prepend.len();
fields.splice(cur..cur, self.to_prepend.drain(..).map(T::from));
cur += 1 + amt;
}
}
fn expand_field(&mut self, item: &mut ComponentField<'a>) {
match item {
ComponentField::Type(t) => self.expand_type_field(t),
ComponentField::Import(t) => {
self.expand_item_sig(&mut t.item);
}
ComponentField::Component(c) => {
for name in c.exports.names.drain(..) {
self.component_fields_to_append.push(export(
c.span,
name,
DefTypeKind::Component,
&mut c.id,
));
}
match &mut c.kind {
NestedComponentKind::Inline(fields) => expand(fields),
NestedComponentKind::Import { import, ty } => {
let idx = self.expand_component_type_use(ty);
*item = ComponentField::Import(ComponentImport {
span: c.span,
name: import.name,
item: ItemSig {
span: c.span,
id: c.id,
name: None,
kind: ItemKind::Component(ComponentTypeUse::Ref(idx)),
},
});
}
}
}
ComponentField::Func(f) => {
for name in f.exports.names.drain(..) {
self.component_fields_to_append.push(export(
f.span,
name,
DefTypeKind::Func,
&mut f.id,
));
}
match &mut f.kind {
ComponentFuncKind::Import { import, ty } => {
let idx = self.expand_component_type_use(ty);
*item = ComponentField::Import(ComponentImport {
span: f.span,
name: import.name,
item: ItemSig {
span: f.span,
id: f.id,
name: None,
kind: ItemKind::Func(ComponentTypeUse::Ref(idx)),
},
});
}
ComponentFuncKind::Inline { body } => match body {
ComponentFuncBody::CanonLift(lift) => {
self.expand_component_type_use(&mut lift.type_);
}
ComponentFuncBody::CanonLower(_) => {}
},
}
}
ComponentField::Module(m) => {
for name in m.exports.names.drain(..) {
self.component_fields_to_append.push(export(
m.span,
name,
DefTypeKind::Module,
&mut m.id,
));
}
match &mut m.kind {
// inline modules are expanded later during resolution
ModuleKind::Inline { .. } => {}
ModuleKind::Import { import, ty } => {
let idx = self.expand_component_type_use(ty);
*item = ComponentField::Import(ComponentImport {
span: m.span,
name: import.name,
item: ItemSig {
span: m.span,
id: m.id,
name: None,
kind: ItemKind::Module(ComponentTypeUse::Ref(idx)),
},
});
}
}
}
ComponentField::Instance(i) => {
for name in i.exports.names.drain(..) {
self.component_fields_to_append.push(export(
i.span,
name,
DefTypeKind::Instance,
&mut i.id,
));
}
match &mut i.kind {
InstanceKind::Import { import, ty } => {
let idx = self.expand_component_type_use(ty);
*item = ComponentField::Import(ComponentImport {
span: i.span,
name: import.name,
item: ItemSig {
span: i.span,
id: i.id,
name: None,
kind: ItemKind::Instance(ComponentTypeUse::Ref(idx)),
},
});
}
InstanceKind::Module { args, .. } => {
for arg in args {
self.expand_module_arg(&mut arg.arg);
}
}
InstanceKind::Component { args, .. } => {
for arg in args {
self.expand_component_arg(&mut arg.arg);
}
}
InstanceKind::BundleOfExports { .. }
| InstanceKind::BundleOfComponentExports { .. } => {}
}
}
ComponentField::Export(e) => {
self.expand_component_arg(&mut e.arg);
}
ComponentField::Alias(_) | ComponentField::Start(_) => {}
}
fn export<'a>(
span: Span,
name: &'a str,
kind: DefTypeKind,
id: &mut Option<Id<'a>>,
) -> ComponentField<'a> {
let id = gensym::fill(span, id);
ComponentField::Export(ComponentExport {
span,
name,
arg: ComponentArg::Def(ItemRef {
idx: Index::Id(id),
kind,
export_names: Vec::new(),
}),
})
}
}
fn expand_type_field(&mut self, field: &mut TypeField<'a>) {
match &mut field.def {
ComponentTypeDef::DefType(t) => self.expand_deftype(t),
ComponentTypeDef::InterType(t) => self.expand_intertype(t),
}
let name = gensym::fill(field.span, &mut field.id);
let name = Index::Id(name);
match &field.def {
ComponentTypeDef::DefType(DefType::Func(t)) => t.key().insert(self, name),
ComponentTypeDef::DefType(DefType::Module(t)) => t.key().insert(self, name),
ComponentTypeDef::DefType(DefType::Component(t)) => t.key().insert(self, name),
ComponentTypeDef::DefType(DefType::Instance(t)) => t.key().insert(self, name),
ComponentTypeDef::DefType(DefType::Value(t)) => t.key().insert(self, name),
ComponentTypeDef::InterType(t) => t.key().insert(self, name),
}
}
fn expand_deftype(&mut self, ty: &mut DefType<'a>) {
match ty {
DefType::Func(t) => self.expand_func_ty(t),
DefType::Module(m) => self.expand_module_ty(m),
DefType::Component(c) => self.expand_component_ty(c),
DefType::Instance(i) => self.expand_instance_ty(i),
DefType::Value(v) => self.expand_value_ty(v),
}
}
fn expand_func_ty(&mut self, ty: &mut ComponentFunctionType<'a>) {
for param in ty.params.iter_mut() {
self.expand_intertype_ref(&mut param.type_);
}
self.expand_intertype_ref(&mut ty.result);
}
fn expand_module_ty(&mut self, ty: &mut ModuleType<'a>) {
use crate::core::resolve::types::{FuncKey, TypeKey, TypeReference};
// Note that this is a custom implementation from everything else in
// this file since this is using core wasm types instead of component
// types, so a small part of the core wasm expansion process is
// inlined here to handle the `TypeUse` from core wasm.
let mut func_type_to_idx = HashMap::new();
let mut to_prepend = Vec::new();
let mut i = 0;
while i < ty.defs.len() {
match &mut ty.defs[i] {
ModuleTypeDef::Type(ty) => match &ty.def {
core::TypeDef::Func(f) => {
let id = gensym::fill(ty.span, &mut ty.id);
func_type_to_idx.insert(f.key(), Index::Id(id));
}
core::TypeDef::Struct(_) => {}
core::TypeDef::Array(_) => {}
},
ModuleTypeDef::Import(ty) => {
expand_sig(&mut ty.item, &mut to_prepend, &mut func_type_to_idx);
}
ModuleTypeDef::Export(_, item) => {
expand_sig(item, &mut to_prepend, &mut func_type_to_idx);
}
}
ty.defs.splice(i..i, to_prepend.drain(..));
i += 1;
}
fn expand_sig<'a>(
item: &mut core::ItemSig<'a>,
to_prepend: &mut Vec<ModuleTypeDef<'a>>,
func_type_to_idx: &mut HashMap<FuncKey<'a>, Index<'a>>,
) {
match &mut item.kind {
core::ItemKind::Func(t) | core::ItemKind::Tag(core::TagType::Exception(t)) => {
// If the index is already filled in then this is skipped
if t.index.is_some() {
return;
}
// Otherwise the inline type information is used to
// generate a type into this module if necessary. If the
// function type already exists we reuse the same key,
// otherwise a fresh type definition is created and we use
// that one instead.
let ty = t.inline.take().unwrap_or_default();
let key = ty.key();
if let Some(idx) = func_type_to_idx.get(&key) {
t.index = Some(idx.clone());
return;
}
let id = gensym::gen(item.span);
to_prepend.push(ModuleTypeDef::Type(core::Type {
span: item.span,
id: Some(id),
name: None,
def: key.to_def(item.span),
}));
let idx = Index::Id(id);
t.index = Some(idx);
}
core::ItemKind::Global(_)
| core::ItemKind::Table(_)
| core::ItemKind::Memory(_) => {}
}
}
}
fn expand_component_ty(&mut self, ty: &mut ComponentType<'a>) {
Expander::default().expand_fields(&mut ty.fields, |e, field| match field {
ComponentTypeField::Type(t) => e.expand_type_field(t),
ComponentTypeField::Alias(_) => {}
ComponentTypeField::Export(t) => e.expand_item_sig(&mut t.item),
ComponentTypeField::Import(t) => e.expand_item_sig(&mut t.item),
})
}
fn expand_instance_ty(&mut self, ty: &mut InstanceType<'a>) {
Expander::default().expand_fields(&mut ty.fields, |e, field| match field {
InstanceTypeField::Type(t) => e.expand_type_field(t),
InstanceTypeField::Alias(_) => {}
InstanceTypeField::Export(t) => e.expand_item_sig(&mut t.item),
})
}
fn expand_item_sig(&mut self, sig: &mut ItemSig<'a>) {
match &mut sig.kind {
ItemKind::Component(t) => self.expand_component_type_use(t),
ItemKind::Module(t) => self.expand_component_type_use(t),
ItemKind::Instance(t) => self.expand_component_type_use(t),
ItemKind::Value(t) => self.expand_component_type_use(t),
ItemKind::Func(t) => self.expand_component_type_use(t),
};
}
fn expand_value_ty(&mut self, ty: &mut ValueType<'a>) {
self.expand_intertype_ref(&mut ty.value_type);
}
fn expand_intertype(&mut self, ty: &mut InterType<'a>) {
match ty {
InterType::Primitive(_) | InterType::Flags(_) | InterType::Enum(_) => {}
InterType::Record(r) => {
for field in r.fields.iter_mut() {
self.expand_intertype_ref(&mut field.type_);
}
}
InterType::Variant(v) => {
for case in v.cases.iter_mut() {
self.expand_intertype_ref(&mut case.type_);
}
}
InterType::List(t) => {
self.expand_intertype_ref(&mut t.element);
}
InterType::Tuple(t) => {
for field in t.fields.iter_mut() {
self.expand_intertype_ref(field);
}
}
InterType::Union(u) => {
for arm in u.arms.iter_mut() {
self.expand_intertype_ref(arm);
}
}
InterType::Option(t) => {
self.expand_intertype_ref(&mut t.element);
}
InterType::Expected(e) => {
self.expand_intertype_ref(&mut e.ok);
self.expand_intertype_ref(&mut e.err);
}
}
}
fn expand_intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) {
let inline = match ty {
InterTypeRef::Primitive(_) | InterTypeRef::Ref(_) => return,
InterTypeRef::Inline(inline) => {
mem::replace(inline, InterType::Primitive(Primitive::Unit))
}
};
// If this inline type has already been defined within this context
// then reuse the previously defined type to avoid injecting too many
// types into the type index space.
if let Some(idx) = inline.key().lookup(self) {
*ty = InterTypeRef::Ref(idx);
return;
}
// And if this type isn't already defined we append it to the index
// space with a fresh and unique name.
let span = Span::from_offset(0); // FIXME(#613): don't manufacture
let id = gensym::gen(span);
self.to_prepend.push(TypeField {
span,
id: Some(id),
name: None,
def: inline.into_def(),
});
let idx = Index::Id(id);
*ty = InterTypeRef::Ref(idx);
}
fn expand_component_type_use<T>(
&mut self,
item: &mut ComponentTypeUse<'a, T>,
) -> ItemRef<'a, kw::r#type>
where
T: TypeReference<'a>,
{
let span = Span::from_offset(0); // FIXME(#613): don't manufacture
let dummy = ComponentTypeUse::Ref(ItemRef {
idx: Index::Num(0, span),
kind: kw::r#type(span),
export_names: Vec::new(),
});
let mut inline = match mem::replace(item, dummy) {
// If this type-use was already a reference to an existing type
// then we put it back the way it was and return the corresponding
// index.
ComponentTypeUse::Ref(idx) => {
*item = ComponentTypeUse::Ref(idx.clone());
return idx;
}
// ... otherwise with an inline type definition we go into
// processing below.
ComponentTypeUse::Inline(inline) => inline,
};
inline.expand(self);
// If this inline type has already been defined within this context
// then reuse the previously defined type to avoid injecting too many
// types into the type index space.
if let Some(idx) = inline.key().lookup(self) {
let ret = ItemRef {
idx,
kind: kw::r#type(span),
export_names: Vec::new(),
};
*item = ComponentTypeUse::Ref(ret.clone());
return ret;
}
// And if this type isn't already defined we append it to the index
// space with a fresh and unique name.
let id = gensym::gen(span);
self.to_prepend.push(TypeField {
span,
id: Some(id),
name: None,
def: inline.into_def(),
});
let idx = Index::Id(id);
let ret = ItemRef {
idx,
kind: kw::r#type(span),
export_names: Vec::new(),
};
*item = ComponentTypeUse::Ref(ret.clone());
return ret;
}
fn expand_module_arg(&mut self, arg: &mut ModuleArg<'a>) {
let (span, args) = match arg {
ModuleArg::Def(_) => return,
ModuleArg::BundleOfExports(span, exports) => (*span, mem::take(exports)),
};
let id = gensym::gen(span);
self.component_fields_to_prepend
.push(ComponentField::Instance(Instance {
span,
id: Some(id),
name: None,
exports: Default::default(),
kind: InstanceKind::BundleOfExports { args },
}));
*arg = ModuleArg::Def(ItemRef {
idx: Index::Id(id),
kind: kw::instance(span),
export_names: Vec::new(),
});
}
fn expand_component_arg(&mut self, arg: &mut ComponentArg<'a>) {
let (span, args) = match arg {
ComponentArg::Def(_) => return,
ComponentArg::BundleOfExports(span, exports) => (*span, mem::take(exports)),
};
let id = gensym::gen(span);
self.component_fields_to_prepend
.push(ComponentField::Instance(Instance {
span,
id: Some(id),
name: None,
exports: Default::default(),
kind: InstanceKind::BundleOfComponentExports { args },
}));
*arg = ComponentArg::Def(ItemRef {
idx: Index::Id(id),
kind: DefTypeKind::Instance,
export_names: Vec::new(),
});
}
}
trait TypeReference<'a> {
type Key: TypeKey<'a>;
fn key(&self) -> Self::Key;
fn expand(&mut self, cx: &mut Expander<'a>);
fn into_def(self) -> ComponentTypeDef<'a>;
}
impl<'a> TypeReference<'a> for InterType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_intertype(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::InterType(self)
}
}
impl<'a> TypeReference<'a> for ComponentType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_component_ty(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::DefType(DefType::Component(self))
}
}
impl<'a> TypeReference<'a> for ModuleType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_module_ty(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::DefType(DefType::Module(self))
}
}
impl<'a> TypeReference<'a> for InstanceType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_instance_ty(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::DefType(DefType::Instance(self))
}
}
impl<'a> TypeReference<'a> for ComponentFunctionType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_func_ty(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::DefType(DefType::Func(self))
}
}
impl<'a> TypeReference<'a> for ValueType<'a> {
type Key = Todo; // FIXME(#598): should implement this
fn key(&self) -> Self::Key {
Todo
}
fn expand(&mut self, cx: &mut Expander<'a>) {
cx.expand_value_ty(self)
}
fn into_def(self) -> ComponentTypeDef<'a> {
ComponentTypeDef::DefType(DefType::Value(self))
}
}
trait TypeKey<'a> {
fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>>;
fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>);
}
struct Todo;
impl<'a> TypeKey<'a> for Todo {
fn lookup(&self, _cx: &Expander<'a>) -> Option<Index<'a>> {
None
}
fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>) {
drop((cx, id));
}
}

26
third_party/rust/wast/src/component/export.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,26 @@
use crate::component::ComponentArg;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::Span;
/// A entry in a WebAssembly component's export section.
///
/// export ::= (export <name> <componentarg>)
#[derive(Debug)]
pub struct ComponentExport<'a> {
/// Where this export was defined.
pub span: Span,
/// The name of this export from the component.
pub name: &'a str,
/// What's being exported from the component.
pub arg: ComponentArg<'a>,
}
impl<'a> Parse<'a> for ComponentExport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::export>()?.0;
let name = parser.parse()?;
let arg = parser.parse()?;
Ok(ComponentExport { span, name, arg })
}
}

197
third_party/rust/wast/src/component/func.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,197 @@
use crate::component::*;
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, LParen, NameAnnotation, Span};
/// A WebAssembly function to be inserted into a module.
///
/// This is a member of both the function and code sections.
#[derive(Debug)]
pub struct ComponentFunc<'a> {
/// Where this `func` was defined.
pub span: Span,
/// An identifier that this function is resolved with (optionally) for name
/// resolution.
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: core::InlineExport<'a>,
/// What kind of function this is, be it an inline-defined or imported
/// function.
pub kind: ComponentFuncKind<'a>,
}
/// Possible ways to define a function in the text format.
#[derive(Debug)]
pub enum ComponentFuncKind<'a> {
/// A function which is actually defined as an import, such as:
///
/// ```text
/// (func (import "foo") (type 3))
/// ```
Import {
/// The import name of this import
import: InlineImport<'a>,
/// The type that this function will have.
ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>,
},
/// Almost all functions, those defined inline in a wasm module.
Inline {
/// The body of the function.
body: ComponentFuncBody<'a>,
},
}
impl<'a> Parse<'a> for ComponentFunc<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::func>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let exports = parser.parse()?;
let kind = if let Some(import) = parser.parse()? {
ComponentFuncKind::Import {
import,
ty: parser.parse()?,
}
} else {
ComponentFuncKind::Inline {
body: parser.parens(|p| p.parse())?,
}
};
Ok(ComponentFunc {
span,
id,
name,
exports,
kind,
})
}
}
/// The body of a `ComponentFunc`.
#[derive(Debug)]
pub enum ComponentFuncBody<'a> {
/// A `canon.lift`.
CanonLift(CanonLift<'a>),
/// A `canon.lower`.
CanonLower(CanonLower<'a>),
}
impl<'a> Parse<'a> for ComponentFuncBody<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::canon_lift>() {
Ok(ComponentFuncBody::CanonLift(parser.parse()?))
} else if parser.peek::<kw::canon_lower>() {
Ok(ComponentFuncBody::CanonLower(parser.parse()?))
} else {
Err(parser.error("Expected canon.lift or canon.lower"))
}
}
}
/// Extra information associated with canon.lift instructions.
#[derive(Debug)]
pub struct CanonLift<'a> {
/// The type exported to other components
pub type_: ComponentTypeUse<'a, ComponentFunctionType<'a>>,
/// Configuration options
pub opts: Vec<CanonOpt<'a>>,
/// The function to wrap
pub func: ItemRef<'a, kw::func>,
}
impl<'a> Parse<'a> for CanonLift<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::canon_lift>()?;
let type_ = if parser.peek2::<kw::func>() {
ComponentTypeUse::Inline(parser.parens(|p| {
p.parse::<kw::func>()?;
p.parse()
})?)
} else {
ComponentTypeUse::Ref(parser.parse()?)
};
let mut opts = Vec::new();
while !parser.peek2::<kw::func>() {
opts.push(parser.parse()?);
}
let func = parser.parse()?;
Ok(CanonLift { type_, opts, func })
}
}
/// Extra information associated with canon.lower instructions.
#[derive(Debug)]
pub struct CanonLower<'a> {
/// Configuration options
pub opts: Vec<CanonOpt<'a>>,
/// The function being wrapped
pub func: ItemRef<'a, kw::func>,
}
impl<'a> Parse<'a> for CanonLower<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::canon_lower>()?;
let mut opts = Vec::new();
while !parser.is_empty() && (!parser.peek::<LParen>() || !parser.peek2::<kw::func>()) {
opts.push(parser.parse()?);
}
let func = parser.parse()?;
Ok(CanonLower { opts, func })
}
}
#[derive(Debug)]
/// Canonical ABI options.
pub enum CanonOpt<'a> {
/// Encode strings as UTF-8.
StringUtf8,
/// Encode strings as UTF-16.
StringUtf16,
/// Encode strings as "compact UTF-16".
StringLatin1Utf16,
/// A target instance which supplies the memory that the canonical ABI
/// should operate on as well as functions that the canonical ABI can call
/// to allocate, reallocate and free linear memory
Into(ItemRef<'a, kw::instance>),
}
impl<'a> Parse<'a> for CanonOpt<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::string_utf8>() {
parser.parse::<kw::string_utf8>()?;
Ok(CanonOpt::StringUtf8)
} else if l.peek::<kw::string_utf16>() {
parser.parse::<kw::string_utf16>()?;
Ok(CanonOpt::StringUtf16)
} else if l.peek::<kw::string_latin1_utf16>() {
parser.parse::<kw::string_latin1_utf16>()?;
Ok(CanonOpt::StringLatin1Utf16)
} else if l.peek::<LParen>() {
parser.parens(|parser| {
let mut l = parser.lookahead1();
if l.peek::<kw::into>() {
parser.parse::<kw::into>()?;
Ok(CanonOpt::Into(parser.parse::<IndexOrRef<'_, _>>()?.0))
} else {
Err(l.error())
}
})
} else {
Err(l.error())
}
}
}
impl Default for kw::instance {
fn default() -> kw::instance {
kw::instance(Span::from_offset(0))
}
}

121
third_party/rust/wast/src/component/import.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,121 @@
use crate::component::*;
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::{Id, NameAnnotation, Span};
/// An `import` statement and entry in a WebAssembly component.
#[derive(Debug)]
pub struct ComponentImport<'a> {
/// Where this `import` was defined
pub span: Span,
/// The name of the item to import.
pub name: &'a str,
/// The item that's being imported.
pub item: ItemSig<'a>,
}
impl<'a> Parse<'a> for ComponentImport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::import>()?.0;
let name = parser.parse()?;
let item = parser.parens(|p| p.parse())?;
Ok(ComponentImport { span, name, item })
}
}
#[derive(Debug)]
#[allow(missing_docs)]
pub struct ItemSig<'a> {
/// Where this item is defined in the source.
pub span: Span,
/// An optional identifier used during name resolution to refer to this item
/// from the rest of the component.
pub id: Option<Id<'a>>,
/// An optional name which, for functions, will be stored in the
/// custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// What kind of item this is.
pub kind: ItemKind<'a>,
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum ItemKind<'a> {
Component(ComponentTypeUse<'a, ComponentType<'a>>),
Module(ComponentTypeUse<'a, ModuleType<'a>>),
Instance(ComponentTypeUse<'a, InstanceType<'a>>),
Value(ComponentTypeUse<'a, ValueType<'a>>),
Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>),
}
impl<'a> Parse<'a> for ItemSig<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
let (span, parse_kind): (_, fn(Parser<'a>) -> Result<ItemKind>) =
if l.peek::<kw::component>() {
let span = parser.parse::<kw::component>()?.0;
(span, |parser| Ok(ItemKind::Component(parser.parse()?)))
} else if l.peek::<kw::module>() {
let span = parser.parse::<kw::module>()?.0;
(span, |parser| Ok(ItemKind::Module(parser.parse()?)))
} else if l.peek::<kw::instance>() {
let span = parser.parse::<kw::instance>()?.0;
(span, |parser| Ok(ItemKind::Instance(parser.parse()?)))
} else if l.peek::<kw::func>() {
let span = parser.parse::<kw::func>()?.0;
(span, |parser| Ok(ItemKind::Func(parser.parse()?)))
} else if l.peek::<kw::value>() {
let span = parser.parse::<kw::value>()?.0;
(span, |parser| Ok(ItemKind::Value(parser.parse()?)))
} else {
return Err(l.error());
};
Ok(ItemSig {
span,
id: parser.parse()?,
name: parser.parse()?,
kind: parse_kind(parser)?,
})
}
}
/// A listing of a inline `(import "foo")` statement.
///
/// This is the same as `core::InlineImport` except only one string import is
/// required.
#[derive(Debug, Copy, Clone)]
#[allow(missing_docs)]
pub struct InlineImport<'a> {
pub name: &'a str,
}
impl<'a> Parse<'a> for InlineImport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parens(|p| {
p.parse::<kw::import>()?;
Ok(InlineImport { name: p.parse()? })
})
}
}
impl Peek for InlineImport<'_> {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
Some(cursor) => cursor,
None => return false,
};
let cursor = match cursor.keyword() {
Some(("import", cursor)) => cursor,
_ => return false,
};
let cursor = match cursor.string() {
Some((_, cursor)) => cursor,
None => return false,
};
cursor.rparen().is_some()
}
fn display() -> &'static str {
"inline import"
}
}

253
third_party/rust/wast/src/component/instance.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,253 @@
use crate::component::*;
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, Index, LParen, NameAnnotation, Span};
/// A nested WebAssembly instance to be created as part of a module.
#[derive(Debug)]
pub struct Instance<'a> {
/// Where this `instance` was defined.
pub span: Span,
/// An identifier that this instance is resolved with (optionally) for name
/// resolution.
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: core::InlineExport<'a>,
/// What kind of instance this is, be it an inline-defined or imported one.
pub kind: InstanceKind<'a>,
}
/// Possible ways to define a instance in the text format.
#[derive(Debug)]
pub enum InstanceKind<'a> {
/// The `(instance (import "x"))` sugar syntax
Import {
/// The name of the import
import: InlineImport<'a>,
/// The type of the instance being imported
ty: ComponentTypeUse<'a, InstanceType<'a>>,
},
/// Instantiate a core module.
Module {
/// Module that we're instantiating
module: ItemRef<'a, kw::module>,
/// Arguments used to instantiate the instance
args: Vec<NamedModuleArg<'a>>,
},
/// Instantiate a component.
Component {
/// Component that we're instantiating
component: ItemRef<'a, kw::component>,
/// Arguments used to instantiate the instance
args: Vec<NamedComponentArg<'a>>,
},
/// A bundle of module exports which isn't an instance, but can be used
/// in places that need an instance.
BundleOfExports {
/// Arguments used to create the anonymous instance
args: Vec<CoreExport<'a>>,
},
/// A bundle of component exports which isn't an instance, but can be used
/// in places that need an instance.
BundleOfComponentExports {
/// Arguments used to create the anonymous instance
args: Vec<ComponentExport<'a>>,
},
}
/// Arguments to the module `instantiate` instruction
#[derive(Debug)]
#[allow(missing_docs)]
pub struct NamedModuleArg<'a> {
pub name: &'a str,
pub arg: ModuleArg<'a>,
}
impl<'a> Parse<'a> for NamedModuleArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::with>()?;
Ok(NamedModuleArg {
name: parser.parse()?,
arg: parser.parse()?,
})
}
}
/// Arguments to the component `instantiate` instruction
#[derive(Debug)]
#[allow(missing_docs)]
pub struct NamedComponentArg<'a> {
pub name: &'a str,
pub arg: ComponentArg<'a>,
}
impl<'a> Parse<'a> for NamedComponentArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::with>()?;
Ok(NamedComponentArg {
name: parser.parse()?,
arg: parser.parse()?,
})
}
}
/// ```text
/// modulearg ::= (instance <instanceidx>)
/// | (instance <core:export>*)
/// ```
#[derive(Debug)]
pub enum ModuleArg<'a> {
/// Core modules can reference instances.
Def(ItemRef<'a, kw::instance>),
/// `instance`, but it isn't actually an instance; it's a tuple of exports
/// which can be used in place of an instance.
BundleOfExports(Span, Vec<CoreExport<'a>>),
}
/// ```text
/// componentarg ::= (module <moduleidx>)
/// | (component <componentidx>)
/// | (instance <instanceidx>)
/// | (func <funcidx>)
/// | (value <valueidx>)
/// | (instance <export>*)
/// ```
#[derive(Debug)]
pub enum ComponentArg<'a> {
/// A reference to an item of one of the deftype kinds.
Def(ItemRef<'a, DefTypeKind>),
/// `instance`, but it isn't actually an instance; it's a tuple of exports
/// which can be used in place of an instance.
BundleOfExports(Span, Vec<ComponentExport<'a>>),
}
impl<'a> Parse<'a> for Instance<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::instance>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let exports = parser.parse()?;
let kind = if let Some(import) = parser.parse()? {
InstanceKind::Import {
import,
ty: parser.parse()?,
}
} else if parser.peek::<LParen>() && parser.peek2::<kw::instantiate>() {
parser.parens(|p| {
p.parse::<kw::instantiate>()?;
if p.peek2::<kw::module>() {
let module = p.parse()?;
let mut args = Vec::new();
while !p.is_empty() {
args.push(p.parens(|p| p.parse())?);
}
Ok(InstanceKind::Module { module, args })
} else if p.peek2::<kw::component>() {
let component = p.parse()?;
let mut args = Vec::new();
while !p.is_empty() {
args.push(p.parens(|p| p.parse())?);
}
Ok(InstanceKind::Component { component, args })
} else {
return Err(parser.error("expected module or component"));
}
})?
} else if parser.peek::<kw::core>() {
parser.parse::<kw::core>()?;
let mut args = Vec::new();
while !parser.is_empty() {
args.push(parser.parens(|p| p.parse())?);
}
InstanceKind::BundleOfExports { args }
} else {
let mut args = Vec::new();
while !parser.is_empty() {
args.push(parser.parens(|p| p.parse())?);
}
InstanceKind::BundleOfComponentExports { args }
};
Ok(Instance {
span,
id,
name,
exports,
kind,
})
}
}
impl<'a> Parse<'a> for ModuleArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<ItemRef<'a, kw::instance>>() && parser.peek3::<Index>() {
// `(instance <index>)`
let def = parser.parse::<ItemRef<kw::instance>>()?;
Ok(ModuleArg::Def(def))
} else if parser.peek::<LParen>() && parser.peek2::<kw::instance>() {
let (span, exports) = parser.parens(|p| {
let span = p.parse::<kw::instance>()?.0;
let mut exports = Vec::new();
while !parser.is_empty() {
exports.push(parser.parens(|parser| parser.parse())?);
}
Ok((span, exports))
})?;
Ok(ModuleArg::BundleOfExports(span, exports))
} else {
Err(parser.error("expected an instance"))
}
}
}
impl<'a> Parse<'a> for ComponentArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<ItemRef<'a, DefTypeKind>>() && parser.peek3::<Index>() {
// `(<deftypekind> <index>)`
let def = parser.parse::<ItemRef<'a, DefTypeKind>>()?;
Ok(ComponentArg::Def(def))
} else if parser.peek::<LParen>() && parser.peek2::<kw::instance>() {
let (span, exports) = parser.parens(|p| {
let span = p.parse::<kw::instance>()?.0;
let mut exports = Vec::new();
while !p.is_empty() {
exports.push(p.parens(|p| p.parse())?);
}
Ok((span, exports))
})?;
Ok(ComponentArg::BundleOfExports(span, exports))
} else {
Err(parser.error("expected def type, type, or instance"))
}
}
}
/// A entry in a WebAssembly module's export section.
#[derive(Debug)]
pub struct CoreExport<'a> {
/// Where this export was defined.
pub span: Span,
/// The name of this export from the module.
pub name: &'a str,
/// What's being exported from the module.
pub index: ItemRef<'a, core::ExportKind>,
}
impl<'a> Parse<'a> for CoreExport<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(CoreExport {
span: parser.parse::<kw::export>()?.0,
name: parser.parse()?,
index: parser.parse()?,
})
}
}

369
third_party/rust/wast/src/component/intertype.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,369 @@
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::*;
/// An interface-types type.
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum Primitive {
Unit,
Bool,
S8,
U8,
S16,
U16,
S32,
U32,
S64,
U64,
Float32,
Float64,
Char,
String,
}
impl<'a> Parse<'a> for Primitive {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::unit>() {
parser.parse::<kw::unit>()?;
Ok(Primitive::Unit)
} else if l.peek::<kw::bool_>() {
parser.parse::<kw::bool_>()?;
Ok(Primitive::Bool)
} else if l.peek::<kw::s8>() {
parser.parse::<kw::s8>()?;
Ok(Primitive::S8)
} else if l.peek::<kw::u8>() {
parser.parse::<kw::u8>()?;
Ok(Primitive::U8)
} else if l.peek::<kw::s16>() {
parser.parse::<kw::s16>()?;
Ok(Primitive::S16)
} else if l.peek::<kw::u16>() {
parser.parse::<kw::u16>()?;
Ok(Primitive::U16)
} else if l.peek::<kw::s32>() {
parser.parse::<kw::s32>()?;
Ok(Primitive::S32)
} else if l.peek::<kw::u32>() {
parser.parse::<kw::u32>()?;
Ok(Primitive::U32)
} else if l.peek::<kw::s64>() {
parser.parse::<kw::s64>()?;
Ok(Primitive::S64)
} else if l.peek::<kw::u64>() {
parser.parse::<kw::u64>()?;
Ok(Primitive::U64)
} else if l.peek::<kw::float32>() {
parser.parse::<kw::float32>()?;
Ok(Primitive::Float32)
} else if l.peek::<kw::float64>() {
parser.parse::<kw::float64>()?;
Ok(Primitive::Float64)
} else if l.peek::<kw::char>() {
parser.parse::<kw::char>()?;
Ok(Primitive::Char)
} else if l.peek::<kw::string>() {
parser.parse::<kw::string>()?;
Ok(Primitive::String)
} else {
Err(l.error())
}
}
}
/// An interface-types type.
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum InterType<'a> {
Primitive(Primitive),
Record(Record<'a>),
Variant(Variant<'a>),
List(List<'a>),
Tuple(Tuple<'a>),
Flags(Flags<'a>),
Enum(Enum<'a>),
Union(Union<'a>),
Option(OptionType<'a>),
Expected(Expected<'a>),
}
impl<'a> Parse<'a> for InterType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<LParen>() {
parser.parens(|parser| {
if parser.peek::<kw::record>() {
let record = parser.parse()?;
Ok(InterType::Record(record))
} else if parser.peek::<kw::variant>() {
let variant = parser.parse()?;
Ok(InterType::Variant(variant))
} else if parser.peek::<kw::list>() {
let list = parser.parse()?;
Ok(InterType::List(list))
} else if parser.peek::<kw::tuple>() {
let tuple = parser.parse()?;
Ok(InterType::Tuple(tuple))
} else if parser.peek::<kw::flags>() {
let flags = parser.parse()?;
Ok(InterType::Flags(flags))
} else if parser.peek::<kw::enum_>() {
let enum_ = parser.parse()?;
Ok(InterType::Enum(enum_))
} else if parser.peek::<kw::union>() {
let union = parser.parse()?;
Ok(InterType::Union(union))
} else if parser.peek::<kw::option>() {
let optional = parser.parse()?;
Ok(InterType::Option(optional))
} else if parser.peek::<kw::expected>() {
let expected = parser.parse()?;
Ok(InterType::Expected(expected))
} else {
Err(parser.error("expected derived intertype"))
}
})
} else {
Ok(InterType::Primitive(parser.parse()?))
}
}
}
/// An interface-types type.
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum InterTypeRef<'a> {
Primitive(Primitive),
Inline(InterType<'a>),
Ref(Index<'a>),
}
impl<'a> Parse<'a> for InterTypeRef<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
Ok(InterTypeRef::Ref(parser.parse()?))
} else if parser.peek::<LParen>() {
Ok(InterTypeRef::Inline(parser.parse()?))
} else {
Ok(InterTypeRef::Primitive(parser.parse()?))
}
}
}
/// An interface-types record, aka a struct.
#[derive(Debug, Clone)]
pub struct Record<'a> {
/// The fields of the struct.
pub fields: Vec<Field<'a>>,
}
impl<'a> Parse<'a> for Record<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::record>()?;
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(|p| p.parse())?);
}
Ok(Record { fields })
}
}
/// An interface-types record field.
#[derive(Debug, Clone)]
pub struct Field<'a> {
/// The name of the field.
pub name: &'a str,
/// The type of the field.
pub type_: InterTypeRef<'a>,
}
impl<'a> Parse<'a> for Field<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::field>()?;
Ok(Field {
name: parser.parse()?,
type_: parser.parse()?,
})
}
}
/// An interface-types variant, aka a discriminated union with named arms.
#[derive(Debug, Clone)]
pub struct Variant<'a> {
/// The cases of the variant type.
pub cases: Vec<Case<'a>>,
}
impl<'a> Parse<'a> for Variant<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::variant>()?;
let mut cases = Vec::new();
while !parser.is_empty() {
cases.push(parser.parens(|p| p.parse())?);
}
Ok(Variant { cases })
}
}
/// An interface-types variant case.
#[derive(Debug, Clone)]
pub struct Case<'a> {
/// The name of the case.
pub name: &'a str,
/// Where this `component` was defined
pub span: Span,
/// The type of the case.
pub type_: InterTypeRef<'a>,
/// The optional defaults-to name.
pub defaults_to: Option<&'a str>,
}
impl<'a> Parse<'a> for Case<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::case>()?.0;
let name = parser.parse()?;
let type_ = parser.parse()?;
let defaults_to = if !parser.is_empty() {
Some(parser.parens(|parser| {
parser.parse::<kw::defaults_to>()?;
Ok(parser.parse()?)
})?)
} else {
None
};
Ok(Case {
name,
span,
type_,
defaults_to,
})
}
}
/// An interface-types list, aka a fixed-size array.
#[derive(Debug, Clone)]
pub struct List<'a> {
/// The element type of the array.
pub element: Box<InterTypeRef<'a>>,
}
impl<'a> Parse<'a> for List<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::list>()?;
let ty = parser.parse()?;
Ok(List {
element: Box::new(ty),
})
}
}
/// An interface-types tuple, aka a record with anonymous fields.
#[derive(Debug, Clone)]
pub struct Tuple<'a> {
/// The types of the fields of the tuple.
pub fields: Vec<InterTypeRef<'a>>,
}
impl<'a> Parse<'a> for Tuple<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::tuple>()?;
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parse()?);
}
Ok(Tuple { fields })
}
}
/// An interface-types flags, aka a fixed-sized bitfield with named fields.
#[derive(Debug, Clone)]
pub struct Flags<'a> {
/// The names of the individual flags.
pub flag_names: Vec<&'a str>,
}
impl<'a> Parse<'a> for Flags<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::flags>()?;
let mut flag_names = Vec::new();
while !parser.is_empty() {
flag_names.push(parser.parse()?);
}
Ok(Flags { flag_names })
}
}
/// An interface-types enum, aka a discriminated union with unit arms.
#[derive(Debug, Clone)]
pub struct Enum<'a> {
/// The arms of the enum.
pub arms: Vec<&'a str>,
}
impl<'a> Parse<'a> for Enum<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::enum_>()?;
let mut arms = Vec::new();
while !parser.is_empty() {
arms.push(parser.parse()?);
}
Ok(Enum { arms })
}
}
/// An interface-types union, aka a discriminated union with anonymous arms.
#[derive(Debug, Clone)]
pub struct Union<'a> {
/// The arms of the union.
pub arms: Vec<InterTypeRef<'a>>,
}
impl<'a> Parse<'a> for Union<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::union>()?;
let mut arms = Vec::new();
while !parser.is_empty() {
arms.push(parser.parse()?);
}
Ok(Union { arms })
}
}
/// An interface-types optional, aka an option.
#[derive(Debug, Clone)]
pub struct OptionType<'a> {
/// The type of the value, when a value is present.
pub element: Box<InterTypeRef<'a>>,
}
impl<'a> Parse<'a> for OptionType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::option>()?;
let ty = parser.parse()?;
Ok(OptionType {
element: Box::new(ty),
})
}
}
/// An interface-types expected, aka an result.
#[derive(Debug, Clone)]
pub struct Expected<'a> {
/// The type on success.
pub ok: Box<InterTypeRef<'a>>,
/// The type on failure.
pub err: Box<InterTypeRef<'a>>,
}
impl<'a> Parse<'a> for Expected<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::expected>()?;
let ok = parser.parse()?;
let err = parser.parse()?;
Ok(Expected {
ok: Box::new(ok),
err: Box::new(err),
})
}
}

98
third_party/rust/wast/src/component/item_ref.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,98 @@
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::Index;
/// Parses `(func $foo)`
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct ItemRef<'a, K> {
pub kind: K,
pub idx: Index<'a>,
pub export_names: Vec<&'a str>,
}
impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parens(|parser| {
let kind = parser.parse::<K>()?;
let idx = parser.parse()?;
let mut export_names = Vec::new();
while !parser.is_empty() {
export_names.push(parser.parse()?);
}
Ok(ItemRef {
kind,
idx,
export_names,
})
})
}
}
impl<'a, K: Peek> Peek for ItemRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
match cursor.lparen() {
// This is a little fancy because when parsing something like:
//
// (type (component (type $foo)))
//
// we need to disambiguate that from
//
// (type (component (type $foo (func))))
//
// where the first is a type reference and the second is an inline
// component type defining a type internally. The peek here not only
// peeks for `K` but also for the index and possibly trailing
// strings.
Some(remaining) if K::peek(remaining) => {
let remaining = match remaining.keyword() {
Some((_, remaining)) => remaining,
None => return false,
};
match remaining
.id()
.map(|p| p.1)
.or_else(|| remaining.integer().map(|p| p.1))
{
Some(remaining) => remaining.rparen().is_some() || remaining.string().is_some(),
None => false,
}
}
_ => false,
}
}
fn display() -> &'static str {
"an item reference"
}
}
/// Convenience structure to parse `$f` or `(item $f)`.
#[derive(Clone, Debug)]
pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>);
impl<'a, K> Parse<'a> for IndexOrRef<'a, K>
where
K: Parse<'a> + Default,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
Ok(IndexOrRef(ItemRef {
kind: K::default(),
idx: parser.parse()?,
export_names: Vec::new(),
}))
} else {
Ok(IndexOrRef(parser.parse()?))
}
}
}
impl<'a, K: Peek> Peek for IndexOrRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
Index::peek(cursor) || ItemRef::<K>::peek(cursor)
}
fn display() -> &'static str {
"an item reference"
}
}

28
third_party/rust/wast/src/component/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
//! Types and support for parsing the component model text format.
mod alias;
mod component;
mod deftype;
mod export;
mod func;
mod import;
mod instance;
mod intertype;
mod item_ref;
mod module;
mod types;
pub use self::alias::*;
pub use self::component::*;
pub use self::deftype::*;
pub use self::export::*;
pub use self::func::*;
pub use self::import::*;
pub use self::instance::*;
pub use self::intertype::*;
pub use self::item_ref::*;
pub use self::module::*;
pub use self::types::*;
mod binary;
mod expand;
mod resolve;

Просмотреть файл

@ -1,42 +1,45 @@
use crate::ast::{self, kw};
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::component::*;
use crate::core;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A nested WebAssembly nested module to be created as part of a module.
/// A nested WebAssembly module to be created as part of a component.
#[derive(Debug)]
pub struct NestedModule<'a> {
pub struct Module<'a> {
/// Where this `nested module` was defined.
pub span: ast::Span,
pub span: Span,
/// An identifier that this nested module is resolved with (optionally) for name
/// resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this module stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
pub exports: core::InlineExport<'a>,
/// What kind of nested module this is, be it an inline-defined or imported one.
pub kind: NestedModuleKind<'a>,
pub kind: ModuleKind<'a>,
}
/// Possible ways to define a nested module in the text format.
#[derive(Debug)]
pub enum NestedModuleKind<'a> {
pub enum ModuleKind<'a> {
/// An nested module which is actually defined as an import, such as:
Import {
/// Where this nested module is imported from
import: ast::InlineImport<'a>,
import: InlineImport<'a>,
/// The type that this nested module will have.
ty: ast::TypeUse<'a, ast::ModuleType<'a>>,
ty: ComponentTypeUse<'a, ModuleType<'a>>,
},
/// Nested modules whose instantiation is defined inline.
/// modules whose instantiation is defined inline.
Inline {
/// Fields in the nested module.
fields: Vec<ast::ModuleField<'a>>,
fields: Vec<core::ModuleField<'a>>,
},
}
impl<'a> Parse<'a> for NestedModule<'a> {
impl<'a> Parse<'a> for Module<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// This is sort of a fundamental limitation of the way this crate is
// designed. Everything is done through recursive descent parsing which
@ -57,7 +60,7 @@ impl<'a> Parse<'a> for NestedModule<'a> {
let exports = parser.parse()?;
let kind = if let Some(import) = parser.parse()? {
NestedModuleKind::Import {
ModuleKind::Import {
import,
ty: parser.parse()?,
}
@ -66,10 +69,10 @@ impl<'a> Parse<'a> for NestedModule<'a> {
while !parser.is_empty() {
fields.push(parser.parens(|p| p.parse())?);
}
NestedModuleKind::Inline { fields }
ModuleKind::Inline { fields }
};
Ok(NestedModule {
Ok(Module {
span,
id,
name,
@ -78,38 +81,3 @@ impl<'a> Parse<'a> for NestedModule<'a> {
})
}
}
// Note that this is a custom implementation to get multi-token lookahead to
// figure out how to parse `(type ...` when it's in an inline module. If this is
// `(type $x)` or `(type 0)` then it's an inline type annotation, otherwise it's
// probably a typedef like `(type $x (func))` or something like that. We only
// want to parse the two-token variant right now.
struct InlineType;
impl Peek for InlineType {
fn peek(cursor: Cursor<'_>) -> bool {
let cursor = match cursor.lparen() {
Some(cursor) => cursor,
None => return false,
};
let cursor = match cursor.keyword() {
Some(("type", cursor)) => cursor,
_ => return false,
};
// optional identifier
let cursor = match cursor.id() {
Some((_, cursor)) => cursor,
None => match cursor.integer() {
Some((_, cursor)) => cursor,
None => return false,
},
};
cursor.rparen().is_some()
}
fn display() -> &'static str {
"inline type"
}
}

726
third_party/rust/wast/src/component/resolve.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,726 @@
use crate::component::*;
use crate::core;
use crate::kw;
use crate::names::Namespace;
use crate::token::{Id, Index};
use crate::Error;
/// Resolve the fields of a component and everything nested within it, changing
/// `Index::Id` to `Index::Num` and expanding alias syntax sugar.
pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> {
let fields = match &mut component.kind {
ComponentKind::Text(fields) => fields,
ComponentKind::Binary(_) => return Ok(()),
};
let mut resolver = Resolver::default();
resolver.fields(component.id, fields)
}
#[derive(Default)]
struct Resolver<'a> {
stack: Vec<ComponentState<'a>>,
// When a name refers to a definition in an outer scope, we'll need to
// insert an outer alias before it. This collects the aliases to be
// inserted during resolution.
aliases_to_insert: Vec<Alias<'a>>,
}
/// Context structure used to perform name resolution.
#[derive(Default)]
struct ComponentState<'a> {
id: Option<Id<'a>>,
// Namespaces within each component. Note that each namespace carries
// with it information about the signature of the item in that namespace.
// The signature is later used to synthesize the type of a component and
// inject type annotations if necessary.
funcs: Namespace<'a>,
globals: Namespace<'a>,
tables: Namespace<'a>,
memories: Namespace<'a>,
types: Namespace<'a>,
tags: Namespace<'a>,
instances: Namespace<'a>,
modules: Namespace<'a>,
components: Namespace<'a>,
values: Namespace<'a>,
}
impl<'a> ComponentState<'a> {
fn new(id: Option<Id<'a>>) -> ComponentState<'a> {
ComponentState {
id,
..ComponentState::default()
}
}
}
impl<'a> Resolver<'a> {
fn current(&mut self) -> &mut ComponentState<'a> {
self.stack
.last_mut()
.expect("should have at least one component state")
}
fn fields(
&mut self,
id: Option<Id<'a>>,
fields: &mut Vec<ComponentField<'a>>,
) -> Result<(), Error> {
self.stack.push(ComponentState::new(id));
self.resolve_prepending_aliases(fields, Resolver::field, ComponentState::register)?;
self.stack.pop();
Ok(())
}
fn resolve_prepending_aliases<T>(
&mut self,
fields: &mut Vec<T>,
resolve: fn(&mut Self, &mut T) -> Result<(), Error>,
register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>,
) -> Result<(), Error>
where
T: From<Alias<'a>>,
{
assert!(self.aliases_to_insert.is_empty());
// Iterate through the fields of the component. We use an index
// instead of an iterator because we'll be inserting aliases
// as we go.
let mut i = 0;
while i < fields.len() {
// Resolve names within the field.
resolve(self, &mut fields[i])?;
// Name resolution may have emitted some aliases. Insert them before
// the current definition.
let amt = self.aliases_to_insert.len();
fields.splice(i..i, self.aliases_to_insert.drain(..).map(T::from));
i += amt;
// Definitions can't refer to themselves or to definitions that appear
// later in the format. Now that we're done resolving this field,
// assign it an index for later defintions to refer to.
register(self.current(), &fields[i])?;
i += 1;
}
Ok(())
}
fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> {
match field {
ComponentField::Import(i) => self.item_sig(&mut i.item),
ComponentField::Type(t) => self.type_field(t),
ComponentField::Func(f) => {
let body = match &mut f.kind {
ComponentFuncKind::Import { .. } => return Ok(()),
ComponentFuncKind::Inline { body } => body,
};
let opts = match body {
ComponentFuncBody::CanonLift(lift) => {
self.type_use(&mut lift.type_)?;
self.item_ref(&mut lift.func)?;
&mut lift.opts
}
ComponentFuncBody::CanonLower(lower) => {
self.item_ref(&mut lower.func)?;
&mut lower.opts
}
};
for opt in opts {
match opt {
CanonOpt::StringUtf8
| CanonOpt::StringUtf16
| CanonOpt::StringLatin1Utf16 => {}
CanonOpt::Into(instance) => {
self.item_ref(instance)?;
}
}
}
Ok(())
}
ComponentField::Instance(i) => match &mut i.kind {
InstanceKind::Module { module, args } => {
self.item_ref(module)?;
for arg in args {
match &mut arg.arg {
ModuleArg::Def(def) => {
self.item_ref(def)?;
}
ModuleArg::BundleOfExports(..) => {
unreachable!("should be expanded already");
}
}
}
Ok(())
}
InstanceKind::Component { component, args } => {
self.item_ref(component)?;
for arg in args {
match &mut arg.arg {
ComponentArg::Def(def) => {
self.item_ref(def)?;
}
ComponentArg::BundleOfExports(..) => {
unreachable!("should be expanded already")
}
}
}
Ok(())
}
InstanceKind::BundleOfExports { args } => {
for arg in args {
self.item_ref(&mut arg.index)?;
}
Ok(())
}
InstanceKind::BundleOfComponentExports { args } => {
for arg in args {
self.arg(&mut arg.arg)?;
}
Ok(())
}
InstanceKind::Import { .. } => {
unreachable!("should be removed by expansion")
}
},
ComponentField::Module(m) => {
match &mut m.kind {
ModuleKind::Inline { fields } => {
crate::core::resolve::resolve(fields)?;
}
ModuleKind::Import { .. } => {
unreachable!("should be expanded already")
}
}
Ok(())
}
ComponentField::Component(c) => match &mut c.kind {
NestedComponentKind::Import { .. } => {
unreachable!("should be expanded already")
}
NestedComponentKind::Inline(fields) => self.fields(c.id, fields),
},
ComponentField::Alias(a) => self.alias(a),
ComponentField::Start(s) => {
self.item_ref(&mut s.func)?;
for arg in s.args.iter_mut() {
self.item_ref(arg)?;
}
Ok(())
}
ComponentField::Export(e) => {
self.arg(&mut e.arg)?;
Ok(())
}
}
}
fn item_sig(&mut self, sig: &mut ItemSig<'a>) -> Result<(), Error> {
match &mut sig.kind {
ItemKind::Component(t) => self.type_use(t),
ItemKind::Module(t) => self.type_use(t),
ItemKind::Instance(t) => self.type_use(t),
ItemKind::Func(t) => self.type_use(t),
ItemKind::Value(t) => self.type_use(t),
}
}
fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> {
match &mut alias.target {
AliasTarget::Export {
instance,
export: _,
} => self.resolve_ns(instance, Ns::Instance),
AliasTarget::Outer { outer, index } => {
// Short-circuit when both indices are already resolved as this
// helps to write tests for invalid modules where wasmparser should
// be the one returning the error.
if let Index::Num(..) = outer {
if let Index::Num(..) = index {
return Ok(());
}
}
// Resolve `outer`, and compute the depth at which to look up
// `index`.
let depth = match outer {
Index::Id(id) => {
let mut depth = 0;
for resolver in self.stack.iter_mut().rev() {
if resolver.id == Some(*id) {
break;
}
depth += 1;
}
if depth as usize == self.stack.len() {
return Err(Error::new(
alias.span,
format!("outer component `{}` not found", id.name()),
));
}
depth
}
Index::Num(n, _span) => *n,
};
*outer = Index::Num(depth, alias.span);
if depth as usize >= self.stack.len() {
return Err(Error::new(
alias.span,
format!("component depth of `{}` is too large", depth),
));
}
// Resolve `index` within the computed scope depth.
let ns = match alias.kind {
AliasKind::Module => Ns::Module,
AliasKind::Component => Ns::Component,
AliasKind::Instance => Ns::Instance,
AliasKind::Value => Ns::Value,
AliasKind::ExportKind(kind) => kind.into(),
};
let computed = self.stack.len() - 1 - depth as usize;
self.stack[computed].resolve(ns, index)?;
Ok(())
}
}
}
fn arg(&mut self, arg: &mut ComponentArg<'a>) -> Result<(), Error> {
match arg {
ComponentArg::Def(item_ref) => {
self.item_ref(item_ref)?;
}
ComponentArg::BundleOfExports(..) => unreachable!("should be expanded already"),
}
Ok(())
}
fn type_use<T>(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> {
let item = match ty {
ComponentTypeUse::Ref(r) => r,
ComponentTypeUse::Inline(_) => {
unreachable!("inline type-use should be expanded by now")
}
};
self.item_ref(item)
}
fn intertype(&mut self, ty: &mut InterType<'a>) -> Result<(), Error> {
match ty {
InterType::Primitive(_) => {}
InterType::Flags(_) => {}
InterType::Enum(_) => {}
InterType::Record(r) => {
for field in r.fields.iter_mut() {
self.intertype_ref(&mut field.type_)?;
}
}
InterType::Variant(v) => {
for case in v.cases.iter_mut() {
self.intertype_ref(&mut case.type_)?;
}
}
InterType::List(l) => {
self.intertype_ref(&mut *l.element)?;
}
InterType::Tuple(t) => {
for field in t.fields.iter_mut() {
self.intertype_ref(field)?;
}
}
InterType::Union(t) => {
for arm in t.arms.iter_mut() {
self.intertype_ref(arm)?;
}
}
InterType::Option(o) => {
self.intertype_ref(&mut *o.element)?;
}
InterType::Expected(r) => {
self.intertype_ref(&mut *r.ok)?;
self.intertype_ref(&mut *r.err)?;
}
}
Ok(())
}
fn intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) -> Result<(), Error> {
match ty {
InterTypeRef::Primitive(_) => Ok(()),
InterTypeRef::Ref(idx) => self.resolve_ns(idx, Ns::Type),
InterTypeRef::Inline(_) => unreachable!("should be expanded by now"),
}
}
fn type_field(&mut self, field: &mut TypeField<'a>) -> Result<(), Error> {
match &mut field.def {
ComponentTypeDef::DefType(DefType::Func(f)) => {
for param in f.params.iter_mut() {
self.intertype_ref(&mut param.type_)?;
}
self.intertype_ref(&mut f.result)?;
}
ComponentTypeDef::DefType(DefType::Module(m)) => {
self.stack.push(ComponentState::new(field.id));
self.moduletype(m)?;
self.stack.pop();
}
ComponentTypeDef::DefType(DefType::Component(c)) => {
self.stack.push(ComponentState::new(field.id));
self.nested_component_type(c)?;
self.stack.pop();
}
ComponentTypeDef::DefType(DefType::Instance(i)) => {
self.stack.push(ComponentState::new(field.id));
self.instance_type(i)?;
self.stack.pop();
}
ComponentTypeDef::DefType(DefType::Value(v)) => {
self.intertype_ref(&mut v.value_type)?
}
ComponentTypeDef::InterType(i) => self.intertype(i)?,
}
Ok(())
}
fn nested_component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> {
self.resolve_prepending_aliases(
&mut c.fields,
|resolver, field| match field {
ComponentTypeField::Alias(alias) => resolver.alias(alias),
ComponentTypeField::Type(ty) => resolver.type_field(ty),
ComponentTypeField::Import(import) => resolver.item_sig(&mut import.item),
ComponentTypeField::Export(export) => resolver.item_sig(&mut export.item),
},
|state, field| {
match field {
ComponentTypeField::Alias(alias) => {
state.register_alias(alias)?;
}
ComponentTypeField::Type(ty) => {
state.types.register(ty.id, "type")?;
}
// Only the type namespace is populated within the component type
// namespace so these are ignored here.
ComponentTypeField::Import(_) | ComponentTypeField::Export(_) => {}
}
Ok(())
},
)
}
fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> {
self.resolve_prepending_aliases(
&mut c.fields,
|resolver, field| match field {
InstanceTypeField::Alias(alias) => resolver.alias(alias),
InstanceTypeField::Type(ty) => resolver.type_field(ty),
InstanceTypeField::Export(export) => resolver.item_sig(&mut export.item),
},
|state, field| {
match field {
InstanceTypeField::Alias(alias) => {
state.register_alias(alias)?;
}
InstanceTypeField::Type(ty) => {
state.types.register(ty.id, "type")?;
}
InstanceTypeField::Export(_export) => {}
}
Ok(())
},
)
}
fn item_ref<K>(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error>
where
K: Into<Ns> + Copy,
{
let last_ns = item.kind.into();
// If there are no extra `export_names` listed then this is a reference to
// something defined within this component's index space, so resolve as
// necessary.
if item.export_names.is_empty() {
self.resolve_ns(&mut item.idx, last_ns)?;
return Ok(());
}
// ... otherwise the `index` of `item` refers to an intance and the
// `export_names` refer to recursive exports from this item. Resolve the
// instance locally and then process the export names one at a time,
// injecting aliases as necessary.
let mut index = item.idx.clone();
self.resolve_ns(&mut index, Ns::Instance)?;
let span = item.idx.span();
for (pos, export_name) in item.export_names.iter().enumerate() {
// The last name is in the namespace of the reference. All others are
// instances.
let ns = if pos == item.export_names.len() - 1 {
last_ns
} else {
Ns::Instance
};
// Record an outer alias to be inserted in front of the current
// definition.
let mut alias = Alias {
span,
id: None,
name: None,
target: AliasTarget::Export {
instance: index,
export: export_name,
},
kind: match ns {
Ns::Module => AliasKind::Module,
Ns::Component => AliasKind::Component,
Ns::Instance => AliasKind::Instance,
Ns::Value => AliasKind::Value,
Ns::Func => AliasKind::ExportKind(core::ExportKind::Func),
Ns::Table => AliasKind::ExportKind(core::ExportKind::Table),
Ns::Global => AliasKind::ExportKind(core::ExportKind::Global),
Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory),
Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag),
Ns::Type => AliasKind::ExportKind(core::ExportKind::Type),
},
};
index = Index::Num(self.current().register_alias(&mut alias)?, span);
self.aliases_to_insert.push(alias);
}
item.idx = index;
item.export_names = Vec::new();
Ok(())
}
fn resolve_ns(&mut self, idx: &mut Index<'a>, ns: Ns) -> Result<(), Error> {
// Perform resolution on a local clone walking up the stack of components
// that we have. Note that a local clone is used since we don't want to use
// the parent's resolved index if a parent matches, instead we want to use
// the index of the alias that we will automatically insert.
let mut idx_clone = idx.clone();
for (depth, resolver) in self.stack.iter_mut().rev().enumerate() {
let depth = depth as u32;
let found = match resolver.resolve(ns, &mut idx_clone) {
Ok(idx) => idx,
// Try the next parent
Err(_) => continue,
};
// If this is the current component then no extra alias is necessary, so
// return success.
if depth == 0 {
*idx = idx_clone;
return Ok(());
}
let id = match idx {
Index::Id(id) => id.clone(),
Index::Num(..) => unreachable!(),
};
// When resolution succeeds in a parent then an outer alias is
// automatically inserted here in this component.
let span = idx.span();
let mut alias = Alias {
span,
id: Some(id),
name: None,
target: AliasTarget::Outer {
outer: Index::Num(depth, span),
index: Index::Num(found, span),
},
kind: match ns {
Ns::Module => AliasKind::Module,
Ns::Component => AliasKind::Component,
Ns::Instance => AliasKind::Instance,
Ns::Value => AliasKind::Value,
Ns::Func => AliasKind::ExportKind(core::ExportKind::Func),
Ns::Table => AliasKind::ExportKind(core::ExportKind::Table),
Ns::Global => AliasKind::ExportKind(core::ExportKind::Global),
Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory),
Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag),
Ns::Type => AliasKind::ExportKind(core::ExportKind::Type),
},
};
let local_index = self.current().register_alias(&mut alias)?;
self.aliases_to_insert.push(alias);
*idx = Index::Num(local_index, span);
return Ok(());
}
// If resolution in any parent failed then simply return the error from our
// local namespace
self.current().resolve(ns, idx)?;
unreachable!()
}
fn moduletype(&mut self, ty: &mut ModuleType<'_>) -> Result<(), Error> {
let mut types = Namespace::default();
for def in ty.defs.iter_mut() {
match def {
ModuleTypeDef::Type(t) => {
types.register(t.id, "type")?;
}
ModuleTypeDef::Import(t) => resolve_item_sig(&mut t.item, &types)?,
ModuleTypeDef::Export(_, t) => resolve_item_sig(t, &types)?,
}
}
return Ok(());
fn resolve_item_sig<'a>(
sig: &mut core::ItemSig<'a>,
names: &Namespace<'a>,
) -> Result<(), Error> {
match &mut sig.kind {
core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => {
let idx = ty.index.as_mut().expect("index should be filled in");
names.resolve(idx, "type")?;
}
core::ItemKind::Memory(_)
| core::ItemKind::Global(_)
| core::ItemKind::Table(_) => {}
}
Ok(())
}
}
}
impl<'a> ComponentState<'a> {
fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result<u32, Error> {
match ns {
Ns::Func => self.funcs.resolve(idx, "func"),
Ns::Table => self.tables.resolve(idx, "table"),
Ns::Global => self.globals.resolve(idx, "global"),
Ns::Memory => self.memories.resolve(idx, "memory"),
Ns::Tag => self.tags.resolve(idx, "tag"),
Ns::Type => self.types.resolve(idx, "type"),
Ns::Component => self.components.resolve(idx, "component"),
Ns::Module => self.modules.resolve(idx, "module"),
Ns::Instance => self.instances.resolve(idx, "instance"),
Ns::Value => self.values.resolve(idx, "instance"),
}
}
/// Assign an index to the given field.
fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> {
match item {
ComponentField::Import(i) => match &i.item.kind {
ItemKind::Module(_) => self.modules.register(i.item.id, "module")?,
ItemKind::Component(_) => self.components.register(i.item.id, "component")?,
ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?,
ItemKind::Value(_) => self.values.register(i.item.id, "value")?,
ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?,
},
ComponentField::Func(i) => self.funcs.register(i.id, "func")?,
ComponentField::Type(i) => self.types.register(i.id, "type")?,
ComponentField::Instance(i) => self.instances.register(i.id, "instance")?,
ComponentField::Module(m) => self.modules.register(m.id, "nested module")?,
ComponentField::Component(c) => self.components.register(c.id, "nested component")?,
ComponentField::Alias(a) => self.register_alias(a)?,
ComponentField::Start(s) => self.values.register(s.result, "value")?,
// These fields don't define any items in any index space.
ComponentField::Export(_) => return Ok(()),
};
Ok(())
}
fn register_alias(&mut self, alias: &Alias<'a>) -> Result<u32, Error> {
match alias.kind {
AliasKind::Module => self.modules.register(alias.id, "module"),
AliasKind::Component => self.components.register(alias.id, "component"),
AliasKind::Instance => self.instances.register(alias.id, "instance"),
AliasKind::Value => self.values.register(alias.id, "value"),
AliasKind::ExportKind(core::ExportKind::Func) => self.funcs.register(alias.id, "func"),
AliasKind::ExportKind(core::ExportKind::Table) => {
self.tables.register(alias.id, "table")
}
AliasKind::ExportKind(core::ExportKind::Memory) => {
self.memories.register(alias.id, "memory")
}
AliasKind::ExportKind(core::ExportKind::Global) => {
self.globals.register(alias.id, "global")
}
AliasKind::ExportKind(core::ExportKind::Tag) => self.tags.register(alias.id, "tag"),
AliasKind::ExportKind(core::ExportKind::Type) => self.types.register(alias.id, "type"),
}
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
enum Ns {
Func,
Table,
Global,
Memory,
Tag,
Type,
Component,
Module,
Instance,
Value,
}
macro_rules! component_kw_conversions {
($($kw:ident => $kind:ident)*) => ($(
impl From<kw::$kw> for Ns {
fn from(_: kw::$kw) -> Ns {
Ns::$kind
}
}
)*);
}
component_kw_conversions! {
func => Func
module => Module
component => Component
instance => Instance
value => Value
table => Table
memory => Memory
global => Global
tag => Tag
r#type => Type
}
impl From<DefTypeKind> for Ns {
fn from(kind: DefTypeKind) -> Self {
match kind {
DefTypeKind::Module => Ns::Module,
DefTypeKind::Component => Ns::Component,
DefTypeKind::Instance => Ns::Instance,
DefTypeKind::Value => Ns::Value,
DefTypeKind::Func => Ns::Func,
}
}
}
impl From<core::ExportKind> for Ns {
fn from(kind: core::ExportKind) -> Self {
match kind {
core::ExportKind::Func => Ns::Func,
core::ExportKind::Table => Ns::Table,
core::ExportKind::Global => Ns::Global,
core::ExportKind::Memory => Ns::Memory,
core::ExportKind::Tag => Ns::Tag,
core::ExportKind::Type => Ns::Type,
}
}
}

91
third_party/rust/wast/src/component/types.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,91 @@
use crate::component::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A definition of a type.
///
/// typeexpr ::= <deftype>
/// | <intertype>
#[derive(Debug)]
pub enum ComponentTypeDef<'a> {
/// The type of an entity.
DefType(DefType<'a>),
/// The type of a value.
InterType(InterType<'a>),
}
/// The type of an exported item from an component or instance.
#[derive(Debug)]
pub struct ComponentExportType<'a> {
/// Where this export was defined.
pub span: Span,
/// The name of this export.
pub name: &'a str,
/// The signature of the item that's exported.
pub item: ItemSig<'a>,
}
impl<'a> Parse<'a> for ComponentExportType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::export>()?.0;
let name = parser.parse()?;
let item = parser.parens(|p| p.parse())?;
Ok(ComponentExportType { span, name, item })
}
}
/// A type declaration in a component.
///
/// type ::= (type <id>? <typeexpr>)
#[derive(Debug)]
pub struct TypeField<'a> {
/// Where this type was defined.
pub span: Span,
/// An optional identifer to refer to this `type` by as part of name
/// resolution.
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<NameAnnotation<'a>>,
/// The type that we're declaring.
pub def: ComponentTypeDef<'a>,
}
impl<'a> Parse<'a> for TypeField<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::r#type>()?.0;
let id = parser.parse()?;
let name = parser.parse()?;
let def = if parser.peek2::<DefTypeKind>() {
ComponentTypeDef::DefType(parser.parens(|p| p.parse())?)
} else {
ComponentTypeDef::InterType(parser.parse()?)
};
Ok(TypeField {
span,
id,
name,
def,
})
}
}
/// A reference to a type defined in this component.
///
/// This is the same as `TypeUse`, but accepts `$T` as shorthand for
/// `(type $T)`.
#[derive(Debug, Clone)]
pub enum ComponentTypeUse<'a, T> {
/// The type that we're referencing.
Ref(ItemRef<'a, kw::r#type>),
/// The inline type.
Inline(T),
}
impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<ItemRef<'a, kw::r#type>>() {
Ok(ComponentTypeUse::Ref(parser.parse()?))
} else {
Ok(ComponentTypeUse::Inline(parser.parse()?))
}
}
}

Просмотреть файл

@ -1,19 +1,14 @@
use crate::ast::*;
use crate::core::*;
use crate::encode::Encode;
use crate::token::*;
pub fn encode(module: &Module<'_>) -> Vec<u8> {
match &module.kind {
ModuleKind::Text(fields) => encode_fields(&module.id, &module.name, fields),
ModuleKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().cloned()).collect(),
}
}
fn encode_fields(
pub fn encode(
module_id: &Option<Id<'_>>,
module_name: &Option<NameAnnotation<'_>>,
fields: &[ModuleField<'_>],
) -> Vec<u8> {
use crate::ast::CustomPlace::*;
use crate::ast::CustomPlaceAnchor::*;
use CustomPlace::*;
use CustomPlaceAnchor::*;
let mut types = Vec::new();
let mut imports = Vec::new();
@ -27,9 +22,6 @@ fn encode_fields(
let mut data = Vec::new();
let mut tags = Vec::new();
let mut customs = Vec::new();
let mut instances = Vec::new();
let mut modules = Vec::new();
let mut aliases = Vec::new();
for field in fields {
match field {
ModuleField::Type(i) => types.push(i),
@ -44,9 +36,6 @@ fn encode_fields(
ModuleField::Data(i) => data.push(i),
ModuleField::Tag(i) => tags.push(i),
ModuleField::Custom(i) => customs.push(i),
ModuleField::Instance(i) => instances.push(i),
ModuleField::NestedModule(i) => modules.push(i),
ModuleField::Alias(a) => aliases.push(a),
}
}
@ -60,47 +49,8 @@ fn encode_fields(
e.custom_sections(BeforeFirst);
let mut items = fields
.iter()
.filter(|i| match i {
ModuleField::Alias(_)
| ModuleField::Type(_)
| ModuleField::Import(_)
| ModuleField::NestedModule(_)
| ModuleField::Instance(_) => true,
_ => false,
})
.peekable();
// A special path is used for now to handle non-module-linking modules to
// work around WebAssembly/annotations#11
if aliases.len() == 0 && modules.len() == 0 && instances.len() == 0 {
e.section_list(1, Type, &types);
e.section_list(2, Import, &imports);
} else {
while let Some(field) = items.next() {
macro_rules! list {
($code:expr, $name:ident) => {
list!($code, $name, $name)
};
($code:expr, $field:ident, $custom:ident) => {
if let ModuleField::$field(f) = field {
let mut list = vec![f];
while let Some(ModuleField::$field(f)) = items.peek() {
list.push(f);
items.next();
}
e.section_list($code, $custom, &list);
}
};
}
list!(1, Type);
list!(2, Import);
list!(14, NestedModule, Module);
list!(15, Instance);
list!(16, Alias);
}
}
e.section_list(1, Type, &types);
e.section_list(2, Import, &imports);
let functys = funcs.iter().map(|f| &f.ty).collect::<Vec<_>>();
e.section_list(3, Func, &functys);
@ -129,7 +79,7 @@ fn encode_fields(
return e.wasm;
fn contains_bulk_memory(funcs: &[&crate::ast::Func<'_>]) -> bool {
fn contains_bulk_memory(funcs: &[&crate::core::Func<'_>]) -> bool {
funcs
.iter()
.filter_map(|f| match &f.kind {
@ -175,75 +125,6 @@ impl Encoder<'_> {
}
}
pub(crate) trait Encode {
fn encode(&self, e: &mut Vec<u8>);
}
impl<T: Encode + ?Sized> Encode for &'_ 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);
for item in self {
item.encode(e);
}
}
}
impl<T: Encode> Encode for Vec<T> {
fn encode(&self, e: &mut Vec<u8>) {
<[T]>::encode(self, e)
}
}
impl Encode for str {
fn encode(&self, e: &mut Vec<u8>) {
self.len().encode(e);
e.extend_from_slice(self.as_bytes());
}
}
impl Encode for usize {
fn encode(&self, e: &mut Vec<u8>) {
assert!(*self <= u32::max_value() as usize);
(*self as u32).encode(e)
}
}
impl Encode for u8 {
fn encode(&self, e: &mut Vec<u8>) {
e.push(*self);
}
}
impl Encode for u32 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::unsigned(e, (*self).into()).unwrap();
}
}
impl Encode for i32 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::signed(e, (*self).into()).unwrap();
}
}
impl Encode for u64 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::unsigned(e, (*self).into()).unwrap();
}
}
impl Encode for i64 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::signed(e, *self).unwrap();
}
}
impl Encode for FunctionType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.params.len().encode(e);
@ -271,19 +152,6 @@ impl Encode for ArrayType<'_> {
}
}
impl Encode for ModuleType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.imports.encode(e);
self.exports.encode(e);
}
}
impl Encode for InstanceType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.exports.encode(e);
}
}
impl Encode for ExportType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
@ -306,14 +174,6 @@ impl Encode for Type<'_> {
e.push(0x5e);
array.encode(e)
}
TypeDef::Module(module) => {
e.push(0x61);
module.encode(e)
}
TypeDef::Instance(instance) => {
e.push(0x62);
instance.encode(e)
}
}
}
}
@ -324,13 +184,6 @@ impl Encode for Option<Id<'_>> {
}
}
impl<T: Encode, U: Encode> Encode for (T, U) {
fn encode(&self, e: &mut Vec<u8>) {
self.0.encode(e);
self.1.encode(e);
}
}
impl<'a> Encode for ValType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
@ -435,13 +288,7 @@ impl<'a> Encode for StorageType<'a> {
impl Encode for Import<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.module.encode(e);
match self.field {
Some(s) => s.encode(e),
None => {
e.push(0x00);
e.push(0xff);
}
}
self.field.encode(e);
self.item.encode(e);
}
}
@ -469,14 +316,6 @@ impl Encode for ItemSig<'_> {
e.push(0x04);
f.encode(e);
}
ItemKind::Module(m) => {
e.push(0x05);
m.encode(e);
}
ItemKind::Instance(i) => {
e.push(0x06);
i.encode(e);
}
}
}
}
@ -499,32 +338,6 @@ impl Encode for Index<'_> {
}
}
impl<T> Encode for IndexOrRef<'_, T> {
fn encode(&self, e: &mut Vec<u8>) {
self.0.encode(e);
}
}
impl<T> Encode for ItemRef<'_, T> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ItemRef::Outer { .. } => panic!("should be expanded previously"),
ItemRef::Item {
idx,
exports,
#[cfg(wast_check_exhaustive)]
visited,
..
} => {
#[cfg(wast_check_exhaustive)]
assert!(*visited);
assert!(exports.is_empty());
idx.encode(e);
}
}
}
}
impl<'a> Encode for TableType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
self.elem.encode(e);
@ -620,10 +433,8 @@ impl Encode for Global<'_> {
impl Encode for Export<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
if let ItemRef::Item { kind, .. } = &self.index {
kind.encode(e);
}
self.index.encode(e);
self.kind.encode(e);
self.item.encode(e);
}
}
@ -635,8 +446,6 @@ impl Encode for ExportKind {
ExportKind::Memory => e.push(0x02),
ExportKind::Global => e.push(0x03),
ExportKind::Tag => e.push(0x04),
ExportKind::Module => e.push(0x05),
ExportKind::Instance => e.push(0x06),
ExportKind::Type => e.push(0x07),
}
}
@ -647,11 +456,7 @@ impl Encode for Elem<'_> {
match (&self.kind, &self.payload) {
(
ElemKind::Active {
table:
ItemRef::Item {
idx: Index::Num(0, _),
..
},
table: Index::Num(0, _),
offset,
},
ElemPayload::Indices(_),
@ -671,11 +476,7 @@ impl Encode for Elem<'_> {
}
(
ElemKind::Active {
table:
ItemRef::Item {
idx: Index::Num(0, _),
..
},
table: Index::Num(0, _),
offset,
},
ElemPayload::Exprs {
@ -732,17 +533,16 @@ impl Encode for Data<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.kind {
DataKind::Passive => e.push(0x01),
DataKind::Active {
memory: Index::Num(0, _),
offset,
} => {
e.push(0x00);
offset.encode(e);
}
DataKind::Active { memory, offset } => {
if let ItemRef::Item {
idx: Index::Num(0, _),
..
} = memory
{
e.push(0x00);
} else {
e.push(0x02);
memory.encode(e);
}
e.push(0x02);
memory.encode(e);
offset.encode(e);
}
}
@ -798,11 +598,7 @@ impl Encode for Expression<'_> {
impl Encode for BlockType<'_> {
fn encode(&self, e: &mut Vec<u8>) {
// block types using an index are encoded as an sleb, not a uleb
if let Some(ItemRef::Item {
idx: Index::Num(n, _),
..
}) = &self.ty.index
{
if let Some(Index::Num(n, _)) = &self.ty.index {
return i64::from(*n).encode(e);
}
let ty = self
@ -842,17 +638,14 @@ impl Encode for LaneArg {
impl Encode for MemArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.memory {
ItemRef::Item {
idx: Index::Num(0, _),
..
} => {
Index::Num(0, _) => {
self.align.trailing_zeros().encode(e);
self.offset.encode(e);
}
n => {
_ => {
(self.align.trailing_zeros() | (1 << 6)).encode(e);
self.offset.encode(e);
n.encode(e);
self.memory.encode(e);
}
}
}
@ -946,10 +739,6 @@ struct Names<'a> {
table_idx: u32,
tags: Vec<(u32, &'a str)>,
tag_idx: u32,
modules: Vec<(u32, &'a str)>,
module_idx: u32,
instances: Vec<(u32, &'a str)>,
instance_idx: u32,
types: Vec<(u32, &'a str)>,
type_idx: u32,
data: Vec<(u32, &'a str)>,
@ -977,8 +766,6 @@ fn find_names<'a>(
Type,
Global,
Func,
Module,
Instance,
Memory,
Table,
Tag,
@ -998,8 +785,6 @@ fn find_names<'a>(
ItemKind::Memory(_) => Name::Memory,
ItemKind::Global(_) => Name::Global,
ItemKind::Tag(_) => Name::Tag,
ItemKind::Instance(_) => Name::Instance,
ItemKind::Module(_) => Name::Module,
},
&i.item.id,
&i.item.name,
@ -1008,26 +793,10 @@ fn find_names<'a>(
ModuleField::Table(t) => (Name::Table, &t.id, &t.name),
ModuleField::Memory(m) => (Name::Memory, &m.id, &m.name),
ModuleField::Tag(t) => (Name::Tag, &t.id, &t.name),
ModuleField::NestedModule(m) => (Name::Module, &m.id, &m.name),
ModuleField::Instance(i) => (Name::Instance, &i.id, &i.name),
ModuleField::Type(t) => (Name::Type, &t.id, &t.name),
ModuleField::Elem(e) => (Name::Elem, &e.id, &e.name),
ModuleField::Data(d) => (Name::Data, &d.id, &d.name),
ModuleField::Func(f) => (Name::Func, &f.id, &f.name),
ModuleField::Alias(a) => (
match a.kind {
ExportKind::Func => Name::Func,
ExportKind::Table => Name::Table,
ExportKind::Memory => Name::Memory,
ExportKind::Global => Name::Global,
ExportKind::Module => Name::Module,
ExportKind::Instance => Name::Instance,
ExportKind::Tag => Name::Tag,
ExportKind::Type => Name::Type,
},
&a.id,
&a.name,
),
ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => continue,
};
@ -1037,8 +806,6 @@ fn find_names<'a>(
Name::Table => (&mut ret.tables, &mut ret.table_idx),
Name::Memory => (&mut ret.memories, &mut ret.memory_idx),
Name::Global => (&mut ret.globals, &mut ret.global_idx),
Name::Module => (&mut ret.modules, &mut ret.module_idx),
Name::Instance => (&mut ret.instances, &mut ret.instance_idx),
Name::Tag => (&mut ret.tags, &mut ret.tag_idx),
Name::Type => (&mut ret.types, &mut ret.type_idx),
Name::Elem => (&mut ret.elems, &mut ret.elem_idx),
@ -1244,56 +1011,3 @@ impl Encode for StructAccess<'_> {
self.field.encode(e);
}
}
impl Encode for NestedModule<'_> {
fn encode(&self, e: &mut Vec<u8>) {
let fields = match &self.kind {
NestedModuleKind::Inline { fields, .. } => fields,
_ => panic!("should only have inline modules in emission"),
};
encode_fields(&self.id, &self.name, fields).encode(e);
}
}
impl Encode for Instance<'_> {
fn encode(&self, e: &mut Vec<u8>) {
assert!(self.exports.names.is_empty());
let (module, args) = match &self.kind {
InstanceKind::Inline { module, args } => (module, args),
_ => panic!("should only have inline instances in emission"),
};
e.push(0x00);
module.encode(e);
args.encode(e);
}
}
impl Encode for InstanceArg<'_> {
fn encode(&self, e: &mut Vec<u8>) {
self.name.encode(e);
if let ItemRef::Item { kind, .. } = &self.index {
kind.encode(e);
}
self.index.encode(e);
}
}
impl Encode for Alias<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match &self.source {
AliasSource::InstanceExport { instance, export } => {
e.push(0x00);
instance.encode(e);
self.kind.encode(e);
export.encode(e);
}
AliasSource::Outer { module, index } => {
e.push(0x01);
module.encode(e);
self.kind.encode(e);
index.encode(e);
}
}
}
}

Просмотреть файл

@ -1,11 +1,12 @@
use crate::ast::{self, annotation, kw};
use crate::parser::{Parse, Parser, Result};
use crate::token::{self, Span};
use crate::{annotation, kw};
/// A wasm custom section within a module.
#[derive(Debug)]
pub struct Custom<'a> {
/// Where this `@custom` was defined.
pub span: ast::Span,
pub span: Span,
/// Name of the custom section.
pub name: &'a str,
@ -36,9 +37,6 @@ pub enum CustomPlace {
pub enum CustomPlaceAnchor {
Type,
Import,
Module,
Instance,
Alias,
Func,
Table,
Memory,
@ -55,7 +53,7 @@ impl<'a> Parse<'a> for Custom<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<annotation::custom>()?.0;
let name = parser.parse()?;
let place = if parser.peek::<ast::LParen>() {
let place = if parser.peek::<token::LParen>() {
parser.parens(|p| p.parse())?
} else {
CustomPlace::AfterLast
@ -147,18 +145,6 @@ impl<'a> Parse<'a> for CustomPlaceAnchor {
parser.parse::<kw::tag>()?;
return Ok(CustomPlaceAnchor::Tag);
}
if parser.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
return Ok(CustomPlaceAnchor::Instance);
}
if parser.peek::<kw::module>() {
parser.parse::<kw::module>()?;
return Ok(CustomPlaceAnchor::Module);
}
if parser.peek::<kw::alias>() {
parser.parse::<kw::alias>()?;
return Ok(CustomPlaceAnchor::Alias);
}
Err(parser.error("expected a valid section name"))
}

Просмотреть файл

@ -1,15 +1,18 @@
use crate::ast::{self, kw};
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::{Index, Span};
/// A entry in a WebAssembly module's export section.
#[derive(Debug)]
pub struct Export<'a> {
/// Where this export was defined.
pub span: ast::Span,
pub span: Span,
/// The name of this export from the module.
pub name: &'a str,
/// The kind of item being exported.
pub kind: ExportKind,
/// What's being exported from the module.
pub index: ast::ItemRef<'a, ExportKind>,
pub item: Index<'a>,
}
/// Different kinds of elements that can be exported from a WebAssembly module,
@ -22,17 +25,19 @@ pub enum ExportKind {
Memory,
Global,
Tag,
Module,
Instance,
Type,
}
impl<'a> Parse<'a> for Export<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let span = parser.parse::<kw::export>()?.0;
let name = parser.parse()?;
let (kind, item) = parser.parens(|p| Ok((p.parse()?, p.parse()?)))?;
Ok(Export {
span: parser.parse::<kw::export>()?.0,
name: parser.parse()?,
index: parser.parse()?,
span,
name,
kind,
item,
})
}
}
@ -55,12 +60,6 @@ impl<'a> Parse<'a> for ExportKind {
} else if l.peek::<kw::tag>() {
parser.parse::<kw::tag>()?;
Ok(ExportKind::Tag)
} else if l.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(ExportKind::Module)
} else if l.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(ExportKind::Instance)
} else if l.peek::<kw::r#type>() {
parser.parse::<kw::r#type>()?;
Ok(ExportKind::Type)
@ -70,6 +69,20 @@ impl<'a> Parse<'a> for ExportKind {
}
}
impl Peek for ExportKind {
fn peek(cursor: Cursor<'_>) -> bool {
kw::func::peek(cursor)
|| kw::table::peek(cursor)
|| kw::memory::peek(cursor)
|| kw::global::peek(cursor)
|| kw::tag::peek(cursor)
|| kw::r#type::peek(cursor)
}
fn display() -> &'static str {
"export kind"
}
}
macro_rules! kw_conversions {
($($kw:ident => $kind:ident)*) => ($(
impl From<kw::$kw> for ExportKind {
@ -80,15 +93,13 @@ macro_rules! kw_conversions {
impl Default for kw::$kw {
fn default() -> kw::$kw {
kw::$kw(ast::Span::from_offset(0))
kw::$kw(Span::from_offset(0))
}
}
)*);
}
kw_conversions! {
instance => Instance
module => Module
func => Func
table => Table
global => Global
@ -99,7 +110,7 @@ kw_conversions! {
/// A listing of inline `(export "foo")` statements on a WebAssembly item in
/// its textual format.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct InlineExport<'a> {
/// The extra names to export an item as, if any.
pub names: Vec<&'a str>,

Просмотреть файл

@ -1,5 +1,8 @@
use crate::ast::{self, kw, HeapType};
use crate::core::*;
use crate::encode::Encode;
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Result};
use crate::token::*;
use std::mem;
/// An expression, or a list of instructions, in the WebAssembly text format.
@ -114,7 +117,7 @@ impl<'a> ExpressionParser<'a> {
// of an `if block then we require that all sub-components are
// s-expressions surrounded by `(` and `)`, so verify that here.
if let Some(Level::If(_)) | Some(Level::Try(_)) = self.stack.last() {
if !parser.is_empty() && !parser.peek::<ast::LParen>() {
if !parser.is_empty() && !parser.peek::<LParen>() {
return Err(parser.error("expected `(`"));
}
}
@ -346,7 +349,7 @@ impl<'a> ExpressionParser<'a> {
if let Try::CatchOrDelegate = i {
// `catch` may be followed by more `catch`s or `catch_all`.
if parser.parse::<Option<kw::catch>>()?.is_some() {
let evt = parser.parse::<ast::Index<'a>>()?;
let evt = parser.parse::<Index<'a>>()?;
self.instrs.push(Instruction::Catch(evt));
*i = Try::Catch;
self.stack.push(Level::TryArm);
@ -361,7 +364,7 @@ impl<'a> ExpressionParser<'a> {
}
// `delegate` has an index, and also ends the block like `end`.
if parser.parse::<Option<kw::delegate>>()?.is_some() {
let depth = parser.parse::<ast::Index<'a>>()?;
let depth = parser.parse::<Index<'a>>()?;
self.instrs.push(Instruction::Delegate(depth));
*i = Try::Delegate;
match self.paren(parser)? {
@ -374,7 +377,7 @@ impl<'a> ExpressionParser<'a> {
if let Try::Catch = i {
if parser.parse::<Option<kw::catch>>()?.is_some() {
let evt = parser.parse::<ast::Index<'a>>()?;
let evt = parser.parse::<Index<'a>>()?;
self.instrs.push(Instruction::Catch(evt));
*i = Try::Catch;
self.stack.push(Level::TryArm);
@ -436,17 +439,17 @@ macro_rules! instructions {
}
}
impl crate::binary::Encode for Instruction<'_> {
impl Encode for Instruction<'_> {
#[allow(non_snake_case)]
fn encode(&self, v: &mut Vec<u8>) {
match self {
$(
Instruction::$name $((instructions!(@first $($arg)*)))? => {
Instruction::$name $((instructions!(@first x $($arg)*)))? => {
fn encode<'a>($(arg: &instructions!(@ty $($arg)*),)? v: &mut Vec<u8>) {
instructions!(@encode v $($binary)*);
$(<instructions!(@ty $($arg)*) as crate::binary::Encode>::encode(arg, v);)?
$(<instructions!(@ty $($arg)*) as Encode>::encode(arg, v);)?
}
encode($( instructions!(@first $($arg)*), )? v)
encode($( instructions!(@first x $($arg)*), )? v)
}
)*
}
@ -484,7 +487,7 @@ macro_rules! instructions {
// simd opcodes prefixed with `0xfd` get a varuint32 encoding for their payload
(@encode $dst:ident 0xfd, $simd:tt) => ({
$dst.push(0xfd);
<u32 as crate::binary::Encode>::encode(&$simd, $dst);
<u32 as Encode>::encode(&$simd, $dst);
});
(@encode $dst:ident $($bytes:tt)*) => ($dst.extend_from_slice(&[$($bytes)*]););
@ -501,21 +504,21 @@ instructions! {
pub enum Instruction<'a> {
Block(BlockType<'a>) : [0x02] : "block",
If(BlockType<'a>) : [0x04] : "if",
Else(Option<ast::Id<'a>>) : [0x05] : "else",
Else(Option<Id<'a>>) : [0x05] : "else",
Loop(BlockType<'a>) : [0x03] : "loop",
End(Option<ast::Id<'a>>) : [0x0b] : "end",
End(Option<Id<'a>>) : [0x0b] : "end",
Unreachable : [0x00] : "unreachable",
Nop : [0x01] : "nop",
Br(ast::Index<'a>) : [0x0c] : "br",
BrIf(ast::Index<'a>) : [0x0d] : "br_if",
Br(Index<'a>) : [0x0c] : "br",
BrIf(Index<'a>) : [0x0d] : "br_if",
BrTable(BrTableIndices<'a>) : [0x0e] : "br_table",
Return : [0x0f] : "return",
Call(ast::IndexOrRef<'a, kw::func>) : [0x10] : "call",
Call(Index<'a>) : [0x10] : "call",
CallIndirect(CallIndirect<'a>) : [0x11] : "call_indirect",
// tail-call proposal
ReturnCall(ast::IndexOrRef<'a, kw::func>) : [0x12] : "return_call",
ReturnCall(Index<'a>) : [0x12] : "return_call",
ReturnCallIndirect(CallIndirect<'a>) : [0x13] : "return_call_indirect",
// function-references proposal
@ -526,11 +529,11 @@ instructions! {
Drop : [0x1a] : "drop",
Select(SelectTypes<'a>) : [] : "select",
LocalGet(ast::Index<'a>) : [0x20] : "local.get" | "get_local",
LocalSet(ast::Index<'a>) : [0x21] : "local.set" | "set_local",
LocalTee(ast::Index<'a>) : [0x22] : "local.tee" | "tee_local",
GlobalGet(ast::IndexOrRef<'a, kw::global>) : [0x23] : "global.get" | "get_global",
GlobalSet(ast::IndexOrRef<'a, kw::global>) : [0x24] : "global.set" | "set_global",
LocalGet(Index<'a>) : [0x20] : "local.get" | "get_local",
LocalSet(Index<'a>) : [0x21] : "local.set" | "set_local",
LocalTee(Index<'a>) : [0x22] : "local.tee" | "tee_local",
GlobalGet(Index<'a>) : [0x23] : "global.get" | "get_global",
GlobalSet(Index<'a>) : [0x24] : "global.set" | "set_global",
TableGet(TableArg<'a>) : [0x25] : "table.get",
TableSet(TableArg<'a>) : [0x26] : "table.set",
@ -565,8 +568,8 @@ instructions! {
MemoryInit(MemoryInit<'a>) : [0xfc, 0x08] : "memory.init",
MemoryCopy(MemoryCopy<'a>) : [0xfc, 0x0a] : "memory.copy",
MemoryFill(MemoryArg<'a>) : [0xfc, 0x0b] : "memory.fill",
DataDrop(ast::Index<'a>) : [0xfc, 0x09] : "data.drop",
ElemDrop(ast::Index<'a>) : [0xfc, 0x0d] : "elem.drop",
DataDrop(Index<'a>) : [0xfc, 0x09] : "data.drop",
ElemDrop(Index<'a>) : [0xfc, 0x0d] : "elem.drop",
TableInit(TableInit<'a>) : [0xfc, 0x0c] : "table.init",
TableCopy(TableCopy<'a>) : [0xfc, 0x0e] : "table.copy",
TableFill(TableArg<'a>) : [0xfc, 0x11] : "table.fill",
@ -576,35 +579,35 @@ instructions! {
RefNull(HeapType<'a>) : [0xd0] : "ref.null",
RefIsNull : [0xd1] : "ref.is_null",
RefExtern(u32) : [0xff] : "ref.extern", // only used in test harness
RefFunc(ast::IndexOrRef<'a, kw::func>) : [0xd2] : "ref.func",
RefFunc(Index<'a>) : [0xd2] : "ref.func",
// function-references proposal
RefAsNonNull : [0xd3] : "ref.as_non_null",
BrOnNull(ast::Index<'a>) : [0xd4] : "br_on_null",
BrOnNonNull(ast::Index<'a>) : [0xd6] : "br_on_non_null",
BrOnNull(Index<'a>) : [0xd4] : "br_on_null",
BrOnNonNull(Index<'a>) : [0xd6] : "br_on_non_null",
// gc proposal: eqref
RefEq : [0xd5] : "ref.eq",
// gc proposal (moz specific, will be removed)
StructNew(ast::Index<'a>) : [0xfb, 0x0] : "struct.new",
StructNew(Index<'a>) : [0xfb, 0x0] : "struct.new",
// gc proposal: struct
StructNewWithRtt(ast::Index<'a>) : [0xfb, 0x01] : "struct.new_with_rtt",
StructNewDefaultWithRtt(ast::Index<'a>) : [0xfb, 0x02] : "struct.new_default_with_rtt",
StructNewWithRtt(Index<'a>) : [0xfb, 0x01] : "struct.new_with_rtt",
StructNewDefaultWithRtt(Index<'a>) : [0xfb, 0x02] : "struct.new_default_with_rtt",
StructGet(StructAccess<'a>) : [0xfb, 0x03] : "struct.get",
StructGetS(StructAccess<'a>) : [0xfb, 0x04] : "struct.get_s",
StructGetU(StructAccess<'a>) : [0xfb, 0x05] : "struct.get_u",
StructSet(StructAccess<'a>) : [0xfb, 0x06] : "struct.set",
// gc proposal: array
ArrayNewWithRtt(ast::Index<'a>) : [0xfb, 0x11] : "array.new_with_rtt",
ArrayNewDefaultWithRtt(ast::Index<'a>) : [0xfb, 0x12] : "array.new_default_with_rtt",
ArrayGet(ast::Index<'a>) : [0xfb, 0x13] : "array.get",
ArrayGetS(ast::Index<'a>) : [0xfb, 0x14] : "array.get_s",
ArrayGetU(ast::Index<'a>) : [0xfb, 0x15] : "array.get_u",
ArraySet(ast::Index<'a>) : [0xfb, 0x16] : "array.set",
ArrayLen(ast::Index<'a>) : [0xfb, 0x17] : "array.len",
ArrayNewWithRtt(Index<'a>) : [0xfb, 0x11] : "array.new_with_rtt",
ArrayNewDefaultWithRtt(Index<'a>) : [0xfb, 0x12] : "array.new_default_with_rtt",
ArrayGet(Index<'a>) : [0xfb, 0x13] : "array.get",
ArrayGetS(Index<'a>) : [0xfb, 0x14] : "array.get_s",
ArrayGetU(Index<'a>) : [0xfb, 0x15] : "array.get_u",
ArraySet(Index<'a>) : [0xfb, 0x16] : "array.set",
ArrayLen(Index<'a>) : [0xfb, 0x17] : "array.len",
// gc proposal, i31
I31New : [0xfb, 0x20] : "i31.new",
@ -612,11 +615,11 @@ instructions! {
I31GetU : [0xfb, 0x22] : "i31.get_u",
// gc proposal, rtt casting
RTTCanon(ast::Index<'a>) : [0xfb, 0x30] : "rtt.canon",
RTTSub(ast::Index<'a>) : [0xfb, 0x31] : "rtt.sub",
RTTCanon(Index<'a>) : [0xfb, 0x30] : "rtt.canon",
RTTSub(Index<'a>) : [0xfb, 0x31] : "rtt.sub",
RefTest : [0xfb, 0x40] : "ref.test",
RefCast : [0xfb, 0x41] : "ref.cast",
BrOnCast(ast::Index<'a>) : [0xfb, 0x42] : "br_on_cast",
BrOnCast(Index<'a>) : [0xfb, 0x42] : "br_on_cast",
// gc proposal, heap casting
RefIsFunc : [0xfb, 0x50] : "ref.is_func",
@ -625,14 +628,14 @@ instructions! {
RefAsFunc : [0xfb, 0x58] : "ref.as_func",
RefAsData : [0xfb, 0x59] : "ref.as_data",
RefAsI31 : [0xfb, 0x5a] : "ref.as_i31",
BrOnFunc(ast::Index<'a>) : [0xfb, 0x60] : "br_on_func",
BrOnData(ast::Index<'a>) : [0xfb, 0x61] : "br_on_data",
BrOnI31(ast::Index<'a>) : [0xfb, 0x62] : "br_on_i31",
BrOnFunc(Index<'a>) : [0xfb, 0x60] : "br_on_func",
BrOnData(Index<'a>) : [0xfb, 0x61] : "br_on_data",
BrOnI31(Index<'a>) : [0xfb, 0x62] : "br_on_i31",
I32Const(i32) : [0x41] : "i32.const",
I64Const(i64) : [0x42] : "i64.const",
F32Const(ast::Float32) : [0x43] : "f32.const",
F64Const(ast::Float64) : [0x44] : "f64.const",
F32Const(Float32) : [0x43] : "f32.const",
F64Const(Float64) : [0x44] : "f64.const",
I32Clz : [0x67] : "i32.clz",
I32Ctz : [0x68] : "i32.ctz",
@ -1120,30 +1123,30 @@ instructions! {
// Exception handling proposal
Try(BlockType<'a>) : [0x06] : "try",
Catch(ast::Index<'a>) : [0x07] : "catch",
Throw(ast::Index<'a>) : [0x08] : "throw",
Rethrow(ast::Index<'a>) : [0x09] : "rethrow",
Delegate(ast::Index<'a>) : [0x18] : "delegate",
Catch(Index<'a>) : [0x07] : "catch",
Throw(Index<'a>) : [0x08] : "throw",
Rethrow(Index<'a>) : [0x09] : "rethrow",
Delegate(Index<'a>) : [0x18] : "delegate",
CatchAll : [0x19] : "catch_all",
// Relaxed SIMD proposal
I8x16SwizzleRelaxed : [0xfd, 0xa2]: "i8x16.swizzle_relaxed",
I32x4TruncSatF32x4SRelaxed : [0xfd, 0xa5]: "i32x4.trunc_f32x4_s_relaxed",
I32x4TruncSatF32x4URelaxed : [0xfd, 0xa6]: "i32x4.trunc_f32x4_u_relaxed",
I32x4TruncSatF64x2SZeroRelaxed : [0xfd, 0xc5]: "i32x4.trunc_f64x2_s_zero_relaxed",
I32x4TruncSatF64x2UZeroRelaxed : [0xfd, 0xc6]: "i32x4.trunc_f64x2_u_zero_relaxed",
F32x4FmaRelaxed : [0xfd, 0xaf]: "f32x4.fma_relaxed",
F32x4FmsRelaxed : [0xfd, 0xb0]: "f32x4.fms_relaxed",
F64x4FmaRelaxed : [0xfd, 0xcf]: "f64x2.fma_relaxed",
F64x4FmsRelaxed : [0xfd, 0xd0]: "f64x2.fms_relaxed",
I8x16RelaxedSwizzle : [0xfd, 0xa2]: "i8x16.relaxed_swizzle",
I32x4RelaxedTruncSatF32x4S : [0xfd, 0xa5]: "i32x4.relaxed_trunc_f32x4_s",
I32x4RelaxedTruncSatF32x4U : [0xfd, 0xa6]: "i32x4.relaxed_trunc_f32x4_u",
I32x4RelaxedTruncSatF64x2SZero : [0xfd, 0xc5]: "i32x4.relaxed_trunc_f64x2_s_zero",
I32x4RelaxedTruncSatF64x2UZero : [0xfd, 0xc6]: "i32x4.relaxed_trunc_f64x2_u_zero",
F32x4Fma : [0xfd, 0xaf]: "f32x4.fma",
F32x4Fms : [0xfd, 0xb0]: "f32x4.fms",
F64x4Fma : [0xfd, 0xcf]: "f64x2.fma",
F64x4Fms : [0xfd, 0xd0]: "f64x2.fms",
I8x16LaneSelect : [0xfd, 0xb2]: "i8x16.laneselect",
I16x8LaneSelect : [0xfd, 0xb3]: "i16x8.laneselect",
I32x4LaneSelect : [0xfd, 0xd2]: "i32x4.laneselect",
I64x2LaneSelect : [0xfd, 0xd3]: "i64x2.laneselect",
F32x4MinRelaxed : [0xfd, 0xb4]: "f32x4.min_relaxed",
F32x4MaxRelaxed : [0xfd, 0xe2]: "f32x4.max_relaxed",
F64x2MinRelaxed : [0xfd, 0xd4]: "f64x2.min_relaxed",
F64x2MaxRelaxed : [0xfd, 0xee]: "f64x2.max_relaxed",
F32x4RelaxedMin : [0xfd, 0xb4]: "f32x4.relaxed_min",
F32x4RelaxedMax : [0xfd, 0xe2]: "f32x4.relaxed_max",
F64x2RelaxedMin : [0xfd, 0xd4]: "f64x2.relaxed_min",
F64x2RelaxedMax : [0xfd, 0xee]: "f64x2.relaxed_max",
}
}
@ -1154,9 +1157,9 @@ instructions! {
#[derive(Debug)]
#[allow(missing_docs)]
pub struct BlockType<'a> {
pub label: Option<ast::Id<'a>>,
pub label_name: Option<ast::NameAnnotation<'a>>,
pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>,
pub label: Option<Id<'a>>,
pub label_name: Option<NameAnnotation<'a>>,
pub ty: TypeUse<'a, FunctionType<'a>>,
}
impl<'a> Parse<'a> for BlockType<'a> {
@ -1165,7 +1168,7 @@ impl<'a> Parse<'a> for BlockType<'a> {
label: parser.parse()?,
label_name: parser.parse()?,
ty: parser
.parse::<ast::TypeUse<'a, ast::FunctionTypeNoNames<'a>>>()?
.parse::<TypeUse<'a, FunctionTypeNoNames<'a>>>()?
.into(),
})
}
@ -1175,14 +1178,14 @@ impl<'a> Parse<'a> for BlockType<'a> {
#[derive(Debug)]
#[allow(missing_docs)]
pub struct FuncBindType<'a> {
pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>,
pub ty: TypeUse<'a, FunctionType<'a>>,
}
impl<'a> Parse<'a> for FuncBindType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(FuncBindType {
ty: parser
.parse::<ast::TypeUse<'a, ast::FunctionTypeNoNames<'a>>>()?
.parse::<TypeUse<'a, FunctionTypeNoNames<'a>>>()?
.into(),
})
}
@ -1193,14 +1196,14 @@ impl<'a> Parse<'a> for FuncBindType<'a> {
#[allow(missing_docs)]
pub struct LetType<'a> {
pub block: BlockType<'a>,
pub locals: Vec<ast::Local<'a>>,
pub locals: Vec<Local<'a>>,
}
impl<'a> Parse<'a> for LetType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(LetType {
block: parser.parse()?,
locals: ast::Local::parse_remainder(parser)?,
locals: Local::parse_remainder(parser)?,
})
}
}
@ -1209,15 +1212,15 @@ impl<'a> Parse<'a> for LetType<'a> {
#[allow(missing_docs)]
#[derive(Debug)]
pub struct BrTableIndices<'a> {
pub labels: Vec<ast::Index<'a>>,
pub default: ast::Index<'a>,
pub labels: Vec<Index<'a>>,
pub default: Index<'a>,
}
impl<'a> Parse<'a> for BrTableIndices<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut labels = Vec::new();
labels.push(parser.parse()?);
while parser.peek::<ast::Index>() {
while parser.peek::<Index>() {
labels.push(parser.parse()?);
}
let default = labels.pop().unwrap();
@ -1264,7 +1267,7 @@ pub struct MemArg<'a> {
/// The offset, in bytes of this access.
pub offset: u64,
/// The memory index we're accessing
pub memory: ast::ItemRef<'a, kw::memory>,
pub memory: Index<'a>,
}
impl<'a> MemArg<'a> {
@ -1287,8 +1290,8 @@ impl<'a> MemArg<'a> {
return Ok((None, c));
}
let num = &kw[1..];
let num = if num.starts_with("0x") {
f(c, &num[2..], 16)?
let num = if let Some(stripped) = num.strip_prefix("0x") {
f(c, stripped, 16)?
} else {
f(c, num, 10)?
};
@ -1310,9 +1313,8 @@ impl<'a> MemArg<'a> {
}
let memory = parser
.parse::<Option<ast::IndexOrRef<'a, kw::memory>>>()?
.map(|i| i.0)
.unwrap_or(idx_zero(parser.prev_span(), kw::memory));
.parse::<Option<_>>()?
.unwrap_or(Index::Num(0, parser.prev_span()));
let offset = parse_u64("offset", parser)?.unwrap_or(0);
let align = match parse_u32("align", parser)? {
Some(n) if !n.is_power_of_two() => {
@ -1329,16 +1331,6 @@ impl<'a> MemArg<'a> {
}
}
fn idx_zero<T>(span: ast::Span, mk_kind: fn(ast::Span) -> T) -> ast::ItemRef<'static, T> {
ast::ItemRef::Item {
kind: mk_kind(span),
idx: ast::Index::Num(0, span),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: false,
}
}
/// Extra data associated with the `loadN_lane` and `storeN_lane` instructions.
#[derive(Debug)]
pub struct LoadOrStoreLane<'a> {
@ -1385,7 +1377,7 @@ impl<'a> LoadOrStoreLane<'a> {
MemArg {
align: default_align,
offset: 0,
memory: idx_zero(parser.prev_span(), kw::memory),
memory: Index::Num(0, parser.prev_span()),
}
},
lane: LaneArg::parse(parser)?,
@ -1397,24 +1389,18 @@ impl<'a> LoadOrStoreLane<'a> {
#[derive(Debug)]
pub struct CallIndirect<'a> {
/// The table that this call is going to be indexing.
pub table: ast::ItemRef<'a, kw::table>,
pub table: Index<'a>,
/// Type type signature that this `call_indirect` instruction is using.
pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>,
pub ty: TypeUse<'a, FunctionType<'a>>,
}
impl<'a> Parse<'a> for CallIndirect<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let prev_span = parser.prev_span();
let mut table: Option<ast::IndexOrRef<_>> = parser.parse()?;
let ty = parser.parse::<ast::TypeUse<'a, ast::FunctionTypeNoNames<'a>>>()?;
// Turns out the official test suite at this time thinks table
// identifiers comes first but wabt's test suites asserts differently
// putting them second. Let's just handle both.
if table.is_none() {
table = parser.parse()?;
}
let table: Option<_> = parser.parse()?;
let ty = parser.parse::<TypeUse<'a, FunctionTypeNoNames<'a>>>()?;
Ok(CallIndirect {
table: table.map(|i| i.0).unwrap_or(idx_zero(prev_span, kw::table)),
table: table.unwrap_or(Index::Num(0, prev_span)),
ty: ty.into(),
})
}
@ -1424,21 +1410,20 @@ impl<'a> Parse<'a> for CallIndirect<'a> {
#[derive(Debug)]
pub struct TableInit<'a> {
/// The index of the table we're copying into.
pub table: ast::ItemRef<'a, kw::table>,
pub table: Index<'a>,
/// The index of the element segment we're copying into a table.
pub elem: ast::Index<'a>,
pub elem: Index<'a>,
}
impl<'a> Parse<'a> for TableInit<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let prev_span = parser.prev_span();
let (elem, table) =
if parser.peek::<ast::ItemRef<kw::table>>() || parser.peek2::<ast::Index>() {
let table = parser.parse::<ast::IndexOrRef<_>>()?.0;
(parser.parse()?, table)
} else {
(parser.parse()?, idx_zero(prev_span, kw::table))
};
let (elem, table) = if parser.peek2::<Index>() {
let table = parser.parse()?;
(parser.parse()?, table)
} else {
(parser.parse()?, Index::Num(0, prev_span))
};
Ok(TableInit { table, elem })
}
}
@ -1447,18 +1432,18 @@ impl<'a> Parse<'a> for TableInit<'a> {
#[derive(Debug)]
pub struct TableCopy<'a> {
/// The index of the destination table to copy into.
pub dst: ast::ItemRef<'a, kw::table>,
pub dst: Index<'a>,
/// The index of the source table to copy from.
pub src: ast::ItemRef<'a, kw::table>,
pub src: Index<'a>,
}
impl<'a> Parse<'a> for TableCopy<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let (dst, src) = match parser.parse::<Option<ast::IndexOrRef<_>>>()? {
Some(dst) => (dst.0, parser.parse::<ast::IndexOrRef<_>>()?.0),
let (dst, src) = match parser.parse::<Option<_>>()? {
Some(dst) => (dst, parser.parse()?),
None => (
idx_zero(parser.prev_span(), kw::table),
idx_zero(parser.prev_span(), kw::table),
Index::Num(0, parser.prev_span()),
Index::Num(0, parser.prev_span()),
),
};
Ok(TableCopy { dst, src })
@ -1469,15 +1454,15 @@ impl<'a> Parse<'a> for TableCopy<'a> {
#[derive(Debug)]
pub struct TableArg<'a> {
/// The index of the table argument.
pub dst: ast::ItemRef<'a, kw::table>,
pub dst: Index<'a>,
}
impl<'a> Parse<'a> for TableArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let dst = if let Some(dst) = parser.parse::<Option<ast::IndexOrRef<_>>>()? {
dst.0
let dst = if let Some(dst) = parser.parse()? {
dst
} else {
idx_zero(parser.prev_span(), kw::table)
Index::Num(0, parser.prev_span())
};
Ok(TableArg { dst })
}
@ -1487,15 +1472,15 @@ impl<'a> Parse<'a> for TableArg<'a> {
#[derive(Debug)]
pub struct MemoryArg<'a> {
/// The index of the memory space.
pub mem: ast::ItemRef<'a, kw::memory>,
pub mem: Index<'a>,
}
impl<'a> Parse<'a> for MemoryArg<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mem = if let Some(mem) = parser.parse::<Option<ast::IndexOrRef<_>>>()? {
mem.0
let mem = if let Some(mem) = parser.parse()? {
mem
} else {
idx_zero(parser.prev_span(), kw::memory)
Index::Num(0, parser.prev_span())
};
Ok(MemoryArg { mem })
}
@ -1505,21 +1490,20 @@ impl<'a> Parse<'a> for MemoryArg<'a> {
#[derive(Debug)]
pub struct MemoryInit<'a> {
/// The index of the data segment we're copying into memory.
pub data: ast::Index<'a>,
pub data: Index<'a>,
/// The index of the memory we're copying into,
pub mem: ast::ItemRef<'a, kw::memory>,
pub mem: Index<'a>,
}
impl<'a> Parse<'a> for MemoryInit<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let prev_span = parser.prev_span();
let (data, mem) =
if parser.peek::<ast::ItemRef<kw::memory>>() || parser.peek2::<ast::Index>() {
let memory = parser.parse::<ast::IndexOrRef<_>>()?.0;
(parser.parse()?, memory)
} else {
(parser.parse()?, idx_zero(prev_span, kw::memory))
};
let (data, mem) = if parser.peek2::<Index>() {
let memory = parser.parse()?;
(parser.parse()?, memory)
} else {
(parser.parse()?, Index::Num(0, prev_span))
};
Ok(MemoryInit { data, mem })
}
}
@ -1528,18 +1512,18 @@ impl<'a> Parse<'a> for MemoryInit<'a> {
#[derive(Debug)]
pub struct MemoryCopy<'a> {
/// The index of the memory we're copying from.
pub src: ast::ItemRef<'a, kw::memory>,
pub src: Index<'a>,
/// The index of the memory we're copying to.
pub dst: ast::ItemRef<'a, kw::memory>,
pub dst: Index<'a>,
}
impl<'a> Parse<'a> for MemoryCopy<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let (src, dst) = match parser.parse::<Option<ast::IndexOrRef<_>>>()? {
Some(dst) => (parser.parse::<ast::IndexOrRef<_>>()?.0, dst.0),
let (src, dst) = match parser.parse()? {
Some(dst) => (parser.parse()?, dst),
None => (
idx_zero(parser.prev_span(), kw::memory),
idx_zero(parser.prev_span(), kw::memory),
Index::Num(0, parser.prev_span()),
Index::Num(0, parser.prev_span()),
),
};
Ok(MemoryCopy { src, dst })
@ -1550,9 +1534,9 @@ impl<'a> Parse<'a> for MemoryCopy<'a> {
#[derive(Debug)]
pub struct StructAccess<'a> {
/// The index of the struct type we're accessing.
pub r#struct: ast::Index<'a>,
pub r#struct: Index<'a>,
/// The index of the field of the struct we're accessing
pub field: ast::Index<'a>,
pub field: Index<'a>,
}
impl<'a> Parse<'a> for StructAccess<'a> {
@ -1573,8 +1557,8 @@ pub enum V128Const {
I16x8([i16; 8]),
I32x4([i32; 4]),
I64x2([i64; 2]),
F32x4([ast::Float32; 4]),
F64x2([ast::Float64; 2]),
F32x4([Float32; 4]),
F64x2([Float64; 2]),
}
impl V128Const {
@ -1767,7 +1751,7 @@ impl<'a> Parse<'a> for I8x16Shuffle {
#[derive(Debug)]
pub struct SelectTypes<'a> {
#[allow(missing_docs)]
pub tys: Option<Vec<ast::ValType<'a>>>,
pub tys: Option<Vec<ValType<'a>>>,
}
impl<'a> Parse<'a> for SelectTypes<'a> {

Просмотреть файл

@ -1,5 +1,7 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A WebAssembly function to be inserted into a module.
///
@ -7,20 +9,20 @@ use crate::parser::{Parse, Parser, Result};
#[derive(Debug)]
pub struct Func<'a> {
/// Where this `func` was defined.
pub span: ast::Span,
pub span: Span,
/// An identifier that this function is resolved with (optionally) for name
/// resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
pub exports: InlineExport<'a>,
/// What kind of function this is, be it an inline-defined or imported
/// function.
pub kind: FuncKind<'a>,
/// The type that this function will have.
pub ty: ast::TypeUse<'a, ast::FunctionType<'a>>,
pub ty: TypeUse<'a, FunctionType<'a>>,
}
/// Possible ways to define a function in the text format.
@ -31,7 +33,7 @@ pub enum FuncKind<'a> {
/// ```text
/// (func (type 3) (import "foo" "bar"))
/// ```
Import(ast::InlineImport<'a>),
Import(InlineImport<'a>),
/// Almost all functions, those defined inline in a wasm module.
Inline {
@ -39,7 +41,7 @@ pub enum FuncKind<'a> {
locals: Vec<Local<'a>>,
/// The instructions of the function.
expression: ast::Expression<'a>,
expression: Expression<'a>,
},
}
@ -83,11 +85,11 @@ impl<'a> Parse<'a> for Func<'a> {
pub struct Local<'a> {
/// An identifier that this local is resolved with (optionally) for name
/// resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this local stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// The value type of this local.
pub ty: ast::ValType<'a>,
pub ty: ValType<'a>,
}
impl<'a> Local<'a> {
@ -105,7 +107,11 @@ impl<'a> Local<'a> {
let parse_more = id.is_none() && name.is_none();
locals.push(Local { id, name, ty });
while parse_more && !p.is_empty() {
locals.push(Local { id: None, name: None, ty: p.parse()? });
locals.push(Local {
id: None,
name: None,
ty: p.parse()?,
});
}
Ok(())
})?;

Просмотреть файл

@ -1,20 +1,22 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A WebAssembly global in a module
#[derive(Debug)]
pub struct Global<'a> {
/// Where this `global` was defined.
pub span: ast::Span,
pub span: Span,
/// An optional name to reference this global by
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
pub exports: InlineExport<'a>,
/// The type of this global, both its value type and whether it's mutable.
pub ty: ast::GlobalType<'a>,
pub ty: GlobalType<'a>,
/// What kind of global this defined as.
pub kind: GlobalKind<'a>,
}
@ -27,10 +29,10 @@ pub enum GlobalKind<'a> {
/// ```text
/// (global i32 (import "foo" "bar"))
/// ```
Import(ast::InlineImport<'a>),
Import(InlineImport<'a>),
/// A global defined inline in the module itself
Inline(ast::Expression<'a>),
Inline(Expression<'a>),
}
impl<'a> Parse<'a> for Global<'a> {

Просмотреть файл

@ -1,15 +1,17 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::{Id, NameAnnotation, Span};
/// An `import` statement and entry in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct Import<'a> {
/// Where this `import` was defined
pub span: ast::Span,
pub span: Span,
/// The module that this statement is importing from
pub module: &'a str,
/// The name of the field in the module this statement imports from.
pub field: Option<&'a str>,
pub field: &'a str,
/// The item that's being imported.
pub item: ItemSig<'a>,
}
@ -33,13 +35,13 @@ impl<'a> Parse<'a> for Import<'a> {
#[allow(missing_docs)]
pub struct ItemSig<'a> {
/// Where this item is defined in the source.
pub span: ast::Span,
pub span: Span,
/// An optional identifier used during name resolution to refer to this item
/// from the rest of the module.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name which, for functions, will be stored in the
/// custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// What kind of item this is.
pub kind: ItemKind<'a>,
}
@ -47,13 +49,11 @@ pub struct ItemSig<'a> {
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum ItemKind<'a> {
Func(ast::TypeUse<'a, ast::FunctionType<'a>>),
Table(ast::TableType<'a>),
Memory(ast::MemoryType),
Global(ast::GlobalType<'a>),
Tag(ast::TagType<'a>),
Module(ast::TypeUse<'a, ast::ModuleType<'a>>),
Instance(ast::TypeUse<'a, ast::InstanceType<'a>>),
Func(TypeUse<'a, FunctionType<'a>>),
Table(TableType<'a>),
Memory(MemoryType),
Global(GlobalType<'a>),
Tag(TagType<'a>),
}
impl<'a> Parse<'a> for ItemSig<'a> {
@ -99,22 +99,6 @@ impl<'a> Parse<'a> for ItemSig<'a> {
name: None,
kind: ItemKind::Tag(parser.parse()?),
})
} else if l.peek::<kw::module>() {
let span = parser.parse::<kw::module>()?.0;
Ok(ItemSig {
span,
id: parser.parse()?,
name: None,
kind: ItemKind::Module(parser.parse()?),
})
} else if l.peek::<kw::instance>() {
let span = parser.parse::<kw::instance>()?.0;
Ok(ItemSig {
span,
id: parser.parse()?,
name: None,
kind: ItemKind::Instance(parser.parse()?),
})
} else {
Err(l.error())
}
@ -131,7 +115,7 @@ impl<'a> Parse<'a> for ItemSig<'a> {
#[allow(missing_docs)]
pub struct InlineImport<'a> {
pub module: &'a str,
pub field: Option<&'a str>,
pub field: &'a str,
}
impl<'a> Parse<'a> for InlineImport<'a> {
@ -160,11 +144,9 @@ impl Peek for InlineImport<'_> {
Some((_, cursor)) => cursor,
None => return false,
};
// optional field
let cursor = match cursor.string() {
Some((_, cursor)) => cursor,
None => cursor,
None => return false,
};
cursor.rparen().is_some()

Просмотреть файл

@ -1,18 +1,20 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Lookahead1, Parse, Parser, Peek, Result};
use crate::token::*;
/// A defined WebAssembly memory instance inside of a module.
#[derive(Debug)]
pub struct Memory<'a> {
/// Where this `memory` was defined
pub span: ast::Span,
pub span: Span,
/// An optional name to refer to this memory by.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
pub exports: InlineExport<'a>,
/// How this memory is defined in the module.
pub kind: MemoryKind<'a>,
}
@ -23,12 +25,12 @@ pub enum MemoryKind<'a> {
/// This memory is actually an inlined import definition.
#[allow(missing_docs)]
Import {
import: ast::InlineImport<'a>,
ty: ast::MemoryType,
import: InlineImport<'a>,
ty: MemoryType,
},
/// A typical memory definition which simply says the limits of the memory
Normal(ast::MemoryType),
Normal(MemoryType),
/// The data of this memory, starting from 0, explicitly listed
Inline {
@ -57,7 +59,7 @@ impl<'a> Parse<'a> for Memory<'a> {
import,
ty: parser.parse()?,
}
} else if l.peek::<ast::LParen>() || parser.peek2::<ast::LParen>() {
} else if l.peek::<LParen>() || parser.peek2::<LParen>() {
let is_32 = if parser.parse::<Option<kw::i32>>()?.is_some() {
true
} else if parser.parse::<Option<kw::i64>>()?.is_some() {
@ -93,13 +95,13 @@ impl<'a> Parse<'a> for Memory<'a> {
#[derive(Debug)]
pub struct Data<'a> {
/// Where this `data` was defined
pub span: ast::Span,
pub span: Span,
/// The optional name of this data segment
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this data stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// Whether this data segment is passive or active
pub kind: DataKind<'a>,
@ -120,10 +122,10 @@ pub enum DataKind<'a> {
/// memory on module instantiation.
Active {
/// The memory that this `Data` will be associated with.
memory: ast::ItemRef<'a, kw::memory>,
memory: Index<'a>,
/// Initial offset to load this data segment at
offset: ast::Expression<'a>,
offset: Expression<'a>,
},
}
@ -133,29 +135,25 @@ impl<'a> Parse<'a> for Data<'a> {
let id = parser.parse()?;
let name = parser.parse()?;
// The `passive` keyword is mentioned in the current spec but isn't
// mentioned in `wabt` tests, so consider it optional for now
let kind = if parser.peek::<kw::passive>() {
parser.parse::<kw::passive>()?;
DataKind::Passive
// If data directly follows then assume this is a passive segment
} else if parser.peek::<&[u8]>() {
let kind = if parser.peek::<&[u8]>() {
DataKind::Passive
// ... and otherwise we must be attached to a particular memory as well
// as having an initialization offset.
} else {
let memory = if let Some(index) = parser.parse::<Option<ast::IndexOrRef<_>>>()? {
index.0
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>() {
parser.parens(|p| {
p.parse::<kw::memory>()?;
p.parse()
})?
} else {
ast::ItemRef::Item {
kind: kw::memory(parser.prev_span()),
idx: ast::Index::Num(0, span),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: false,
}
Index::Num(0, span)
};
let offset = parser.parens(|parser| {
if parser.peek::<kw::offset>() {
@ -167,7 +165,7 @@ impl<'a> Parse<'a> for Data<'a> {
// single-instruction expression.
let insn = parser.parse()?;
if parser.is_empty() {
return Ok(ast::Expression {
return Ok(Expression {
instrs: [insn].into(),
});
}
@ -183,10 +181,10 @@ impl<'a> Parse<'a> for Data<'a> {
// (data (offset ...))
//
// but alas
let expr: ast::Expression = parser.parse()?;
let expr: Expression = parser.parse()?;
let mut instrs = Vec::from(expr.instrs);
instrs.push(insn);
Ok(ast::Expression {
Ok(Expression {
instrs: instrs.into(),
})
}
@ -237,7 +235,7 @@ impl DataVal<'_> {
impl<'a> Parse<'a> for DataVal<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if !parser.peek::<ast::LParen>() {
if !parser.peek::<LParen>() {
return Ok(DataVal::String(parser.parse()?));
}
@ -250,15 +248,9 @@ impl<'a> Parse<'a> for DataVal<'a> {
|| consume::<kw::i16, i16, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
|| consume::<kw::i32, i32, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
|| consume::<kw::i64, i64, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
|| consume::<kw::f32, ast::Float32, _>(p, l, r, |u, v| {
v.extend(&u.bits.to_le_bytes())
})?
|| consume::<kw::f64, ast::Float64, _>(p, l, r, |u, v| {
v.extend(&u.bits.to_le_bytes())
})?
|| consume::<kw::v128, ast::V128Const, _>(p, l, r, |u, v| {
v.extend(&u.to_le_bytes())
})?
|| consume::<kw::f32, Float32, _>(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))?
|| consume::<kw::f64, Float64, _>(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))?
|| consume::<kw::v128, V128Const, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
{
Ok(DataVal::Integral(result))
} else {

27
third_party/rust/wast/src/core/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
//! Types and support for parsing the core wasm text format.
mod custom;
mod export;
mod expr;
mod func;
mod global;
mod import;
mod memory;
mod module;
mod table;
mod tag;
mod types;
pub use self::custom::*;
pub use self::export::*;
pub use self::expr::*;
pub use self::func::*;
pub use self::global::*;
pub use self::import::*;
pub use self::memory::*;
pub use self::module::*;
pub use self::table::*;
pub use self::tag::*;
pub use self::types::*;
pub(crate) mod binary;
pub(crate) mod resolve;

Просмотреть файл

@ -1,50 +1,19 @@
use crate::ast::{self, annotation, kw};
use crate::core::*;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, Index, NameAnnotation, Span};
use crate::{annotation, kw};
pub use crate::resolve::Names;
pub use crate::core::resolve::Names;
/// A `*.wat` file parser, or a parser for one parenthesized module.
///
/// This is the top-level type which you'll frequently parse when working with
/// this crate. A `*.wat` file is either one `module` s-expression or a sequence
/// of s-expressions that are module fields.
#[derive(Debug)]
pub struct Wat<'a> {
#[allow(missing_docs)]
pub module: Module<'a>,
}
impl<'a> Parse<'a> for Wat<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if !parser.has_meaningful_tokens() {
return Err(parser.error("expected at least one module field"));
}
let _r = parser.register_annotation("custom");
let module = if !parser.peek2::<kw::module>() {
let fields = ModuleField::parse_remaining(parser)?;
Module {
span: ast::Span { offset: 0 },
id: None,
name: None,
kind: ModuleKind::Text(fields),
}
} else {
parser.parens(|parser| parser.parse())?
};
module.validate(parser)?;
Ok(Wat { module })
}
}
/// A parsed WebAssembly module.
/// A parsed WebAssembly core module.
#[derive(Debug)]
pub struct Module<'a> {
/// Where this `module` was defined
pub span: ast::Span,
pub span: Span,
/// An optional identifier this module is known by
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional `@name` annotation for this module
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// What kind of module this was parsed as.
pub kind: ModuleKind<'a>,
}
@ -71,9 +40,9 @@ impl<'a> Module<'a> {
/// where expansion and name resolution happens.
///
/// This function will mutate the AST of this [`Module`] and replace all
/// [`super::Index`] arguments with `Index::Num`. This will also expand inline
/// exports/imports listed on fields and handle various other shorthands of
/// the text format.
/// [`Index`](crate::token::Index) arguments with `Index::Num`. This will
/// also expand inline exports/imports listed on fields and handle various
/// other shorthands of the text format.
///
/// If successful the AST was modified to be ready for binary encoding. A
/// [`Names`] structure is also returned so if you'd like to do your own
@ -84,7 +53,11 @@ impl<'a> Module<'a> {
/// If an error happens during resolution, such a name resolution error or
/// items are found in the wrong order, then an error is returned.
pub fn resolve(&mut self) -> std::result::Result<Names<'a>, crate::Error> {
crate::resolve::resolve(self)
let names = match &mut self.kind {
ModuleKind::Text(fields) => crate::core::resolve::resolve(fields)?,
ModuleKind::Binary(_blobs) => Default::default(),
};
Ok(names)
}
/// Encodes this [`Module`] to its binary form.
@ -113,10 +86,13 @@ impl<'a> Module<'a> {
/// expansion-related errors.
pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> {
self.resolve()?;
Ok(crate::binary::encode(self))
Ok(match &self.kind {
ModuleKind::Text(fields) => crate::core::binary::encode(&self.id, &self.name, fields),
ModuleKind::Binary(blobs) => blobs.iter().flat_map(|b| b.iter().cloned()).collect(),
})
}
fn validate(&self, parser: Parser<'_>) -> Result<()> {
pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> {
let mut starts = 0;
if let ModuleKind::Text(fields) = &self.kind {
for item in fields.iter() {
@ -162,25 +138,22 @@ impl<'a> Parse<'a> for Module<'a> {
#[allow(missing_docs)]
#[derive(Debug)]
pub enum ModuleField<'a> {
Type(ast::Type<'a>),
Import(ast::Import<'a>),
Func(ast::Func<'a>),
Table(ast::Table<'a>),
Memory(ast::Memory<'a>),
Global(ast::Global<'a>),
Export(ast::Export<'a>),
Start(ast::ItemRef<'a, kw::func>),
Elem(ast::Elem<'a>),
Data(ast::Data<'a>),
Tag(ast::Tag<'a>),
Custom(ast::Custom<'a>),
Instance(ast::Instance<'a>),
NestedModule(ast::NestedModule<'a>),
Alias(ast::Alias<'a>),
Type(Type<'a>),
Import(Import<'a>),
Func(Func<'a>),
Table(Table<'a>),
Memory(Memory<'a>),
Global(Global<'a>),
Export(Export<'a>),
Start(Index<'a>),
Elem(Elem<'a>),
Data(Data<'a>),
Tag(Tag<'a>),
Custom(Custom<'a>),
}
impl<'a> ModuleField<'a> {
fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ModuleField>> {
pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ModuleField>> {
let mut fields = Vec::new();
while !parser.is_empty() {
fields.push(parser.parens(ModuleField::parse)?);
@ -214,7 +187,7 @@ impl<'a> Parse<'a> for ModuleField<'a> {
}
if parser.peek::<kw::start>() {
parser.parse::<kw::start>()?;
return Ok(ModuleField::Start(parser.parse::<ast::IndexOrRef<_>>()?.0));
return Ok(ModuleField::Start(parser.parse()?));
}
if parser.peek::<kw::elem>() {
return Ok(ModuleField::Elem(parser.parse()?));
@ -228,15 +201,6 @@ impl<'a> Parse<'a> for ModuleField<'a> {
if parser.peek::<annotation::custom>() {
return Ok(ModuleField::Custom(parser.parse()?));
}
if parser.peek::<kw::instance>() {
return Ok(ModuleField::Instance(parser.parse()?));
}
if parser.peek::<kw::module>() {
return Ok(ModuleField::NestedModule(parser.parse()?));
}
if parser.peek::<kw::alias>() {
return Ok(ModuleField::Alias(parser.parse()?));
}
Err(parser.error("expected valid module field"))
}
}

Просмотреть файл

@ -1,5 +1,6 @@
use crate::ast::*;
use crate::resolve::gensym;
use crate::core::*;
use crate::gensym;
use crate::token::{Id, Index, Span};
use std::mem;
pub fn run(fields: &mut Vec<ModuleField>) {
@ -80,7 +81,7 @@ pub fn run(fields: &mut Vec<ModuleField>) {
id: None,
name: None,
kind: DataKind::Active {
memory: item_ref(kw::memory(m.span), id),
memory: Index::Id(id),
offset: Expression {
instrs: Box::new([if is_32 {
Instruction::I32Const(0)
@ -139,7 +140,7 @@ pub fn run(fields: &mut Vec<ModuleField>) {
id: None,
name: None,
kind: ElemKind::Active {
table: item_ref(kw::table(t.span), id),
table: Index::Id(id),
offset: Expression {
instrs: Box::new([Instruction::I32Const(0)]),
},
@ -196,62 +197,9 @@ pub fn run(fields: &mut Vec<ModuleField>) {
}
}
ModuleField::Instance(i) => {
for name in i.exports.names.drain(..) {
to_append.push(export(i.span, name, ExportKind::Instance, &mut i.id));
}
match &mut i.kind {
InstanceKind::Import { import, ty } => {
*item = ModuleField::Import(Import {
span: i.span,
module: import.module,
field: import.field,
item: ItemSig {
span: i.span,
id: i.id,
name: None,
kind: ItemKind::Instance(mem::replace(
ty,
TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))),
)),
},
});
}
InstanceKind::Inline { .. } => {}
}
}
ModuleField::NestedModule(m) => {
for name in m.exports.names.drain(..) {
to_append.push(export(m.span, name, ExportKind::Module, &mut m.id));
}
match &mut m.kind {
NestedModuleKind::Import { import, ty } => {
*item = ModuleField::Import(Import {
span: m.span,
module: import.module,
field: import.field,
item: ItemSig {
span: m.span,
id: m.id,
name: m.name,
kind: ItemKind::Module(mem::replace(
ty,
TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))),
)),
},
});
}
NestedModuleKind::Inline { fields, .. } => {
run(fields);
}
};
}
ModuleField::Import(_)
| ModuleField::Type(_)
| ModuleField::Export(_)
| ModuleField::Alias(_)
| ModuleField::Start(_)
| ModuleField::Elem(_)
| ModuleField::Data(_)
@ -279,16 +227,7 @@ fn export<'a>(
ModuleField::Export(Export {
span,
name,
index: item_ref(kind, id),
kind,
item: Index::Id(id),
})
}
fn item_ref<'a, K>(kind: K, id: impl Into<Index<'a>>) -> ItemRef<'a, K> {
ItemRef::Item {
kind,
idx: id.into(),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: false,
}
}

Просмотреть файл

@ -1,11 +1,10 @@
use crate::ast::*;
use crate::Error;
use crate::core::*;
use crate::token::Index;
use crate::{gensym, Error};
mod aliases;
mod deinline_import_export;
mod gensym;
mod names;
mod types;
pub(crate) mod types;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Ns {
@ -13,33 +12,11 @@ pub enum Ns {
Table,
Global,
Memory,
Module,
Instance,
Tag,
Type,
}
impl Ns {
fn from_export(kind: &ExportKind) -> Ns {
match kind {
ExportKind::Func => Ns::Func,
ExportKind::Table => Ns::Table,
ExportKind::Global => Ns::Global,
ExportKind::Memory => Ns::Memory,
ExportKind::Instance => Ns::Instance,
ExportKind::Module => Ns::Module,
ExportKind::Tag => Ns::Tag,
ExportKind::Type => Ns::Type,
}
}
}
pub fn resolve<'a>(module: &mut Module<'a>) -> Result<Names<'a>, Error> {
let fields = match &mut module.kind {
ModuleKind::Text(fields) => fields,
_ => return Ok(Default::default()),
};
pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Names<'a>, Error> {
// Ensure that each resolution of a module is deterministic in the names
// that it generates by resetting our thread-local symbol generator.
gensym::reset();
@ -51,8 +28,6 @@ pub fn resolve<'a>(module: &mut Module<'a>) -> Result<Names<'a>, Error> {
// field.
deinline_import_export::run(fields);
aliases::run(fields);
// With a canonical form of imports make sure that imports are all listed
// first.
let mut last = None;
@ -77,15 +52,15 @@ pub fn resolve<'a>(module: &mut Module<'a>) -> Result<Names<'a>, Error> {
// Perform name resolution over all `Index` items to resolve them all to
// indices instead of symbolic names.
let resolver = names::resolve(module.id, fields)?;
let resolver = names::resolve(fields)?;
Ok(Names { resolver })
}
/// Representation of the results of name resolution for a module.
///
/// This structure is returned from the
/// [`Module::resolve`](crate::Module::resolve) function and can be used to
/// resolve your own name arguments if you have any.
/// [`Module::resolve`](crate::core::Module::resolve) function and can be used
/// to resolve your own name arguments if you have any.
#[derive(Default)]
pub struct Names<'a> {
resolver: names::Resolver<'a>,

Просмотреть файл

@ -1,21 +1,12 @@
use crate::ast::*;
use crate::resolve::Ns;
use crate::core::resolve::Ns;
use crate::core::*;
use crate::names::{resolve_error, Namespace};
use crate::token::{Id, Index};
use crate::Error;
use std::collections::{HashMap, HashSet};
pub fn resolve<'a>(
id: Option<Id<'a>>,
fields: &mut Vec<ModuleField<'a>>,
) -> Result<Resolver<'a>, Error> {
let mut names = HashMap::new();
let mut parents = Parents {
prev: None,
cur_id: id,
depth: 0,
names: &mut names,
};
pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Resolver<'a>, Error> {
let mut resolver = Resolver::default();
resolver.process(&mut parents, fields)?;
resolver.process(fields)?;
Ok(resolver)
}
@ -32,21 +23,14 @@ pub struct Resolver<'a> {
memories: Namespace<'a>,
types: Namespace<'a>,
tags: Namespace<'a>,
modules: Namespace<'a>,
instances: Namespace<'a>,
datas: Namespace<'a>,
elems: Namespace<'a>,
fields: Namespace<'a>,
type_info: Vec<TypeInfo<'a>>,
implicit_instances: HashSet<&'a str>,
}
impl<'a> Resolver<'a> {
fn process(
&mut self,
parents: &mut Parents<'a, '_>,
fields: &mut Vec<ModuleField<'a>>,
) -> Result<(), Error> {
fn process(&mut self, fields: &mut Vec<ModuleField<'a>>) -> Result<(), Error> {
// Number everything in the module, recording what names correspond to
// what indices.
for field in fields.iter_mut() {
@ -56,37 +40,24 @@ impl<'a> Resolver<'a> {
// Then we can replace all our `Index::Id` instances with `Index::Num`
// in the AST. Note that this also recurses into nested modules.
for field in fields.iter_mut() {
self.resolve_field(field, parents)?;
self.resolve_field(field)?;
}
Ok(())
}
fn register(&mut self, item: &ModuleField<'a>) -> Result<(), Error> {
match item {
ModuleField::Import(i) => {
// Account for implicit instances created by two-level imports
// first. At this time they never have a name.
if i.field.is_some() {
if self.implicit_instances.insert(i.module) {
self.instances.register(None, "instance")?;
}
}
match &i.item.kind {
ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?,
ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?,
ItemKind::Table(_) => self.tables.register(i.item.id, "table")?,
ItemKind::Global(_) => self.globals.register(i.item.id, "global")?,
ItemKind::Tag(_) => self.tags.register(i.item.id, "tag")?,
ItemKind::Module(_) => self.modules.register(i.item.id, "module")?,
ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?,
}
}
ModuleField::Import(i) => match &i.item.kind {
ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?,
ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?,
ItemKind::Table(_) => self.tables.register(i.item.id, "table")?,
ItemKind::Global(_) => self.globals.register(i.item.id, "global")?,
ItemKind::Tag(_) => self.tags.register(i.item.id, "tag")?,
},
ModuleField::Global(i) => self.globals.register(i.id, "global")?,
ModuleField::Memory(i) => self.memories.register(i.id, "memory")?,
ModuleField::Func(i) => self.funcs.register(i.id, "func")?,
ModuleField::Table(i) => self.tables.register(i.id, "table")?,
ModuleField::NestedModule(m) => self.modules.register(m.id, "module")?,
ModuleField::Instance(i) => self.instances.register(i.id, "instance")?,
ModuleField::Type(i) => {
match &i.def {
@ -103,10 +74,7 @@ impl<'a> Resolver<'a> {
}
}
TypeDef::Instance(_)
| TypeDef::Array(_)
| TypeDef::Func(_)
| TypeDef::Module(_) => {}
TypeDef::Array(_) | TypeDef::Func(_) => {}
}
// Record function signatures as we see them to so we can
@ -126,19 +94,6 @@ impl<'a> Resolver<'a> {
ModuleField::Elem(e) => self.elems.register(e.id, "elem")?,
ModuleField::Data(d) => self.datas.register(d.id, "data")?,
ModuleField::Tag(t) => self.tags.register(t.id, "tag")?,
ModuleField::Alias(a) => match a.kind {
ExportKind::Func => self.funcs.register(a.id, "func")?,
ExportKind::Table => self.tables.register(a.id, "table")?,
ExportKind::Memory => self.memories.register(a.id, "memory")?,
ExportKind::Global => self.globals.register(a.id, "global")?,
ExportKind::Instance => self.instances.register(a.id, "instance")?,
ExportKind::Module => self.modules.register(a.id, "module")?,
ExportKind::Tag => self.tags.register(a.id, "tag")?,
ExportKind::Type => {
self.type_info.push(TypeInfo::Other);
self.types.register(a.id, "type")?
}
},
// These fields don't define any items in any index space.
ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => {
@ -149,11 +104,7 @@ impl<'a> Resolver<'a> {
Ok(())
}
fn resolve_field(
&self,
field: &mut ModuleField<'a>,
parents: &mut Parents<'a, '_>,
) -> Result<(), Error> {
fn resolve_field(&self, field: &mut ModuleField<'a>) -> Result<(), Error> {
match field {
ModuleField::Import(i) => {
self.resolve_item_sig(&mut i.item)?;
@ -169,8 +120,6 @@ impl<'a> Resolver<'a> {
}
}
TypeDef::Array(array) => self.resolve_storagetype(&mut array.ty)?,
TypeDef::Module(m) => m.resolve(self)?,
TypeDef::Instance(i) => i.resolve(self)?,
}
Ok(())
}
@ -225,7 +174,7 @@ impl<'a> Resolver<'a> {
ModuleField::Elem(e) => {
match &mut e.kind {
ElemKind::Active { table, offset } => {
self.resolve_item_ref(table)?;
self.resolve(table, Ns::Table)?;
self.resolve_expr(offset)?;
}
ElemKind::Passive { .. } | ElemKind::Declared { .. } => {}
@ -233,7 +182,7 @@ impl<'a> Resolver<'a> {
match &mut e.payload {
ElemPayload::Indices(elems) => {
for idx in elems {
self.resolve_item_ref(idx)?;
self.resolve(idx, Ns::Func)?;
}
}
ElemPayload::Exprs { exprs, ty } => {
@ -248,19 +197,29 @@ impl<'a> Resolver<'a> {
ModuleField::Data(d) => {
if let DataKind::Active { memory, offset } = &mut d.kind {
self.resolve_item_ref(memory)?;
self.resolve(memory, Ns::Memory)?;
self.resolve_expr(offset)?;
}
Ok(())
}
ModuleField::Start(i) => {
self.resolve_item_ref(i)?;
self.resolve(i, Ns::Func)?;
Ok(())
}
ModuleField::Export(e) => {
self.resolve_item_ref(&mut e.index)?;
self.resolve(
&mut e.item,
match e.kind {
ExportKind::Func => Ns::Func,
ExportKind::Table => Ns::Table,
ExportKind::Memory => Ns::Memory,
ExportKind::Global => Ns::Global,
ExportKind::Tag => Ns::Tag,
ExportKind::Type => Ns::Type,
},
)?;
Ok(())
}
@ -281,25 +240,6 @@ impl<'a> Resolver<'a> {
Ok(())
}
ModuleField::Instance(i) => {
if let InstanceKind::Inline { module, args } = &mut i.kind {
self.resolve_item_ref(module)?;
for arg in args {
self.resolve_item_ref(&mut arg.index)?;
}
}
Ok(())
}
ModuleField::NestedModule(m) => {
let fields = match &mut m.kind {
NestedModuleKind::Inline { fields } => fields,
NestedModuleKind::Import { .. } => panic!("should only be inline"),
};
Resolver::default().process(&mut parents.push(self, m.id), fields)?;
Ok(())
}
ModuleField::Table(t) => {
if let TableKind::Normal(t) = &mut t.kind {
self.resolve_heaptype(&mut t.elem.heap)?;
@ -307,29 +247,6 @@ impl<'a> Resolver<'a> {
Ok(())
}
ModuleField::Alias(a) => {
match &mut a.source {
AliasSource::InstanceExport { instance, .. } => {
self.resolve_item_ref(instance)?;
}
AliasSource::Outer { module, index } => {
match (index, module) {
// If both indices are numeric then don't try to
// resolve anything since we could fail to walk up
// the parent chain, producing a wat2wasm error that
// should probably be a wasm validation error.
(Index::Num(..), Index::Num(..)) => {}
(index, module) => {
parents
.resolve(module)?
.resolve(index, Ns::from_export(&a.kind))?;
}
}
}
}
Ok(())
}
ModuleField::Memory(_) | ModuleField::Custom(_) => Ok(()),
}
}
@ -369,12 +286,6 @@ impl<'a> Resolver<'a> {
self.resolve_type_use(t)?;
}
ItemKind::Global(t) => self.resolve_valtype(&mut t.ty)?,
ItemKind::Instance(t) => {
self.resolve_type_use(t)?;
}
ItemKind::Module(m) => {
self.resolve_type_use(m)?;
}
ItemKind::Table(t) => {
self.resolve_heaptype(&mut t.elem.heap)?;
}
@ -391,7 +302,7 @@ impl<'a> Resolver<'a> {
T: TypeReference<'a>,
{
let idx = ty.index.as_mut().unwrap();
let idx = self.resolve_item_ref(idx)?;
self.resolve(idx, Ns::Type)?;
// If the type was listed inline *and* it was specified via a type index
// we need to assert they're the same.
@ -416,137 +327,10 @@ impl<'a> Resolver<'a> {
Ns::Table => self.tables.resolve(idx, "table"),
Ns::Global => self.globals.resolve(idx, "global"),
Ns::Memory => self.memories.resolve(idx, "memory"),
Ns::Instance => self.instances.resolve(idx, "instance"),
Ns::Module => self.modules.resolve(idx, "module"),
Ns::Tag => self.tags.resolve(idx, "tag"),
Ns::Type => self.types.resolve(idx, "type"),
}
}
fn resolve_item_ref<'b, K>(&self, item: &'b mut ItemRef<'a, K>) -> Result<&'b Index<'a>, Error>
where
K: Into<ExportKind> + Copy,
{
match item {
ItemRef::Item {
idx,
kind,
exports,
#[cfg(wast_check_exhaustive)]
visited,
} => {
#[cfg(wast_check_exhaustive)]
{
if !*visited {
return Err(Error::new(
idx.span(),
format!("BUG: this index wasn't visited"),
));
}
}
debug_assert!(exports.len() == 0);
self.resolve(
idx,
match (*kind).into() {
ExportKind::Func => Ns::Func,
ExportKind::Table => Ns::Table,
ExportKind::Global => Ns::Global,
ExportKind::Memory => Ns::Memory,
ExportKind::Instance => Ns::Instance,
ExportKind::Module => Ns::Module,
ExportKind::Tag => Ns::Tag,
ExportKind::Type => Ns::Type,
},
)?;
Ok(idx)
}
// should be expanded by now
ItemRef::Outer { .. } => unreachable!(),
}
}
}
#[derive(Default)]
pub struct Namespace<'a> {
names: HashMap<Id<'a>, u32>,
count: u32,
}
impl<'a> Namespace<'a> {
fn register(&mut self, name: Option<Id<'a>>, desc: &str) -> Result<u32, Error> {
let index = self.alloc();
if let Some(name) = name {
if let Some(_prev) = self.names.insert(name, index) {
// FIXME: temporarily allow duplicately-named data and element
// segments. This is a sort of dumb hack to get the spec test
// suite working (ironically).
//
// So as background, the text format disallows duplicate
// identifiers, causing a parse error if they're found. There
// are two tests currently upstream, however, data.wast and
// elem.wast, which *look* like they have duplicately named
// element and data segments. These tests, however, are using
// pre-bulk-memory syntax where a bare identifier was the
// table/memory being initialized. In post-bulk-memory this
// identifier is the name of the segment. Since we implement
// post-bulk-memory features that means that we're parsing the
// memory/table-to-initialize as the name of the segment.
//
// This is technically incorrect behavior but no one is
// hopefully relying on this too much. To get the spec tests
// passing we ignore errors for elem/data segments. Once the
// spec tests get updated enough we can remove this condition
// and return errors for them.
if desc != "elem" && desc != "data" {
return Err(Error::new(
name.span(),
format!("duplicate {} identifier", desc),
));
}
}
}
Ok(index)
}
fn alloc(&mut self) -> u32 {
let index = self.count;
self.count += 1;
return index;
}
fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> {
if let Some(_prev) = self.names.insert(name, index) {
return Err(Error::new(
name.span(),
format!("duplicate identifier for {}", desc),
));
}
Ok(())
}
fn resolve(&self, idx: &mut Index<'a>, desc: &str) -> Result<u32, Error> {
let id = match idx {
Index::Num(n, _) => return Ok(*n),
Index::Id(id) => id,
};
if let Some(&n) = self.names.get(id) {
*idx = Index::Num(n, id.span());
return Ok(n);
}
Err(resolve_error(*id, desc))
}
}
fn resolve_error(id: Id<'_>, ns: &str) -> Error {
assert!(
!id.is_gensym(),
"symbol generated by `wast` itself cannot be resolved {:?}",
id
);
Error::new(
id.span(),
format!("failed to find {} named `${}`", ns, id.name()),
)
}
#[derive(Debug, Clone)]
@ -634,23 +418,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
}
fn resolve_instr(&mut self, instr: &mut Instruction<'a>) -> Result<(), Error> {
use crate::ast::Instruction::*;
use Instruction::*;
if let Some(m) = instr.memarg_mut() {
self.resolver.resolve_item_ref(&mut m.memory)?;
self.resolver.resolve(&mut m.memory, Ns::Memory)?;
}
match instr {
MemorySize(i) | MemoryGrow(i) | MemoryFill(i) => {
self.resolver.resolve_item_ref(&mut i.mem)?;
self.resolver.resolve(&mut i.mem, Ns::Memory)?;
}
MemoryInit(i) => {
self.resolver.datas.resolve(&mut i.data, "data")?;
self.resolver.resolve_item_ref(&mut i.mem)?;
self.resolver.resolve(&mut i.mem, Ns::Memory)?;
}
MemoryCopy(i) => {
self.resolver.resolve_item_ref(&mut i.src)?;
self.resolver.resolve_item_ref(&mut i.dst)?;
self.resolver.resolve(&mut i.src, Ns::Memory)?;
self.resolver.resolve(&mut i.dst, Ns::Memory)?;
}
DataDrop(i) => {
self.resolver.datas.resolve(i, "data")?;
@ -658,23 +442,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
TableInit(i) => {
self.resolver.elems.resolve(&mut i.elem, "elem")?;
self.resolver.resolve_item_ref(&mut i.table)?;
self.resolver.resolve(&mut i.table, Ns::Table)?;
}
ElemDrop(i) => {
self.resolver.elems.resolve(i, "elem")?;
}
TableCopy(i) => {
self.resolver.resolve_item_ref(&mut i.dst)?;
self.resolver.resolve_item_ref(&mut i.src)?;
self.resolver.resolve(&mut i.dst, Ns::Table)?;
self.resolver.resolve(&mut i.src, Ns::Table)?;
}
TableFill(i) | TableSet(i) | TableGet(i) | TableSize(i) | TableGrow(i) => {
self.resolver.resolve_item_ref(&mut i.dst)?;
self.resolver.resolve(&mut i.dst, Ns::Table)?;
}
GlobalSet(i) | GlobalGet(i) => {
self.resolver.resolve_item_ref(&mut i.0)?;
self.resolver.resolve(i, Ns::Global)?;
}
LocalSet(i) | LocalGet(i) | LocalTee(i) => {
@ -698,11 +482,11 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
}
Call(i) | RefFunc(i) | ReturnCall(i) => {
self.resolver.resolve_item_ref(&mut i.0)?;
self.resolver.resolve(i, Ns::Func)?;
}
CallIndirect(c) | ReturnCallIndirect(c) => {
self.resolver.resolve_item_ref(&mut c.table)?;
self.resolver.resolve(&mut c.table, Ns::Table)?;
self.resolver.resolve_type_use(&mut c.ty)?;
}
@ -864,96 +648,6 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
}
}
struct Parents<'a, 'b> {
prev: Option<ParentNode<'a, 'b>>,
cur_id: Option<Id<'a>>,
depth: usize,
names: &'b mut HashMap<Id<'a>, usize>,
}
struct ParentNode<'a, 'b> {
resolver: &'b Resolver<'a>,
id: Option<Id<'a>>,
prev: Option<&'b ParentNode<'a, 'b>>,
prev_depth: Option<usize>,
}
impl<'a, 'b> Parents<'a, 'b> {
fn push<'c>(&'c mut self, resolver: &'c Resolver<'a>, id: Option<Id<'a>>) -> Parents<'a, 'c>
where
'b: 'c,
{
let prev_depth = if let Some(id) = self.cur_id {
self.names.insert(id, self.depth)
} else {
None
};
Parents {
prev: Some(ParentNode {
prev: self.prev.as_ref(),
resolver,
id: self.cur_id,
prev_depth,
}),
cur_id: id,
depth: self.depth + 1,
names: &mut *self.names,
}
}
fn resolve(&self, index: &mut Index<'a>) -> Result<&'b Resolver<'a>, Error> {
let mut i = match *index {
Index::Num(n, _) => n,
Index::Id(id) => match self.names.get(&id) {
Some(idx) => (self.depth - *idx - 1) as u32,
None => return Err(resolve_error(id, "parent module")),
},
};
*index = Index::Num(i, index.span());
let mut cur = match self.prev.as_ref() {
Some(n) => n,
None => {
return Err(Error::new(
index.span(),
"cannot use `outer` alias in root module".to_string(),
))
}
};
while i > 0 {
cur = match cur.prev {
Some(n) => n,
None => {
return Err(Error::new(
index.span(),
"alias to `outer` module index too large".to_string(),
))
}
};
i -= 1;
}
Ok(cur.resolver)
}
}
impl<'a, 'b> Drop for Parents<'a, 'b> {
fn drop(&mut self) {
let (id, prev_depth) = match &self.prev {
Some(n) => (n.id, n.prev_depth),
None => return,
};
if let Some(id) = id {
match prev_depth {
Some(i) => {
self.names.insert(id, i);
}
None => {
self.names.remove(&id);
}
}
}
}
}
enum TypeInfo<'a> {
Func {
params: Box<[ValType<'a>]>,
@ -1023,40 +717,3 @@ impl<'a> TypeReference<'a> for FunctionType<'a> {
Ok(())
}
}
impl<'a> TypeReference<'a> for InstanceType<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> {
drop(cx);
Err(Error::new(
idx.span(),
format!("cannot specify instance type as a reference and inline"),
))
}
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
for export in self.exports.iter_mut() {
cx.resolve_item_sig(&mut export.item)?;
}
Ok(())
}
}
impl<'a> TypeReference<'a> for ModuleType<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> {
drop(cx);
Err(Error::new(
idx.span(),
format!("cannot specify module type as a reference and inline"),
))
}
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
for i in self.imports.iter_mut() {
cx.resolve_item_sig(&mut i.item)?;
}
for e in self.exports.iter_mut() {
cx.resolve_item_sig(&mut e.item)?;
}
Ok(())
}
}

Просмотреть файл

@ -1,5 +1,6 @@
use crate::ast::*;
use crate::resolve::gensym;
use crate::core::*;
use crate::gensym;
use crate::token::{Index, Span};
use std::collections::HashMap;
pub fn expand<'a>(fields: &mut Vec<ModuleField<'a>>) {
@ -8,16 +9,11 @@ pub fn expand<'a>(fields: &mut Vec<ModuleField<'a>>) {
}
#[derive(Default)]
struct Expander<'a> {
// See the comment in `process` for why this exists.
process_imports_early: bool,
pub(crate) struct Expander<'a> {
// Maps used to "intern" types. These maps are populated as type annotations
// are seen and inline type annotations use previously defined ones if
// there's a match.
func_type_to_idx: HashMap<FuncKey<'a>, Index<'a>>,
instance_type_to_idx: HashMap<InstanceKey<'a>, Index<'a>>,
module_type_to_idx: HashMap<ModuleKey<'a>, Index<'a>>,
/// Fields, during processing, which should be prepended to the
/// currently-being-processed field. This should always be empty after
@ -27,22 +23,6 @@ struct Expander<'a> {
impl<'a> Expander<'a> {
fn process(&mut self, fields: &mut Vec<ModuleField<'a>>) {
// For the given list of fields this determines whether imports are
// processed as part of `expand_header` or as part of `expand`. The
// reason for this distinction is that pre-module-linking types were
// always sorted to the front of the module so new types were always
// appended to the end. After module-linking, however, types are
// interspersed with imports and order matters. This means that imports
// can't use intern'd types which appear later.
//
// This is a bit of a hack and ideally something that needs to be
// addressed in the upstream spec. WebAssembly/module-linking#25
// represents this issue.
self.process_imports_early = fields.iter().any(|f| match f {
ModuleField::Alias(_) | ModuleField::NestedModule(_) | ModuleField::Instance(_) => true,
_ => false,
});
// Next we expand "header" fields which are those like types and
// imports. In this context "header" is defined by the previous
// `process_imports_early` annotation.
@ -75,20 +55,9 @@ impl<'a> Expander<'a> {
TypeDef::Func(f) => {
f.key().insert(self, Index::Id(id));
}
TypeDef::Instance(i) => {
i.expand(self);
i.key().insert(self, Index::Id(id));
}
TypeDef::Module(m) => {
m.expand(self);
m.key().insert(self, Index::Id(id));
}
TypeDef::Array(_) | TypeDef::Struct(_) => {}
}
}
ModuleField::Import(i) if self.process_imports_early => {
self.expand_item_sig(&mut i.item);
}
_ => {}
}
}
@ -99,10 +68,7 @@ impl<'a> Expander<'a> {
ModuleField::Type(_) => {}
ModuleField::Import(i) => {
// Only expand here if not expanded above
if !self.process_imports_early {
self.expand_item_sig(&mut i.item);
}
self.expand_item_sig(&mut i.item);
}
ModuleField::Func(f) => {
self.expand_type_use(&mut f.ty);
@ -135,15 +101,8 @@ impl<'a> Expander<'a> {
self.expand_type_use(ty);
}
},
ModuleField::NestedModule(m) => {
if let NestedModuleKind::Inline { fields } = &mut m.kind {
Expander::default().process(fields);
}
}
ModuleField::Alias(_)
| ModuleField::Instance(_)
| ModuleField::Table(_)
ModuleField::Table(_)
| ModuleField::Memory(_)
| ModuleField::Start(_)
| ModuleField::Export(_)
@ -156,14 +115,6 @@ impl<'a> Expander<'a> {
ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => {
self.expand_type_use(t);
}
ItemKind::Instance(t) => {
self.expand_type_use(t);
t.inline.take();
}
ItemKind::Module(m) => {
self.expand_type_use(m);
m.inline.take();
}
ItemKind::Global(_) | ItemKind::Table(_) | ItemKind::Memory(_) => {}
}
}
@ -228,13 +179,7 @@ impl<'a> Expander<'a> {
T: TypeReference<'a>,
{
if let Some(idx) = &item.index {
match idx {
ItemRef::Item { idx, exports, .. } => {
debug_assert!(exports.len() == 0);
return idx.clone();
}
ItemRef::Outer { .. } => unreachable!(),
}
return idx.clone();
}
let key = match item.inline.as_mut() {
Some(ty) => {
@ -243,15 +188,9 @@ impl<'a> Expander<'a> {
}
None => T::default().key(),
};
let span = Span::from_offset(0); // FIXME: don't manufacture
let span = Span::from_offset(0); // FIXME(#613): don't manufacture
let idx = self.key_to_idx(span, key);
item.index = Some(ItemRef::Item {
idx,
kind: kw::r#type(span),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: true,
});
item.index = Some(idx);
return idx;
}
@ -277,19 +216,19 @@ impl<'a> Expander<'a> {
}
}
trait TypeReference<'a>: Default {
pub(crate) trait TypeReference<'a>: Default {
type Key: TypeKey<'a>;
fn key(&self) -> Self::Key;
fn expand(&mut self, cx: &mut Expander<'a>);
}
trait TypeKey<'a> {
pub(crate) trait TypeKey<'a> {
fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>>;
fn to_def(&self, span: Span) -> TypeDef<'a>;
fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>);
}
type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>);
pub(crate) type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>);
impl<'a> TypeReference<'a> for FunctionType<'a> {
type Key = FuncKey<'a>;
@ -319,159 +258,3 @@ impl<'a> TypeKey<'a> for FuncKey<'a> {
cx.func_type_to_idx.entry(self.clone()).or_insert(idx);
}
}
// A list of the exports of a module as well as the signature they export.
type InstanceKey<'a> = Vec<(&'a str, Item<'a>)>;
impl<'a> TypeReference<'a> for InstanceType<'a> {
type Key = InstanceKey<'a>;
fn key(&self) -> Self::Key {
self.exports
.iter()
.map(|export| (export.name, Item::new(&export.item)))
.collect()
}
fn expand(&mut self, cx: &mut Expander<'a>) {
for export in self.exports.iter_mut() {
cx.expand_item_sig(&mut export.item);
}
}
}
impl<'a> TypeKey<'a> for InstanceKey<'a> {
fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>> {
cx.instance_type_to_idx.get(self).cloned()
}
fn to_def(&self, span: Span) -> TypeDef<'a> {
let exports = self
.iter()
.map(|(name, item)| ExportType {
span,
name,
item: item.to_sig(span),
})
.collect();
TypeDef::Instance(InstanceType { exports })
}
fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) {
cx.instance_type_to_idx.entry(self.clone()).or_insert(idx);
}
}
// The first element of this pair is the list of imports in the module, and the
// second element is the list of exports.
type ModuleKey<'a> = (
Vec<(&'a str, Option<&'a str>, Item<'a>)>,
Vec<(&'a str, Item<'a>)>,
);
impl<'a> TypeReference<'a> for ModuleType<'a> {
type Key = ModuleKey<'a>;
fn key(&self) -> Self::Key {
let imports = self
.imports
.iter()
.map(|import| (import.module, import.field, Item::new(&import.item)))
.collect();
let exports = self
.exports
.iter()
.map(|export| (export.name, Item::new(&export.item)))
.collect();
(imports, exports)
}
fn expand(&mut self, cx: &mut Expander<'a>) {
for export in self.exports.iter_mut() {
cx.expand_item_sig(&mut export.item);
}
for import in self.imports.iter_mut() {
cx.expand_item_sig(&mut import.item);
}
}
}
impl<'a> TypeKey<'a> for ModuleKey<'a> {
fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>> {
cx.module_type_to_idx.get(self).cloned()
}
fn to_def(&self, span: Span) -> TypeDef<'a> {
let imports = self
.0
.iter()
.map(|(module, field, item)| Import {
span,
module,
field: *field,
item: item.to_sig(span),
})
.collect();
let exports = self
.1
.iter()
.map(|(name, item)| ExportType {
span,
name,
item: item.to_sig(span),
})
.collect();
TypeDef::Module(ModuleType { imports, exports })
}
fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) {
cx.module_type_to_idx.entry(self.clone()).or_insert(idx);
}
}
// A lookalike to `ItemKind` except without all non-relevant information for
// hashing. This is used as a hash key for instance/module type lookup.
#[derive(Clone, PartialEq, Eq, Hash)]
enum Item<'a> {
Func(Index<'a>),
Table(TableType<'a>),
Memory(MemoryType),
Global(GlobalType<'a>),
Tag(Index<'a>),
Module(Index<'a>),
Instance(Index<'a>),
}
impl<'a> Item<'a> {
fn new(item: &ItemSig<'a>) -> Item<'a> {
match &item.kind {
ItemKind::Func(f) => Item::Func(*f.index.as_ref().unwrap().unwrap_index()),
ItemKind::Instance(f) => Item::Instance(*f.index.as_ref().unwrap().unwrap_index()),
ItemKind::Module(f) => Item::Module(*f.index.as_ref().unwrap().unwrap_index()),
ItemKind::Tag(TagType::Exception(f)) => {
Item::Tag(*f.index.as_ref().unwrap().unwrap_index())
}
ItemKind::Table(t) => Item::Table(t.clone()),
ItemKind::Memory(t) => Item::Memory(t.clone()),
ItemKind::Global(t) => Item::Global(t.clone()),
}
}
fn to_sig(&self, span: Span) -> ItemSig<'a> {
let kind = match self {
Item::Func(index) => ItemKind::Func(TypeUse::new_with_index(*index)),
Item::Tag(index) => ItemKind::Tag(TagType::Exception(TypeUse::new_with_index(*index))),
Item::Instance(index) => ItemKind::Instance(TypeUse::new_with_index(*index)),
Item::Module(index) => ItemKind::Module(TypeUse::new_with_index(*index)),
Item::Table(t) => ItemKind::Table(t.clone()),
Item::Memory(t) => ItemKind::Memory(t.clone()),
Item::Global(t) => ItemKind::Global(t.clone()),
};
ItemSig {
span,
id: None,
name: None,
kind,
}
}
}

Просмотреть файл

@ -1,18 +1,20 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, Index, LParen, NameAnnotation, Span};
/// A WebAssembly `table` directive in a module.
#[derive(Debug)]
pub struct Table<'a> {
/// Where this table was defined.
pub span: ast::Span,
pub span: Span,
/// An optional name to refer to this table by.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// If present, inline export annotations which indicate names this
/// definition should be exported under.
pub exports: ast::InlineExport<'a>,
pub exports: InlineExport<'a>,
/// How this table is textually defined in the module.
pub kind: TableKind<'a>,
}
@ -23,17 +25,17 @@ pub enum TableKind<'a> {
/// This table is actually an inlined import definition.
#[allow(missing_docs)]
Import {
import: ast::InlineImport<'a>,
ty: ast::TableType<'a>,
import: InlineImport<'a>,
ty: TableType<'a>,
},
/// A typical memory definition which simply says the limits of the table
Normal(ast::TableType<'a>),
Normal(TableType<'a>),
/// The elem segments of this table, starting from 0, explicitly listed
Inline {
/// The element type of this table.
elem: ast::RefType<'a>,
elem: RefType<'a>,
/// The element table entries to have, and the length of this list is
/// the limits of the table as well.
payload: ElemPayload<'a>,
@ -53,11 +55,11 @@ impl<'a> Parse<'a> for Table<'a> {
// * `(import "a" "b") limits`
// * `limits`
let mut l = parser.lookahead1();
let kind = if l.peek::<ast::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::<ast::LParen>() {
let ty = if parser.peek::<LParen>() {
Some(elem)
} else {
None
@ -89,11 +91,11 @@ impl<'a> Parse<'a> for Table<'a> {
#[derive(Debug)]
pub struct Elem<'a> {
/// Where this `elem` was defined.
pub span: ast::Span,
pub span: Span,
/// An optional name by which to refer to this segment.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this element stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// The way this segment was defined in the module.
pub kind: ElemKind<'a>,
/// The payload of this element segment, typically a list of functions.
@ -114,9 +116,9 @@ pub enum ElemKind<'a> {
/// An active segment associated with a table.
Active {
/// The table this `elem` is initializing.
table: ast::ItemRef<'a, kw::table>,
table: Index<'a>,
/// The offset within `table` that we'll initialize at.
offset: ast::Expression<'a>,
offset: Expression<'a>,
},
}
@ -124,15 +126,15 @@ pub enum ElemKind<'a> {
#[derive(Debug)]
pub enum ElemPayload<'a> {
/// This element segment has a contiguous list of function indices
Indices(Vec<ast::ItemRef<'a, kw::func>>),
Indices(Vec<Index<'a>>),
/// This element segment has a list of optional function indices,
/// represented as expressions using `ref.func` and `ref.null`.
Exprs {
/// The desired type of each expression below.
ty: ast::RefType<'a>,
ty: RefType<'a>,
/// The expressions in this segment.
exprs: Vec<ast::Expression<'a>>,
exprs: Vec<Expression<'a>>,
},
}
@ -142,19 +144,23 @@ impl<'a> Parse<'a> for Elem<'a> {
let id = parser.parse()?;
let name = parser.parse()?;
let kind = if parser.peek::<u32>()
|| (parser.peek::<ast::LParen>() && !parser.peek::<ast::RefType>())
{
let table = if let Some(index) = parser.parse::<Option<ast::IndexOrRef<_>>>()? {
index.0
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>() {
// 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::table>() {
parser.parens(|p| {
p.parse::<kw::table>()?;
p.parse()
})?
} else {
ast::ItemRef::Item {
kind: kw::table(parser.prev_span()),
idx: ast::Index::Num(0, span),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: false,
}
Index::Num(0, span)
};
let offset = parser.parens(|parser| {
if parser.peek::<kw::offset>() {
@ -163,9 +169,6 @@ impl<'a> Parse<'a> for Elem<'a> {
parser.parse()
})?;
ElemKind::Active { table, offset }
} else if parser.peek::<kw::declare>() {
parser.parse::<kw::declare>()?;
ElemKind::Declared
} else {
ElemKind::Passive
};
@ -187,19 +190,19 @@ impl<'a> Parse<'a> for ElemPayload<'a> {
}
impl<'a> ElemPayload<'a> {
fn parse_tail(parser: Parser<'a>, ty: Option<ast::RefType<'a>>) -> Result<Self> {
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, ast::RefType::func())
(true, RefType::func())
}
Some(ty) => (false, ty),
};
if let ast::HeapType::Func = ty.heap {
if must_use_indices || parser.peek::<ast::IndexOrRef<kw::func>>() {
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::<ast::IndexOrRef<_>>()?.0);
elems.push(parser.parse()?);
}
return Ok(ElemPayload::Indices(elems));
}
@ -214,7 +217,7 @@ impl<'a> ElemPayload<'a> {
// Without `item` this is "sugar" for a single-instruction
// expression.
let insn = parser.parse()?;
Ok(ast::Expression {
Ok(Expression {
instrs: [insn].into(),
})
}

Просмотреть файл

@ -1,17 +1,19 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::{Id, NameAnnotation, Span};
/// A WebAssembly tag directive, part of the exception handling proposal.
#[derive(Debug)]
pub struct Tag<'a> {
/// Where this tag was defined
pub span: ast::Span,
pub span: Span,
/// An optional name by which to refer to this tag in name resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// Optional export directives for this tag.
pub exports: ast::InlineExport<'a>,
pub exports: InlineExport<'a>,
/// The type of tag that is defined.
pub ty: TagType<'a>,
/// What kind of tag this is defined as.
@ -23,7 +25,7 @@ pub struct Tag<'a> {
pub enum TagType<'a> {
/// An exception tag, where the payload is the type signature of the tag
/// (constructor parameters, etc).
Exception(ast::TypeUse<'a, ast::FunctionType<'a>>),
Exception(TypeUse<'a, FunctionType<'a>>),
}
/// Different kinds of tags that can be defined in a module.
@ -34,7 +36,7 @@ pub enum TagKind<'a> {
/// ```text
/// (tag (type 0) (import "foo" "bar"))
/// ```
Import(ast::InlineImport<'a>),
Import(InlineImport<'a>),
/// A tag defined inline in the module itself
Inline(),

Просмотреть файл

@ -1,5 +1,7 @@
use crate::ast::{self, kw};
use crate::core::*;
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::{Id, Index, LParen, NameAnnotation, Span};
use std::mem;
/// The value types for a wasm module.
@ -12,7 +14,7 @@ pub enum ValType<'a> {
F64,
V128,
Ref(RefType<'a>),
Rtt(Option<u32>, ast::Index<'a>),
Rtt(Option<u32>, Index<'a>),
}
impl<'a> Parse<'a> for ValType<'a> {
@ -35,7 +37,7 @@ impl<'a> Parse<'a> for ValType<'a> {
Ok(ValType::V128)
} else if l.peek::<RefType>() {
Ok(ValType::Ref(parser.parse()?))
} else if l.peek::<ast::LParen>() {
} else if l.peek::<LParen>() {
parser.parens(|p| {
let mut l = p.lookahead1();
if l.peek::<kw::rtt>() {
@ -58,7 +60,7 @@ impl<'a> Peek for ValType<'a> {
|| kw::f32::peek(cursor)
|| kw::f64::peek(cursor)
|| kw::v128::peek(cursor)
|| (ast::LParen::peek(cursor) && kw::rtt::peek2(cursor))
|| (LParen::peek(cursor) && kw::rtt::peek2(cursor))
|| RefType::peek(cursor)
}
fn display() -> &'static str {
@ -89,7 +91,7 @@ pub enum HeapType<'a> {
I31,
/// A reference to a function, struct, or array: ref T. This is part of the
/// GC proposal.
Index(ast::Index<'a>),
Index(Index<'a>),
}
impl<'a> Parse<'a> for HeapType<'a> {
@ -113,7 +115,7 @@ impl<'a> Parse<'a> for HeapType<'a> {
} else if l.peek::<kw::i31>() {
parser.parse::<kw::i31>()?;
Ok(HeapType::I31)
} else if l.peek::<ast::Index>() {
} else if l.peek::<Index>() {
Ok(HeapType::Index(parser.parse()?))
} else {
Err(l.error())
@ -129,7 +131,7 @@ impl<'a> Peek for HeapType<'a> {
|| kw::eq::peek(cursor)
|| kw::data::peek(cursor)
|| kw::i31::peek(cursor)
|| (ast::LParen::peek(cursor) && kw::r#type::peek2(cursor))
|| (LParen::peek(cursor) && kw::r#type::peek2(cursor))
}
fn display() -> &'static str {
"heaptype"
@ -218,7 +220,7 @@ impl<'a> Parse<'a> for RefType<'a> {
} else if l.peek::<kw::i31ref>() {
parser.parse::<kw::i31ref>()?;
Ok(RefType::i31())
} else if l.peek::<ast::LParen>() {
} else if l.peek::<LParen>() {
parser.parens(|p| {
let mut l = parser.lookahead1();
if l.peek::<kw::r#ref>() {
@ -253,7 +255,7 @@ impl<'a> Peek for RefType<'a> {
|| kw::eqref::peek(cursor)
|| kw::dataref::peek(cursor)
|| kw::i31ref::peek(cursor)
|| (ast::LParen::peek(cursor) && kw::r#ref::peek2(cursor))
|| (LParen::peek(cursor) && kw::r#ref::peek2(cursor))
}
fn display() -> &'static str {
"reftype"
@ -414,13 +416,7 @@ impl<'a> Parse<'a> for MemoryType {
pub struct FunctionType<'a> {
/// The parameters of a function, optionally each having an identifier for
/// name resolution and a name for the custom `name` section.
pub params: Box<
[(
Option<ast::Id<'a>>,
Option<ast::NameAnnotation<'a>>,
ValType<'a>,
)],
>,
pub params: Box<[(Option<Id<'a>>, Option<NameAnnotation<'a>>, ValType<'a>)]>,
/// The results types of a function.
pub results: Box<[ValType<'a>]>,
}
@ -559,7 +555,7 @@ impl<'a> Parse<'a> for StructType<'a> {
#[derive(Clone, Debug)]
pub struct StructField<'a> {
/// An optional identifier for name resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// Whether this field may be mutated or not.
pub mutable: bool,
/// The storage type stored in this field.
@ -606,102 +602,15 @@ impl<'a> Parse<'a> for ArrayType<'a> {
}
}
/// A type for a nested module
#[derive(Clone, Debug, Default)]
pub struct ModuleType<'a> {
/// The imports that are expected for this module type.
pub imports: Vec<ast::Import<'a>>,
/// The exports that this module type is expected to have.
pub exports: Vec<ExportType<'a>>,
}
impl<'a> Parse<'a> for ModuleType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// See comments in `nested_module.rs` for why this is tested here.
if parser.parens_depth() > 100 {
return Err(parser.error("module type nesting too deep"));
}
let mut imports = Vec::new();
while parser.peek2::<kw::import>() {
imports.push(parser.parens(|p| p.parse())?);
}
let mut exports = Vec::new();
while parser.peek2::<kw::export>() {
parser.parens(|p| {
exports.push(p.parse()?);
Ok(())
})?;
}
Ok(ModuleType { imports, exports })
}
}
impl<'a> Peek for ModuleType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
if let Some(next) = cursor.lparen() {
match next.keyword() {
Some(("import", _)) | Some(("export", _)) => return true,
_ => {}
}
}
false
}
fn display() -> &'static str {
"module type"
}
}
/// A type for a nested instance
#[derive(Clone, Debug, Default)]
pub struct InstanceType<'a> {
/// The exported types from this instance
pub exports: Vec<ExportType<'a>>,
}
impl<'a> Parse<'a> for InstanceType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
// See comments in `nested_module.rs` for why this is tested here.
if parser.parens_depth() > 100 {
return Err(parser.error("instance type nesting too deep"));
}
let mut exports = Vec::new();
while !parser.is_empty() {
exports.push(parser.parens(|p| p.parse())?);
}
Ok(InstanceType { exports })
}
}
impl<'a> Peek for InstanceType<'a> {
fn peek(cursor: Cursor<'_>) -> bool {
if let Some(next) = cursor.lparen() {
match next.keyword() {
Some(("export", _)) => return true,
_ => {}
}
}
false
}
fn display() -> &'static str {
"instance type"
}
}
/// The type of an exported item from a module or instance.
#[derive(Debug, Clone)]
pub struct ExportType<'a> {
/// Where this export was defined.
pub span: ast::Span,
pub span: Span,
/// The name of this export.
pub name: &'a str,
/// The signature of the item that's exported.
pub item: ast::ItemSig<'a>,
pub item: ItemSig<'a>,
}
impl<'a> Parse<'a> for ExportType<'a> {
@ -722,22 +631,18 @@ pub enum TypeDef<'a> {
Struct(StructType<'a>),
/// An array type definition.
Array(ArrayType<'a>),
/// A module type definition.
Module(ModuleType<'a>),
/// An instance type definition.
Instance(InstanceType<'a>),
}
/// A type declaration in a module
#[derive(Debug)]
pub struct Type<'a> {
/// Where this type was defined.
pub span: ast::Span,
pub span: Span,
/// An optional identifer to refer to this `type` by as part of name
/// resolution.
pub id: Option<ast::Id<'a>>,
pub id: Option<Id<'a>>,
/// An optional name for this function stored in the custom `name` section.
pub name: Option<ast::NameAnnotation<'a>>,
pub name: Option<NameAnnotation<'a>>,
/// The type that we're declaring.
pub def: TypeDef<'a>,
}
@ -758,12 +663,6 @@ impl<'a> Parse<'a> for Type<'a> {
} else if l.peek::<kw::array>() {
parser.parse::<kw::array>()?;
Ok(TypeDef::Array(parser.parse()?))
} else if l.peek::<kw::module>() {
parser.parse::<kw::module>()?;
Ok(TypeDef::Module(parser.parse()?))
} else if l.peek::<kw::instance>() {
parser.parse::<kw::instance>()?;
Ok(TypeDef::Instance(parser.parse()?))
} else {
Err(l.error())
}
@ -781,7 +680,7 @@ impl<'a> Parse<'a> for Type<'a> {
#[derive(Clone, Debug)]
pub struct TypeUse<'a, T> {
/// The type that we're referencing, if it was present.
pub index: Option<ast::ItemRef<'a, kw::r#type>>,
pub index: Option<Index<'a>>,
/// The inline type, if present.
pub inline: Option<T>,
}
@ -789,15 +688,9 @@ pub struct TypeUse<'a, T> {
impl<'a, T> TypeUse<'a, T> {
/// Constructs a new instance of `TypeUse` without an inline definition but
/// with an index specified.
pub fn new_with_index(idx: ast::Index<'a>) -> TypeUse<'a, T> {
pub fn new_with_index(idx: Index<'a>) -> TypeUse<'a, T> {
TypeUse {
index: Some(ast::ItemRef::Item {
idx,
kind: kw::r#type::default(),
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: true,
}),
index: Some(idx),
inline: None,
}
}
@ -806,7 +699,10 @@ impl<'a, T> TypeUse<'a, T> {
impl<'a, T: Peek + Parse<'a>> Parse<'a> for TypeUse<'a, T> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let index = if parser.peek2::<kw::r#type>() {
Some(parser.parse()?)
Some(parser.parens(|p| {
p.parse::<kw::r#type>()?;
p.parse()
})?)
} else {
None
};

75
third_party/rust/wast/src/encode.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,75 @@
pub(crate) trait Encode {
fn encode(&self, e: &mut Vec<u8>);
}
impl<T: Encode + ?Sized> Encode for &'_ 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);
for item in self {
item.encode(e);
}
}
}
impl<T: Encode> Encode for Vec<T> {
fn encode(&self, e: &mut Vec<u8>) {
<[T]>::encode(self, e)
}
}
impl Encode for str {
fn encode(&self, e: &mut Vec<u8>) {
self.len().encode(e);
e.extend_from_slice(self.as_bytes());
}
}
impl Encode for usize {
fn encode(&self, e: &mut Vec<u8>) {
assert!(*self <= u32::max_value() as usize);
(*self as u32).encode(e)
}
}
impl Encode for u8 {
fn encode(&self, e: &mut Vec<u8>) {
e.push(*self);
}
}
impl Encode for u32 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::unsigned(e, (*self).into()).unwrap();
}
}
impl Encode for i32 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::signed(e, (*self).into()).unwrap();
}
}
impl Encode for u64 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::unsigned(e, (*self).into()).unwrap();
}
}
impl Encode for i64 {
fn encode(&self, e: &mut Vec<u8>) {
leb128::write::signed(e, *self).unwrap();
}
}
impl<T: Encode, U: Encode> Encode for (T, U) {
fn encode(&self, e: &mut Vec<u8>) {
self.0.encode(e);
self.1.encode(e);
}
}

196
third_party/rust/wast/src/error.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,196 @@
use crate::lexer::LexError;
use crate::token::Span;
use std::fmt;
use std::path::{Path, PathBuf};
use unicode_width::UnicodeWidthStr;
/// A convenience error type to tie together all the detailed errors produced by
/// this crate.
///
/// This type can be created from a [`LexError`]. This also contains
/// storage for file/text information so a nice error can be rendered along the
/// same lines of rustc's own error messages (minus the color).
///
/// This type is typically suitable for use in public APIs for consumers of this
/// crate.
#[derive(Debug)]
pub struct Error {
inner: Box<ErrorInner>,
}
#[derive(Debug)]
struct ErrorInner {
text: Option<Text>,
file: Option<PathBuf>,
span: Span,
kind: ErrorKind,
}
#[derive(Debug)]
struct Text {
line: usize,
col: usize,
snippet: String,
}
#[derive(Debug)]
enum ErrorKind {
Lex(LexError),
Custom(String),
}
impl Error {
pub(crate) fn lex(span: Span, content: &str, kind: LexError) -> Error {
let mut ret = Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Lex(kind),
}),
};
ret.set_text(content);
return ret;
}
pub(crate) fn parse(span: Span, content: &str, message: String) -> Error {
let mut ret = Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Custom(message),
}),
};
ret.set_text(content);
return ret;
}
/// Creates a new error with the given `message` which is targeted at the
/// given `span`
///
/// Note that you'll want to ensure that `set_text` or `set_path` is called
/// on the resulting error to improve the rendering of the error message.
pub fn new(span: Span, message: String) -> Error {
Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Custom(message),
}),
}
}
/// Return the `Span` for this error.
pub fn span(&self) -> Span {
self.inner.span
}
/// To provide a more useful error this function can be used to extract
/// relevant textual information about this error into the error itself.
///
/// The `contents` here should be the full text of the original file being
/// parsed, and this will extract a sub-slice as necessary to render in the
/// `Display` implementation later on.
pub fn set_text(&mut self, contents: &str) {
if self.inner.text.is_some() {
return;
}
self.inner.text = Some(Text::new(contents, self.inner.span));
}
/// To provide a more useful error this function can be used to set
/// the file name that this error is associated with.
///
/// The `path` here will be stored in this error and later rendered in the
/// `Display` implementation.
pub fn set_path(&mut self, path: &Path) {
if self.inner.file.is_some() {
return;
}
self.inner.file = Some(path.to_path_buf());
}
/// Returns the underlying `LexError`, if any, that describes this error.
pub fn lex_error(&self) -> Option<&LexError> {
match &self.inner.kind {
ErrorKind::Lex(e) => Some(e),
_ => None,
}
}
/// Returns the underlying message, if any, that describes this error.
pub fn message(&self) -> String {
match &self.inner.kind {
ErrorKind::Lex(e) => e.to_string(),
ErrorKind::Custom(e) => e.clone(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let err = match &self.inner.kind {
ErrorKind::Lex(e) => e as &dyn fmt::Display,
ErrorKind::Custom(e) => e as &dyn fmt::Display,
};
let text = match &self.inner.text {
Some(text) => text,
None => {
return write!(f, "{} at byte offset {}", err, self.inner.span.offset);
}
};
let file = self
.inner
.file
.as_ref()
.and_then(|p| p.to_str())
.unwrap_or("<anon>");
write!(
f,
"\
{err}
--> {file}:{line}:{col}
|
{line:4} | {text}
| {marker:>0$}",
text.col + 1,
file = file,
line = text.line + 1,
col = text.col + 1,
err = err,
text = text.snippet,
marker = "^",
)
}
}
impl std::error::Error for Error {}
impl Text {
fn new(content: &str, span: Span) -> Text {
let (line, col) = span.linecol_in(content);
let contents = content.lines().nth(line).unwrap_or("");
let mut snippet = String::new();
for ch in contents.chars() {
match ch {
// Replace tabs with spaces to render consistently
'\t' => {
snippet.push_str(" ");
}
// these codepoints change how text is rendered so for clarity
// in error messages they're dropped.
'\u{202a}' | '\u{202b}' | '\u{202d}' | '\u{202e}' | '\u{2066}' | '\u{2067}'
| '\u{2068}' | '\u{206c}' | '\u{2069}' => {}
c => snippet.push(c),
}
}
// Use the `unicode-width` crate to figure out how wide the snippet, up
// to our "column", actually is. That'll tell us how many spaces to
// place before the `^` character that points at the problem
let col = snippet.get(..col).map(|s| s.width()).unwrap_or(col);
Text { line, col, snippet }
}
}

Просмотреть файл

@ -1,4 +1,4 @@
use crate::ast::{Id, Span};
use crate::token::{Id, Span};
use std::cell::Cell;
thread_local!(static NEXT: Cell<u32> = Cell::new(0));

21
third_party/rust/wast/src/lexer.rs поставляемый
Просмотреть файл

@ -24,7 +24,8 @@
//!
//! [`Lexer`]: crate::lexer::Lexer
use crate::{Error, Span};
use crate::token::Span;
use crate::Error;
use std::borrow::Cow;
use std::char;
use std::fmt;
@ -32,7 +33,7 @@ use std::str;
/// A structure used to lex the s-expression syntax of WAT files.
///
/// This structure is used to generate [`Source`] items, which should account for
/// This structure is used to generate [`Token`] items, which should account for
/// every single byte of the input as we iterate over it. A [`LexError`] is
/// returned for any non-lexable text.
#[derive(Clone)]
@ -483,10 +484,10 @@ impl<'a> Lexer<'a> {
}
fn number(&self, src: &'a str) -> Option<Token<'a>> {
let (sign, num) = if src.starts_with('+') {
(Some(SignToken::Plus), &src[1..])
} else if src.starts_with('-') {
(Some(SignToken::Minus), &src[1..])
let (sign, num) = if let Some(stripped) = src.strip_prefix('+') {
(Some(SignToken::Plus), stripped)
} else if let Some(stripped) = src.strip_prefix('-') {
(Some(SignToken::Minus), stripped)
} else {
(None, src)
};
@ -507,8 +508,8 @@ impl<'a> Lexer<'a> {
negative,
},
}))));
} else if num.starts_with("nan:0x") {
let mut it = num[6..].chars();
} else if let Some(stripped) = num.strip_prefix("nan:0x") {
let mut it = stripped.chars();
let to_parse = skip_undescores(&mut it, false, char::is_ascii_hexdigit)?;
if it.next().is_some() {
return None;
@ -524,9 +525,9 @@ impl<'a> Lexer<'a> {
}
// Figure out if we're a hex number or not
let (mut it, hex, test_valid) = if num.starts_with("0x") {
let (mut it, hex, test_valid) = if let Some(stripped) = num.strip_prefix("0x") {
(
num[2..].chars(),
stripped.chars(),
true,
char::is_ascii_hexdigit as fn(&char) -> bool,
)

647
third_party/rust/wast/src/lib.rs поставляемый
Просмотреть файл

@ -20,9 +20,10 @@
//! around working with a [`Parser`](`parser::Parser`) to parse streams of
//! tokens.
//!
//! * [`Module`] - this contains an Abstract Syntax Tree (AST) of the
//! WebAssembly Text format (WAT) as well as the unofficial WAST format. This
//! also has a [`Module::encode`] method to emit a module in its binary form.
//! * [`Module`](crate::core::Module) - this contains an Abstract Syntax Tree
//! (AST) of the WebAssembly Text format (WAT) as well as the unofficial WAST
//! format. This also has a [`Module::encode`](crate::core::Module::encode)
//! method to emit a module in its binary form.
//!
//! # Stability and WebAssembly Features
//!
@ -47,209 +48,463 @@
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
use std::fmt;
use std::path::{Path, PathBuf};
use unicode_width::UnicodeWidthStr;
/// A macro to create a custom keyword parser.
///
/// This macro is invoked in one of two forms:
///
/// ```
/// // keyword derived from the Rust identifier:
/// wast::custom_keyword!(foo);
///
/// // or an explicitly specified string representation of the keyword:
/// wast::custom_keyword!(my_keyword = "the-wasm-keyword");
/// ```
///
/// This can then be used to parse custom keyword for custom items, such as:
///
/// ```
/// use wast::parser::{Parser, Result, Parse};
///
/// struct InlineModule<'a> {
/// inline_text: &'a str,
/// }
///
/// mod kw {
/// wast::custom_keyword!(inline);
/// }
///
/// // Parse an inline string module of the form:
/// //
/// // (inline "(module (func))")
/// impl<'a> Parse<'a> for InlineModule<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// parser.parse::<kw::inline>()?;
/// Ok(InlineModule {
/// inline_text: parser.parse()?,
/// })
/// }
/// }
/// ```
///
/// Note that the keyword name can only start with a lower-case letter, i.e. 'a'..'z'.
#[macro_export]
macro_rules! custom_keyword {
($name:ident) => {
$crate::custom_keyword!($name = stringify!($name));
};
($name:ident = $kw:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone)]
pub struct $name(pub $crate::token::Span);
#[cfg(feature = "wasm-module")]
mod binary;
#[cfg(feature = "wasm-module")]
mod resolve;
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((kw, rest)) = c.keyword() {
if kw == $kw {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected keyword `", $kw, "`")))
})
}
}
mod ast;
pub use self::ast::*;
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((kw, _rest)) = cursor.keyword() {
kw == $kw
} else {
false
}
}
fn display() -> &'static str {
concat!("`", $kw, "`")
}
}
};
}
/// A macro for defining custom reserved symbols.
///
/// This is like `custom_keyword!` but for reserved symbols (`Token::Reserved`)
/// instead of keywords (`Token::Keyword`).
///
/// ```
/// use wast::parser::{Parser, Result, Parse};
///
/// // Define a custom reserved symbol, the "spaceship" operator: `<=>`.
/// wast::custom_reserved!(spaceship = "<=>");
///
/// /// A "three-way comparison" like `(<=> a b)` that returns -1 if `a` is less
/// /// than `b`, 0 if they're equal, and 1 if `a` is greater than `b`.
/// struct ThreeWayComparison<'a> {
/// lhs: wast::core::Expression<'a>,
/// rhs: wast::core::Expression<'a>,
/// }
///
/// impl<'a> Parse<'a> for ThreeWayComparison<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// parser.parse::<spaceship>()?;
/// let lhs = parser.parse()?;
/// let rhs = parser.parse()?;
/// Ok(ThreeWayComparison { lhs, rhs })
/// }
/// }
/// ```
#[macro_export]
macro_rules! custom_reserved {
($name:ident) => {
$crate::custom_reserved!($name = stringify!($name));
};
($name:ident = $rsv:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug)]
pub struct $name(pub $crate::token::Span);
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((rsv, rest)) = c.reserved() {
if rsv == $rsv {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected reserved symbol `", $rsv, "`")))
})
}
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((rsv, _rest)) = cursor.reserved() {
rsv == $rsv
} else {
false
}
}
fn display() -> &'static str {
concat!("`", $rsv, "`")
}
}
};
}
/// A macro, like [`custom_keyword`], to create a type which can be used to
/// parse/peek annotation directives.
///
/// Note that when you're parsing custom annotations it can be somewhat tricky
/// due to the nature that most of them are skipped. You'll want to be sure to
/// consult the documentation of [`Parser::register_annotation`][register] when
/// using this macro.
///
/// # Examples
///
/// To see an example of how to use this macro, let's invent our own syntax for
/// the [producers section][section] which looks like:
///
/// ```wat
/// (@producer "wat" "1.0.2")
/// ```
///
/// Here, for simplicity, we'll assume everything is a `processed-by` directive,
/// but you could get much more fancy with this as well.
///
/// ```
/// # use wast::*;
/// # use wast::parser::*;
///
/// // First we define the custom annotation keyword we're using, and by
/// // convention we define it in an `annotation` module.
/// mod annotation {
/// wast::annotation!(producer);
/// }
///
/// struct Producer<'a> {
/// name: &'a str,
/// version: &'a str,
/// }
///
/// impl<'a> Parse<'a> for Producer<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// // Remember that parser conventionally parse the *interior* of an
/// // s-expression, so we parse our `@producer` annotation and then we
/// // parse the payload of our annotation.
/// parser.parse::<annotation::producer>()?;
/// Ok(Producer {
/// name: parser.parse()?,
/// version: parser.parse()?,
/// })
/// }
/// }
/// ```
///
/// Note though that this is only half of the parser for annotations. The other
/// half is calling the [`register_annotation`][register] method at the right
/// time to ensure the parser doesn't automatically skip our `@producer`
/// directive. Note that we *can't* call it inside the `Parse for Producer`
/// definition because that's too late and the annotation would already have
/// been skipped.
///
/// Instead we'll need to call it from a higher level-parser before the
/// parenthesis have been parsed, like so:
///
/// ```
/// # use wast::*;
/// # use wast::parser::*;
/// struct Module<'a> {
/// fields: Vec<ModuleField<'a>>,
/// }
///
/// impl<'a> Parse<'a> for Module<'a> {
/// fn parse(parser: Parser<'a>) -> Result<Self> {
/// // .. parse module header here ...
///
/// // register our custom `@producer` annotation before we start
/// // parsing the parentheses of each field
/// let _r = parser.register_annotation("producer");
///
/// let mut fields = Vec::new();
/// while !parser.is_empty() {
/// fields.push(parser.parens(|p| p.parse())?);
/// }
/// Ok(Module { fields })
/// }
/// }
///
/// enum ModuleField<'a> {
/// Producer(Producer<'a>),
/// // ...
/// }
/// # struct Producer<'a>(&'a str);
/// # impl<'a> Parse<'a> for Producer<'a> {
/// # fn parse(parser: Parser<'a>) -> Result<Self> { Ok(Producer(parser.parse()?)) }
/// # }
/// # mod annotation { wast::annotation!(producer); }
///
/// impl<'a> Parse<'a> for ModuleField<'a> {
/// 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>() {
/// return Ok(ModuleField::Producer(parser.parse()?));
/// }
///
/// // .. typically we'd parse other module fields here...
///
/// Err(parser.error("unknown module field"))
/// }
/// }
/// ```
///
/// [register]: crate::parser::Parser::register_annotation
/// [section]: https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md
#[macro_export]
macro_rules! annotation {
($name:ident) => {
$crate::annotation!($name = stringify!($name));
};
($name:ident = $annotation:expr) => {
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Debug)]
pub struct $name(pub $crate::token::Span);
impl<'a> $crate::parser::Parse<'a> for $name {
fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result<Self> {
parser.step(|c| {
if let Some((a, rest)) = c.annotation() {
if a == $annotation {
return Ok(($name(c.cur_span()), rest));
}
}
Err(c.error(concat!("expected annotation `@", $annotation, "`")))
})
}
}
impl $crate::parser::Peek for $name {
fn peek(cursor: $crate::parser::Cursor<'_>) -> bool {
if let Some((a, _rest)) = cursor.annotation() {
a == $annotation
} else {
false
}
}
fn display() -> &'static str {
concat!("`@", $annotation, "`")
}
}
};
}
pub mod lexer;
pub mod parser;
pub mod token;
/// A convenience error type to tie together all the detailed errors produced by
/// this crate.
///
/// This type can be created from a [`lexer::LexError`] or [`parser::Error`].
/// This also contains storage for file/text information so a nice error can be
/// rendered along the same lines of rustc's own error messages (minus the
/// color).
///
/// This type is typically suitable for use in public APIs for consumers of this
/// crate.
#[derive(Debug)]
pub struct Error {
inner: Box<ErrorInner>,
mod encode;
mod error;
mod gensym;
mod names;
pub use self::error::*;
macro_rules! id {
($($t:tt)*) => ($($t)*)
}
#[derive(Debug)]
struct ErrorInner {
text: Option<Text>,
file: Option<PathBuf>,
span: Span,
kind: ErrorKind,
#[cfg(feature = "wasm-module")]
id! {
mod assert_expr;
mod wast;
mod wat;
pub use self::assert_expr::*;
pub use self::wast::*;
pub use self::wat::*;
// Support for core wasm parsing
pub mod core;
// Support for component model parsing
pub mod component;
}
#[derive(Debug)]
struct Text {
line: usize,
col: usize,
snippet: String,
/// Common keyword used to parse WebAssembly text files.
pub mod kw {
custom_keyword!(after);
custom_keyword!(alias);
custom_keyword!(any);
custom_keyword!(anyfunc);
custom_keyword!(anyref);
custom_keyword!(arg);
custom_keyword!(array);
custom_keyword!(assert_exception);
custom_keyword!(assert_exhaustion);
custom_keyword!(assert_invalid);
custom_keyword!(assert_malformed);
custom_keyword!(assert_return);
custom_keyword!(assert_trap);
custom_keyword!(assert_unlinkable);
custom_keyword!(before);
custom_keyword!(binary);
custom_keyword!(block);
custom_keyword!(catch);
custom_keyword!(catch_all);
custom_keyword!(code);
custom_keyword!(component);
custom_keyword!(data);
custom_keyword!(dataref);
custom_keyword!(declare);
custom_keyword!(delegate);
custom_keyword!(r#do = "do");
custom_keyword!(elem);
custom_keyword!(end);
custom_keyword!(tag);
custom_keyword!(export);
custom_keyword!(r#extern = "extern");
custom_keyword!(externref);
custom_keyword!(eq);
custom_keyword!(eqref);
custom_keyword!(f32);
custom_keyword!(f32x4);
custom_keyword!(f64);
custom_keyword!(f64x2);
custom_keyword!(field);
custom_keyword!(first);
custom_keyword!(func);
custom_keyword!(funcref);
custom_keyword!(get);
custom_keyword!(global);
custom_keyword!(i16);
custom_keyword!(i16x8);
custom_keyword!(i31);
custom_keyword!(i31ref);
custom_keyword!(i32);
custom_keyword!(i32x4);
custom_keyword!(i64);
custom_keyword!(i64x2);
custom_keyword!(i8);
custom_keyword!(i8x16);
custom_keyword!(import);
custom_keyword!(instance);
custom_keyword!(instantiate);
custom_keyword!(invoke);
custom_keyword!(item);
custom_keyword!(last);
custom_keyword!(local);
custom_keyword!(memory);
custom_keyword!(module);
custom_keyword!(modulecode);
custom_keyword!(nan_arithmetic = "nan:arithmetic");
custom_keyword!(nan_canonical = "nan:canonical");
custom_keyword!(null);
custom_keyword!(nullref);
custom_keyword!(offset);
custom_keyword!(outer);
custom_keyword!(param);
custom_keyword!(parent);
custom_keyword!(passive);
custom_keyword!(quote);
custom_keyword!(r#else = "else");
custom_keyword!(r#if = "if");
custom_keyword!(r#loop = "loop");
custom_keyword!(r#mut = "mut");
custom_keyword!(r#type = "type");
custom_keyword!(r#ref = "ref");
custom_keyword!(ref_func = "ref.func");
custom_keyword!(ref_null = "ref.null");
custom_keyword!(register);
custom_keyword!(result);
custom_keyword!(rtt);
custom_keyword!(shared);
custom_keyword!(start);
custom_keyword!(r#struct = "struct");
custom_keyword!(table);
custom_keyword!(then);
custom_keyword!(r#try = "try");
custom_keyword!(v128);
custom_keyword!(value);
custom_keyword!(s8);
custom_keyword!(s16);
custom_keyword!(s32);
custom_keyword!(s64);
custom_keyword!(u8);
custom_keyword!(u16);
custom_keyword!(u32);
custom_keyword!(u64);
custom_keyword!(char);
custom_keyword!(case);
custom_keyword!(defaults_to = "defaults-to");
custom_keyword!(record);
custom_keyword!(string);
custom_keyword!(bool_ = "bool");
custom_keyword!(float32);
custom_keyword!(float64);
custom_keyword!(variant);
custom_keyword!(unit);
custom_keyword!(flags);
custom_keyword!(option);
custom_keyword!(tuple);
custom_keyword!(list);
custom_keyword!(union);
custom_keyword!(expected);
custom_keyword!(canon_lift = "canon.lift");
custom_keyword!(canon_lower = "canon.lower");
custom_keyword!(enum_ = "enum");
custom_keyword!(string_utf8 = "string=utf8");
custom_keyword!(string_utf16 = "string=utf16");
custom_keyword!(string_latin1_utf16 = "string=latin1+utf16");
custom_keyword!(into);
custom_keyword!(with);
custom_keyword!(core);
}
#[derive(Debug)]
enum ErrorKind {
Lex(lexer::LexError),
Custom(String),
}
impl Error {
fn lex(span: Span, content: &str, kind: lexer::LexError) -> Error {
let mut ret = Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Lex(kind),
}),
};
ret.set_text(content);
return ret;
}
fn parse(span: Span, content: &str, message: String) -> Error {
let mut ret = Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Custom(message),
}),
};
ret.set_text(content);
return ret;
}
/// Creates a new error with the given `message` which is targeted at the
/// given `span`
///
/// Note that you'll want to ensure that `set_text` or `set_path` is called
/// on the resulting error to improve the rendering of the error message.
pub fn new(span: Span, message: String) -> Error {
Error {
inner: Box::new(ErrorInner {
text: None,
file: None,
span,
kind: ErrorKind::Custom(message),
}),
}
}
/// Return the `Span` for this error.
pub fn span(&self) -> Span {
self.inner.span
}
/// To provide a more useful error this function can be used to extract
/// relevant textual information about this error into the error itself.
///
/// The `contents` here should be the full text of the original file being
/// parsed, and this will extract a sub-slice as necessary to render in the
/// `Display` implementation later on.
pub fn set_text(&mut self, contents: &str) {
if self.inner.text.is_some() {
return;
}
self.inner.text = Some(Text::new(contents, self.inner.span));
}
/// To provide a more useful error this function can be used to set
/// the file name that this error is associated with.
///
/// The `path` here will be stored in this error and later rendered in the
/// `Display` implementation.
pub fn set_path(&mut self, path: &Path) {
if self.inner.file.is_some() {
return;
}
self.inner.file = Some(path.to_path_buf());
}
/// Returns the underlying `LexError`, if any, that describes this error.
pub fn lex_error(&self) -> Option<&lexer::LexError> {
match &self.inner.kind {
ErrorKind::Lex(e) => Some(e),
_ => None,
}
}
/// Returns the underlying message, if any, that describes this error.
pub fn message(&self) -> String {
match &self.inner.kind {
ErrorKind::Lex(e) => e.to_string(),
ErrorKind::Custom(e) => e.clone(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let err = match &self.inner.kind {
ErrorKind::Lex(e) => e as &dyn fmt::Display,
ErrorKind::Custom(e) => e as &dyn fmt::Display,
};
let text = match &self.inner.text {
Some(text) => text,
None => {
return write!(f, "{} at byte offset {}", err, self.inner.span.offset);
}
};
let file = self
.inner
.file
.as_ref()
.and_then(|p| p.to_str())
.unwrap_or("<anon>");
write!(
f,
"\
{err}
--> {file}:{line}:{col}
|
{line:4} | {text}
| {marker:>0$}",
text.col + 1,
file = file,
line = text.line + 1,
col = text.col + 1,
err = err,
text = text.snippet,
marker = "^",
)
}
}
impl std::error::Error for Error {}
impl Text {
fn new(content: &str, span: Span) -> Text {
let (line, col) = span.linecol_in(content);
let contents = content.lines().nth(line).unwrap_or("");
let mut snippet = String::new();
for ch in contents.chars() {
match ch {
// Replace tabs with spaces to render consistently
'\t' => {
snippet.push_str(" ");
}
// these codepoints change how text is rendered so for clarity
// in error messages they're dropped.
'\u{202a}' | '\u{202b}' | '\u{202d}' | '\u{202e}' | '\u{2066}' | '\u{2067}'
| '\u{2068}' | '\u{206c}' | '\u{2069}' => {}
c => snippet.push(c),
}
}
// Use the `unicode-width` crate to figure out how wide the snippet, up
// to our "column", actually is. That'll tell us how many spaces to
// place before the `^` character that points at the problem
let col = snippet.get(..col).map(|s| s.width()).unwrap_or(col);
Text { line, col, snippet }
}
/// Common annotations used to parse WebAssembly text files.
pub mod annotation {
annotation!(custom);
annotation!(name);
}

86
third_party/rust/wast/src/names.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,86 @@
use crate::token::{Id, Index};
use crate::Error;
use std::collections::HashMap;
#[derive(Default)]
pub struct Namespace<'a> {
names: HashMap<Id<'a>, u32>,
count: u32,
}
impl<'a> Namespace<'a> {
pub fn register(&mut self, name: Option<Id<'a>>, desc: &str) -> Result<u32, Error> {
let index = self.alloc();
if let Some(name) = name {
if let Some(_prev) = self.names.insert(name, index) {
// FIXME: temporarily allow duplicately-named data and element
// segments. This is a sort of dumb hack to get the spec test
// suite working (ironically).
//
// So as background, the text format disallows duplicate
// identifiers, causing a parse error if they're found. There
// are two tests currently upstream, however, data.wast and
// elem.wast, which *look* like they have duplicately named
// element and data segments. These tests, however, are using
// pre-bulk-memory syntax where a bare identifier was the
// table/memory being initialized. In post-bulk-memory this
// identifier is the name of the segment. Since we implement
// post-bulk-memory features that means that we're parsing the
// memory/table-to-initialize as the name of the segment.
//
// This is technically incorrect behavior but no one is
// hopefully relying on this too much. To get the spec tests
// passing we ignore errors for elem/data segments. Once the
// spec tests get updated enough we can remove this condition
// and return errors for them.
if desc != "elem" && desc != "data" {
return Err(Error::new(
name.span(),
format!("duplicate {} identifier", desc),
));
}
}
}
Ok(index)
}
pub fn alloc(&mut self) -> u32 {
let index = self.count;
self.count += 1;
return index;
}
pub fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> {
if let Some(_prev) = self.names.insert(name, index) {
return Err(Error::new(
name.span(),
format!("duplicate identifier for {}", desc),
));
}
Ok(())
}
pub fn resolve(&self, idx: &mut Index<'a>, desc: &str) -> Result<u32, Error> {
let id = match idx {
Index::Num(n, _) => return Ok(*n),
Index::Id(id) => id,
};
if let Some(&n) = self.names.get(id) {
*idx = Index::Num(n, id.span());
return Ok(n);
}
Err(resolve_error(*id, desc))
}
}
pub fn resolve_error(id: Id<'_>, ns: &str) -> Error {
assert!(
!id.is_gensym(),
"symbol generated by `wast` itself cannot be resolved {:?}",
id
);
Error::new(
id.span(),
format!("failed to find {} named `${}`", ns, id.name()),
)
}

53
third_party/rust/wast/src/parser.rs поставляемый
Просмотреть файл

@ -24,7 +24,8 @@
//! [`Parse`](crate::parser::Parse) trait:
//!
//! ```
//! use wast::{kw, Import, Func};
//! use wast::kw;
//! use wast::core::{Import, Func};
//! use wast::parser::{Parser, Parse, Result};
//!
//! // Fields of a WebAssembly which only allow imports and functions, and all
@ -64,7 +65,8 @@
//! likely also draw inspiration from the excellent examples in the `syn` crate.
use crate::lexer::{Float, Integer, Lexer, Token};
use crate::{Error, Span};
use crate::token::Span;
use crate::Error;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
@ -118,7 +120,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
/// The [`Parse`] trait is main abstraction you'll be working with when defining
/// custom parser or custom syntax for your WebAssembly text format (or when
/// using the official format items). Almost all items in the
/// [`ast`](crate::ast) module implement the [`Parse`] trait, and you'll
/// [`core`](crate::core) module implement the [`Parse`] trait, and you'll
/// commonly use this with:
///
/// * The top-level [`parse`] function to parse an entire input.
@ -139,7 +141,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
/// (import "foo" "bar" (func (type 0)))
/// ```
///
/// but the [`Import`](crate::ast::Import) type parser looks like:
/// but the [`Import`](crate::core::Import) type parser looks like:
///
/// ```
/// # use wast::kw;
@ -170,7 +172,8 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
/// before all functions. An example [`Parse`] implementation might look like:
///
/// ```
/// use wast::{Import, Func, kw};
/// use wast::core::{Import, Func};
/// use wast::kw;
/// use wast::parser::{Parser, Parse, Result};
///
/// // Fields of a WebAssembly which only allow imports and functions, and all
@ -268,7 +271,7 @@ pub trait Peek {
/// A convenience type definition for `Result` where the error is hardwired to
/// [`Error`].
pub type Result<T> = std::result::Result<T, Error>;
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// A low-level buffer of tokens which represents a completely lexed file.
///
@ -475,7 +478,7 @@ impl<'a> Parser<'a> {
/// and a [`RefType`]
///
/// ```
/// # use wast::*;
/// # use wast::core::*;
/// # use wast::parser::*;
/// struct TableType<'a> {
/// limits: Limits,
@ -493,9 +496,9 @@ impl<'a> Parser<'a> {
/// }
/// ```
///
/// [`Limits`]: crate::ast::Limits
/// [`TableType`]: crate::ast::TableType
/// [`RefType`]: crate::ast::RefType
/// [`Limits`]: crate::core::Limits
/// [`TableType`]: crate::core::TableType
/// [`RefType`]: crate::core::RefType
pub fn parse<T: Parse<'a>>(self) -> Result<T> {
T::parse(self)
}
@ -552,7 +555,7 @@ impl<'a> Parser<'a> {
/// ```
///
/// [spec]: https://webassembly.github.io/spec/core/text/types.html#limits
/// [`Limits`]: crate::ast::Limits
/// [`Limits`]: crate::core::Limits
pub fn peek<T: Peek>(self) -> bool {
T::peek(self.cursor())
}
@ -568,6 +571,17 @@ impl<'a> Parser<'a> {
}
}
/// Same as the [`Parser::peek2`] method, except checks the next next token,
/// not the next token.
pub fn peek3<T: Peek>(self) -> bool {
let mut cursor = self.cursor();
if cursor.advance_token().is_some() && cursor.advance_token().is_some() {
T::peek(cursor)
} else {
false
}
}
/// A helper structure to perform a sequence of `peek` operations and if
/// they all fail produce a nice error message.
///
@ -592,7 +606,7 @@ impl<'a> Parser<'a> {
/// parsing an [`Index`] we can do:
///
/// ```
/// # use wast::*;
/// # use wast::token::*;
/// # use wast::parser::*;
/// enum Index<'a> {
/// Num(u32),
@ -615,8 +629,8 @@ impl<'a> Parser<'a> {
/// ```
///
/// [spec]: https://webassembly.github.io/spec/core/text/modules.html#indices
/// [`Index`]: crate::ast::Index
/// [`Id`]: crate::ast::Id
/// [`Index`]: crate::token::Index
/// [`Id`]: crate::token::Id
pub fn lookahead1(self) -> Lookahead1<'a> {
Lookahead1 {
attempts: Vec::new(),
@ -646,7 +660,8 @@ impl<'a> Parser<'a> {
/// the exact definition, but it's close enough!
///
/// ```
/// # use wast::*;
/// # use wast::kw;
/// # use wast::core::*;
/// # use wast::parser::*;
/// struct Module<'a> {
/// fields: Vec<ModuleField<'a>>,
@ -708,7 +723,7 @@ impl<'a> Parser<'a> {
/// A low-level parsing method you probably won't use.
///
/// This is used to implement parsing of the most primitive types in the
/// [`ast`](crate::ast) module. You probably don't want to use this, but
/// [`core`](crate::core) module. You probably don't want to use this, but
/// probably want to use something like [`Parser::parse`] or
/// [`Parser::parens`].
pub fn step<F, T>(self, f: F) -> Result<T>
@ -793,7 +808,8 @@ impl<'a> Parser<'a> {
/// to get an idea of how this works:
///
/// ```
/// # use wast::*;
/// # use wast::kw;
/// # use wast::token::NameAnnotation;
/// # use wast::parser::*;
/// struct Module<'a> {
/// name: Option<NameAnnotation<'a>>,
@ -824,7 +840,8 @@ impl<'a> Parser<'a> {
/// registered *before* we parse the parentheses of the annotation.
///
/// ```
/// # use wast::*;
/// # use wast::{kw, annotation};
/// # use wast::core::Custom;
/// # use wast::parser::*;
/// struct Module<'a> {
/// fields: Vec<ModuleField<'a>>,

335
third_party/rust/wast/src/resolve/aliases.rs поставляемый
Просмотреть файл

@ -1,335 +0,0 @@
use crate::ast::*;
use crate::resolve::gensym;
use std::collections::{hash_map::Entry, HashMap};
pub fn run(fields: &mut Vec<ModuleField>) {
let mut cur = 0;
let mut cx = Expander::default();
// Note that insertion here is somewhat tricky. We're injecting aliases
// which will affect the index spaces for each kind of item being aliased.
// In the final binary aliases will come before all locally defined items,
// notably via the sorting in binary emission of this crate. To account for
// this index space behavior we need to ensure that aliases all appear at
// the right place in the module.
//
// The general algorithm here is that aliases discovered in the "header" of
// the module, e.g. imports/aliases/types/etc, are all inserted preceding
// the field that the alias is found within. After the header, however, the
// position of the header is recorded and all future aliases will be
// inserted at that location.
//
// This ends up meaning that aliases found in globals/functions/tables/etc
// will precede all of those definitions, being positioned at a point that
// should come after all the instances that are defined as well. Overall
// this isn't the cleanest algorithm and probably isn't the final form of
// those. It's hoped that discussion on WebAssembly/module-linking#25 might
// lead to a good solution.
let mut insertion_point = None;
while cur < fields.len() {
let field = &mut fields[cur];
match field {
ModuleField::Alias(_)
| ModuleField::Type(_)
| ModuleField::Import(_)
| ModuleField::NestedModule(_)
| ModuleField::Instance(_) => {}
_ if insertion_point.is_none() => insertion_point = Some(cur),
_ => {}
}
cx.process(field);
if insertion_point.is_none() {
for item in cx.to_prepend.drain(..) {
fields.insert(cur, item);
cur += 1;
}
}
cur += 1;
}
if let Some(mut i) = insertion_point {
for item in cx.to_prepend.drain(..) {
fields.insert(i, item);
i += 1;
}
}
assert!(cx.to_prepend.is_empty());
}
#[derive(Default)]
struct Expander<'a> {
to_prepend: Vec<ModuleField<'a>>,
instances: HashMap<(Index<'a>, &'a str, ExportKind), Index<'a>>,
parents: HashMap<(Index<'a>, Index<'a>, ExportKind), Index<'a>>,
}
impl<'a> Expander<'a> {
fn process(&mut self, field: &mut ModuleField<'a>) {
match field {
ModuleField::Alias(a) => {
let id = gensym::fill(a.span, &mut a.id);
match &mut a.source {
AliasSource::InstanceExport { instance, export } => {
self.expand(instance);
self.instances
.insert((*instance.unwrap_index(), export, a.kind), id.into());
}
AliasSource::Outer { module, index } => {
self.parents.insert((*module, *index, a.kind), id.into());
}
}
}
ModuleField::Instance(i) => {
if let InstanceKind::Inline { module, args } = &mut i.kind {
self.expand(module);
for arg in args {
self.expand(&mut arg.index);
}
}
}
ModuleField::Elem(e) => {
if let ElemKind::Active { table, offset, .. } = &mut e.kind {
self.expand(table);
self.expand_expr(offset);
}
match &mut e.payload {
ElemPayload::Indices(funcs) => {
for func in funcs {
self.expand(func);
}
}
ElemPayload::Exprs { exprs, .. } => {
for expr in exprs {
self.expand_expr(expr);
}
}
}
}
ModuleField::Data(e) => {
if let DataKind::Active { memory, offset, .. } = &mut e.kind {
self.expand(memory);
self.expand_expr(offset);
}
}
ModuleField::Export(e) => self.expand(&mut e.index),
ModuleField::Func(f) => {
self.expand_type_use(&mut f.ty);
if let FuncKind::Inline { expression, .. } = &mut f.kind {
self.expand_expr(expression);
}
}
ModuleField::Import(i) => self.expand_item_sig(&mut i.item),
ModuleField::Global(g) => {
if let GlobalKind::Inline(expr) = &mut g.kind {
self.expand_expr(expr);
}
}
ModuleField::Start(s) => self.expand(s),
ModuleField::Tag(t) => match &mut t.ty {
TagType::Exception(t) => self.expand_type_use(t),
},
ModuleField::NestedModule(m) => match &mut m.kind {
NestedModuleKind::Import { ty, .. } => self.expand_type_use(ty),
NestedModuleKind::Inline { fields } => run(fields),
},
ModuleField::Type(t) => match &mut t.def {
TypeDef::Func(f) => f.expand(self),
TypeDef::Struct(_) => {}
TypeDef::Array(_) => {}
TypeDef::Module(m) => m.expand(self),
TypeDef::Instance(i) => i.expand(self),
},
ModuleField::Custom(_) | ModuleField::Memory(_) | ModuleField::Table(_) => {}
}
}
fn expand_item_sig(&mut self, sig: &mut ItemSig<'a>) {
match &mut sig.kind {
ItemKind::Func(t) => self.expand_type_use(t),
ItemKind::Module(t) => self.expand_type_use(t),
ItemKind::Instance(t) => self.expand_type_use(t),
ItemKind::Table(_) => {}
ItemKind::Memory(_) => {}
ItemKind::Global(_) => {}
ItemKind::Tag(t) => match t {
TagType::Exception(t) => self.expand_type_use(t),
},
}
}
fn expand_type_use<T: Expand<'a>>(&mut self, ty: &mut TypeUse<'a, T>) {
if let Some(index) = &mut ty.index {
self.expand(index);
}
if let Some(inline) = &mut ty.inline {
inline.expand(self);
}
}
fn expand_expr(&mut self, expr: &mut Expression<'a>) {
for instr in expr.instrs.iter_mut() {
self.expand_instr(instr);
}
}
fn expand_instr(&mut self, instr: &mut Instruction<'a>) {
use Instruction::*;
if let Some(m) = instr.memarg_mut() {
self.expand(&mut m.memory);
}
match instr {
Call(i) | ReturnCall(i) | RefFunc(i) => self.expand(&mut i.0),
CallIndirect(i) | ReturnCallIndirect(i) => {
self.expand(&mut i.table);
self.expand_type_use(&mut i.ty);
}
TableInit(i) => self.expand(&mut i.table),
MemoryInit(i) => self.expand(&mut i.mem),
TableCopy(i) => {
self.expand(&mut i.src);
self.expand(&mut i.dst);
}
MemoryCopy(i) => {
self.expand(&mut i.src);
self.expand(&mut i.dst);
}
GlobalSet(g) | GlobalGet(g) => self.expand(&mut g.0),
TableGet(t) | TableSet(t) | TableFill(t) | TableSize(t) | TableGrow(t) => {
self.expand(&mut t.dst)
}
MemorySize(m) | MemoryGrow(m) | MemoryFill(m) => self.expand(&mut m.mem),
Let(t) => self.expand_type_use(&mut t.block.ty),
Block(bt) | If(bt) | Loop(bt) | Try(bt) => self.expand_type_use(&mut bt.ty),
FuncBind(t) => self.expand_type_use(&mut t.ty),
_ => {}
}
}
fn expand<T>(&mut self, item: &mut ItemRef<'a, T>)
where
T: Into<ExportKind> + Copy,
{
match item {
ItemRef::Outer { kind, module, idx } => {
let key = (*module, *idx, (*kind).into());
let idx = match self.parents.entry(key) {
Entry::Occupied(e) => *e.get(),
Entry::Vacant(v) => {
let span = idx.span();
let id = gensym::gen(span);
self.to_prepend.push(ModuleField::Alias(Alias {
span,
id: Some(id),
name: None,
source: AliasSource::Outer {
module: *module,
index: *idx,
},
kind: (*kind).into(),
}));
*v.insert(Index::Id(id))
}
};
*item = ItemRef::Item {
kind: *kind,
idx,
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: true,
};
}
ItemRef::Item {
kind,
idx,
exports,
#[cfg(wast_check_exhaustive)]
visited,
} => {
#[cfg(wast_check_exhaustive)]
{
*visited = true;
}
let mut cur = *idx;
let len = exports.len();
for (i, export) in exports.drain(..).enumerate() {
let kind = if i < len - 1 {
ExportKind::Instance
} else {
(*kind).into()
};
let key = (cur, export, kind);
cur = match self.instances.entry(key) {
Entry::Occupied(e) => *e.get(),
Entry::Vacant(v) => {
let span = idx.span();
let id = gensym::gen(span);
self.to_prepend.push(ModuleField::Alias(Alias {
span,
id: Some(id),
name: None,
kind,
source: AliasSource::InstanceExport {
instance: ItemRef::Item {
kind: kw::instance(span),
idx: cur,
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: true,
},
export,
},
}));
*v.insert(Index::Id(id))
}
};
}
*idx = cur;
}
}
}
}
trait Expand<'a> {
fn expand(&mut self, cx: &mut Expander<'a>);
}
impl<'a> Expand<'a> for FunctionType<'a> {
fn expand(&mut self, _cx: &mut Expander<'a>) {}
}
impl<'a> Expand<'a> for ModuleType<'a> {
fn expand(&mut self, cx: &mut Expander<'a>) {
for i in self.imports.iter_mut() {
cx.expand_item_sig(&mut i.item);
}
for e in self.exports.iter_mut() {
cx.expand_item_sig(&mut e.item);
}
}
}
impl<'a> Expand<'a> for InstanceType<'a> {
fn expand(&mut self, cx: &mut Expander<'a>) {
for e in self.exports.iter_mut() {
cx.expand_item_sig(&mut e.item);
}
}
}

Просмотреть файл

@ -1,4 +1,8 @@
use crate::ast::{annotation, kw};
//! Common tokens that implement the [`Parse`] trait which are otherwise not
//! associated specifically with the wasm text format per se (useful in other
//! contexts too perhaps).
use crate::annotation;
use crate::lexer::FloatVal;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use std::fmt;
@ -217,65 +221,19 @@ impl Hash for Index<'_> {
}
/// Parses `(func $foo)`
///
/// Optionally includes export strings for module-linking sugar syntax for alias
/// injection.
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum ItemRef<'a, K> {
Outer {
kind: K,
module: Index<'a>,
idx: Index<'a>,
},
Item {
kind: K,
idx: Index<'a>,
exports: Vec<&'a str>,
#[cfg(wast_check_exhaustive)]
visited: bool,
},
}
impl<'a, K> ItemRef<'a, K> {
/// Unwraps the underlying `Index` for `ItemRef::Item`.
///
/// Panics if this is `ItemRef::Outer` or if exports haven't been expanded
/// yet.
pub fn unwrap_index(&self) -> &Index<'a> {
match self {
ItemRef::Item { idx, exports, .. } => {
debug_assert!(exports.len() == 0);
idx
}
ItemRef::Outer { .. } => panic!("unwrap_index called on Parent"),
}
}
pub struct ItemRef<'a, K> {
pub kind: K,
pub idx: Index<'a>,
}
impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parens(|parser| {
let kind = parser.parse::<K>()?;
if parser.peek::<kw::outer>() {
parser.parse::<kw::outer>()?;
let module = parser.parse()?;
let idx = parser.parse()?;
Ok(ItemRef::Outer { kind, module, idx })
} else {
let idx = parser.parse()?;
let mut exports = Vec::new();
while !parser.is_empty() {
exports.push(parser.parse()?);
}
Ok(ItemRef::Item {
kind,
idx,
exports,
#[cfg(wast_check_exhaustive)]
visited: false,
})
}
let idx = parser.parse()?;
Ok(ItemRef { kind, idx })
})
}
}
@ -293,39 +251,6 @@ impl<'a, K: Peek> Peek for ItemRef<'a, K> {
}
}
/// Convenience structure to parse `$f` or `(item $f)`.
#[derive(Clone, Debug)]
pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>);
impl<'a, K> Parse<'a> for IndexOrRef<'a, K>
where
K: Parse<'a> + Default,
{
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<Index<'_>>() {
Ok(IndexOrRef(ItemRef::Item {
kind: K::default(),
idx: parser.parse()?,
exports: Vec::new(),
#[cfg(wast_check_exhaustive)]
visited: false,
}))
} else {
Ok(IndexOrRef(parser.parse()?))
}
}
}
impl<'a, K: Peek> Peek for IndexOrRef<'a, K> {
fn peek(cursor: Cursor<'_>) -> bool {
Index::peek(cursor) || ItemRef::<K>::peek(cursor)
}
fn display() -> &'static str {
"an item reference"
}
}
/// An `@name` annotation in source, currently of the form `@name "foo"`
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct NameAnnotation<'a> {

Просмотреть файл

@ -1,6 +1,8 @@
use crate::ast::{self, kw};
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::{AssertExpression, NanPattern, V128Pattern};
use crate::core::Expression;
use crate::kw;
use crate::parser::{self, Cursor, Parse, ParseBuffer, Parser, Peek, Result};
use crate::token::{Id, Span};
use crate::{AssertExpression, Error, Wat};
/// A parsed representation of a `*.wast` file.
///
@ -24,8 +26,8 @@ impl<'a> Parse<'a> for Wast<'a> {
directives.push(parser.parens(|p| p.parse())?);
}
} else {
let module = parser.parse::<ast::Wat>()?.module;
directives.push(WastDirective::Module(module));
let module = parser.parse::<Wat>()?;
directives.push(WastDirective::Wat(QuoteWat::Wat(module)));
}
Ok(Wast { directives })
}
@ -39,7 +41,11 @@ impl Peek for WastDirectiveToken {
Some((kw, _)) => kw,
None => return false,
};
kw.starts_with("assert_") || kw == "module" || kw == "register" || kw == "invoke"
kw.starts_with("assert_")
|| kw == "module"
|| kw == "component"
|| kw == "register"
|| kw == "invoke"
}
fn display() -> &'static str {
@ -54,61 +60,59 @@ impl Peek for WastDirectiveToken {
#[allow(missing_docs)]
#[derive(Debug)]
pub enum WastDirective<'a> {
Module(ast::Module<'a>),
QuoteModule {
span: ast::Span,
source: Vec<&'a [u8]>,
},
Wat(QuoteWat<'a>),
AssertMalformed {
span: ast::Span,
module: QuoteModule<'a>,
span: Span,
module: QuoteWat<'a>,
message: &'a str,
},
AssertInvalid {
span: ast::Span,
module: QuoteModule<'a>,
span: Span,
module: QuoteWat<'a>,
message: &'a str,
},
Register {
span: ast::Span,
span: Span,
name: &'a str,
module: Option<ast::Id<'a>>,
module: Option<Id<'a>>,
},
Invoke(WastInvoke<'a>),
AssertTrap {
span: ast::Span,
span: Span,
exec: WastExecute<'a>,
message: &'a str,
},
AssertReturn {
span: ast::Span,
span: Span,
exec: WastExecute<'a>,
results: Vec<ast::AssertExpression<'a>>,
results: Vec<AssertExpression<'a>>,
},
AssertExhaustion {
span: ast::Span,
span: Span,
call: WastInvoke<'a>,
message: &'a str,
},
AssertUnlinkable {
span: ast::Span,
module: ast::Module<'a>,
span: Span,
module: Wat<'a>,
message: &'a str,
},
AssertException {
span: ast::Span,
span: Span,
exec: WastExecute<'a>,
},
}
impl WastDirective<'_> {
/// Returns the location in the source that this directive was defined at
pub fn span(&self) -> ast::Span {
pub fn span(&self) -> Span {
match self {
WastDirective::Module(m) => m.span,
WastDirective::Wat(QuoteWat::Wat(Wat::Module(m))) => m.span,
WastDirective::Wat(QuoteWat::Wat(Wat::Component(c))) => c.span,
WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span,
WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span,
WastDirective::AssertMalformed { span, .. }
| WastDirective::Register { span, .. }
| WastDirective::QuoteModule { span, .. }
| WastDirective::AssertTrap { span, .. }
| WastDirective::AssertReturn { span, .. }
| WastDirective::AssertExhaustion { span, .. }
@ -123,18 +127,8 @@ impl WastDirective<'_> {
impl<'a> Parse<'a> for WastDirective<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::module>() {
if parser.peek2::<kw::quote>() {
parser.parse::<kw::module>()?;
let span = parser.parse::<kw::quote>()?.0;
let mut source = Vec::new();
while !parser.is_empty() {
source.push(parser.parse()?);
}
Ok(WastDirective::QuoteModule { span, source })
} else {
Ok(WastDirective::Module(parser.parse()?))
}
if l.peek::<kw::module>() || l.peek::<kw::component>() {
Ok(WastDirective::Wat(parser.parse()?))
} else if l.peek::<kw::assert_malformed>() {
let span = parser.parse::<kw::assert_malformed>()?.0;
Ok(WastDirective::AssertMalformed {
@ -177,69 +171,6 @@ impl<'a> Parse<'a> for WastDirective<'a> {
exec,
results,
})
} else if l.peek::<kw::assert_return_canonical_nan>() {
let span = parser.parse::<kw::assert_return_canonical_nan>()?.0;
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::LegacyCanonicalNaN],
})
} else if l.peek::<kw::assert_return_canonical_nan_f32x4>() {
let span = parser.parse::<kw::assert_return_canonical_nan_f32x4>()?.0;
let pat = V128Pattern::F32x4([
NanPattern::CanonicalNan,
NanPattern::CanonicalNan,
NanPattern::CanonicalNan,
NanPattern::CanonicalNan,
]);
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::V128(pat)],
})
} else if l.peek::<kw::assert_return_canonical_nan_f64x2>() {
let span = parser.parse::<kw::assert_return_canonical_nan_f64x2>()?.0;
let pat = V128Pattern::F64x2([NanPattern::CanonicalNan, NanPattern::CanonicalNan]);
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::V128(pat)],
})
} else if l.peek::<kw::assert_return_arithmetic_nan>() {
let span = parser.parse::<kw::assert_return_arithmetic_nan>()?.0;
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::LegacyArithmeticNaN],
})
} else if l.peek::<kw::assert_return_arithmetic_nan_f32x4>() {
let span = parser.parse::<kw::assert_return_arithmetic_nan_f32x4>()?.0;
let pat = V128Pattern::F32x4([
NanPattern::ArithmeticNan,
NanPattern::ArithmeticNan,
NanPattern::ArithmeticNan,
NanPattern::ArithmeticNan,
]);
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::V128(pat)],
})
} else if l.peek::<kw::assert_return_arithmetic_nan_f64x2>() {
let span = parser.parse::<kw::assert_return_arithmetic_nan_f64x2>()?.0;
let pat = V128Pattern::F64x2([NanPattern::ArithmeticNan, NanPattern::ArithmeticNan]);
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::V128(pat)],
})
} else if l.peek::<kw::assert_return_func>() {
let span = parser.parse::<kw::assert_return_func>()?.0;
Ok(WastDirective::AssertReturn {
span,
exec: parser.parens(|p| p.parse())?,
results: vec![AssertExpression::RefFunc(None)],
})
} else if l.peek::<kw::assert_exhaustion>() {
let span = parser.parse::<kw::assert_exhaustion>()?.0;
Ok(WastDirective::AssertExhaustion {
@ -251,7 +182,7 @@ impl<'a> Parse<'a> for WastDirective<'a> {
let span = parser.parse::<kw::assert_unlinkable>()?.0;
Ok(WastDirective::AssertUnlinkable {
span,
module: parser.parens(|p| p.parse())?,
module: parser.parens(parse_wat)?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_exception>() {
@ -270,9 +201,9 @@ impl<'a> Parse<'a> for WastDirective<'a> {
#[derive(Debug)]
pub enum WastExecute<'a> {
Invoke(WastInvoke<'a>),
Module(ast::Module<'a>),
Wat(Wat<'a>),
Get {
module: Option<ast::Id<'a>>,
module: Option<Id<'a>>,
global: &'a str,
},
}
@ -282,8 +213,8 @@ impl<'a> Parse<'a> for WastExecute<'a> {
let mut l = parser.lookahead1();
if l.peek::<kw::invoke>() {
Ok(WastExecute::Invoke(parser.parse()?))
} else if l.peek::<kw::module>() {
Ok(WastExecute::Module(parser.parse()?))
} else if l.peek::<kw::module>() || l.peek::<kw::component>() {
Ok(WastExecute::Wat(parse_wat(parser)?))
} else if l.peek::<kw::get>() {
parser.parse::<kw::get>()?;
Ok(WastExecute::Get {
@ -296,13 +227,27 @@ impl<'a> Parse<'a> for WastExecute<'a> {
}
}
fn parse_wat<'a>(parser: Parser<'a>) -> Result<Wat<'a>> {
// Note that this doesn't use `Parse for Wat` since the `parser` provided
// has already peeled back the first layer of parentheses while `Parse for
// Wat` expects to be the top layer which means it also tries to peel off
// the parens. Instead we can skip the sugar that `Wat` has for simply a
// list of fields (no `(module ...)` container) and just parse the `Module`
// itself.
if parser.peek::<kw::component>() {
Ok(Wat::Component(parser.parse()?))
} else {
Ok(Wat::Module(parser.parse()?))
}
}
#[allow(missing_docs)]
#[derive(Debug)]
pub struct WastInvoke<'a> {
pub span: ast::Span,
pub module: Option<ast::Id<'a>>,
pub span: Span,
pub module: Option<Id<'a>>,
pub name: &'a str,
pub args: Vec<ast::Expression<'a>>,
pub args: Vec<Expression<'a>>,
}
impl<'a> Parse<'a> for WastInvoke<'a> {
@ -325,60 +270,61 @@ impl<'a> Parse<'a> for WastInvoke<'a> {
#[allow(missing_docs)]
#[derive(Debug)]
pub enum QuoteModule<'a> {
Module(ast::Module<'a>),
Quote(Vec<&'a [u8]>),
pub enum QuoteWat<'a> {
Wat(Wat<'a>),
QuoteModule(Span, Vec<(Span, &'a [u8])>),
QuoteComponent(Span, Vec<(Span, &'a [u8])>),
}
impl<'a> Parse<'a> for QuoteModule<'a> {
impl QuoteWat<'_> {
/// Encodes this module to bytes, either by encoding the module directly or
/// parsing the contents and then encoding it.
pub fn encode(&mut self) -> Result<Vec<u8>, Error> {
let (source, prefix) = match self {
QuoteWat::Wat(m) => return m.encode(),
QuoteWat::QuoteModule(_, source) => (source, None),
QuoteWat::QuoteComponent(_, source) => (source, Some("(component")),
};
let mut ret = String::new();
for (span, src) in source {
match std::str::from_utf8(src) {
Ok(s) => ret.push_str(s),
Err(_) => {
return Err(Error::new(*span, "malformed UTF-8 encoding".to_string()));
}
}
ret.push_str(" ");
}
if let Some(prefix) = prefix {
ret.insert_str(0, prefix);
ret.push_str(")");
}
let buf = ParseBuffer::new(&ret)?;
let mut wat = parser::parse::<Wat<'_>>(&buf)?;
wat.encode()
}
}
impl<'a> Parse<'a> for QuoteWat<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek2::<kw::quote>() {
parser.parse::<kw::module>()?;
parser.parse::<kw::quote>()?;
let ctor = if parser.peek::<kw::component>() {
parser.parse::<kw::component>()?;
QuoteWat::QuoteComponent
} else {
parser.parse::<kw::module>()?;
QuoteWat::QuoteModule
};
let span = parser.parse::<kw::quote>()?.0;
let mut src = Vec::new();
while !parser.is_empty() {
src.push(parser.parse()?);
let span = parser.cur_span();
let string = parser.parse()?;
src.push((span, string));
}
Ok(QuoteModule::Quote(src))
Ok(ctor(span, src))
} else {
Ok(QuoteModule::Module(parser.parse()?))
Ok(QuoteWat::Wat(parse_wat(parser)?))
}
}
}
#[cfg(test)]
mod tests {
use crate::ast::wast::WastDirective;
use crate::parser::{parse, ParseBuffer};
macro_rules! assert_parses_to_directive {
($text:expr, $pattern:pat) => {{
let buffer = ParseBuffer::new($text).unwrap();
let directive: WastDirective = parse(&buffer).unwrap();
if let $pattern = directive {
} else {
panic!("assertion failed")
}
}};
}
#[test]
fn assert_nan() {
assert_parses_to_directive!(
"assert_return_canonical_nan_f32x4 (invoke \"foo\" (f32.const 0))",
WastDirective::AssertReturn { .. }
);
assert_parses_to_directive!(
"assert_return_canonical_nan_f64x2 (invoke \"foo\" (f32.const 0))",
WastDirective::AssertReturn { .. }
);
assert_parses_to_directive!(
"assert_return_arithmetic_nan_f32x4 (invoke \"foo\" (f32.const 0))",
WastDirective::AssertReturn { .. }
);
assert_parses_to_directive!(
"assert_return_arithmetic_nan_f64x2 (invoke \"foo\" (f32.const 0))",
WastDirective::AssertReturn { .. }
);
}
}

60
third_party/rust/wast/src/wat.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,60 @@
use crate::component::Component;
use crate::core::{Module, ModuleField, ModuleKind};
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::Span;
/// A `*.wat` file parser, or a parser for one parenthesized module.
///
/// This is the top-level type which you'll frequently parse when working with
/// this crate. A `*.wat` file is either one `module` s-expression or a sequence
/// of s-expressions that are module fields.
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Wat<'a> {
Module(Module<'a>),
Component(Component<'a>),
}
impl Wat<'_> {
fn validate(&self, parser: Parser<'_>) -> Result<()> {
match self {
Wat::Module(m) => m.validate(parser),
Wat::Component(c) => c.validate(parser),
}
}
/// Encodes this `Wat` to binary form. This calls either [`Module::encode`]
/// or [`Component::encode`].
pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> {
match self {
Wat::Module(m) => m.encode(),
Wat::Component(c) => c.encode(),
}
}
}
impl<'a> Parse<'a> for Wat<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if !parser.has_meaningful_tokens() {
return Err(parser.error("expected at least one module field"));
}
let _r = parser.register_annotation("custom");
let wat = if parser.peek2::<kw::module>() {
Wat::Module(parser.parens(|parser| parser.parse())?)
} else if parser.peek2::<kw::component>() {
Wat::Component(parser.parens(|parser| parser.parse())?)
} else {
let fields = ModuleField::parse_remaining(parser)?;
Wat::Module(Module {
span: Span { offset: 0 },
id: None,
name: None,
kind: ModuleKind::Text(fields),
})
};
wat.validate(parser)?;
Ok(wat)
}
}

82
third_party/rust/wast/tests/annotations.rs поставляемый
Просмотреть файл

@ -95,14 +95,10 @@ fn assert_local_name(name: &str, wat: &str) -> anyhow::Result<()> {
fn get_name_section(wasm: &[u8]) -> anyhow::Result<NameSectionReader<'_>> {
for payload in Parser::new(0).parse_all(&wasm) {
if let Payload::CustomSection {
name: "name",
data,
data_offset,
range: _,
} = payload?
{
return Ok(NameSectionReader::new(data, data_offset)?);
if let Payload::CustomSection(c) = payload? {
if c.name() == "name" {
return Ok(NameSectionReader::new(c.data(), c.data_offset())?);
}
}
}
panic!("no name section found");
@ -110,7 +106,7 @@ fn get_name_section(wasm: &[u8]) -> anyhow::Result<NameSectionReader<'_>> {
#[test]
fn custom_section_order() -> anyhow::Result<()> {
let wasm = wat::parse_str(
let bytes = wat::parse_str(
r#"
(module
(@custom "A" "aaa")
@ -131,33 +127,71 @@ fn custom_section_order() -> anyhow::Result<()> {
"#,
)?;
macro_rules! assert_matches {
($a:expr, $b:pat $(,)?) => {
($a:expr, $b:pat $(if $cond:expr)? $(,)?) => {
match &$a {
$b => {}
$b $(if $cond)? => {}
a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)),
}
};
}
let wasm = Parser::new(0)
.parse_all(&wasm)
.parse_all(&bytes)
.collect::<Result<Vec<_>>>()?;
assert_matches!(wasm[0], Payload::Version { .. });
assert_matches!(wasm[1], Payload::CustomSection { name: "K", .. });
assert_matches!(wasm[2], Payload::CustomSection { name: "F", .. });
assert_matches!(
wasm[1],
Payload::CustomSection(c) if c.name() == "K"
);
assert_matches!(
wasm[2],
Payload::CustomSection(c) if c.name() == "F"
);
assert_matches!(wasm[3], Payload::TypeSection(_));
assert_matches!(wasm[4], Payload::CustomSection { name: "E", .. });
assert_matches!(wasm[5], Payload::CustomSection { name: "C", .. });
assert_matches!(wasm[6], Payload::CustomSection { name: "J", .. });
assert_matches!(
wasm[4],
Payload::CustomSection(c) if c.name() == "E"
);
assert_matches!(
wasm[5],
Payload::CustomSection(c) if c.name() == "C"
);
assert_matches!(
wasm[6],
Payload::CustomSection(c) if c.name() == "J"
);
assert_matches!(wasm[7], Payload::FunctionSection(_));
assert_matches!(wasm[8], Payload::CustomSection { name: "B", .. });
assert_matches!(wasm[9], Payload::CustomSection { name: "I", .. });
assert_matches!(
wasm[8],
Payload::CustomSection(c) if c.name() == "B"
);
assert_matches!(
wasm[9],
Payload::CustomSection(c) if c.name() == "I"
);
assert_matches!(wasm[10], Payload::TableSection(_));
assert_matches!(wasm[11], Payload::CodeSectionStart { .. });
assert_matches!(wasm[12], Payload::CodeSectionEntry { .. });
assert_matches!(wasm[13], Payload::CustomSection { name: "H", .. });
assert_matches!(wasm[14], Payload::CustomSection { name: "G", .. });
assert_matches!(wasm[15], Payload::CustomSection { name: "A", .. });
assert_matches!(wasm[16], Payload::CustomSection { name: "D", .. });
assert_matches!(wasm[17], Payload::End);
assert_matches!(
wasm[13],
Payload::CustomSection(c) if c.name() == "H"
);
assert_matches!(
wasm[14],
Payload::CustomSection(c) if c.name() == "G"
);
assert_matches!(
wasm[15],
Payload::CustomSection(c) if c.name() == "A"
);
assert_matches!(
wasm[16],
Payload::CustomSection(c) if c.name() == "D"
);
match &wasm[17] {
Payload::End(x) if *x == bytes.len() => {}
p => panic!("`{:?}` doesn't match expected length of {}", p, bytes.len()),
}
Ok(())
}

4
third_party/rust/wast/tests/comments.rs поставляемый
Просмотреть файл

@ -49,7 +49,7 @@ fn parse_comments() -> anyhow::Result<()> {
"#,
)?;
let d: Documented<wast::Module> = parser::parse(&buf)?;
let d: Documented<wast::core::Module> = parser::parse(&buf)?;
assert_eq!(d.comments.comments, vec![" hello", " again "]);
drop(d.item);
@ -66,7 +66,7 @@ multiple;)
"#,
)?;
let d: Documented<wast::Func> = parser::parse(&buf)?;
let d: Documented<wast::core::Func> = parser::parse(&buf)?;
assert_eq!(
d.comments.comments,
vec![" this", " is\non\nmultiple", " lines"]

2
third_party/rust/wat/.cargo-checksum.json поставляемый
Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"dec2dec4738c8ff5e0176744a1e16619ee371a8a1616e055eab15cd97ad26e83","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"86861dc59a785c0eb143e1798668e29076e25f69d7e802b5425054862c635be3","src/lib.rs":"b272ee59a5a1b713625cdf4443e5055d888966b9ec78014e01087895e9fc09bc"},"package":"ab98ed25494f97c69f28758617f27c3e92e5336040b5c3a14634f2dd3fe61830"}
{"files":{"Cargo.toml":"2faa554ccc82ab2ffb485ac05f9738f3c6675e0b051f4b8ec3e92883fbd21f64","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"86861dc59a785c0eb143e1798668e29076e25f69d7e802b5425054862c635be3","src/lib.rs":"806f68f35b3c309b7dbdb24f14da254a9f7f5b14eef3b8015c95c3e9753e3bb0"},"package":"48b3b9b3e39e66c7fd3f8be785e74444d216260f491e93369e317ed6482ff80f"}

12
third_party/rust/wat/Cargo.toml поставляемый
Просмотреть файл

@ -10,15 +10,19 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
edition = "2021"
name = "wat"
version = "1.0.41"
version = "1.0.43"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
description = "Rust parser for the WebAssembly Text format, WAT\n"
description = """
Rust parser for the WebAssembly Text format, WAT
"""
homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat"
documentation = "https://docs.rs/wat"
readme = "README.md"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat"
resolver = "2"
[dependencies.wast]
version = "39.0.0"
version = "41.0.0"

2
third_party/rust/wat/src/lib.rs поставляемый
Просмотреть файл

@ -218,7 +218,7 @@ pub fn parse_str(wat: impl AsRef<str>) -> Result<Vec<u8>> {
fn _parse_str(wat: &str) -> Result<Vec<u8>> {
let buf = ParseBuffer::new(&wat).map_err(|e| Error::cvt(e, wat))?;
let mut ast = parser::parse::<wast::Wat>(&buf).map_err(|e| Error::cvt(e, wat))?;
Ok(ast.module.encode().map_err(|e| Error::cvt(e, wat))?)
Ok(ast.encode().map_err(|e| Error::cvt(e, wat))?)
}
/// A convenience type definition for `Result` where the error is [`Error`]