wain_syntax_binary/
parser.rs

1use crate::error::{Error, ErrorKind, Result};
2use crate::leb128::Leb128;
3use crate::source::BinarySource;
4use std::borrow::Cow;
5use std::convert::TryInto;
6use std::marker::PhantomData;
7use std::str;
8use wain_ast::*;
9
10mod section_id {
11    pub const CUSTOM: u8 = 0;
12    pub const TYPE: u8 = 1;
13    pub const IMPORT: u8 = 2;
14    pub const FUNCTION: u8 = 3;
15    pub const TABLE: u8 = 4;
16    pub const MEMORY: u8 = 5;
17    pub const GLOBAL: u8 = 6;
18    pub const EXPORT: u8 = 7;
19    pub const START: u8 = 8;
20    pub const ELEMENT: u8 = 9;
21    pub const CODE: u8 = 10;
22    pub const DATA: u8 = 11;
23
24    pub fn to_name(id: u8) -> &'static str {
25        // https://webassembly.github.io/spec/core/binary/modules.html#sections
26        match id {
27            self::CUSTOM => "custom section",
28            self::TYPE => "type section",
29            self::IMPORT => "import section",
30            self::FUNCTION => "function section",
31            self::TABLE => "table section",
32            self::MEMORY => "memory section",
33            self::GLOBAL => "global section",
34            self::EXPORT => "export section",
35            self::START => "start section",
36            self::ELEMENT => "element section",
37            self::CODE => "code section",
38            self::DATA => "data section",
39            _ => unreachable!(),
40        }
41    }
42}
43
44// An iterator to iterate vec(P)
45// https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec
46struct VecItems<'p, 's, P: Parse<'s>> {
47    parser: &'p mut Parser<'s>,
48    count: usize,
49    phantom: PhantomData<P>, // Without this, P is not constrainted in Iterator implementation
50}
51
52impl<'p, 's, P: Parse<'s>> VecItems<'p, 's, P> {
53    fn new(parser: &'p mut Parser<'s>, count: usize) -> Self {
54        Self {
55            parser,
56            count,
57            phantom: PhantomData,
58        }
59    }
60
61    // Helper method to collect as Vec<P>. Without this, type must be specified for ? operator as bellow
62    //   parser.parse_vec()?.collect::<Result<'_, _>>()
63    fn into_vec(self) -> Result<'s, Vec<P>> {
64        self.collect()
65    }
66}
67
68impl<'p, 's, P: Parse<'s>> Iterator for VecItems<'p, 's, P> {
69    type Item = Result<'s, P>;
70
71    fn next(&mut self) -> Option<Self::Item> {
72        if self.count == 0 {
73            return None;
74        }
75        self.count -= 1;
76        Some(self.parser.parse())
77    }
78
79    fn size_hint(&self) -> (usize, Option<usize>) {
80        (self.count, Some(self.count))
81    }
82}
83
84pub struct Parser<'source> {
85    source: &'source [u8],
86    input: &'source [u8],
87    rest_len: usize,
88    // What is being parsed for better error message
89    parsing: &'static str,
90}
91
92impl<'s> Parser<'s> {
93    pub fn new(input: &'s [u8]) -> Parser<'s> {
94        Self {
95            source: input,
96            input,
97            rest_len: 0,
98            parsing: "module",
99        }
100    }
101
102    fn eat(&mut self, bytes: usize) {
103        self.input = &self.input[bytes..];
104    }
105
106    fn consume(&mut self, expected: &'static str) -> Result<'s, u8> {
107        if self.input.is_empty() {
108            Err(self.error(ErrorKind::UnexpectedEof { expected }))
109        } else {
110            let b = self.input[0];
111            self.input = &self.input[1..];
112            Ok(b)
113        }
114    }
115
116    fn current_pos(&self) -> usize {
117        self.source.len() - self.input.len() - self.rest_len
118    }
119
120    fn error(&self, kind: ErrorKind) -> Box<Error<'s>> {
121        let pos = self.current_pos();
122        Error::new(kind, pos, self.source, self.parsing)
123    }
124
125    fn unexpected_byte<T: AsRef<[u8]>>(&self, expected: T, got: u8, what: &'static str) -> Box<Error<'s>> {
126        let pos = self.current_pos() - 1; // Unget one character for magic
127        let kind = ErrorKind::UnexpectedByte {
128            expected: expected.as_ref().to_vec(),
129            got,
130            what,
131        };
132        Error::new(kind, pos, self.source, self.parsing)
133    }
134
135    pub fn parse<P: Parse<'s>>(&mut self) -> Result<'s, P> {
136        Parse::parse(self)
137    }
138
139    fn parse_int<I: Leb128>(&mut self) -> Result<'s, I> {
140        match I::read_leb128(self.input) {
141            Ok((i, len)) => {
142                self.eat(len);
143                Ok(i)
144            }
145            Err(kind) => Err(self.error(*kind)),
146        }
147    }
148
149    fn check_len(&self, len: usize, what: &'static str) -> Result<'s, ()> {
150        if self.input.len() < len {
151            Err(self.error(ErrorKind::LengthOutOfInput {
152                input: self.input.len(),
153                specified: len,
154                what,
155            }))
156        } else {
157            Ok(())
158        }
159    }
160
161    fn sub_parser(&self, sub_len: usize, what: &'static str) -> Result<'s, Parser<'s>> {
162        self.check_len(sub_len, what)?;
163        Ok(Parser {
164            source: self.source,
165            rest_len: self.input.len() - sub_len,
166            input: &self.input[..sub_len],
167            parsing: what,
168        })
169    }
170
171    fn section_parser(&mut self) -> Result<'s, Parser<'s>> {
172        let section = section_id::to_name(self.input[0]);
173        self.eat(1); // Eat section ID
174        let size = self.parse_int::<u32>()? as usize;
175        let parser = self.sub_parser(size, section)?;
176        self.eat(size);
177        Ok(parser)
178    }
179
180    // Note: Custom section is a pair of name and bytes payload. Currently custom section is simply
181    // ignored since it is not necessary to execute wasm binary.
182    fn ignore_custom_sections(&mut self) -> Result<'s, ()> {
183        while let [section_id::CUSTOM, ..] = self.input {
184            let mut inner = self.section_parser()?;
185            let _: Name = inner.parse()?;
186        }
187        Ok(())
188    }
189
190    fn parse_flag(&mut self, byte: u8, what: &'static str) -> Result<'s, ()> {
191        let b = self.consume(what)?;
192        if b == byte {
193            Ok(())
194        } else {
195            Err(self.unexpected_byte([byte], b, what))
196        }
197    }
198
199    // https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec
200    fn parse_vec<P: Parse<'s>>(&mut self) -> Result<'s, VecItems<'_, 's, P>> {
201        let size = self.parse_int::<u32>()? as usize;
202        // At least `size` bytes must be followed. This is necessary to check the size is correct
203        // before actually allocating Vec capacity. Otherwise Vec::reserve crashes (#30)
204        self.check_len(size, "size of vec elements")?;
205        Ok(VecItems::new(self, size))
206    }
207
208    fn check_section_end(&self, section_id: u8) -> Result<'s, ()> {
209        if self.input.is_empty() {
210            Ok(())
211        } else {
212            Err(self.error(ErrorKind::MalformedSectionSize {
213                name: section_id::to_name(section_id),
214                remaining_bytes: self.input.len(),
215            }))
216        }
217    }
218
219    fn push_vec_items<P: Parse<'s>>(&mut self, section_id: u8, vec: &mut Vec<P>) -> Result<'s, ()> {
220        if let [b, ..] = self.input {
221            if *b == section_id {
222                let mut inner = self.section_parser()?;
223                let vec_items = inner.parse_vec()?;
224                vec.reserve(vec_items.count);
225                for elem in vec_items {
226                    vec.push(elem?);
227                }
228                inner.check_section_end(section_id)?;
229            }
230        }
231        Ok(())
232    }
233}
234
235pub trait Parse<'source>: Sized {
236    fn parse(parser: &mut Parser<'source>) -> Result<'source, Self>;
237}
238
239// Parse u32 for typeidx, funcidx, memidx, ...
240impl<'s> Parse<'s> for u32 {
241    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
242        parser.parse_int()
243    }
244}
245
246impl<'s> Parse<'s> for Root<'s, BinarySource<'s>> {
247    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
248        Ok(Root {
249            module: parser.parse()?,
250            source: BinarySource(parser.source),
251        })
252    }
253}
254
255// https://webassembly.github.io/spec/core/binary/modules.html#binary-module
256impl<'s> Parse<'s> for Module<'s> {
257    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
258        fn parse_section_into_vec<'s, P: Parse<'s>>(parser: &mut Parser<'s>, id: u8) -> Result<'s, Vec<P>> {
259            if parser.input.starts_with(&[id]) {
260                let mut inner = parser.section_parser()?;
261                let vec = inner.parse_vec()?.into_vec();
262                inner.check_section_end(id)?;
263                vec
264            } else {
265                Ok(vec![])
266            }
267        }
268
269        let start = parser.current_pos();
270
271        match parser.input {
272            [0x00, 0x61, 0x73, 0x6d, ..] => parser.eat(4), // b"\0asm"
273            _ => return Err(parser.error(ErrorKind::WasmMagicNotFound)),
274        }
275
276        parser.check_len(4, "wasm version")?;
277        match parser.input {
278            [0x01, 0x00, 0x00, 0x00, ..] => parser.eat(4),
279            _ => {
280                let bytes = parser.input[..4].try_into().unwrap();
281                return Err(parser.error(ErrorKind::VersionMismatch(bytes)));
282            }
283        }
284
285        parser.ignore_custom_sections()?;
286
287        // Type section
288        let types = parse_section_into_vec(parser, section_id::TYPE)?;
289
290        parser.ignore_custom_sections()?;
291
292        let mut funcs = vec![];
293        let mut tables = vec![];
294        let mut memories = vec![];
295        let mut globals = vec![];
296
297        // Import section
298        if let [section_id::IMPORT, ..] = parser.input {
299            let mut inner = parser.section_parser()?;
300            for desc in inner.parse_vec()? {
301                match desc? {
302                    ImportDesc::Func(f) => funcs.push(f),
303                    ImportDesc::Table(t) => tables.push(t),
304                    ImportDesc::Memory(m) => memories.push(m),
305                    ImportDesc::Global(g) => globals.push(g),
306                }
307            }
308            inner.check_section_end(section_id::IMPORT)?;
309        }
310
311        parser.ignore_custom_sections()?;
312
313        // Function section
314        // https://webassembly.github.io/spec/core/binary/modules.html#binary-funcsec
315        // Only type indices are stored in function section. Locals and bodies are stored in code section
316        let func_indices: Vec<u32> = parse_section_into_vec(parser, section_id::FUNCTION)?;
317        funcs.reserve(func_indices.len());
318
319        parser.ignore_custom_sections()?;
320
321        // Table section
322        parser.push_vec_items(section_id::TABLE, &mut tables)?;
323
324        parser.ignore_custom_sections()?;
325
326        // Memory section
327        parser.push_vec_items(section_id::MEMORY, &mut memories)?;
328
329        parser.ignore_custom_sections()?;
330
331        // Global section
332        parser.push_vec_items(section_id::GLOBAL, &mut globals)?;
333
334        parser.ignore_custom_sections()?;
335
336        let exports = parse_section_into_vec(parser, section_id::EXPORT)?;
337
338        parser.ignore_custom_sections()?;
339
340        // Start function section
341        let entrypoint = if let [section_id::START, ..] = parser.input {
342            let mut inner = parser.section_parser()?;
343            let start = inner.parse()?;
344            inner.check_section_end(section_id::START)?;
345            Some(start)
346        } else {
347            None
348        };
349
350        parser.ignore_custom_sections()?;
351
352        // Element segments section
353        let elems = parse_section_into_vec(parser, section_id::ELEMENT)?;
354
355        parser.ignore_custom_sections()?;
356
357        // Code section
358        if let [section_id::CODE, ..] = parser.input {
359            let mut inner = parser.section_parser()?;
360
361            let codes = inner.parse_vec::<Code>()?;
362            if codes.count != func_indices.len() {
363                return Err(codes.parser.error(ErrorKind::FuncCodeLengthMismatch {
364                    num_funcs: func_indices.len(),
365                    num_codes: codes.count,
366                }));
367            }
368
369            for (code, typeidx) in codes.zip(func_indices.into_iter()) {
370                let code = code?;
371                funcs.push(Func {
372                    start: code.start,
373                    idx: typeidx,
374                    kind: FuncKind::Body {
375                        locals: code.locals,
376                        expr: code.expr,
377                    },
378                });
379            }
380
381            inner.check_section_end(section_id::CODE)?
382        } else if !func_indices.is_empty() {
383            return Err(parser.error(ErrorKind::FuncCodeLengthMismatch {
384                num_funcs: func_indices.len(),
385                num_codes: 0,
386            }));
387        }
388
389        parser.ignore_custom_sections()?;
390
391        let data = parse_section_into_vec(parser, section_id::DATA)?;
392
393        parser.ignore_custom_sections()?;
394
395        if !parser.input.is_empty() {
396            return Err(parser.error(ErrorKind::ExpectedEof(parser.input[0])));
397        }
398
399        Ok(Module {
400            start,
401            id: None,
402            types,
403            exports,
404            funcs,
405            elems,
406            tables,
407            data,
408            memories,
409            globals,
410            entrypoint,
411        })
412    }
413}
414
415// https://webassembly.github.io/spec/core/binary/values.html#names
416impl<'s> Parse<'s> for Name<'s> {
417    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
418        let size = parser.parse_int::<u32>()? as usize;
419        parser.check_len(size, "name")?;
420        match str::from_utf8(&parser.input[..size]) {
421            Ok(name) => {
422                parser.eat(size);
423                Ok(Name(Cow::Borrowed(name)))
424            }
425            Err(error) => Err(parser.error(ErrorKind::InvalidUtf8 { what: "name", error })),
426        }
427    }
428}
429
430// https://webassembly.github.io/spec/core/binary/types.html#function-types
431impl<'s> Parse<'s> for FuncType {
432    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
433        let start = parser.current_pos();
434        parser.parse_flag(0x60, "function type")?;
435        let params = parser.parse_vec()?.into_vec()?;
436        let results = parser.parse_vec()?.into_vec()?;
437        Ok(FuncType { start, params, results })
438    }
439}
440
441// https://webassembly.github.io/spec/core/binary/types.html#binary-valtype
442impl<'s> Parse<'s> for ValType {
443    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
444        match parser.consume("value type")? {
445            0x7f => Ok(ValType::I32),
446            0x7e => Ok(ValType::I64),
447            0x7d => Ok(ValType::F32),
448            0x7c => Ok(ValType::F64),
449            b => Err(parser.unexpected_byte([0x7f, 0x7e, 0x7d, 0x7c], b, "value type")),
450        }
451    }
452}
453
454// https://webassembly.github.io/spec/core/binary/modules.html#binary-import
455enum ImportDesc<'s> {
456    Func(Func<'s>),
457    Table(Table<'s>),
458    Memory(Memory<'s>),
459    Global(Global<'s>),
460}
461impl<'s> Parse<'s> for ImportDesc<'s> {
462    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
463        let start = parser.current_pos();
464        let import = Import {
465            mod_name: parser.parse()?,
466            name: parser.parse()?,
467        };
468        match parser.consume("import description")? {
469            0x00 => Ok(ImportDesc::Func(Func {
470                start,
471                idx: parser.parse()?,
472                kind: FuncKind::Import(import),
473            })),
474            0x01 => Ok(ImportDesc::Table(Table {
475                start,
476                ty: parser.parse()?,
477                import: Some(import),
478            })),
479            0x02 => Ok(ImportDesc::Memory(Memory {
480                start,
481                ty: parser.parse()?,
482                import: Some(import),
483            })),
484            0x03 => {
485                let GlobalType(mutable, ty) = parser.parse()?;
486                Ok(ImportDesc::Global(Global {
487                    start,
488                    mutable,
489                    ty,
490                    kind: GlobalKind::Import(import),
491                }))
492            }
493            b => Err(parser.unexpected_byte([0x00, 0x01, 0x02, 0x03], b, "import description")),
494        }
495    }
496}
497
498// https://webassembly.github.io/spec/core/binary/types.html#binary-tabletype
499impl<'s> Parse<'s> for TableType {
500    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
501        parser.parse_flag(0x70, "funcref of table type")?;
502        Ok(TableType { limit: parser.parse()? })
503    }
504}
505
506// https://webassembly.github.io/spec/core/binary/types.html#binary-limits
507impl<'s> Parse<'s> for Limits {
508    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
509        match parser.consume("limit")? {
510            0x00 => Ok(Limits::From(parser.parse_int()?)),
511            0x01 => Ok(Limits::Range(parser.parse_int()?, parser.parse_int()?)),
512            b => Err(parser.unexpected_byte([0x00, 0x01], b, "limit")),
513        }
514    }
515}
516
517// https://webassembly.github.io/spec/core/binary/types.html#memory-types
518impl<'s> Parse<'s> for MemType {
519    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
520        Ok(MemType { limit: parser.parse()? })
521    }
522}
523
524// https://webassembly.github.io/spec/core/binary/types.html#global-types
525struct GlobalType(bool, ValType);
526impl<'s> Parse<'s> for GlobalType {
527    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
528        let ty = parser.parse()?;
529        let mutable = match parser.consume("mutability of global type")? {
530            0x00 => false,
531            0x01 => true,
532            b => return Err(parser.unexpected_byte([0x00, 0x01], b, "mutability of global type")),
533        };
534        Ok(GlobalType(mutable, ty))
535    }
536}
537
538// https://webassembly.github.io/spec/core/binary/modules.html#binary-tablesec
539impl<'s> Parse<'s> for Table<'s> {
540    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
541        Ok(Table {
542            start: parser.current_pos(),
543            ty: parser.parse()?,
544            import: None,
545        })
546    }
547}
548
549// https://webassembly.github.io/spec/core/binary/modules.html#binary-memsec
550impl<'s> Parse<'s> for Memory<'s> {
551    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
552        Ok(Memory {
553            start: parser.current_pos(),
554            ty: parser.parse()?,
555            import: None,
556        })
557    }
558}
559
560// https://webassembly.github.io/spec/core/binary/modules.html#binary-globalsec
561impl<'s> Parse<'s> for Global<'s> {
562    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
563        let start = parser.current_pos();
564        let GlobalType(mutable, ty) = parser.parse()?;
565        let Expr(insns) = parser.parse()?;
566        Ok(Global {
567            start,
568            mutable,
569            ty,
570            kind: GlobalKind::Init(insns),
571        })
572    }
573}
574
575// https://webassembly.github.io/spec/core/binary/instructions.html#expressions
576struct Expr(Vec<Instruction>);
577impl<'s> Parse<'s> for Expr {
578    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
579        let mut insns = vec![];
580        loop {
581            if let [0x0b, ..] = parser.input {
582                parser.eat(1);
583                return Ok(Expr(insns));
584            }
585            insns.push(parser.parse()?);
586        }
587    }
588}
589
590// https://webassembly.github.io/spec/core/binary/types.html#binary-blocktype
591struct BlockType(Option<ValType>);
592impl<'s> Parse<'s> for BlockType {
593    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
594        if let [0x40, ..] = parser.input {
595            parser.eat(1);
596            return Ok(BlockType(None));
597        }
598        Ok(BlockType(Some(parser.parse()?)))
599    }
600}
601
602// https://webassembly.github.io/spec/core/binary/instructions.html#instructions
603impl<'s> Parse<'s> for Instruction {
604    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
605        use InsnKind::*;
606        let start = parser.current_pos();
607        let kind = match parser.consume("instruction")? {
608            // Control instructions
609            // https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions
610            0x00 => Unreachable,
611            0x01 => Nop,
612            0x02 => {
613                let BlockType(ty) = parser.parse()?;
614                let Expr(body) = parser.parse()?;
615                Block { ty, body }
616            }
617            0x03 => {
618                let BlockType(ty) = parser.parse()?;
619                let Expr(body) = parser.parse()?;
620                Loop { ty, body }
621            }
622            0x04 => {
623                let BlockType(ty) = parser.parse()?;
624
625                let mut then_body = vec![];
626                let has_else = loop {
627                    match parser.input {
628                        [0x05, ..] => break true,
629                        [0x0b, ..] => break false,
630                        _ => then_body.push(parser.parse()?),
631                    }
632                };
633                parser.eat(1);
634
635                let else_body = if has_else {
636                    let Expr(insns) = parser.parse()?;
637                    insns
638                } else {
639                    vec![]
640                };
641
642                If {
643                    ty,
644                    then_body,
645                    else_body,
646                }
647            }
648            0x0c => Br(parser.parse()?),
649            0x0d => BrIf(parser.parse()?),
650            0x0e => BrTable {
651                labels: parser.parse_vec()?.into_vec()?,
652                default_label: parser.parse()?,
653            },
654            0x0f => Return,
655            0x10 => Call(parser.parse()?),
656            0x11 => {
657                let insn = CallIndirect(parser.parse()?);
658                parser.parse_flag(0x00, "reserved byte in call_indirect")?;
659                insn
660            }
661            // Parametric instructions
662            // https://webassembly.github.io/spec/core/binary/instructions.html#parametric-instructions
663            0x1a => Drop,
664            0x1b => Select,
665            // Variable instructions
666            // https://webassembly.github.io/spec/core/binary/instructions.html#variable-instructions
667            0x20 => LocalGet(parser.parse()?),
668            0x21 => LocalSet(parser.parse()?),
669            0x22 => LocalTee(parser.parse()?),
670            0x23 => GlobalGet(parser.parse()?),
671            0x24 => GlobalSet(parser.parse()?),
672            // Memory instructions
673            // https://webassembly.github.io/spec/core/binary/instructions.html#memory-instructions
674            0x28 => I32Load(parser.parse()?),
675            0x29 => I64Load(parser.parse()?),
676            0x2a => F32Load(parser.parse()?),
677            0x2b => F64Load(parser.parse()?),
678            0x2c => I32Load8S(parser.parse()?),
679            0x2d => I32Load8U(parser.parse()?),
680            0x2e => I32Load16S(parser.parse()?),
681            0x2f => I32Load16U(parser.parse()?),
682            0x30 => I64Load8S(parser.parse()?),
683            0x31 => I64Load8U(parser.parse()?),
684            0x32 => I64Load16S(parser.parse()?),
685            0x33 => I64Load16U(parser.parse()?),
686            0x34 => I64Load32S(parser.parse()?),
687            0x35 => I64Load32U(parser.parse()?),
688            0x36 => I32Store(parser.parse()?),
689            0x37 => I64Store(parser.parse()?),
690            0x38 => F32Store(parser.parse()?),
691            0x39 => F64Store(parser.parse()?),
692            0x3a => I32Store8(parser.parse()?),
693            0x3b => I32Store16(parser.parse()?),
694            0x3c => I64Store8(parser.parse()?),
695            0x3d => I64Store16(parser.parse()?),
696            0x3e => I64Store32(parser.parse()?),
697            0x3f => {
698                parser.parse_flag(0x00, "reserved byte in memory.size")?;
699                MemorySize
700            }
701            0x40 => {
702                parser.parse_flag(0x00, "reserved byte in memory.grow")?;
703                MemoryGrow
704            }
705            // Numeric instructions
706            // constants
707            0x41 => I32Const(parser.parse_int()?),
708            0x42 => I64Const(parser.parse_int()?),
709            0x43 => F32Const(parser.parse()?),
710            0x44 => F64Const(parser.parse()?),
711            // test and relation operators
712            0x45 => I32Eqz,
713            0x46 => I32Eq,
714            0x47 => I32Ne,
715            0x48 => I32LtS,
716            0x49 => I32LtU,
717            0x4a => I32GtS,
718            0x4b => I32GtU,
719            0x4c => I32LeS,
720            0x4d => I32LeU,
721            0x4e => I32GeS,
722            0x4f => I32GeU,
723            0x50 => I64Eqz,
724            0x51 => I64Eq,
725            0x52 => I64Ne,
726            0x53 => I64LtS,
727            0x54 => I64LtU,
728            0x55 => I64GtS,
729            0x56 => I64GtU,
730            0x57 => I64LeS,
731            0x58 => I64LeU,
732            0x59 => I64GeS,
733            0x5a => I64GeU,
734            0x5b => F32Eq,
735            0x5c => F32Ne,
736            0x5d => F32Lt,
737            0x5e => F32Gt,
738            0x5f => F32Le,
739            0x60 => F32Ge,
740            0x61 => F64Eq,
741            0x62 => F64Ne,
742            0x63 => F64Lt,
743            0x64 => F64Gt,
744            0x65 => F64Le,
745            0x66 => F64Ge,
746            // i32 operations
747            0x67 => I32Clz,
748            0x68 => I32Ctz,
749            0x69 => I32Popcnt,
750            0x6a => I32Add,
751            0x6b => I32Sub,
752            0x6c => I32Mul,
753            0x6d => I32DivS,
754            0x6e => I32DivU,
755            0x6f => I32RemS,
756            0x70 => I32RemU,
757            0x71 => I32And,
758            0x72 => I32Or,
759            0x73 => I32Xor,
760            0x74 => I32Shl,
761            0x75 => I32ShrS,
762            0x76 => I32ShrU,
763            0x77 => I32Rotl,
764            0x78 => I32Rotr,
765            // i64 operations
766            0x79 => I64Clz,
767            0x7a => I64Ctz,
768            0x7b => I64Popcnt,
769            0x7c => I64Add,
770            0x7d => I64Sub,
771            0x7e => I64Mul,
772            0x7f => I64DivS,
773            0x80 => I64DivU,
774            0x81 => I64RemS,
775            0x82 => I64RemU,
776            0x83 => I64And,
777            0x84 => I64Or,
778            0x85 => I64Xor,
779            0x86 => I64Shl,
780            0x87 => I64ShrS,
781            0x88 => I64ShrU,
782            0x89 => I64Rotl,
783            0x8a => I64Rotr,
784            // f32 operations
785            0x8b => F32Abs,
786            0x8c => F32Neg,
787            0x8d => F32Ceil,
788            0x8e => F32Floor,
789            0x8f => F32Trunc,
790            0x90 => F32Nearest,
791            0x91 => F32Sqrt,
792            0x92 => F32Add,
793            0x93 => F32Sub,
794            0x94 => F32Mul,
795            0x95 => F32Div,
796            0x96 => F32Min,
797            0x97 => F32Max,
798            0x98 => F32Copysign,
799            // f64 operations
800            0x99 => F64Abs,
801            0x9a => F64Neg,
802            0x9b => F64Ceil,
803            0x9c => F64Floor,
804            0x9d => F64Trunc,
805            0x9e => F64Nearest,
806            0x9f => F64Sqrt,
807            0xa0 => F64Add,
808            0xa1 => F64Sub,
809            0xa2 => F64Mul,
810            0xa3 => F64Div,
811            0xa4 => F64Min,
812            0xa5 => F64Max,
813            0xa6 => F64Copysign,
814            // conversions
815            0xa7 => I32WrapI64,
816            0xa8 => I32TruncF32S,
817            0xa9 => I32TruncF32U,
818            0xaa => I32TruncF64S,
819            0xab => I32TruncF64U,
820            0xac => I64ExtendI32S,
821            0xad => I64ExtendI32U,
822            0xae => I64TruncF32S,
823            0xaf => I64TruncF32U,
824            0xb0 => I64TruncF64S,
825            0xb1 => I64TruncF64U,
826            0xb2 => F32ConvertI32S,
827            0xb3 => F32ConvertI32U,
828            0xb4 => F32ConvertI64S,
829            0xb5 => F32ConvertI64U,
830            0xb6 => F32DemoteF64,
831            0xb7 => F64ConvertI32S,
832            0xb8 => F64ConvertI32U,
833            0xb9 => F64ConvertI64S,
834            0xba => F64ConvertI64U,
835            0xbb => F64PromoteF32,
836            0xbc => I32ReinterpretF32,
837            0xbd => I64ReinterpretF64,
838            0xbe => F32ReinterpretI32,
839            0xbf => F64ReinterpretI64,
840            // sign extension
841            0xc0 => I32Extend8S,
842            0xc1 => I32Extend16S,
843            0xc2 => I64Extend8S,
844            0xc3 => I64Extend16S,
845            0xc4 => I64Extend32S,
846            // https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions
847            b => return Err(parser.unexpected_byte([], b, "instruction")),
848        };
849        Ok(Instruction { start, kind })
850    }
851}
852
853// https://webassembly.github.io/spec/core/binary/instructions.html#binary-memarg
854impl<'s> Parse<'s> for Mem {
855    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
856        let align = parser.parse_int()?;
857        let offset = parser.parse_int()?;
858        Ok(Mem { align, offset })
859    }
860}
861
862// https://webassembly.github.io/spec/core/binary/values.html#floating-point
863impl<'s> Parse<'s> for f32 {
864    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
865        if parser.input.len() < 4 {
866            return Err(parser.error(ErrorKind::UnexpectedEof {
867                expected: "32bit floating point number",
868            }));
869        }
870        let buf: [u8; 4] = parser.input[..4].try_into().unwrap();
871        parser.eat(4);
872        Ok(f32::from_le_bytes(buf))
873    }
874}
875
876// https://webassembly.github.io/spec/core/binary/values.html#floating-point
877impl<'s> Parse<'s> for f64 {
878    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
879        if parser.input.len() < 8 {
880            return Err(parser.error(ErrorKind::UnexpectedEof {
881                expected: "32bit floating point number",
882            }));
883        }
884        let buf: [u8; 8] = parser.input[..8].try_into().unwrap();
885        parser.eat(8);
886        Ok(f64::from_le_bytes(buf))
887    }
888}
889
890// https://webassembly.github.io/spec/core/binary/modules.html#binary-export
891impl<'s> Parse<'s> for Export<'s> {
892    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
893        let start = parser.current_pos();
894        let name = parser.parse()?;
895        let kind = match parser.consume("export description")? {
896            0x00 => ExportKind::Func(parser.parse()?),
897            0x01 => ExportKind::Table(parser.parse()?),
898            0x02 => ExportKind::Memory(parser.parse()?),
899            0x03 => ExportKind::Global(parser.parse()?),
900            b => {
901                return Err(parser.unexpected_byte([0x00, 0x01, 0x02, 0x03], b, "export description"));
902            }
903        };
904        Ok(Export { start, name, kind })
905    }
906}
907
908// https://webassembly.github.io/spec/core/binary/modules.html#start-section
909impl<'s> Parse<'s> for StartFunction {
910    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
911        Ok(StartFunction {
912            start: parser.current_pos(),
913            idx: parser.parse()?,
914        })
915    }
916}
917
918// https://webassembly.github.io/spec/core/binary/modules.html#binary-elem
919impl<'s> Parse<'s> for ElemSegment {
920    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
921        let start = parser.current_pos();
922        let idx = parser.parse()?;
923        let Expr(offset) = parser.parse()?;
924        let init = parser.parse_vec()?.into_vec()?;
925        Ok(ElemSegment {
926            start,
927            idx,
928            offset,
929            init,
930        })
931    }
932}
933
934// https://webassembly.github.io/spec/core/binary/modules.html#binary-code
935struct Code {
936    start: usize,
937    locals: Vec<ValType>,
938    expr: Vec<Instruction>,
939}
940impl<'s> Parse<'s> for Code {
941    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
942        let start = parser.current_pos();
943        let size = parser.parse_int::<u32>()? as usize;
944        // Parsing code section out of the size is malformed. To check it,
945        // here we parse the subsequence with nested parser.
946        let mut inner = parser.sub_parser(size, "code section")?;
947        parser.eat(size);
948
949        let mut locals = vec![];
950        for loc in inner.parse_vec::<Locals>()? {
951            let loc = loc?;
952            if let Some(c) = loc.count.checked_add(locals.len() as u32) {
953                locals.resize(c as usize, loc.ty);
954            } else {
955                return Err(parser.error(ErrorKind::TooManyLocalVariables(locals.len())));
956            }
957        }
958
959        let Expr(expr) = inner.parse()?;
960        if !inner.input.is_empty() {
961            return Err(inner.error(ErrorKind::MalformedCodeSize {
962                remaining_bytes: inner.input.len(),
963            }));
964        }
965        Ok(Code { start, locals, expr })
966    }
967}
968
969// https://webassembly.github.io/spec/core/binary/modules.html#binary-local
970struct Locals {
971    count: u32,
972    ty: ValType,
973}
974impl<'s> Parse<'s> for Locals {
975    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
976        Ok(Locals {
977            count: parser.parse_int()?,
978            ty: parser.parse()?,
979        })
980    }
981}
982
983// https://webassembly.github.io/spec/core/binary/modules.html#binary-data
984impl<'s> Parse<'s> for DataSegment<'s> {
985    fn parse(parser: &mut Parser<'s>) -> Result<'s, Self> {
986        let start = parser.current_pos();
987        let idx = parser.parse()?;
988        let Expr(offset) = parser.parse()?;
989
990        // Parse vec(byte) with zero allocation
991        let size = parser.parse_int::<u32>()? as usize;
992        if size > parser.input.len() {
993            return Err(parser.error(ErrorKind::LengthOutOfInput {
994                input: parser.input.len(),
995                specified: size,
996                what: "byte buffer in data segment",
997            }));
998        }
999        let data = &parser.input[..size];
1000        parser.eat(size);
1001
1002        Ok(DataSegment {
1003            start,
1004            idx,
1005            offset,
1006            data: Cow::Borrowed(data),
1007        })
1008    }
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013    use super::*;
1014    use std::env;
1015    use std::fs;
1016
1017    fn unwrap<T>(res: Result<'_, T>) -> T {
1018        match res {
1019            Ok(x) => x,
1020            Err(e) => panic!("unexpected error: {}", e),
1021        }
1022    }
1023
1024    fn read_hello_file(name: &'static str) -> Vec<u8> {
1025        let mut dir = env::current_dir().unwrap();
1026        dir.pop();
1027        dir.push("examples");
1028        dir.push("hello");
1029        dir.push(name);
1030        fs::read(dir).unwrap()
1031    }
1032
1033    // From examples
1034    #[test]
1035    fn hello_world() {
1036        let bin = read_hello_file("hello.wasm");
1037
1038        let mut parser = Parser::new(&bin);
1039        let root: Root<'_, _> = unwrap(parser.parse());
1040
1041        let t = &root.module.types;
1042        assert_eq!(t.len(), 3);
1043        assert_eq!(&t[0].params, &[ValType::I32]);
1044        assert_eq!(&t[0].results, &[ValType::I32]);
1045        assert_eq!(&t[1].params, &[ValType::I32]);
1046        assert_eq!(&t[1].results, &[]);
1047        assert_eq!(&t[2].params, &[]);
1048        assert_eq!(&t[2].results, &[]);
1049
1050        let f = &root.module.funcs;
1051        assert_eq!(f.len(), 3);
1052        assert!(matches!(&f[0], Func {
1053            idx: 0,
1054            kind: FuncKind::Import(Import {
1055                mod_name: Name(n1),
1056                name: Name(n2),
1057            }),
1058            ..
1059        } if n1 == "env" && n2 == "putchar"));
1060        assert!(matches!(
1061            &f[1],
1062            Func {
1063                idx: 1,
1064                kind: FuncKind::Body { .. },
1065                ..
1066            }
1067        ));
1068        assert!(matches!(
1069            &f[2],
1070            Func {
1071                idx: 2,
1072                kind: FuncKind::Body { .. },
1073                ..
1074            }
1075        ));
1076
1077        let e = &root.module.exports;
1078        assert_eq!(e.len(), 2);
1079        assert!(matches!(&e[0], Export {
1080            name: Name(n),
1081            kind: ExportKind::Memory(0),
1082            ..
1083        } if n == "memory"));
1084        assert!(matches!(&e[1], Export {
1085            name: Name(n),
1086            kind: ExportKind::Func(2),
1087            ..
1088        } if n == "_start"));
1089
1090        assert!(root.module.elems.is_empty());
1091
1092        let t = &root.module.tables;
1093        assert_eq!(t.len(), 1);
1094        assert!(matches!(
1095            &t[0],
1096            Table {
1097                ty: TableType {
1098                    limit: Limits::Range(1, 1)
1099                },
1100                import: None,
1101                ..
1102            }
1103        ));
1104
1105        let m = &root.module.memories;
1106        assert_eq!(m.len(), 1);
1107        assert!(matches!(
1108            &m[0],
1109            Memory {
1110                ty: MemType { limit: Limits::From(2) },
1111                import: None,
1112                ..
1113            }
1114        ));
1115
1116        let d = &root.module.data;
1117        assert_eq!(d.len(), 1);
1118        assert_eq!(d[0].idx, 0);
1119        assert!(matches!(
1120            d[0].offset.as_slice(),
1121            [Instruction {
1122                kind: InsnKind::I32Const(1024),
1123                ..
1124            }]
1125        ));
1126        assert_eq!(d[0].data.as_ref(), b"Hello, world\n\0".as_ref());
1127
1128        let g = &root.module.globals;
1129        assert_eq!(g.len(), 1);
1130        assert!(matches!(&g[0], Global {
1131            mutable: true,
1132            ty: ValType::I32,
1133            kind: GlobalKind::Init(expr),
1134            ..
1135        } if matches!(
1136            expr.as_slice(),
1137            [
1138                Instruction {
1139                    kind: InsnKind::I32Const(66576),
1140                    ..
1141                }
1142            ]
1143        )));
1144
1145        assert!(root.module.entrypoint.is_none());
1146
1147        let bin = read_hello_file("hello_global.wasm");
1148        let mut parser = Parser::new(&bin);
1149        let _: Root<'_, _> = unwrap(parser.parse());
1150
1151        let bin = read_hello_file("hello_indirect_call.wasm");
1152        let mut parser = Parser::new(&bin);
1153        let _: Root<'_, _> = unwrap(parser.parse());
1154
1155        let bin = read_hello_file("hello_struct.wasm");
1156        let mut parser = Parser::new(&bin);
1157        let _: Root<'_, _> = unwrap(parser.parse());
1158    }
1159
1160    macro_rules! test_parse_error {
1161        ($name:ident, $expected:pat, $bin:expr) => {
1162            #[test]
1163            fn $name() {
1164                let bin: &[_] = $bin;
1165                let mut parser = Parser::new(bin);
1166                match parser.parse::<Module<'_>>() {
1167                    Ok(_) => panic!("unexpected success"),
1168                    Err(err) => assert!(matches!(err.kind, $expected)),
1169                }
1170            }
1171        };
1172    }
1173
1174    test_parse_error!(
1175        regression_issue_29,
1176        ErrorKind::VersionMismatch(_),
1177        b"\x00\x61\x73\x6d\x01\x31\x39\x00\x61\x73\x6d\x01\x31\x39\x35\x01" // .asm.19.asm.195.
1178    );
1179
1180    test_parse_error!(
1181        regression_issue_30,
1182        ErrorKind::LengthOutOfInput {
1183            what: "size of vec elements",
1184            ..
1185        },
1186        b"\x00\x61\x73\x6d\x01\x00\x00\x00\x05\x05\xff\xff\xff\x0d\xfb\x81\x05\x00\x00"
1187    );
1188
1189    test_parse_error!(
1190        code_size,
1191        ErrorKind::MalformedCodeSize { remaining_bytes: 1 },
1192        b"\x00\x61\x73\x6d\
1193          \x01\x00\x00\x00\
1194          \x01\x04\x01\x60\x00\x00\
1195          \x03\x02\x01\x00\
1196          \x0a\x05\x01\x03\x00\x0b\x0b"
1197    );
1198}