Coverage Report

Created: 2023-04-25 07:07

/src/wasm-tools/crates/wast/src/wast.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::component::WastVal;
2
use crate::core::{WastArgCore, WastRetCore};
3
use crate::kw;
4
use crate::parser::{self, Cursor, Parse, ParseBuffer, Parser, Peek, Result};
5
use crate::token::{Id, Span};
6
use crate::{Error, Wat};
7
8
/// A parsed representation of a `*.wast` file.
9
///
10
/// WAST files are not officially specified but are used in the official test
11
/// suite to write official spec tests for wasm. This type represents a parsed
12
/// `*.wast` file which parses a list of directives in a file.
13
0
#[derive(Debug)]
14
pub struct Wast<'a> {
15
    #[allow(missing_docs)]
16
    pub directives: Vec<WastDirective<'a>>,
17
}
18
19
impl<'a> Parse<'a> for Wast<'a> {
20
10.9k
    fn parse(parser: Parser<'a>) -> Result<Self> {
21
10.9k
        let mut directives = Vec::new();
22
10.9k
23
10.9k
        // If it looks like a directive token is in the stream then we parse a
24
10.9k
        // bunch of directives, otherwise assume this is an inline module.
25
10.9k
        if parser.peek2::<WastDirectiveToken>() {
26
17.0k
            while !parser.is_empty() {
27
16.2k
                directives.push(parser.parens(|p| p.parse())?);
28
            }
29
539
        } else {
30
7.30k
            let module = parser.parse::<Wat>()?;
31
539
            directives.push(WastDirective::Wat(QuoteWat::Wat(module)));
32
        }
33
1.41k
        Ok(Wast { directives })
34
10.9k
    }
35
}
36
37
struct WastDirectiveToken;
38
39
impl Peek for WastDirectiveToken {
40
10.8k
    fn peek(cursor: Cursor<'_>) -> bool {
41
10.8k
        let kw = match cursor.keyword() {
42
10.3k
            Some((kw, _)) => kw,
43
553
            None => return false,
44
        };
45
10.3k
        kw.starts_with("assert_")
46
9.64k
            || kw == "module"
47
9.56k
            || kw == "component"
48
6.79k
            || kw == "register"
49
6.78k
            || kw == "invoke"
50
10.8k
    }
51
52
0
    fn display() -> &'static str {
53
0
        unimplemented!()
54
0
    }
