wast/core/
module.rs

1use crate::core::binary::EncodeOptions;
2use crate::core::*;
3use crate::parser::{Parse, Parser, Result};
4use crate::token::{Id, Index, NameAnnotation, Span};
5use crate::{annotation, kw};
6
7pub use crate::core::resolve::Names;
8
9/// A parsed WebAssembly core module.
10#[derive(Debug)]
11pub struct Module<'a> {
12    /// Where this `module` was defined
13    pub span: Span,
14    /// An optional identifier this module is known by
15    pub id: Option<Id<'a>>,
16    /// An optional `@name` annotation for this module
17    pub name: Option<NameAnnotation<'a>>,
18    /// What kind of module this was parsed as.
19    pub kind: ModuleKind<'a>,
20}
21
22/// The different kinds of ways to define a module.
23#[derive(Debug)]
24pub enum ModuleKind<'a> {
25    /// A module defined in the textual s-expression format.
26    Text(Vec<ModuleField<'a>>),
27    /// A module that had its raw binary bytes defined via the `binary`
28    /// directive.
29    Binary(Vec<&'a [u8]>),
30}
31
32impl<'a> Module<'a> {
33    /// Performs a name resolution pass on this [`Module`], resolving all
34    /// symbolic names to indices.
35    ///
36    /// The WAT format contains a number of shorthands to make it easier to
37    /// write, such as inline exports, inline imports, inline type definitions,
38    /// etc. Additionally it allows using symbolic names such as `$foo` instead
39    /// of using indices. This module will postprocess an AST to remove all of
40    /// this syntactic sugar, preparing the AST for binary emission.  This is
41    /// where expansion and name resolution happens.
42    ///
43    /// This function will mutate the AST of this [`Module`] and replace all
44    /// [`Index`](crate::token::Index) arguments with `Index::Num`. This will
45    /// also expand inline exports/imports listed on fields and handle various
46    /// other shorthands of the text format.
47    ///
48    /// If successful the AST was modified to be ready for binary encoding. A
49    /// [`Names`] structure is also returned so if you'd like to do your own
50    /// name lookups on the result you can do so as well.
51    ///
52    /// # Errors
53    ///
54    /// If an error happens during resolution, such a name resolution error or
55    /// items are found in the wrong order, then an error is returned.
56    pub fn resolve(&mut self) -> std::result::Result<Names<'a>, crate::Error> {
57        let names = match &mut self.kind {
58            ModuleKind::Text(fields) => crate::core::resolve::resolve(fields)?,
59            ModuleKind::Binary(_blobs) => Default::default(),
60        };
61        Ok(names)
62    }
63
64    /// Encodes this [`Module`] to its binary form.
65    ///
66    /// This function will take the textual representation in [`Module`] and
67    /// perform all steps necessary to convert it to a binary WebAssembly
68    /// module, suitable for writing to a `*.wasm` file. This function may
69    /// internally modify the [`Module`], for example:
70    ///
71    /// * Name resolution is performed to ensure that `Index::Id` isn't present
72    ///   anywhere in the AST.
73    ///
74    /// * Inline shorthands such as imports/exports/types are all expanded to be
75    ///   dedicated fields of the module.
76    ///
77    /// * Module fields may be shuffled around to preserve index ordering from
78    ///   expansions.
79    ///
80    /// After all of this expansion has happened the module will be converted to
81    /// its binary form and returned as a `Vec<u8>`. This is then suitable to
82    /// hand off to other wasm runtimes and such.
83    ///
84    /// # Errors
85    ///
86    /// This function can return an error for name resolution errors and other
87    /// expansion-related errors.
88    pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> {
89        EncodeOptions::default().encode_module(self)
90    }
91
92    pub(crate) fn parse_without_module_keyword(
93        module_keyword_span: Span,
94        parser: Parser<'a>,
95    ) -> Result<Self> {
96        let id = parser.parse()?;
97        let name = parser.parse()?;
98
99        let kind = if parser.peek::<kw::binary>()? {
100            parser.parse::<kw::binary>()?;
101            let mut data = Vec::new();
102            while !parser.is_empty() {
103                data.push(parser.parse()?);
104            }
105            ModuleKind::Binary(data)
106        } else {
107            ModuleKind::Text(ModuleField::parse_remaining(parser)?)
108        };
109        Ok(Module {
110            span: module_keyword_span,
111            id,
112            name,
113            kind,
114        })
115    }
116}
117
118impl<'a> Parse<'a> for Module<'a> {
119    fn parse(parser: Parser<'a>) -> Result<Self> {
120        parser.with_standard_annotations_registered(|parser| {
121            let span = parser.parse::<kw::module>()?.0;
122            Self::parse_without_module_keyword(span, parser)
123        })
124    }
125}
126
127/// A listing of all possible fields that can make up a WebAssembly module.
128#[allow(missing_docs)]
129#[derive(Debug)]
130pub enum ModuleField<'a> {
131    Type(Type<'a>),
132    Rec(Rec<'a>),
133    Import(Import<'a>),
134    Func(Func<'a>),
135    Table(Table<'a>),
136    Memory(Memory<'a>),
137    Global(Global<'a>),
138    Export(Export<'a>),
139    Start(Index<'a>),
140    Elem(Elem<'a>),
141    Data(Data<'a>),
142    Tag(Tag<'a>),
143    Custom(Custom<'a>),
144}
145
146impl<'a> ModuleField<'a> {
147    pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ModuleField<'a>>> {
148        let mut fields = Vec::new();
149        while !parser.is_empty() {
150            fields.push(parser.parens(ModuleField::parse)?);
151        }
152        Ok(fields)
153    }
154}
155
156impl<'a> Parse<'a> for ModuleField<'a> {
157    fn parse(parser: Parser<'a>) -> Result<Self> {
158        if parser.peek::<Type<'a>>()? {
159            return Ok(ModuleField::Type(parser.parse()?));
160        }
161        if parser.peek::<kw::rec>()? {
162            return Ok(ModuleField::Rec(parser.parse()?));
163        }
164        if parser.peek::<kw::import>()? {
165            return Ok(ModuleField::Import(parser.parse()?));
166        }
167        if parser.peek::<kw::func>()? {
168            return Ok(ModuleField::Func(parser.parse()?));
169        }
170        if parser.peek::<kw::table>()? {
171            return Ok(ModuleField::Table(parser.parse()?));
172        }
173        if parser.peek::<kw::memory>()? {
174            return Ok(ModuleField::Memory(parser.parse()?));
175        }
176        if parser.peek::<kw::global>()? {
177            return Ok(ModuleField::Global(parser.parse()?));
178        }
179        if parser.peek::<kw::export>()? {
180            return Ok(ModuleField::Export(parser.parse()?));
181        }
182        if parser.peek::<kw::start>()? {
183            parser.parse::<kw::start>()?;
184            return Ok(ModuleField::Start(parser.parse()?));
185        }
186        if parser.peek::<kw::elem>()? {
187            return Ok(ModuleField::Elem(parser.parse()?));
188        }
189        if parser.peek::<kw::data>()? {
190            return Ok(ModuleField::Data(parser.parse()?));
191        }
192        if parser.peek::<kw::tag>()? {
193            return Ok(ModuleField::Tag(parser.parse()?));
194        }
195        if parser.peek::<annotation::custom>()?
196            || parser.peek::<annotation::producers>()?
197            || parser.peek::<annotation::dylink_0>()?
198        {
199            return Ok(ModuleField::Custom(parser.parse()?));
200        }
201        Err(parser.error("expected valid module field"))
202    }
203}