inf_wast/component/
export.rs

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 = parser.parse::<kw::export>()?.0;
26        let id = parser.parse()?;
27        let debug_name = parser.parse()?;
28        let name = parser.parse()?;
29        let kind = parser.parse()?;
30        let ty = if !parser.is_empty() {
31            Some(parser.parens(|p| 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::new();
49        while !parser.is_empty() {
50            exports.push(parser.parens(|parser| 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| {
121            let mut l = 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::new();
182        while parser.peek::<Self>()? {
183            names.push(parser.parens(|p| {
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}