| 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 | |