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