1 | use super::{ComponentExternName, ItemRef, ItemSigNoName}; |
2 | use crate::kw; |
3 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | use crate::token::{Id, Index, NameAnnotation, Span}; |
5 | |
6 | /// An entry in a WebAssembly component's export section. |
7 | #[derive (Debug)] |
8 | pub 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 | |
23 | impl<'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 | |
46 | impl<'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)] |
58 | pub 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 | |
76 | impl<'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 | |
118 | impl<'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 | |
143 | impl 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)] |
174 | pub struct InlineExport<'a> { |
175 | /// The extra names to export an item as, if any. |
176 | pub names: Vec<ComponentExternName<'a>>, |
177 | } |
178 | |
179 | impl<'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 | |
192 | impl 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 | |