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}