1use super::{ComponentExternName, ItemRef, ItemSigNoName};
2use crate::kw;
3use crate::parser::{Cursor, Parse, Parser, Peek, Result};
4use crate::token::{Id, Index, NameAnnotation, Span};
5
6/// An entry in a WebAssembly component's export section.
7#[derive(Debug)]
8pub struct ComponentExport<'a> {
9 /// Where this export was defined.
10 pub span: Span,
11 /// Optional identifier bound to this export.
12 pub id: Option<Id<'a>>,
13 /// An optional name for this instance stored in the custom `name` section.
14 pub debug_name: Option<NameAnnotation<'a>>,
15 /// The name of this export from the component.
16 pub name: ComponentExternName<'a>,
17 /// The kind of export.
18 pub kind: ComponentExportKind<'a>,
19 /// The kind of export.
20 pub ty: Option<ItemSigNoName<'a>>,
21}
22
23impl<'a> Parse<'a> for ComponentExport<'a> {
24 fn parse(parser: Parser<'a>) -> Result<Self> {
25 let span: Span = parser.parse::<kw::export>()?.0;
26 let id: Option> = parser.parse()?;
27 let debug_name: Option> = parser.parse()?;
28 let name: ComponentExternName<'_> = parser.parse()?;
29 let kind: ComponentExportKind<'_> = parser.parse()?;
30 let ty: Option> = if !parser.is_empty() {
31 Some(parser.parens(|p: Parser<'a>| p.parse())?)
32 } else {
33 None
34 };
35 Ok(ComponentExport {
36 span,
37 id,
38 debug_name,
39 name,
40 kind,
41 ty,
42 })
43 }
44}
45
46impl<'a> Parse<'a> for Vec<ComponentExport<'a>> {
47 fn parse(parser: Parser<'a>) -> Result<Self> {
48 let mut exports: Vec> = Vec::new();
49 while !parser.is_empty() {
50 exports.push(parser.parens(|parser: Parser<'a>| parser.parse())?);
51 }
52 Ok(exports)
53 }
54}
55
56/// The kind of exported item.
57#[derive(Debug)]
58pub enum ComponentExportKind<'a> {
59 /// The export is a core module.
60 ///
61 /// Note this isn't a core item ref as currently only
62 /// components can export core modules.
63 CoreModule(ItemRef<'a, kw::module>),
64 /// The export is a function.
65 Func(ItemRef<'a, kw::func>),
66 /// The export is a value.
67 Value(ItemRef<'a, kw::value>),
68 /// The export is a type.
69 Type(ItemRef<'a, kw::r#type>),
70 /// The export is a component.
71 Component(ItemRef<'a, kw::component>),
72 /// The export is an instance.
73 Instance(ItemRef<'a, kw::instance>),
74}
75
76impl<'a> ComponentExportKind<'a> {
77 pub(crate) fn module(span: Span, id: Id<'a>) -> Self {
78 Self::CoreModule(ItemRef {
79 kind: kw::module(span),
80 idx: Index::Id(id),
81 export_names: Default::default(),
82 })
83 }
84
85 pub(crate) fn component(span: Span, id: Id<'a>) -> Self {
86 Self::Component(ItemRef {
87 kind: kw::component(span),
88 idx: Index::Id(id),
89 export_names: Default::default(),
90 })
91 }
92
93 pub(crate) fn instance(span: Span, id: Id<'a>) -> Self {
94 Self::Instance(ItemRef {
95 kind: kw::instance(span),
96 idx: Index::Id(id),
97 export_names: Default::default(),
98 })
99 }
100
101 pub(crate) fn func(span: Span, id: Id<'a>) -> Self {
102 Self::Func(ItemRef {
103 kind: kw::func(span),
104 idx: Index::Id(id),
105 export_names: Default::default(),
106 })
107 }
108
109 pub(crate) fn ty(span: Span, id: Id<'a>) -> Self {
110 Self::Type(ItemRef {
111 kind: kw::r#type(span),
112 idx: Index::Id(id),
113 export_names: Default::default(),
114 })
115 }
116}
117
118impl<'a> Parse<'a> for ComponentExportKind<'a> {
119 fn parse(parser: Parser<'a>) -> Result<Self> {
120 parser.parens(|parser: Parser<'a>| {
121 let mut l: Lookahead1<'_> = parser.lookahead1();
122 if l.peek::<kw::core>()? {
123 // Remove core prefix
124 parser.parse::<kw::core>()?;
125 Ok(Self::CoreModule(parser.parse()?))
126 } else if l.peek::<kw::func>()? {
127 Ok(Self::Func(parser.parse()?))
128 } else if l.peek::<kw::value>()? {
129 Ok(Self::Value(parser.parse()?))
130 } else if l.peek::<kw::r#type>()? {
131 Ok(Self::Type(parser.parse()?))
132 } else if l.peek::<kw::component>()? {
133 Ok(Self::Component(parser.parse()?))
134 } else if l.peek::<kw::instance>()? {
135 Ok(Self::Instance(parser.parse()?))
136 } else {
137 Err(l.error())
138 }
139 })
140 }
141}
142
143impl Peek for ComponentExportKind<'_> {
144 fn peek(cursor: Cursor) -> Result<bool> {
145 let cursor = match cursor.lparen()? {
146 Some(c) => c,
147 None => return Ok(false),
148 };
149
150 let cursor = match cursor.keyword()? {
151 Some(("core", c)) => match c.keyword()? {
152 Some(("module", c)) => c,
153 _ => return Ok(false),
154 },
155 Some(("func", c))
156 | Some(("value", c))
157 | Some(("type", c))
158 | Some(("component", c))
159 | Some(("instance", c)) => c,
160 _ => return Ok(false),
161 };
162
163 Index::peek(cursor)
164 }
165
166 fn display() -> &'static str {
167 "component export"
168 }
169}
170
171/// A listing of inline `(export "foo" <url>)` statements on a WebAssembly
172/// component item in its textual format.
173#[derive(Debug, Default)]
174pub struct InlineExport<'a> {
175 /// The extra names to export an item as, if any.
176 pub names: Vec<ComponentExternName<'a>>,
177}
178
179impl<'a> Parse<'a> for InlineExport<'a> {
180 fn parse(parser: Parser<'a>) -> Result<Self> {
181 let mut names: Vec> = Vec::new();
182 while parser.peek::<Self>()? {
183 names.push(parser.parens(|p: Parser<'a>| {
184 p.parse::<kw::export>()?;
185 p.parse()
186 })?);
187 }
188 Ok(InlineExport { names })
189 }
190}
191
192impl Peek for InlineExport<'_> {
193 fn peek(cursor: Cursor<'_>) -> Result<bool> {
194 let cursor = match cursor.lparen()? {
195 Some(cursor) => cursor,
196 None => return Ok(false),
197 };
198 let cursor = match cursor.keyword()? {
199 Some(("export", cursor)) => cursor,
200 _ => return Ok(false),
201 };
202
203 // (export "foo")
204 if let Some((_, cursor)) = cursor.string()? {
205 return Ok(cursor.rparen()?.is_some());
206 }
207
208 // (export (interface "foo"))
209 let cursor = match cursor.lparen()? {
210 Some(cursor) => cursor,
211 None => return Ok(false),
212 };
213 let cursor = match cursor.keyword()? {
214 Some(("interface", cursor)) => cursor,
215 _ => return Ok(false),
216 };
217 let cursor = match cursor.string()? {
218 Some((_, cursor)) => cursor,
219 _ => return Ok(false),
220 };
221 let cursor = match cursor.rparen()? {
222 Some(cursor) => cursor,
223 _ => return Ok(false),
224 };
225 Ok(cursor.rparen()?.is_some())
226 }
227
228 fn display() -> &'static str {
229 "inline export"
230 }
231}
232