1use crate::annotation;
2use crate::component::*;
3use crate::core::{self, Producers};
4use crate::kw;
5use crate::parser::{Parse, Parser, Result};
6use crate::token::Index;
7use crate::token::{Id, NameAnnotation, Span};
8
9/// A parsed WebAssembly component module.
10#[derive(Debug)]
11#[non_exhaustive]
12pub struct Component<'a> {
13 /// Where this `component` was defined
14 pub span: Span,
15 /// An optional identifier this component is known by
16 pub id: Option<Id<'a>>,
17 /// An optional `@name` annotation for this component
18 pub name: Option<NameAnnotation<'a>>,
19 /// What kind of component this was parsed as.
20 pub kind: ComponentKind<'a>,
21}
22
23/// The different kinds of ways to define a component.
24#[derive(Debug)]
25pub enum ComponentKind<'a> {
26 /// A component defined in the textual s-expression format.
27 Text(Vec<ComponentField<'a>>),
28 /// A component that had its raw binary bytes defined via the `binary`
29 /// directive.
30 Binary(Vec<&'a [u8]>),
31}
32
33impl<'a> Component<'a> {
34 /// Performs a name resolution pass on this [`Component`], 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 [`Component`] 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.
50 ///
51 /// # Errors
52 ///
53 /// If an error happens during resolution, such a name resolution error or
54 /// items are found in the wrong order, then an error is returned.
55 pub fn resolve(&mut self) -> std::result::Result<(), crate::Error> {
56 match &mut self.kind {
57 ComponentKind::Text(fields) => {
58 crate::component::expand::expand(fields);
59 }
60 ComponentKind::Binary(_) => {}
61 }
62 crate::component::resolve::resolve(self)
63 }
64
65 /// Encodes this [`Component`] to its binary form.
66 ///
67 /// This function will take the textual representation in [`Component`] and
68 /// perform all steps necessary to convert it to a binary WebAssembly
69 /// component, suitable for writing to a `*.wasm` file. This function may
70 /// internally modify the [`Component`], 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 component.
77 ///
78 /// * Component fields may be shuffled around to preserve index ordering from
79 /// expansions.
80 ///
81 /// After all of this expansion has happened the component 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) -> std::result::Result<Vec<u8>, crate::Error> {
90 crate::core::EncodeOptions::default().encode_component(self)
91 }
92
93 pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> {
94 let mut starts = 0;
95 if let ComponentKind::Text(fields) = &self.kind {
96 for item in fields.iter() {
97 if let ComponentField::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_component_keyword(
109 component_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 ComponentKind::Binary(data)
122 } else {
123 ComponentKind::Text(ComponentField::parse_remaining(parser)?)
124 };
125 Ok(Component {
126 span: component_keyword_span,
127 id,
128 name,
129 kind,
130 })
131 }
132}
133
134impl<'a> Parse<'a> for Component<'a> {
135 fn parse(parser: Parser<'a>) -> Result<Self> {
136 parser.with_standard_annotations_registered(|parser: Parser<'a>| {
137 let span: Span = parser.parse::<kw::component>()?.0;
138 Component::parse_without_component_keyword(span, parser)
139 })
140 }
141}
142
143/// A listing of all possible fields that can make up a WebAssembly component.
144#[allow(missing_docs)]
145#[derive(Debug)]
146pub enum ComponentField<'a> {
147 CoreModule(CoreModule<'a>),
148 CoreInstance(CoreInstance<'a>),
149 CoreType(CoreType<'a>),
150 CoreRec(core::Rec<'a>),
151 Component(NestedComponent<'a>),
152 Instance(Instance<'a>),
153 Alias(Alias<'a>),
154 Type(Type<'a>),
155 CanonicalFunc(CanonicalFunc<'a>),
156 CoreFunc(CoreFunc<'a>), // Supports inverted forms of other items
157 Func(Func<'a>), // Supports inverted forms of other items
158 Start(Start<'a>),
159 Import(ComponentImport<'a>),
160 Export(ComponentExport<'a>),
161 Custom(Custom<'a>),
162 Producers(Producers<'a>),
163}
164
165impl<'a> ComponentField<'a> {
166 fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ComponentField<'a>>> {
167 let mut fields: Vec> = Vec::new();
168 while !parser.is_empty() {
169 fields.push(parser.parens(ComponentField::parse)?);
170 }
171 Ok(fields)
172 }
173}
174
175impl<'a> Parse<'a> for ComponentField<'a> {
176 fn parse(parser: Parser<'a>) -> Result<Self> {
177 if parser.peek::<kw::core>()? {
178 if parser.peek2::<kw::module>()? {
179 return Ok(Self::CoreModule(parser.parse()?));
180 }
181 if parser.peek2::<kw::instance>()? {
182 return Ok(Self::CoreInstance(parser.parse()?));
183 }
184 if parser.peek2::<kw::r#type>()? {
185 return Ok(Self::CoreType(parser.parse()?));
186 }
187 if parser.peek2::<kw::func>()? {
188 return Ok(Self::CoreFunc(parser.parse()?));
189 }
190 if parser.peek2::<kw::rec>()? {
191 parser.parse::<kw::core>()?;
192 return Ok(Self::CoreRec(parser.parse()?));
193 }
194 } else {
195 if parser.peek::<kw::component>()? {
196 return Ok(Self::Component(parser.parse()?));
197 }
198 if parser.peek::<kw::instance>()? {
199 return Ok(Self::Instance(parser.parse()?));
200 }
201 if parser.peek::<kw::alias>()? {
202 return Ok(Self::Alias(parser.parse()?));
203 }
204 if parser.peek::<kw::r#type>()? {
205 return Ok(Self::Type(Type::parse_maybe_with_inline_exports(parser)?));
206 }
207 if parser.peek::<kw::import>()? {
208 return Ok(Self::Import(parser.parse()?));
209 }
210 if parser.peek::<kw::func>()? {
211 return Ok(Self::Func(parser.parse()?));
212 }
213 if parser.peek::<kw::export>()? {
214 return Ok(Self::Export(parser.parse()?));
215 }
216 if parser.peek::<kw::start>()? {
217 return Ok(Self::Start(parser.parse()?));
218 }
219 if parser.peek::<annotation::custom>()? {
220 return Ok(Self::Custom(parser.parse()?));
221 }
222 if parser.peek::<annotation::producers>()? {
223 return Ok(Self::Producers(parser.parse()?));
224 }
225 }
226 Err(parser.error("expected valid component field"))
227 }
228}
229
230/// A function to call at instantiation time.
231#[derive(Debug)]
232pub struct Start<'a> {
233 /// The function to call.
234 pub func: Index<'a>,
235 /// The arguments to pass to the function.
236 pub args: Vec<ItemRef<'a, kw::value>>,
237 /// Names of the result values.
238 pub results: Vec<Option<Id<'a>>>,
239}
240
241impl<'a> Parse<'a> for Start<'a> {
242 fn parse(parser: Parser<'a>) -> Result<Self> {
243 parser.parse::<kw::start>()?;
244 let func = parser.parse()?;
245 let mut args = Vec::new();
246 while !parser.is_empty() && !parser.peek2::<kw::result>()? {
247 args.push(parser.parens(|parser| parser.parse())?);
248 }
249
250 let mut results = Vec::new();
251 while !parser.is_empty() && parser.peek2::<kw::result>()? {
252 results.push(parser.parens(|parser| {
253 parser.parse::<kw::result>()?;
254 parser.parens(|parser| {
255 parser.parse::<kw::value>()?;
256 parser.parse()
257 })
258 })?);
259 }
260
261 Ok(Start {
262 func,
263 args,
264 results,
265 })
266 }
267}
268
269/// A nested WebAssembly component.
270#[derive(Debug)]
271pub struct NestedComponent<'a> {
272 /// Where this `component` was defined
273 pub span: Span,
274 /// An optional identifier this component is known by
275 pub id: Option<Id<'a>>,
276 /// An optional `@name` annotation for this component
277 pub name: Option<NameAnnotation<'a>>,
278 /// If present, inline export annotations which indicate names this
279 /// definition should be exported under.
280 pub exports: InlineExport<'a>,
281 /// What kind of component this was parsed as.
282 pub kind: NestedComponentKind<'a>,
283}
284
285/// The different kinds of ways to define a nested component.
286#[derive(Debug)]
287pub enum NestedComponentKind<'a> {
288 /// This is actually an inline import of a component
289 Import {
290 /// The information about where this is being imported from.
291 import: InlineImport<'a>,
292 /// The type of component being imported.
293 ty: ComponentTypeUse<'a, ComponentType<'a>>,
294 },
295 /// The component is defined inline as a local definition with its fields
296 /// listed here.
297 Inline(Vec<ComponentField<'a>>),
298}
299
300impl<'a> Parse<'a> for NestedComponent<'a> {
301 fn parse(parser: Parser<'a>) -> Result<Self> {
302 parser.depth_check()?;
303
304 let span = parser.parse::<kw::component>()?.0;
305 let id = parser.parse()?;
306 let name = parser.parse()?;
307 let exports = parser.parse()?;
308
309 let kind = if let Some(import) = parser.parse()? {
310 NestedComponentKind::Import {
311 import,
312 ty: parser.parse()?,
313 }
314 } else {
315 let mut fields = Vec::new();
316 while !parser.is_empty() {
317 fields.push(parser.parens(|p| p.parse())?);
318 }
319 NestedComponentKind::Inline(fields)
320 };
321
322 Ok(NestedComponent {
323 span,
324 id,
325 name,
326 exports,
327 kind,
328 })
329 }
330}
331