1 | use crate::parser::{Parse, Parser, Result}; |
2 | use crate::token::{self, Span}; |
3 | use crate::{annotation, kw}; |
4 | |
5 | /// A custom section within a wasm module. |
6 | #[derive (Debug)] |
7 | pub enum Custom<'a> { |
8 | /// A raw custom section with the manual placement and bytes specified. |
9 | Raw(RawCustomSection<'a>), |
10 | /// A producers custom section. |
11 | Producers(Producers<'a>), |
12 | /// The `dylink.0` custom section |
13 | Dylink0(Dylink0<'a>), |
14 | } |
15 | |
16 | impl Custom<'_> { |
17 | /// Where this custom section is placed. |
18 | pub fn place(&self) -> CustomPlace { |
19 | match self { |
20 | Custom::Raw(s: &RawCustomSection<'_>) => s.place, |
21 | Custom::Producers(_) => CustomPlace::AfterLast, |
22 | Custom::Dylink0(_) => CustomPlace::BeforeFirst, |
23 | } |
24 | } |
25 | |
26 | /// The name of this custom section |
27 | pub fn name(&self) -> &str { |
28 | match self { |
29 | Custom::Raw(s: &RawCustomSection<'_>) => s.name, |
30 | Custom::Producers(_) => "producers" , |
31 | Custom::Dylink0(_) => "dylink.0" , |
32 | } |
33 | } |
34 | } |
35 | |
36 | impl<'a> Parse<'a> for Custom<'a> { |
37 | fn parse(parser: Parser<'a>) -> Result<Self> { |
38 | if parser.peek::<annotation::producers>()? { |
39 | Ok(Custom::Producers(parser.parse()?)) |
40 | } else if parser.peek::<annotation::dylink_0>()? { |
41 | Ok(Custom::Dylink0(parser.parse()?)) |
42 | } else { |
43 | Ok(Custom::Raw(parser.parse()?)) |
44 | } |
45 | } |
46 | } |
47 | |
48 | /// A wasm custom section within a module. |
49 | #[derive (Debug)] |
50 | pub struct RawCustomSection<'a> { |
51 | /// Where this `@custom` was defined. |
52 | pub span: Span, |
53 | |
54 | /// Name of the custom section. |
55 | pub name: &'a str, |
56 | |
57 | /// Where the custom section is being placed, |
58 | pub place: CustomPlace, |
59 | |
60 | /// Payload of this custom section. |
61 | pub data: Vec<&'a [u8]>, |
62 | } |
63 | |
64 | /// Possible locations to place a custom section within a module. |
65 | #[derive (Debug, PartialEq, Copy, Clone)] |
66 | pub enum CustomPlace { |
67 | /// This custom section will appear before the first section in the module. |
68 | BeforeFirst, |
69 | /// This custom section will be placed just before a known section. |
70 | Before(CustomPlaceAnchor), |
71 | /// This custom section will be placed just after a known section. |
72 | After(CustomPlaceAnchor), |
73 | /// This custom section will appear after the last section in the module. |
74 | AfterLast, |
75 | } |
76 | |
77 | /// Known sections that custom sections can be placed relative to. |
78 | #[derive (Debug, PartialEq, Eq, Copy, Clone)] |
79 | #[allow (missing_docs)] |
80 | pub enum CustomPlaceAnchor { |
81 | Type, |
82 | Import, |
83 | Func, |
84 | Table, |
85 | Memory, |
86 | Global, |
87 | Export, |
88 | Start, |
89 | Elem, |
90 | Code, |
91 | Data, |
92 | Tag, |
93 | } |
94 | |
95 | impl<'a> Parse<'a> for RawCustomSection<'a> { |
96 | fn parse(parser: Parser<'a>) -> Result<Self> { |
97 | let span: Span = parser.parse::<annotation::custom>()?.0; |
98 | let name: &str = parser.parse()?; |
99 | let place: CustomPlace = if parser.peek::<token::LParen>()? { |
100 | parser.parens(|p: Parser<'a>| p.parse())? |
101 | } else { |
102 | CustomPlace::AfterLast |
103 | }; |
104 | let mut data: Vec<&[u8]> = Vec::new(); |
105 | while !parser.is_empty() { |
106 | data.push(parser.parse()?); |
107 | } |
108 | Ok(RawCustomSection { |
109 | span, |
110 | name, |
111 | place, |
112 | data, |
113 | }) |
114 | } |
115 | } |
116 | |
117 | impl<'a> Parse<'a> for CustomPlace { |
118 | fn parse(parser: Parser<'a>) -> Result<Self> { |
119 | let mut l: Lookahead1<'_> = parser.lookahead1(); |
120 | let ctor: fn(CustomPlaceAnchor) -> … = if l.peek::<kw::before>()? { |
121 | parser.parse::<kw::before>()?; |
122 | if l.peek::<kw::first>()? { |
123 | parser.parse::<kw::first>()?; |
124 | return Ok(CustomPlace::BeforeFirst); |
125 | } |
126 | CustomPlace::Before as fn(CustomPlaceAnchor) -> _ |
127 | } else if l.peek::<kw::after>()? { |
128 | parser.parse::<kw::after>()?; |
129 | if l.peek::<kw::last>()? { |
130 | parser.parse::<kw::last>()?; |
131 | return Ok(CustomPlace::AfterLast); |
132 | } |
133 | CustomPlace::After |
134 | } else { |
135 | return Err(l.error()); |
136 | }; |
137 | Ok(ctor(parser.parse()?)) |
138 | } |
139 | } |
140 | |
141 | impl<'a> Parse<'a> for CustomPlaceAnchor { |
142 | fn parse(parser: Parser<'a>) -> Result<Self> { |
143 | if parser.peek::<kw::r#type>()? { |
144 | parser.parse::<kw::r#type>()?; |
145 | return Ok(CustomPlaceAnchor::Type); |
146 | } |
147 | if parser.peek::<kw::import>()? { |
148 | parser.parse::<kw::import>()?; |
149 | return Ok(CustomPlaceAnchor::Import); |
150 | } |
151 | if parser.peek::<kw::func>()? { |
152 | parser.parse::<kw::func>()?; |
153 | return Ok(CustomPlaceAnchor::Func); |
154 | } |
155 | if parser.peek::<kw::table>()? { |
156 | parser.parse::<kw::table>()?; |
157 | return Ok(CustomPlaceAnchor::Table); |
158 | } |
159 | if parser.peek::<kw::memory>()? { |
160 | parser.parse::<kw::memory>()?; |
161 | return Ok(CustomPlaceAnchor::Memory); |
162 | } |
163 | if parser.peek::<kw::global>()? { |
164 | parser.parse::<kw::global>()?; |
165 | return Ok(CustomPlaceAnchor::Global); |
166 | } |
167 | if parser.peek::<kw::export>()? { |
168 | parser.parse::<kw::export>()?; |
169 | return Ok(CustomPlaceAnchor::Export); |
170 | } |
171 | if parser.peek::<kw::start>()? { |
172 | parser.parse::<kw::start>()?; |
173 | return Ok(CustomPlaceAnchor::Start); |
174 | } |
175 | if parser.peek::<kw::elem>()? { |
176 | parser.parse::<kw::elem>()?; |
177 | return Ok(CustomPlaceAnchor::Elem); |
178 | } |
179 | if parser.peek::<kw::code>()? { |
180 | parser.parse::<kw::code>()?; |
181 | return Ok(CustomPlaceAnchor::Code); |
182 | } |
183 | if parser.peek::<kw::data>()? { |
184 | parser.parse::<kw::data>()?; |
185 | return Ok(CustomPlaceAnchor::Data); |
186 | } |
187 | if parser.peek::<kw::tag>()? { |
188 | parser.parse::<kw::tag>()?; |
189 | return Ok(CustomPlaceAnchor::Tag); |
190 | } |
191 | |
192 | Err(parser.error("expected a valid section name" )) |
193 | } |
194 | } |
195 | |
196 | /// A producers custom section |
197 | #[allow (missing_docs)] |
198 | #[derive (Debug)] |
199 | pub struct Producers<'a> { |
200 | pub fields: Vec<(&'a str, Vec<(&'a str, &'a str)>)>, |
201 | } |
202 | |
203 | impl<'a> Parse<'a> for Producers<'a> { |
204 | fn parse(parser: Parser<'a>) -> Result<Self> { |
205 | parser.parse::<annotation::producers>()?.0; |
206 | let mut languages = Vec::new(); |
207 | let mut sdks = Vec::new(); |
208 | let mut processed_by = Vec::new(); |
209 | while !parser.is_empty() { |
210 | parser.parens(|parser| { |
211 | let mut l = parser.lookahead1(); |
212 | let dst = if l.peek::<kw::language>()? { |
213 | parser.parse::<kw::language>()?; |
214 | &mut languages |
215 | } else if l.peek::<kw::sdk>()? { |
216 | parser.parse::<kw::sdk>()?; |
217 | &mut sdks |
218 | } else if l.peek::<kw::processed_by>()? { |
219 | parser.parse::<kw::processed_by>()?; |
220 | &mut processed_by |
221 | } else { |
222 | return Err(l.error()); |
223 | }; |
224 | |
225 | dst.push((parser.parse()?, parser.parse()?)); |
226 | Ok(()) |
227 | })?; |
228 | } |
229 | |
230 | let mut fields = Vec::new(); |
231 | if !languages.is_empty() { |
232 | fields.push(("language" , languages)); |
233 | } |
234 | if !sdks.is_empty() { |
235 | fields.push(("sdk" , sdks)); |
236 | } |
237 | if !processed_by.is_empty() { |
238 | fields.push(("processed-by" , processed_by)); |
239 | } |
240 | Ok(Producers { fields }) |
241 | } |
242 | } |
243 | |
244 | /// A `dylink.0` custom section |
245 | #[allow (missing_docs)] |
246 | #[derive (Debug)] |
247 | pub struct Dylink0<'a> { |
248 | pub subsections: Vec<Dylink0Subsection<'a>>, |
249 | } |
250 | |
251 | /// Possible subsections of the `dylink.0` custom section |
252 | #[derive (Debug)] |
253 | #[allow (missing_docs)] |
254 | pub enum Dylink0Subsection<'a> { |
255 | MemInfo { |
256 | memory_size: u32, |
257 | memory_align: u32, |
258 | table_size: u32, |
259 | table_align: u32, |
260 | }, |
261 | Needed(Vec<&'a str>), |
262 | ExportInfo(Vec<(&'a str, u32)>), |
263 | ImportInfo(Vec<(&'a str, &'a str, u32)>), |
264 | } |
265 | |
266 | impl<'a> Parse<'a> for Dylink0<'a> { |
267 | fn parse(parser: Parser<'a>) -> Result<Self> { |
268 | parser.parse::<annotation::dylink_0>()?.0; |
269 | let mut ret: Dylink0<'_> = Dylink0 { |
270 | subsections: Vec::new(), |
271 | }; |
272 | while !parser.is_empty() { |
273 | parser.parens(|p: Parser<'a>| ret.parse_next(parser:p))?; |
274 | } |
275 | Ok(ret) |
276 | } |
277 | } |
278 | |
279 | impl<'a> Dylink0<'a> { |
280 | fn parse_next(&mut self, parser: Parser<'a>) -> Result<()> { |
281 | let mut l = parser.lookahead1(); |
282 | if l.peek::<kw::mem_info>()? { |
283 | parser.parse::<kw::mem_info>()?; |
284 | let mut memory_size = 0; |
285 | let mut memory_align = 0; |
286 | let mut table_size = 0; |
287 | let mut table_align = 0; |
288 | if parser.peek2::<kw::memory>()? { |
289 | parser.parens(|p| { |
290 | p.parse::<kw::memory>()?; |
291 | memory_size = p.parse()?; |
292 | memory_align = p.parse()?; |
293 | Ok(()) |
294 | })?; |
295 | } |
296 | if parser.peek2::<kw::table>()? { |
297 | parser.parens(|p| { |
298 | p.parse::<kw::table>()?; |
299 | table_size = p.parse()?; |
300 | table_align = p.parse()?; |
301 | Ok(()) |
302 | })?; |
303 | } |
304 | self.subsections.push(Dylink0Subsection::MemInfo { |
305 | memory_size, |
306 | memory_align, |
307 | table_size, |
308 | table_align, |
309 | }); |
310 | } else if l.peek::<kw::needed>()? { |
311 | parser.parse::<kw::needed>()?; |
312 | let mut names = Vec::new(); |
313 | while !parser.is_empty() { |
314 | names.push(parser.parse()?); |
315 | } |
316 | self.subsections.push(Dylink0Subsection::Needed(names)); |
317 | } else if l.peek::<kw::export_info>()? { |
318 | parser.parse::<kw::export_info>()?; |
319 | let name = parser.parse()?; |
320 | let flags = parse_sym_flags(parser)?; |
321 | match self.subsections.last_mut() { |
322 | Some(Dylink0Subsection::ExportInfo(list)) => list.push((name, flags)), |
323 | _ => self |
324 | .subsections |
325 | .push(Dylink0Subsection::ExportInfo(vec![(name, flags)])), |
326 | } |
327 | } else if l.peek::<kw::import_info>()? { |
328 | parser.parse::<kw::import_info>()?; |
329 | let module = parser.parse()?; |
330 | let name = parser.parse()?; |
331 | let flags = parse_sym_flags(parser)?; |
332 | match self.subsections.last_mut() { |
333 | Some(Dylink0Subsection::ImportInfo(list)) => list.push((module, name, flags)), |
334 | _ => self |
335 | .subsections |
336 | .push(Dylink0Subsection::ImportInfo(vec![(module, name, flags)])), |
337 | } |
338 | } else { |
339 | return Err(l.error()); |
340 | } |
341 | Ok(()) |
342 | } |
343 | } |
344 | |
345 | fn parse_sym_flags(parser: Parser<'_>) -> Result<u32> { |
346 | let mut flags = 0; |
347 | while !parser.is_empty() { |
348 | let mut l = parser.lookahead1(); |
349 | if l.peek::<u32>()? { |
350 | flags |= parser.parse::<u32>()?; |
351 | continue; |
352 | } |
353 | macro_rules! parse_flags { |
354 | ($($kw:tt = $val:expr,)*) => {$({ |
355 | custom_keyword!(flag = $kw); |
356 | if l.peek::<flag>()? { |
357 | parser.parse::<flag>()?; |
358 | flags |= $val; |
359 | continue; |
360 | } |
361 | })*}; |
362 | } |
363 | // N.B.: Keep in sync with `print_dylink0_flags` in `crates/wasmprinter/src/lib.rs`. |
364 | parse_flags! { |
365 | "binding-weak" = 1 << 0, |
366 | "binding-local" = 1 << 1, |
367 | "visibility-hidden" = 1 << 2, |
368 | "undefined" = 1 << 4, |
369 | "exported" = 1 << 5, |
370 | "explicit-name" = 1 << 6, |
371 | "no-strip" = 1 << 7, |
372 | "tls" = 1 << 8, |
373 | "absolute" = 1 << 9, |
374 | } |
375 | return Err(l.error()); |
376 | } |
377 | Ok(flags) |
378 | } |
379 | |
380 | mod flag {} |
381 | |
382 | impl Dylink0Subsection<'_> { |
383 | /// Returns the byte id of this subsection used to identify it. |
384 | pub fn id(&self) -> u8 { |
385 | use Dylink0Subsection::*; |
386 | match self { |
387 | MemInfo { .. } => 1, |
388 | Needed(..) => 2, |
389 | ExportInfo(..) => 3, |
390 | ImportInfo(..) => 4, |
391 | } |
392 | } |
393 | } |
394 | |