55
}
56
57
/// The different kinds of directives found in a `*.wast` file.
58
///
59
/// It's not entirely clear to me what all of these are per se, but they're only
60
/// really interesting to test harnesses mostly.
61
#[allow(missing_docs)]
62
0
#[derive(Debug)]
63
pub enum WastDirective<'a> {
64
    Wat(QuoteWat<'a>),
65
    AssertMalformed {
66
        span: Span,
67
        module: QuoteWat<'a>,
68
        message: &'a str,
69
    },
70
    AssertInvalid {
71
        span: Span,
72
        module: QuoteWat<'a>,
73
        message: &'a str,
74
    },
75
    Register {
76
        span: Span,
77
        name: &'a str,
78
        module: Option<Id<'a>>,
79
    },
80
    Invoke(WastInvoke<'a>),
81
    AssertTrap {
82
        span: Span,
83
        exec: WastExecute<'a>,
84
        message: &'a str,
85
    },
86
    AssertReturn {
87
        span: Span,
88
        exec: WastExecute<'a>,
89
        results: Vec<WastRet<'a>>,
90
    },
91
    AssertExhaustion {
92
        span: Span,
93
        call: WastInvoke<'a>,
94
        message: &'a str,
95
    },
96
    AssertUnlinkable {
97
        span: Span,
98
        module: Wat<'a>,
99
        message: &'a str,
100
    },
101
    AssertException {
102
        span: Span,
103
        exec: WastExecute<'a>,
104
    },
105
}
106
107
impl WastDirective<'_> {
108
    /// Returns the location in the source that this directive was defined at
109
    pub fn span(&self) -> Span {
110
0
        match self {
111
0
            WastDirective::Wat(QuoteWat::Wat(Wat::Module(m))) => m.span,
112
0
            WastDirective::Wat(QuoteWat::Wat(Wat::Component(c))) => c.span,
113
0
            WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span,
114
0
            WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span,
115
0
            WastDirective::AssertMalformed { span, .. }
116
0
            | WastDirective::Register { span, .. }
117
0
            | WastDirective::AssertTrap { span, .. }
118
0
            | WastDirective::AssertReturn { span, .. }
119
0
            | WastDirective::AssertExhaustion { span, .. }
120
0
            | WastDirective::AssertUnlinkable { span, .. }
121
0
            | WastDirective::AssertInvalid { span, .. }
122
0
            | WastDirective::AssertException { span, .. } => *span,
123
0
            WastDirective::Invoke(i) => i.span,
124
        }
125
0
    }
126
}
127
128
impl<'a> Parse<'a> for WastDirective<'a> {
129
16.1k
    fn parse(parser: Parser<'a>) -> Result<Self> {
130
16.1k
        let mut l = parser.lookahead1();
131
16.1k
        if l.peek::<kw::module>() || l.peek::<kw::component>() {
132
12.7k
            Ok(WastDirective::Wat(parser.parse()?))
133
3.49k
        } else if l.peek::<kw::assert_malformed>() {
134
1
            let span = parser.parse::<kw::assert_malformed>()?.0;
135
            Ok(WastDirective::AssertMalformed {
136
1
                span,
137
1
                module: parser.parens(|p| p.parse())?,
138
1
                message: parser.parse()?,
139
            })
140
3.49k
        } else if l.peek::<kw::assert_invalid>() {
141
23
            let span = parser.parse::<kw::assert_invalid>()?.0;
142
            Ok(WastDirective::AssertInvalid {
143
23
                span,
144
23
                module: parser.parens(|p| p.parse())?,
145
18
                message: parser.parse()?,
146
            })
147
3.46k
        } else if l.peek::<kw::register>() {
148
21
            let span = parser.parse::<kw::register>()?.0;
149
            Ok(WastDirective::Register {
150
21
                span,
151
21
                name: parser.parse()?,
152
20
                module: parser.parse()?,
153
            })
154
3.44k
        } else if l.peek::<kw::invoke>() {
155
551
            Ok(WastDirective::Invoke(parser.parse()?))
156
2.89k
        } else if l.peek::<kw::assert_trap>() {
157
30
            let span = parser.parse::<kw::assert_trap>()?.0;
158
            Ok(WastDirective::AssertTrap {
159
30
                span,
160
30
                exec: parser.parens(|p| p.parse())?,
161
16
                message: parser.parse()?,
162
            })
163
2.86k
        } else if l.peek::<kw::assert_return>() {
164
2.11k
            let span = parser.parse::<kw::assert_return>()?.0;
165
2.11k
            let exec = parser.parens(|p| p.parse())?;
166
2.08k
            let mut results = Vec::new();
167
16.3k
            while !parser.is_empty() {
168
14.5k
                results.push(parser.parens(|p| p.parse())?);
169
            }
170
1.72k
            Ok(WastDirective::AssertReturn {
171
1.72k
                span,
172
1.72k
                exec,
173
1.72k
                results,
174
1.72k
            })
175
754
        } else if l.peek::<kw::assert_exhaustion>() {
176
16
            let span = parser.parse::<kw::assert_exhaustion>()?.0;
177
            Ok(WastDirective::AssertExhaustion {
178
16
                span,
179
16
                call: parser.parens(|p| p.parse())?,
180
3
                message: parser.parse()?,
181
            })
182
738
        } else if l.peek::<kw::assert_unlinkable>() {
183
24
            let span = parser.parse::<kw::assert_unlinkable>()?.0;
184
            Ok(WastDirective::AssertUnlinkable {
185
24
                span,
186
24
                module: parser.parens(parse_wat)?,
187
8
                message: parser.parse()?,
188
            })
189
714
        } else if l.peek::<kw::assert_exception>() {
190
620
            let span = parser.parse::<kw::assert_exception>()?.0;
191
            Ok(WastDirective::AssertException {
192
620
                span,
193
620
                exec: parser.parens(|p| p.parse())?,
194
            })
195
        } else {
196
94
            Err(l.error())
197
        }
198
16.1k
    }
199
}
200
201
#[allow(missing_docs)]
202
0
#[derive(Debug)]
203
pub enum WastExecute<'a> {
204
    Invoke(WastInvoke<'a>),
205
    Wat(Wat<'a>),
206
    Get {
207
        module: Option<Id<'a>>,
208
        global: &'a str,
209
    },
210
}
211
212
impl<'a> Parse<'a> for WastExecute<'a> {
213
2.75k
    fn parse(parser: Parser<'a>) -> Result<Self> {
214
2.75k
        let mut l = parser.lookahead1();
215
2.75k
        if l.peek::<kw::invoke>() {
216
327
            Ok(WastExecute::Invoke(parser.parse()?))
217
2.42k
        } else if l.peek::<kw::module>() || l.peek::<kw::component>() {
218
2.39k
            Ok(WastExecute::Wat(parse_wat(parser)?))
219
29
        } else if l.peek::<kw::get>() {
220
6
            parser.parse::<kw::get>()?;
221
            Ok(WastExecute::Get {
222
6
                module: parser.parse()?,
223
6
                global: parser.parse()?,
224
            })
225
        } else {
226
23
            Err(l.error())
227
        }
228
2.75k
    }
229
}
230
231
15.0k
fn parse_wat(parser: Parser) -> Result<Wat> {
232
15.0k
    // Note that this doesn't use `Parse for Wat` since the `parser` provided
233
15.0k
    // has already peeled back the first layer of parentheses while `Parse for
234
15.0k
    // Wat` expects to be the top layer which means it also tries to peel off
235
15.0k
    // the parens. Instead we can skip the sugar that `Wat` has for simply a
236
15.0k
    // list of fields (no `(module ...)` container) and just parse the `Module`
237
15.0k
    // itself.
238
15.0k
    if parser.peek::<kw::component>() {
239
6.73k
        Ok(Wat::Component(parser.parse()?))
240
    } else {
241
8.33k
        Ok(Wat::Module(parser.parse()?))
242
    }
243
15.0k
}
244
245
#[allow(missing_docs)]
246
0
#[derive(Debug)]
247
pub struct WastInvoke<'a> {
248
    pub span: Span,
