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