wast/component/
wast.rs

1use crate::kw;
2use crate::parser::{Cursor, Parse, Parser, Peek, Result};
3use crate::token::{F32, F64};
4
5/// Expression that can be used inside of `invoke` expressions for core wasm
6/// functions.
7#[derive(Debug)]
8#[allow(missing_docs)]
9pub enum WastVal<'a> {
10    Bool(bool),
11    U8(u8),
12    S8(i8),
13    U16(u16),
14    S16(i16),
15    U32(u32),
16    S32(i32),
17    U64(u64),
18    S64(i64),
19    F32(F32),
20    F64(F64),
21    Char(char),
22    String(&'a str),
23    List(Vec<WastVal<'a>>),
24    Record(Vec<(&'a str, WastVal<'a>)>),
25    Tuple(Vec<WastVal<'a>>),
26    Variant(&'a str, Option<Box<WastVal<'a>>>),
27    Enum(&'a str),
28    Option(Option<Box<WastVal<'a>>>),
29    Result(Result<Option<Box<WastVal<'a>>>, Option<Box<WastVal<'a>>>>),
30    Flags(Vec<&'a str>),
31}
32
33static CASES: &[(&str, fn(Parser<'_>) -> Result<WastVal<'_>>)] = {
34    use WastVal::*;
35    &[
36        ("bool.const", |p| {
37            let mut l = p.lookahead1();
38            if l.peek::<kw::true_>()? {
39                p.parse::<kw::true_>()?;
40                Ok(Bool(true))
41            } else if l.peek::<kw::false_>()? {
42                p.parse::<kw::false_>()?;
43                Ok(Bool(false))
44            } else {
45                Err(l.error())
46            }
47        }),
48        ("u8.const", |p| Ok(U8(p.parse()?))),
49        ("s8.const", |p| Ok(S8(p.parse()?))),
50        ("u16.const", |p| Ok(U16(p.parse()?))),
51        ("s16.const", |p| Ok(S16(p.parse()?))),
52        ("u32.const", |p| Ok(U32(p.parse()?))),
53        ("s32.const", |p| Ok(S32(p.parse()?))),
54        ("u64.const", |p| Ok(U64(p.parse()?))),
55        ("s64.const", |p| Ok(S64(p.parse()?))),
56        ("f32.const", |p| Ok(F32(p.parse()?))),
57        ("f64.const", |p| Ok(F64(p.parse()?))),
58        ("char.const", |p| {
59            let s = p.parse::<&str>()?;
60            let mut ch = s.chars();
61            let ret = match ch.next() {
62                Some(c) => c,
63                None => return Err(p.error("empty string")),
64            };
65            if ch.next().is_some() {
66                return Err(p.error("more than one character"));
67            }
68            Ok(Char(ret))
69        }),
70        ("str.const", |p| Ok(String(p.parse()?))),
71        ("list.const", |p| {
72            let mut ret = Vec::new();
73            while !p.is_empty() {
74                ret.push(p.parens(|p| p.parse())?);
75            }
76            Ok(List(ret))
77        }),
78        ("record.const", |p| {
79            let mut ret = Vec::new();
80            while !p.is_empty() {
81                ret.push(p.parens(|p| {
82                    p.parse::<kw::field>()?;
83                    Ok((p.parse()?, p.parse()?))
84                })?);
85            }
86            Ok(Record(ret))
87        }),
88        ("tuple.const", |p| {
89            let mut ret = Vec::new();
90            while !p.is_empty() {
91                ret.push(p.parens(|p| p.parse())?);
92            }
93            Ok(Tuple(ret))
94        }),
95        ("variant.const", |p| {
96            let name = p.parse()?;
97            let payload = if p.is_empty() {
98                None
99            } else {
100                Some(Box::new(p.parens(|p| p.parse())?))
101            };
102            Ok(Variant(name, payload))
103        }),
104        ("enum.const", |p| Ok(Enum(p.parse()?))),
105        ("option.none", |_| Ok(Option(None))),
106        ("option.some", |p| {
107            Ok(Option(Some(Box::new(p.parens(|p| p.parse())?))))
108        }),
109        ("result.ok", |p| {
110            Ok(Result(Ok(if p.is_empty() {
111                None
112            } else {
113                Some(Box::new(p.parens(|p| p.parse())?))
114            })))
115        }),
116        ("result.err", |p| {
117            Ok(Result(Err(if p.is_empty() {
118                None
119            } else {
120                Some(Box::new(p.parens(|p| p.parse())?))
121            })))
122        }),
123        ("flags.const", |p| {
124            let mut ret = Vec::new();
125            while !p.is_empty() {
126                ret.push(p.parse()?);
127            }
128            Ok(Flags(ret))
129        }),
130    ]
131};
132
133impl<'a> Parse<'a> for WastVal<'a> {
134    fn parse(parser: Parser<'a>) -> Result<Self> {
135        parser.depth_check()?;
136        let parse = parser.step(|c| {
137            if let Some((kw, rest)) = c.keyword()? {
138                if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) {
139                    return Ok((CASES[i].1, rest));
140                }
141            }
142            Err(c.error("expected a [type].const expression"))
143        })?;
144        parse(parser)
145    }
146}
147
148impl Peek for WastVal<'_> {
149    fn peek(cursor: Cursor<'_>) -> Result<bool> {
150        let kw = match cursor.keyword()? {
151            Some((kw, _)) => kw,
152            None => return Ok(false),
153        };
154        Ok(CASES.iter().any(|(name, _)| *name == kw))
155    }
156
157    fn display() -> &'static str {
158        "core wasm argument"
159    }
160}