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: Parser<'_>| Ok(I32(p.parse()?))),
25 ("i64.const", |p: Parser<'_>| Ok(I64(p.parse()?))),
26 ("f32.const", |p: Parser<'_>| Ok(F32(p.parse()?))),
27 ("f64.const", |p: Parser<'_>| Ok(F64(p.parse()?))),
28 ("v128.const", |p: Parser<'_>| Ok(V128(p.parse()?))),
29 ("ref.null", |p: Parser<'_>| Ok(RefNull(p.parse()?))),
30 ("ref.extern", |p: Parser<'_>| Ok(RefExtern(p.parse()?))),
31 ("ref.host", |p: Parser<'_>| 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: fn(Parser<'_>) -> Result<…, …> = parser.step(|c: Cursor<'a>| {
38 if let Some((kw: &'a str, rest: Cursor<'a>)) = c.keyword()? {
39 if let Some(i: usize) = ARGS.iter().position(|(name: &&str, _)| *name == kw) {
40 return Ok((ARGS[i].1, rest));
41 }
42 }
43 Err(c.error(msg:"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: &str = match cursor.keyword()? {
52 Some((kw: &str, _)) => kw,
53 None => return Ok(false),
54 };
55 Ok(ARGS.iter().find(|(name: &&str, _)| *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: fn(Parser<'_>) -> Result<…, …> = parser.step(|c: Cursor<'a>| {
131 if let Some((kw: &'a str, rest: Cursor<'a>)) = c.keyword()? {
132 if let Some(i: usize) = RETS.iter().position(|(name: &&str, _)| *name == kw) {
133 return Ok((RETS[i].1, rest));
134 }
135 }
136 Err(c.error(msg:"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: &str = match cursor.keyword()? {
145 Some((kw: &str, _)) => kw,
146 None => return Ok(false),
147 };
148 Ok(RETS.iter().find(|(name: &&str, _)| *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: T = 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}
260