/build/cargo-vendor-dir/wast-200.0.0/src/core/wast.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::core::{HeapType, V128Const}; |
2 | | use crate::kw; |
3 | | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | | use crate::token::{Float32, Float64, Index}; |
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(Float32), |
14 | | F64(Float64), |
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 | 0 | ("i32.const", |p| Ok(I32(p.parse()?))), |
25 | 0 | ("i64.const", |p| Ok(I64(p.parse()?))), |
26 | 0 | ("f32.const", |p| Ok(F32(p.parse()?))), |
27 | 0 | ("f64.const", |p| Ok(F64(p.parse()?))), |
28 | 0 | ("v128.const", |p| Ok(V128(p.parse()?))), |
29 | 0 | ("ref.null", |p| Ok(RefNull(p.parse()?))), |
30 | 0 | ("ref.extern", |p| Ok(RefExtern(p.parse()?))), |
31 | 0 | ("ref.host", |p| Ok(RefHost(p.parse()?))), |
32 | | ] |
33 | | }; |
34 | | |
35 | | impl<'a> Parse<'a> for WastArgCore<'a> { |
36 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
37 | 0 | let parse = parser.step(|c| { |
38 | 0 | if let Some((kw, rest)) = c.keyword()? { |
39 | 0 | if let Some(i) = ARGS.iter().position(|(name, _)| *name == kw) { |
40 | 0 | return Ok((ARGS[i].1, rest)); |
41 | 0 | } |
42 | 0 | } |
43 | 0 | Err(c.error("expected a [type].const expression")) |
44 | 0 | })?; |
45 | 0 | parse(parser) |
46 | 0 | } |
47 | | } |
48 | | |
49 | | impl Peek for WastArgCore<'_> { |
50 | 0 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
51 | 0 | let kw = match cursor.keyword()? { |
52 | 0 | Some((kw, _)) => kw, |
53 | 0 | None => return Ok(false), |
54 | | }; |
55 | 0 | Ok(ARGS.iter().find(|(name, _)| *name == kw).is_some()) |
56 | 0 | } |
57 | | |
58 | 0 | fn display() -> &'static str { |
59 | 0 | "core wasm argument" |
60 | 0 | } |
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<Float32>), |
71 | | F64(NanPattern<Float64>), |
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 | | |
94 | | Either(Vec<WastRetCore<'a>>), |
95 | | } |
96 | | |
97 | | static RETS: &[(&str, fn(Parser<'_>) -> Result<WastRetCore<'_>>)] = { |
98 | | use WastRetCore::*; |
99 | | &[ |
100 | 0 | ("i32.const", |p| Ok(I32(p.parse()?))), |
101 | 0 | ("i64.const", |p| Ok(I64(p.parse()?))), |
102 | 0 | ("f32.const", |p| Ok(F32(p.parse()?))), |
103 | 0 | ("f64.const", |p| Ok(F64(p.parse()?))), |
104 | 0 | ("v128.const", |p| Ok(V128(p.parse()?))), |
105 | 0 | ("ref.null", |p| Ok(RefNull(p.parse()?))), |
106 | 0 | ("ref.extern", |p| Ok(RefExtern(p.parse()?))), |
107 | 0 | ("ref.host", |p| Ok(RefHost(p.parse()?))), |
108 | 0 | ("ref.func", |p| Ok(RefFunc(p.parse()?))), |
109 | 0 | ("ref.any", |_| Ok(RefAny)), |
110 | 0 | ("ref.eq", |_| Ok(RefEq)), |
111 | 0 | ("ref.array", |_| Ok(RefArray)), |
112 | 0 | ("ref.struct", |_| Ok(RefStruct)), |
113 | 0 | ("ref.i31", |_| Ok(RefI31)), |
114 | 0 | ("either", |p| { |
115 | 0 | p.depth_check()?; |
116 | 0 | let mut cases = Vec::new(); |
117 | 0 | while !p.is_empty() { |
118 | 0 | cases.push(p.parens(|p| p.parse())?); |
119 | | } |
120 | 0 | Ok(Either(cases)) |
121 | 0 | }), |
122 | | ] |
123 | | }; |
124 | | |
125 | | impl<'a> Parse<'a> for WastRetCore<'a> { |
126 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
127 | 0 | let parse = parser.step(|c| { |
128 | 0 | if let Some((kw, rest)) = c.keyword()? { |
129 | 0 | if let Some(i) = RETS.iter().position(|(name, _)| *name == kw) { |
130 | 0 | return Ok((RETS[i].1, rest)); |
131 | 0 | } |
132 | 0 | } |
133 | 0 | Err(c.error("expected a [type].const expression")) |
134 | 0 | })?; |
135 | 0 | parse(parser) |
136 | 0 | } |
137 | | } |
138 | | |
139 | | impl Peek for WastRetCore<'_> { |
140 | 0 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
141 | 0 | let kw = match cursor.keyword()? { |
142 | 0 | Some((kw, _)) => kw, |
143 | 0 | None => return Ok(false), |
144 | | }; |
145 | 0 | Ok(RETS.iter().find(|(name, _)| *name == kw).is_some()) |
146 | 0 | } |
147 | | |
148 | 0 | fn display() -> &'static str { |
149 | 0 | "core wasm return value" |
150 | 0 | } |
151 | | } |
152 | | |
153 | | /// Either a NaN pattern (`nan:canonical`, `nan:arithmetic`) or a value of type `T`. |
154 | | #[derive(Debug, PartialEq)] |
155 | | #[allow(missing_docs)] |
156 | | pub enum NanPattern<T> { |
157 | | CanonicalNan, |
158 | | ArithmeticNan, |
159 | | Value(T), |
160 | | } |
161 | | |
162 | | impl<'a, T> Parse<'a> for NanPattern<T> |
163 | | where |
164 | | T: Parse<'a>, |
165 | | { |
166 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
167 | 0 | if parser.peek::<kw::nan_canonical>()? { |
168 | 0 | parser.parse::<kw::nan_canonical>()?; |
169 | 0 | Ok(NanPattern::CanonicalNan) |
170 | 0 | } else if parser.peek::<kw::nan_arithmetic>()? { |
171 | 0 | parser.parse::<kw::nan_arithmetic>()?; |
172 | 0 | Ok(NanPattern::ArithmeticNan) |
173 | | } else { |
174 | 0 | let val = parser.parse()?; |
175 | 0 | Ok(NanPattern::Value(val)) |
176 | | } |
177 | 0 | } |
178 | | } |
179 | | |
180 | | /// A version of `V128Const` that allows `NanPattern`s. |
181 | | /// |
182 | | /// This implementation is necessary because only float types can include NaN patterns; otherwise |
183 | | /// it is largely similar to the implementation of `V128Const`. |
184 | | #[derive(Debug)] |
185 | | #[allow(missing_docs)] |
186 | | pub enum V128Pattern { |
187 | | I8x16([i8; 16]), |
188 | | I16x8([i16; 8]), |
189 | | I32x4([i32; 4]), |
190 | | I64x2([i64; 2]), |
191 | | F32x4([NanPattern<Float32>; 4]), |
192 | | F64x2([NanPattern<Float64>; 2]), |
193 | | } |
194 | | |
195 | | impl<'a> Parse<'a> for V128Pattern { |
196 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
197 | 0 | let mut l = parser.lookahead1(); |
198 | 0 | if l.peek::<kw::i8x16>()? { |
199 | 0 | parser.parse::<kw::i8x16>()?; |
200 | | Ok(V128Pattern::I8x16([ |
201 | 0 | parser.parse()?, |
202 | 0 | parser.parse()?, |
203 | 0 | parser.parse()?, |
204 | 0 | parser.parse()?, |
205 | 0 | parser.parse()?, |
206 | 0 | parser.parse()?, |
207 | 0 | parser.parse()?, |
208 | 0 | parser.parse()?, |
209 | 0 | parser.parse()?, |
210 | 0 | parser.parse()?, |
211 | 0 | parser.parse()?, |
212 | 0 | parser.parse()?, |
213 | 0 | parser.parse()?, |
214 | 0 | parser.parse()?, |
215 | 0 | parser.parse()?, |
216 | 0 | parser.parse()?, |
217 | | ])) |
218 | 0 | } else if l.peek::<kw::i16x8>()? { |
219 | 0 | parser.parse::<kw::i16x8>()?; |
220 | | Ok(V128Pattern::I16x8([ |
221 | 0 | parser.parse()?, |
222 | 0 | parser.parse()?, |
223 | 0 | parser.parse()?, |
224 | 0 | parser.parse()?, |
225 | 0 | parser.parse()?, |
226 | 0 | parser.parse()?, |
227 | 0 | parser.parse()?, |
228 | 0 | parser.parse()?, |
229 | | ])) |
230 | 0 | } else if l.peek::<kw::i32x4>()? { |
231 | 0 | parser.parse::<kw::i32x4>()?; |
232 | | Ok(V128Pattern::I32x4([ |
233 | 0 | parser.parse()?, |
234 | 0 | parser.parse()?, |
235 | 0 | parser.parse()?, |
236 | 0 | parser.parse()?, |
237 | | ])) |
238 | 0 | } else if l.peek::<kw::i64x2>()? { |
239 | 0 | parser.parse::<kw::i64x2>()?; |
240 | 0 | Ok(V128Pattern::I64x2([parser.parse()?, parser.parse()?])) |
241 | 0 | } else if l.peek::<kw::f32x4>()? { |
242 | 0 | parser.parse::<kw::f32x4>()?; |
243 | | Ok(V128Pattern::F32x4([ |
244 | 0 | parser.parse()?, |
245 | 0 | parser.parse()?, |
246 | 0 | parser.parse()?, |
247 | 0 | parser.parse()?, |
248 | | ])) |
249 | 0 | } else if l.peek::<kw::f64x2>()? { |
250 | 0 | parser.parse::<kw::f64x2>()?; |
251 | 0 | Ok(V128Pattern::F64x2([parser.parse()?, parser.parse()?])) |
252 | | } else { |
253 | 0 | Err(l.error()) |
254 | | } |
255 | 0 | } |
256 | | } |