1use crate::parser::{Parse, Parser, Result};
2use crate::token::{self, Span};
3use crate::{annotation, kw};
4
5/// A custom section within a wasm module.
6#[derive(Debug)]
7pub 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
16impl 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
36impl<'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)]
50pub 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)]
66pub 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)]
80pub 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
95impl<'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
117impl<'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
141impl<'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)]
199pub struct Producers<'a> {
200 pub fields: Vec<(&'a str, Vec<(&'a str, &'a str)>)>,
201}
202
203impl<'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)]
247pub 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)]
254pub 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
266impl<'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
279impl<'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
345fn 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
380mod flag {}
381
382impl 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