1 | use crate::core::{HeapType, V128Const}; |
2 | use crate::kw; |
3 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | use 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)] |
10 | pub 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 | |
21 | static 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 | |
35 | impl<'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 | |
49 | impl 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)] |
67 | pub 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 | |
99 | static 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 | |
128 | impl<'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 | |
142 | impl 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)] |
159 | pub enum NanPattern<T> { |
160 | CanonicalNan, |
161 | ArithmeticNan, |
162 | Value(T), |
163 | } |
164 | |
165 | impl<'a, T> Parse<'a> for NanPattern<T> |
166 | where |
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)] |
189 | pub 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 | |
198 | impl<'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 | |