Coverage Report

Created: 2024-09-10 12:50

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