1 | use crate::kw; |
2 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
3 | use crate::token::{Index, Span}; |
4 | |
5 | /// A entry in a WebAssembly module's export section. |
6 | #[derive (Debug)] |
7 | pub struct Export<'a> { |
8 | /// Where this export was defined. |
9 | pub span: Span, |
10 | /// The name of this export from the module. |
11 | pub name: &'a str, |
12 | /// The kind of item being exported. |
13 | pub kind: ExportKind, |
14 | /// What's being exported from the module. |
15 | pub item: Index<'a>, |
16 | } |
17 | |
18 | /// Different kinds of elements that can be exported from a WebAssembly module, |
19 | /// contained in an [`Export`]. |
20 | #[derive (Debug, Clone, Copy, Hash, Eq, PartialEq)] |
21 | #[allow (missing_docs)] |
22 | pub enum ExportKind { |
23 | Func, |
24 | Table, |
25 | Memory, |
26 | Global, |
27 | Tag, |
28 | } |
29 | |
30 | impl<'a> Parse<'a> for Export<'a> { |
31 | fn parse(parser: Parser<'a>) -> Result<Self> { |
32 | let span: Span = parser.parse::<kw::export>()?.0; |
33 | let name: &str = parser.parse()?; |
34 | let (kind: ExportKind, item: Index<'_>) = parser.parens(|p: Parser<'a>| Ok((p.parse()?, p.parse()?)))?; |
35 | Ok(Export { |
36 | span, |
37 | name, |
38 | kind, |
39 | item, |
40 | }) |
41 | } |
42 | } |
43 | |
44 | impl<'a> Parse<'a> for ExportKind { |
45 | fn parse(parser: Parser<'a>) -> Result<Self> { |
46 | let mut l: Lookahead1<'_> = parser.lookahead1(); |
47 | if l.peek::<kw::func>()? { |
48 | parser.parse::<kw::func>()?; |
49 | Ok(ExportKind::Func) |
50 | } else if l.peek::<kw::table>()? { |
51 | parser.parse::<kw::table>()?; |
52 | Ok(ExportKind::Table) |
53 | } else if l.peek::<kw::memory>()? { |
54 | parser.parse::<kw::memory>()?; |
55 | Ok(ExportKind::Memory) |
56 | } else if l.peek::<kw::global>()? { |
57 | parser.parse::<kw::global>()?; |
58 | Ok(ExportKind::Global) |
59 | } else if l.peek::<kw::tag>()? { |
60 | parser.parse::<kw::tag>()?; |
61 | Ok(ExportKind::Tag) |
62 | } else { |
63 | Err(l.error()) |
64 | } |
65 | } |
66 | } |
67 | |
68 | impl Peek for ExportKind { |
69 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
70 | Ok(kw::func::peek(cursor)? |
71 | || kw::table::peek(cursor)? |
72 | || kw::memory::peek(cursor)? |
73 | || kw::global::peek(cursor)? |
74 | || kw::tag::peek(cursor)?) |
75 | } |
76 | fn display() -> &'static str { |
77 | "export kind" |
78 | } |
79 | } |
80 | |
81 | macro_rules! kw_conversions { |
82 | ($($kw:ident => $kind:ident)*) => ($( |
83 | impl From<kw::$kw> for ExportKind { |
84 | fn from(_: kw::$kw) -> ExportKind { |
85 | ExportKind::$kind |
86 | } |
87 | } |
88 | |
89 | impl Default for kw::$kw { |
90 | fn default() -> kw::$kw { |
91 | kw::$kw(Span::from_offset(0)) |
92 | } |
93 | } |
94 | )*); |
95 | } |
96 | |
97 | kw_conversions! { |
98 | func => Func |
99 | table => Table |
100 | global => Global |
101 | tag => Tag |
102 | memory => Memory |
103 | } |
104 | |
105 | /// A listing of inline `(export "foo")` statements on a WebAssembly item in |
106 | /// its textual format. |
107 | #[derive (Debug, Default)] |
108 | pub struct InlineExport<'a> { |
109 | /// The extra names to export an item as, if any. |
110 | pub names: Vec<&'a str>, |
111 | } |
112 | |
113 | impl<'a> Parse<'a> for InlineExport<'a> { |
114 | fn parse(parser: Parser<'a>) -> Result<Self> { |
115 | let mut names: Vec<&str> = Vec::new(); |
116 | while parser.peek::<Self>()? { |
117 | names.push(parser.parens(|p: Parser<'a>| { |
118 | p.parse::<kw::export>()?; |
119 | p.parse::<&str>() |
120 | })?); |
121 | } |
122 | Ok(InlineExport { names }) |
123 | } |
124 | } |
125 | |
126 | impl Peek for InlineExport<'_> { |
127 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
128 | let cursor: Cursor<'_> = match cursor.lparen()? { |
129 | Some(cursor: Cursor<'_>) => cursor, |
130 | None => return Ok(false), |
131 | }; |
132 | let cursor: Cursor<'_> = match cursor.keyword()? { |
133 | Some(("export" , cursor: Cursor<'_>)) => cursor, |
134 | _ => return Ok(false), |
135 | }; |
136 | let cursor: Cursor<'_> = match cursor.string()? { |
137 | Some((_, cursor: Cursor<'_>)) => cursor, |
138 | None => return Ok(false), |
139 | }; |
140 | Ok(cursor.rparen()?.is_some()) |
141 | } |
142 | |
143 | fn display() -> &'static str { |
144 | "inline export" |
145 | } |
146 | } |
147 | |