1use crate::kw;
2use crate::parser::{Cursor, Parse, Parser, Peek, Result};
3use crate::token::{Index, Span};
4
5/// A entry in a WebAssembly module's export section.
6#[derive(Debug)]
7pub 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)]
22pub enum ExportKind {
23 Func,
24 Table,
25 Memory,
26 Global,
27 Tag,
28}
29
30impl<'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
44impl<'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
68impl 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
81macro_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
97kw_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)]
108pub struct InlineExport<'a> {
109 /// The extra names to export an item as, if any.
110 pub names: Vec<&'a str>,
111}
112
113impl<'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
126impl 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