249
    pub module: Option<Id<'a>>,
250
    pub name: &'a str,
251
    pub args: Vec<WastArg<'a>>,
252
}
253
254
impl<'a> Parse<'a> for WastInvoke<'a> {
255
893
    fn parse(parser: Parser<'a>) -> Result<Self> {
256
893
        let span = parser.parse::<kw::invoke>()?.0;
257
891
        let module = parser.parse()?;
258
891
        let name = parser.parse()?;
259
880
        let mut args = Vec::new();
260
7.20k
        while !parser.is_empty() {
261
6.40k
            args.push(parser.parens(|p| p.parse())?);
262
        }
263
800
        Ok(WastInvoke {
264
800
            span,
265
800
            module,
266
800
            name,
267
800
            args,
268
800
        })
269
893
    }
270
}
271
272
#[allow(missing_docs)]
273
0
#[derive(Debug)]
274
pub enum QuoteWat<'a> {
275
    Wat(Wat<'a>),
276
    QuoteModule(Span, Vec<(Span, &'a [u8])>),
277
    QuoteComponent(Span, Vec<(Span, &'a [u8])>),
278
}
279
280
impl QuoteWat<'_> {
281
    /// Encodes this module to bytes, either by encoding the module directly or
282
    /// parsing the contents and then encoding it.
283
0
    pub fn encode(&mut self) -> Result<Vec<u8>, Error> {
284
0
        let (source, prefix) = match self {
285
0
            QuoteWat::Wat(m) => return m.encode(),
286
0
            QuoteWat::QuoteModule(_, source) => (source, None),
287
0
            QuoteWat::QuoteComponent(_, source) => (source, Some("(component")),
288
        };
289
0
        let mut ret = String::new();
290
0
        for (span, src) in source {
291
0
            match std::str::from_utf8(src) {
292
0
                Ok(s) => ret.push_str(s),
293
                Err(_) => {
294
0
                    return Err(Error::new(*span, "malformed UTF-8 encoding".to_string()));
295
                }
296
            }
297
0
            ret.push(' ');
298
        }
299
0
        if let Some(prefix) = prefix {
300
0
            ret.insert_str(0, prefix);
301
0
            ret.push(')');
302
0
        }
303
0
        let buf = ParseBuffer::new(&ret)?;
304
0
        let mut wat = parser::parse::<Wat<'_>>(&buf)?;
305
0
        wat.encode()
306
0
    }
307
}
308
309
impl<'a> Parse<'a> for QuoteWat<'a> {
310
12.7k
    fn parse(parser: Parser<'a>) -> Result<Self> {
311
12.7k
        if parser.peek2::<kw::quote>() {
312
73
            let ctor = if parser.peek::<kw::component>() {
313
56
                parser.parse::<kw::component>()?;
314
56
                QuoteWat::QuoteComponent
315
            } else {
316
17
                parser.parse::<kw::module>()?;
317
17
                QuoteWat::QuoteModule
318
            };
319
73
            let span = parser.parse::<kw::quote>()?.0;
320
73
            let mut src = Vec::new();
321
698
            while !parser.is_empty() {
322
631
                let span = parser.cur_span();
323
631
                let string = parser.parse()?;
324
625
                src.push((span, string));
325
            }
326
67
            Ok(ctor(span, src))
327
        } else {
328
12.6k
            Ok(QuoteWat::Wat(parse_wat(parser)?))
329
        }
330
12.7k
    }
331
}
332
333
0
#[derive(Debug)]
334
#[allow(missing_docs)]
335
pub enum WastArg<'a> {
336
    Core(WastArgCore<'a>),
337
    Component(WastVal<'a>),
338
}
339
340
impl<'a> Parse<'a> for WastArg<'a> {
341
6.40k
    fn parse(parser: Parser<'a>) -> Result<Self> {
342
6.40k
        if parser.peek::<WastArgCore<'_>>() {
343
3.04k
            Ok(WastArg::Core(parser.parse()?))
344
        } else {
345
3.35k
            Ok(WastArg::Component(parser.parse()?))
346
        }
347
6.40k
    }
348
}
349
350
0
#[derive(Debug)]
351
#[allow(missing_docs)]
352
pub enum WastRet<'a> {
353
    Core(WastRetCore<'a>),
354
    Component(WastVal<'a>),
355
}
356
357
impl<'a> Parse<'a> for WastRet<'a> {
358
14.5k
    fn parse(parser: Parser<'a>) -> Result<Self> {
359
14.5k
        if parser.peek::<WastRetCore<'_>>() {
360
2.21k
            Ok(WastRet::Core(parser.parse()?))
361
        } else {
362
12.3k
            Ok(WastRet::Component(parser.parse()?))
363
        }
364
14.5k
    }
365
}