inf_wast/core/
wast.rs

1use crate::core::{HeapType, V128Const};
2use crate::kw;
3use crate::parser::{Cursor, Parse, Parser, Peek, Result};
4use crate::token::{Index, F32, F64};
5
6/// Expression that can be used inside of `invoke` expressions for core wasm
7/// functions.
8#[derive(Debug)]
9#[allow(missing_docs)]
10pub enum WastArgCore<'a> {
11    I32(i32),
12    I64(i64),
13    F32(F32),
14    F64(F64),
15    V128(V128Const),
16    RefNull(HeapType<'a>),
17    RefExtern(u32),
18    RefHost(u32),
19}
20
21static ARGS: &[(&str, fn(Parser<'_>) -> Result<WastArgCore<'_>>)] = {
22    use WastArgCore::*;
23    &[
24        ("i32.const", |p| Ok(I32(p.parse()?))),
25        ("i64.const", |p| Ok(I64(p.parse()?))),
26        ("f32.const", |p| Ok(F32(p.parse()?))),
27        ("f64.const", |p| Ok(F64(p.parse()?))),
28        ("v128.const", |p| Ok(V128(p.parse()?))),
29        ("ref.null", |p| Ok(RefNull(p.parse()?))),
30        ("ref.extern", |p| Ok(RefExtern(p.parse()?))),
31        ("ref.host", |p| Ok(RefHost(p.parse()?))),
32    ]
33};
34
35impl<'a> Parse<'a> for WastArgCore<'a> {
36    fn parse(parser: Parser<'a>) -> Result<Self> {
37        let parse = parser.step(|c| {
38            if let Some((kw, rest)) = c.keyword()? {
39                if let Some(i) = ARGS.iter().position(|(name, _)| *name == kw) {
40                    return Ok((ARGS[i].1, rest));
41                }
42            }
43            Err(c.error("expected a [type].const expression"))
44        })?;
45        parse(parser)
46    }
47}
48
49impl Peek for WastArgCore<'_> {
50    fn peek(cursor: Cursor<'_>) -> Result<bool> {
51        let kw = match cursor.keyword()? {
52            Some((kw, _)) => kw,
53            None => return Ok(false),
54        };
55        Ok(ARGS.iter().find(|(name, _)| *name == kw).is_some())
56    }
57
58    fn display() -> &'static str {
59        "core wasm argument"
60    }
61}
62
63/// Expressions that can be used inside of `assert_return` to validate the
64/// return value of a core wasm function.
65#[derive(Debug)]
66#[allow(missing_docs)]
67pub enum WastRetCore<'a> {
68    I32(i32),
69    I64(i64),
70    F32(NanPattern<F32>),
71    F64(NanPattern<F64>),
72    V128(V128Pattern),
73
74    /// A null reference is expected, optionally with a specified type.
75    RefNull(Option<HeapType<'a>>),
76    /// A non-null externref is expected which should contain the specified
77    /// value.
78    RefExtern(Option<u32>),
79    /// A non-null anyref is expected which should contain the specified host value.
80    RefHost(u32),
81    /// A non-null funcref is expected.
82    RefFunc(Option<Index<'a>>),
83    /// A non-null anyref is expected.
84    RefAny,
85    /// A non-null eqref is expected.
86    RefEq,
87    /// A non-null arrayref is expected.
88    RefArray,
89    /// A non-null structref is expected.
90    RefStruct,
91    /// A non-null i31ref is expected.
92    RefI31,
93    /// A non-null, shared i31ref is expected.
94    RefI31Shared,
95
96    Either(Vec<WastRetCore<'a>>),
97}
98
99static RETS: &[(&str, fn(Parser<'_>) -> Result<WastRetCore<'_>>)] = {
100    use WastRetCore::*;
101    &[
102        ("i32.const", |p| Ok(I32(p.parse()?))),
103        ("i64.const", |p| Ok(I64(p.parse()?))),
104        ("f32.const", |p| Ok(F32(p.parse()?))),
105        ("f64.const", |p| Ok(F64(p.parse()?))),
106        ("v128.const", |p| Ok(V128(p.parse()?))),
107        ("ref.null", |p| Ok(RefNull(p.parse()?))),
108        ("ref.extern", |p| Ok(RefExtern(p.parse()?))),
109        ("ref.host", |p| Ok(RefHost(p.parse()?))),
110        ("ref.func", |p| Ok(RefFunc(p.parse()?))),
111        ("ref.any", |_| Ok(RefAny)),
112        ("ref.eq", |_| Ok(RefEq)),
113        ("ref.array", |_| Ok(RefArray)),
114        ("ref.struct", |_| Ok(RefStruct)),
115        ("ref.i31", |_| Ok(RefI31)),
116        ("ref.i31_shared", |_| Ok(RefI31Shared)),
117        ("either", |p| {
118            p.depth_check()?;
119            let mut cases = Vec::new();
120            while !p.is_empty() {
121                cases.push(p.parens(|p| p.parse())?);
122            }
123            Ok(Either(cases))
124        }),
125    ]
126};
127
128impl<'a> Parse<'a> for WastRetCore<'a> {
129    fn parse(parser: Parser<'a>) -> Result<Self> {
130        let parse = parser.step(|c| {
131            if let Some((kw, rest)) = c.keyword()? {
132                if let Some(i) = RETS.iter().position(|(name, _)| *name == kw) {
133                    return Ok((RETS[i].1, rest));
134                }
135            }
136            Err(c.error("expected a [type].const expression"))
137        })?;
138        parse(parser)
139    }
140}
141
142impl Peek for WastRetCore<'_> {
143    fn peek(cursor: Cursor<'_>) -> Result<bool> {
144        let kw = match cursor.keyword()? {
145            Some((kw, _)) => kw,
146            None => return Ok(false),
147        };
148        Ok(RETS.iter().find(|(name, _)| *name == kw).is_some())
149    }
150
151    fn display() -> &'static str {
152        "core wasm return value"
153    }
154}
155
156/// Either a NaN pattern (`nan:canonical`, `nan:arithmetic`) or a value of type `T`.
157#[derive(Copy, Clone, Debug, PartialEq)]
158#[allow(missing_docs)]
159pub enum NanPattern<T> {
160    CanonicalNan,
161    ArithmeticNan,
162    Value(T),
163}
164
165impl<'a, T> Parse<'a> for NanPattern<T>
166where
167    T: Parse<'a>,
168{
169    fn parse(parser: Parser<'a>) -> Result<Self> {
170        if parser.peek::<kw::nan_canonical>()? {
171            parser.parse::<kw::nan_canonical>()?;
172            Ok(NanPattern::CanonicalNan)
173        } else if parser.peek::<kw::nan_arithmetic>()? {
174            parser.parse::<kw::nan_arithmetic>()?;
175            Ok(NanPattern::ArithmeticNan)
176        } else {
177            let val = parser.parse()?;
178            Ok(NanPattern::Value(val))
179        }
180    }
181}
182
183/// A version of `V128Const` that allows `NanPattern`s.
184///
185/// This implementation is necessary because only float types can include NaN patterns; otherwise
186/// it is largely similar to the implementation of `V128Const`.
187#[derive(Clone, Debug)]
188#[allow(missing_docs)]
189pub enum V128Pattern {
190    I8x16([i8; 16]),
191    I16x8([i16; 8]),
192    I32x4([i32; 4]),
193    I64x2([i64; 2]),
194    F32x4([NanPattern<F32>; 4]),
195    F64x2([NanPattern<F64>; 2]),
196}
197
198impl<'a> Parse<'a> for V128Pattern {
199    fn parse(parser: Parser<'a>) -> Result<Self> {
200        let mut l = parser.lookahead1();
201        if l.peek::<kw::i8x16>()? {
202            parser.parse::<kw::i8x16>()?;
203            Ok(V128Pattern::I8x16([
204                parser.parse()?,
205                parser.parse()?,
206                parser.parse()?,
207                parser.parse()?,
208                parser.parse()?,
209                parser.parse()?,
210                parser.parse()?,
211                parser.parse()?,
212                parser.parse()?,
213                parser.parse()?,
214                parser.parse()?,
215                parser.parse()?,
216                parser.parse()?,
217                parser.parse()?,
218                parser.parse()?,
219                parser.parse()?,
220            ]))
221        } else if l.peek::<kw::i16x8>()? {
222            parser.parse::<kw::i16x8>()?;
223            Ok(V128Pattern::I16x8([
224                parser.parse()?,
225                parser.parse()?,
226                parser.parse()?,
227                parser.parse()?,
228                parser.parse()?,
229                parser.parse()?,
230                parser.parse()?,
231                parser.parse()?,
232            ]))
233        } else if l.peek::<kw::i32x4>()? {
234            parser.parse::<kw::i32x4>()?;
235            Ok(V128Pattern::I32x4([
236                parser.parse()?,
237                parser.parse()?,
238                parser.parse()?,
239                parser.parse()?,
240            ]))
241        } else if l.peek::<kw::i64x2>()? {
242            parser.parse::<kw::i64x2>()?;
243            Ok(V128Pattern::I64x2([parser.parse()?, parser.parse()?]))
244        } else if l.peek::<kw::f32x4>()? {
245            parser.parse::<kw::f32x4>()?;
246            Ok(V128Pattern::F32x4([
247                parser.parse()?,
248                parser.parse()?,
249                parser.parse()?,
250                parser.parse()?,
251            ]))
252        } else if l.peek::<kw::f64x2>()? {
253            parser.parse::<kw::f64x2>()?;
254            Ok(V128Pattern::F64x2([parser.parse()?, parser.parse()?]))
255        } else {
256            Err(l.error())
257        }
258    }
259}