1 | use crate::core::*; |
2 | use crate::kw; |
3 | use crate::parser::{Parse, Parser, Result}; |
4 | use 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)] |
10 | pub 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)] |
30 | pub 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 | |
48 | impl<'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)] |
85 | pub 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 |
98 | pub struct LocalParser<'a> { |
99 | /// All the locals associated with this `local` instruction. |
100 | pub locals: Vec<Local<'a>>, |
101 | } |
102 | |
103 | impl<'a> Parse<'a> for LocalParser<'a> { |
104 | fn parse(parser: Parser<'a>) -> Result<Self> { |
105 | let mut locals: Vec> = 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: ValType<'_> = parser.parse()?; |
111 | let parse_more: bool = 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 | |
125 | impl<'a> Local<'a> { |
126 | pub(crate) fn parse_remainder(parser: Parser<'a>) -> Result<Vec<Local<'a>>> { |
127 | let mut locals: Vec> = Vec::new(); |
128 | while parser.peek2::<kw::local>()? { |
129 | parser.parens(|p: Parser<'a>| { |
130 | locals.extend(iter:p.parse::<LocalParser>()?.locals); |
131 | Ok(()) |
132 | })?; |
133 | } |
134 | Ok(locals) |
135 | } |
136 | } |
137 | |