summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wast/src/component/wast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wast/src/component/wast.rs')
-rw-r--r--third_party/rust/wast/src/component/wast.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/third_party/rust/wast/src/component/wast.rs b/third_party/rust/wast/src/component/wast.rs
new file mode 100644
index 0000000000..8409a6c969
--- /dev/null
+++ b/third_party/rust/wast/src/component/wast.rs
@@ -0,0 +1,166 @@
+use crate::kw;
+use crate::parser::{Cursor, Parse, Parser, Peek, Result};
+use crate::token::{Float32, Float64};
+
+/// Expression that can be used inside of `invoke` expressions for core wasm
+/// functions.
+#[derive(Debug)]
+#[allow(missing_docs)]
+pub enum WastVal<'a> {
+ Bool(bool),
+ U8(u8),
+ S8(i8),
+ U16(u16),
+ S16(i16),
+ U32(u32),
+ S32(i32),
+ U64(u64),
+ S64(i64),
+ Float32(Float32),
+ Float64(Float64),
+ Char(char),
+ String(&'a str),
+ List(Vec<WastVal<'a>>),
+ Record(Vec<(&'a str, WastVal<'a>)>),
+ Tuple(Vec<WastVal<'a>>),
+ Variant(&'a str, Option<Box<WastVal<'a>>>),
+ Enum(&'a str),
+ Union(u32, Box<WastVal<'a>>),
+ Option(Option<Box<WastVal<'a>>>),
+ Result(Result<Option<Box<WastVal<'a>>>, Option<Box<WastVal<'a>>>>),
+ Flags(Vec<&'a str>),
+}
+
+static CASES: &[(&str, fn(Parser<'_>) -> Result<WastVal<'_>>)] = {
+ use WastVal::*;
+ &[
+ ("bool.const", |p| {
+ let mut l = p.lookahead1();
+ if l.peek::<kw::true_>() {
+ p.parse::<kw::true_>()?;
+ Ok(Bool(true))
+ } else if l.peek::<kw::false_>() {
+ p.parse::<kw::false_>()?;
+ Ok(Bool(false))
+ } else {
+ Err(l.error())
+ }
+ }),
+ ("u8.const", |p| Ok(U8(p.parse()?))),
+ ("s8.const", |p| Ok(S8(p.parse()?))),
+ ("u16.const", |p| Ok(U16(p.parse()?))),
+ ("s16.const", |p| Ok(S16(p.parse()?))),
+ ("u32.const", |p| Ok(U32(p.parse()?))),
+ ("s32.const", |p| Ok(S32(p.parse()?))),
+ ("u64.const", |p| Ok(U64(p.parse()?))),
+ ("s64.const", |p| Ok(S64(p.parse()?))),
+ ("f32.const", |p| Ok(Float32(p.parse()?))),
+ ("f64.const", |p| Ok(Float64(p.parse()?))),
+ ("char.const", |p| {
+ let s = p.parse::<&str>()?;
+ let mut ch = s.chars();
+ let ret = match ch.next() {
+ Some(c) => c,
+ None => return Err(p.error("empty string")),
+ };
+ if ch.next().is_some() {
+ return Err(p.error("more than one character"));
+ }
+ Ok(Char(ret))
+ }),
+ ("str.const", |p| Ok(String(p.parse()?))),
+ ("list.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| p.parse())?);
+ }
+ Ok(List(ret))
+ }),
+ ("record.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| {
+ p.parse::<kw::field>()?;
+ Ok((p.parse()?, p.parse()?))
+ })?);
+ }
+ Ok(Record(ret))
+ }),
+ ("tuple.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| p.parse())?);
+ }
+ Ok(Tuple(ret))
+ }),
+ ("variant.const", |p| {
+ let name = p.parse()?;
+ let payload = if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ };
+ Ok(Variant(name, payload))
+ }),
+ ("enum.const", |p| Ok(Enum(p.parse()?))),
+ ("union.const", |p| {
+ let num = p.parse()?;
+ let payload = Box::new(p.parens(|p| p.parse())?);
+ Ok(Union(num, payload))
+ }),
+ ("option.none", |_| Ok(Option(None))),
+ ("option.some", |p| {
+ Ok(Option(Some(Box::new(p.parens(|p| p.parse())?))))
+ }),
+ ("result.ok", |p| {
+ Ok(Result(Ok(if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ })))
+ }),
+ ("result.err", |p| {
+ Ok(Result(Err(if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ })))
+ }),
+ ("flags.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parse()?);
+ }
+ Ok(Flags(ret))
+ }),
+ ]
+};
+
+impl<'a> Parse<'a> for WastVal<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ let parse = parser.step(|c| {
+ if let Some((kw, rest)) = c.keyword() {
+ if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) {
+ return Ok((CASES[i].1, rest));
+ }
+ }
+ Err(c.error("expected a [type].const expression"))
+ })?;
+ parse(parser)
+ }
+}
+
+impl Peek for WastVal<'_> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ let kw = match cursor.keyword() {
+ Some((kw, _)) => kw,
+ None => return false,
+ };
+ CASES.iter().any(|(name, _)| *name == kw)
+ }
+
+ fn display() -> &'static str {
+ "core wasm argument"
+ }
+}