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 validate(&self, parser: Parser<'_>) -> Result<()> {
93 let mut starts = 0;
94 if let ModuleKind::Text(fields) = &self.kind {
95 for item in fields.iter() {
96 if let ModuleField::Start(_) = item {
97 starts += 1;
98 }
99 }
100 }
101 if starts > 1 {
102 return Err(parser.error("multiple start sections found"));
103 }
104 Ok(())
105 }
106
107 pub(crate) fn parse_without_module_keyword(
108 module_keyword_span: Span,
109 parser: Parser<'a>,
110 ) -> Result<Self> {
111 let id = parser.parse()?;
112 let name = parser.parse()?;
113
114 let kind = if parser.peek::<kw::binary>()? {
115 parser.parse::<kw::binary>()?;
116 let mut data = Vec::new();
117 while !parser.is_empty() {
118 data.push(parser.parse()?);
119 }
120 ModuleKind::Binary(data)
121 } else {
122 ModuleKind::Text(ModuleField::parse_remaining(parser)?)
123 };
124 Ok(Module {
125 span: module_keyword_span,
126 id,
127 name,
128 kind,
129 })
130 }
131}
132
133impl<'a> Parse<'a> for Module<'a> {
134 fn parse(parser: Parser<'a>) -> Result<Self> {
135 parser.with_standard_annotations_registered(|parser: Parser<'a>| {
136 let span: Span = parser.parse::<kw::module>()?.0;
137 Self::parse_without_module_keyword(span, parser)
138 })
139 }
140}
141
142/// A listing of all possible fields that can make up a WebAssembly module.
143#[allow(missing_docs)]
144#[derive(Debug)]
145pub enum ModuleField<'a> {
146 Type(Type<'a>),
147 Rec(Rec<'a>),
148 Import(Import<'a>),
149 Func(Func<'a>),
150 Table(Table<'a>),
151 Memory(Memory<'a>),
152 Global(Global<'a>),
153 Export(Export<'a>),
154 Start(Index<'a>),
155 Elem(Elem<'a>),
156 Data(Data<'a>),
157 Tag(Tag<'a>),
158 Custom(Custom<'a>),
159}
160
161impl<'a> ModuleField<'a> {
162 pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ModuleField<'a>>> {
163 let mut fields: Vec> = Vec::new();
164 while !parser.is_empty() {
165 fields.push(parser.parens(ModuleField::parse)?);
166 }
167 Ok(fields)
168 }
169}
170
171impl<'a> Parse<'a> for ModuleField<'a> {
172 fn parse(parser: Parser<'a>) -> Result<Self> {
173 if parser.peek::<Type<'a>>()? {
174 return Ok(ModuleField::Type(parser.parse()?));
175 }
176 if parser.peek::<kw::rec>()? {
177 return Ok(ModuleField::Rec(parser.parse()?));
178 }
179 if parser.peek::<kw::import>()? {
180 return Ok(ModuleField::Import(parser.parse()?));
181 }
182 if parser.peek::<kw::func>()? {
183 return Ok(ModuleField::Func(parser.parse()?));
184 }
185 if parser.peek::<kw::table>()? {
186 return Ok(ModuleField::Table(parser.parse()?));
187 }
188 if parser.peek::<kw::memory>()? {
189 return Ok(ModuleField::Memory(parser.parse()?));
190 }
191 if parser.peek::<kw::global>()? {
192 return Ok(ModuleField::Global(parser.parse()?));
193 }
194 if parser.peek::<kw::export>()? {
195 return Ok(ModuleField::Export(parser.parse()?));
196 }
197 if parser.peek::<kw::start>()? {
198 parser.parse::<kw::start>()?;
199 return Ok(ModuleField::Start(parser.parse()?));
200 }
201 if parser.peek::<kw::elem>()? {
202 return Ok(ModuleField::Elem(parser.parse()?));
203 }
204 if parser.peek::<kw::data>()? {
205 return Ok(ModuleField::Data(parser.parse()?));
206 }
207 if parser.peek::<kw::tag>()? {
208 return Ok(ModuleField::Tag(parser.parse()?));
209 }
210 if parser.peek::<annotation::custom>()?
211 || parser.peek::<annotation::producers>()?
212 || parser.peek::<annotation::dylink_0>()?
213 {
214 return Ok(ModuleField::Custom(parser.parse()?));
215 }
216 Err(parser.error("expected valid module field"))
217 }
218}
219