wast/core/func.rs
1use crate::core::*;
2use crate::kw;
3use crate::parser::{Parse, Parser, Result};
4use crate::token::{Id, NameAnnotation, Span};
5
6/// A WebAssembly function to be inserted into a module.
7///
8/// This is a member of both the function and code sections.
9#[derive(Debug)]
10pub struct Func<'a> {
11 /// Where this `func` was defined.
12 pub span: Span,
13 /// An identifier that this function is resolved with (optionally) for name
14 /// resolution.
15 pub id: Option<Id<'a>>,
16 /// An optional name for this function stored in the custom `name` section.
17 pub name: Option<NameAnnotation<'a>>,
18 /// If present, inline export annotations which indicate names this
19 /// definition should be exported under.
20 pub exports: InlineExport<'a>,
21 /// What kind of function this is, be it an inline-defined or imported
22 /// function.
23 pub kind: FuncKind<'a>,
24 /// The type that this function will have.
25 pub ty: TypeUse<'a, FunctionType<'a>>,
26}
27
28/// Possible ways to define a function in the text format.
29#[derive(Debug)]
30pub enum FuncKind<'a> {
31 /// A function which is actually defined as an import, such as:
32 ///
33 /// ```text
34 /// (func (type 3) (import "foo" "bar"))
35 /// ```
36 Import(InlineImport<'a>),
37
38 /// Almost all functions, those defined inline in a wasm module.
39 Inline {
40 /// The list of locals, if any, for this function.
41 locals: Box<[Local<'a>]>,
42
43 /// The instructions of the function.
44 expression: Expression<'a>,
45 },
46}
47
48impl<'a> Parse<'a> for Func<'a> {
49 fn parse(parser: Parser<'a>) -> Result<Self> {
50 let span = parser.parse::<kw::func>()?.0;
51 let id = parser.parse()?;
52 let name = parser.parse()?;
53 let exports = parser.parse()?;
54
55 let (ty, kind) = if let Some(import) = parser.parse()? {
56 (parser.parse()?, FuncKind::Import(import))
57 } else {
58 let ty = parser.parse()?;
59 let locals = Local::parse_remainder(parser)?.into();
60 (
61 ty,
62 FuncKind::Inline {
63 locals,
64 expression: parser.parse()?,
65 },
66 )
67 };
68
69 Ok(Func {
70 span,
71 id,
72 name,
73 exports,
74 ty,
75 kind,
76 })
77 }
78}
79
80/// A local for a `func` or `let` instruction.
81///
82/// Each local has an optional identifier for name resolution, an optional name
83/// for the custom `name` section, and a value type.
84#[derive(Debug, Clone)]
85pub struct Local<'a> {
86 /// An identifier that this local is resolved with (optionally) for name
87 /// resolution.
88 pub id: Option<Id<'a>>,
89 /// An optional name for this local stored in the custom `name` section.
90 pub name: Option<NameAnnotation<'a>>,
91 /// The value type of this local.
92 pub ty: ValType<'a>,
93}
94
95/// Parser for `local` instruction.
96///
97/// A single `local` instruction can generate multiple locals, hence this parser
98pub struct LocalParser<'a> {
99 /// All the locals associated with this `local` instruction.
100 pub locals: Vec<Local<'a>>,
101}
102
103impl<'a> Parse<'a> for LocalParser<'a> {
104 fn parse(parser: Parser<'a>) -> Result<Self> {
105 let mut locals = Vec::new();
106 parser.parse::<kw::local>()?;
107 if !parser.is_empty() {
108 let id: Option<_> = parser.parse()?;
109 let name: Option<_> = parser.parse()?;
110 let ty = parser.parse()?;
111 let parse_more = id.is_none() && name.is_none();
112 locals.push(Local { id, name, ty });
113 while parse_more && !parser.is_empty() {
114 locals.push(Local {
115 id: None,
116 name: None,
117 ty: parser.parse()?,
118 });
119 }
120 }
121 Ok(LocalParser { locals })
122 }
123}
124
125impl<'a> Local<'a> {
126 pub(crate) fn parse_remainder(parser: Parser<'a>) -> Result<Vec<Local<'a>>> {
127 let mut locals = Vec::new();
128 while parser.peek2::<kw::local>()? {
129 parser.parens(|p| {
130 locals.extend(p.parse::<LocalParser>()?.locals);
131 Ok(())
132 })?;
133 }
134 Ok(locals)
135 }
136}