summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wast/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wast/src/lib.rs')
-rw-r--r--third_party/rust/wast/src/lib.rs518
1 files changed, 518 insertions, 0 deletions
diff --git a/third_party/rust/wast/src/lib.rs b/third_party/rust/wast/src/lib.rs
new file mode 100644
index 0000000000..d5d04c07e4
--- /dev/null
+++ b/third_party/rust/wast/src/lib.rs
@@ -0,0 +1,518 @@
+//! A crate for low-level parsing of the WebAssembly text formats: WAT and WAST.
+//!
+//! This crate is intended to be a low-level detail of the `wat` crate,
+//! providing a low-level parsing API for parsing WebAssembly text format
+//! structures. The API provided by this crate is very similar to
+//! [`syn`](https://docs.rs/syn) and provides the ability to write customized
+//! parsers which may be an extension to the core WebAssembly text format. For
+//! more documentation see the [`parser`] module.
+//!
+//! # High-level Overview
+//!
+//! This crate provides a few major pieces of functionality
+//!
+//! * [`lexer`] - this is a raw lexer for the wasm text format. This is not
+//! customizable, but if you'd like to iterate over raw tokens this is the
+//! module for you. You likely won't use this much.
+//!
+//! * [`parser`] - this is the workhorse of this crate. The [`parser`] module
+//! provides the [`Parse`][] trait primarily and utilities
+//! around working with a [`Parser`](`parser::Parser`) to parse streams of
+//! tokens.
+//!
+//! * [`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
+//!
+//! This crate provides support for many in-progress WebAssembly features such
+//! as reference types, multi-value, etc. Be sure to check out the documentation
+//! of the [`wast` crate](https://docs.rs/wast) for policy information on crate
+//! stability vs WebAssembly Features. The tl;dr; version is that this crate
+//! will issue semver-non-breaking releases which will break the parsing of the
+//! text format. This crate, unlike `wast`, is expected to have numerous Rust
+//! public API changes, all of which will be accompanied with a semver-breaking
+//! release.
+//!
+//! # Compile-time Cargo features
+//!
+//! This crate has a `wasm-module` feature which is turned on by default which
+//! includes all necessary support to parse full WebAssembly modules. If you
+//! don't need this (for example you're parsing your own s-expression format)
+//! then this feature can be disabled.
+//!
+//! [`Parse`]: parser::Parse
+//! [`LexError`]: lexer::LexError
+
+#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
+
+/// 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);
+
+ 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::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;
+
+mod encode;
+mod error;
+mod gensym;
+mod names;
+pub use self::error::*;
+
+macro_rules! id {
+ ($($t:tt)*) => ($($t)*)
+}
+
+#[cfg(feature = "wasm-module")]
+id! {
+ mod wast;
+ mod wat;
+ pub use self::wast::*;
+ pub use self::wat::*;
+
+ // Support for core wasm parsing
+ pub mod core;
+
+ // Support for component model parsing
+ pub mod component;
+}
+
+/// 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!(arrayref);
+ 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!(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!(nofunc);
+ custom_keyword!(noextern);
+ custom_keyword!(none);
+ custom_keyword!(null);
+ custom_keyword!(nullfuncref);
+ custom_keyword!(nullexternref);
+ 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!(rec);
+ custom_keyword!(result);
+ custom_keyword!(shared);
+ custom_keyword!(start);
+ custom_keyword!(sub);
+ 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!(refines);
+ custom_keyword!(record);
+ custom_keyword!(string);
+ custom_keyword!(bool_ = "bool");
+ custom_keyword!(float32);
+ custom_keyword!(float64);
+ custom_keyword!(variant);
+ custom_keyword!(flags);
+ custom_keyword!(option);
+ custom_keyword!(tuple);
+ custom_keyword!(list);
+ custom_keyword!(error);
+ custom_keyword!(union);
+ custom_keyword!(canon);
+ custom_keyword!(lift);
+ custom_keyword!(lower);
+ custom_keyword!(enum_ = "enum");
+ custom_keyword!(string_utf8 = "string-encoding=utf8");
+ custom_keyword!(string_utf16 = "string-encoding=utf16");
+ custom_keyword!(string_latin1_utf16 = "string-encoding=latin1+utf16");
+ custom_keyword!(r#struct = "struct");
+ custom_keyword!(structref);
+ custom_keyword!(realloc);
+ custom_keyword!(post_return = "post-return");
+ custom_keyword!(with);
+ custom_keyword!(core);
+ custom_keyword!(true_ = "true");
+ custom_keyword!(false_ = "false");
+}
+
+/// Common annotations used to parse WebAssembly text files.
+pub mod annotation {
+ annotation!(custom);
+ annotation!(name);
+}