use super::{ComponentExternName, ItemRef, ItemSigNoName}; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::{Id, Index, NameAnnotation, Span}; /// An entry in a WebAssembly component's export section. #[derive(Debug)] pub struct ComponentExport<'a> { /// Where this export was defined. pub span: Span, /// Optional identifier bound to this export. pub id: Option>, /// An optional name for this instance stored in the custom `name` section. pub debug_name: Option>, /// The name of this export from the component. pub name: ComponentExternName<'a>, /// The kind of export. pub kind: ComponentExportKind<'a>, /// The kind of export. pub ty: Option>, } impl<'a> Parse<'a> for ComponentExport<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let debug_name = parser.parse()?; let name = parser.parse()?; let kind = parser.parse()?; let ty = if !parser.is_empty() { Some(parser.parens(|p| p.parse())?) } else { None }; Ok(ComponentExport { span, id, debug_name, name, kind, ty, }) } } impl<'a> Parse<'a> for Vec> { fn parse(parser: Parser<'a>) -> Result { let mut exports = Vec::new(); while !parser.is_empty() { exports.push(parser.parens(|parser| parser.parse())?); } Ok(exports) } } /// The kind of exported item. #[derive(Debug)] pub enum ComponentExportKind<'a> { /// The export is a core module. /// /// Note this isn't a core item ref as currently only /// components can export core modules. CoreModule(ItemRef<'a, kw::module>), /// The export is a function. Func(ItemRef<'a, kw::func>), /// The export is a value. Value(ItemRef<'a, kw::value>), /// The export is a type. Type(ItemRef<'a, kw::r#type>), /// The export is a component. Component(ItemRef<'a, kw::component>), /// The export is an instance. Instance(ItemRef<'a, kw::instance>), } impl<'a> ComponentExportKind<'a> { pub(crate) fn module(span: Span, id: Id<'a>) -> Self { Self::CoreModule(ItemRef { kind: kw::module(span), idx: Index::Id(id), export_names: Default::default(), }) } pub(crate) fn component(span: Span, id: Id<'a>) -> Self { Self::Component(ItemRef { kind: kw::component(span), idx: Index::Id(id), export_names: Default::default(), }) } pub(crate) fn instance(span: Span, id: Id<'a>) -> Self { Self::Instance(ItemRef { kind: kw::instance(span), idx: Index::Id(id), export_names: Default::default(), }) } pub(crate) fn func(span: Span, id: Id<'a>) -> Self { Self::Func(ItemRef { kind: kw::func(span), idx: Index::Id(id), export_names: Default::default(), }) } pub(crate) fn ty(span: Span, id: Id<'a>) -> Self { Self::Type(ItemRef { kind: kw::r#type(span), idx: Index::Id(id), export_names: Default::default(), }) } } impl<'a> Parse<'a> for ComponentExportKind<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let mut l = parser.lookahead1(); if l.peek::()? { // Remove core prefix parser.parse::()?; Ok(Self::CoreModule(parser.parse()?)) } else if l.peek::()? { Ok(Self::Func(parser.parse()?)) } else if l.peek::()? { Ok(Self::Value(parser.parse()?)) } else if l.peek::()? { Ok(Self::Type(parser.parse()?)) } else if l.peek::()? { Ok(Self::Component(parser.parse()?)) } else if l.peek::()? { Ok(Self::Instance(parser.parse()?)) } else { Err(l.error()) } }) } } impl Peek for ComponentExportKind<'_> { fn peek(cursor: Cursor) -> Result { let cursor = match cursor.lparen()? { Some(c) => c, None => return Ok(false), }; let cursor = match cursor.keyword()? { Some(("core", c)) => match c.keyword()? { Some(("module", c)) => c, _ => return Ok(false), }, Some(("func", c)) | Some(("value", c)) | Some(("type", c)) | Some(("component", c)) | Some(("instance", c)) => c, _ => return Ok(false), }; Index::peek(cursor) } fn display() -> &'static str { "component export" } } /// A listing of inline `(export "foo" )` statements on a WebAssembly /// component item in its textual format. #[derive(Debug, Default)] pub struct InlineExport<'a> { /// The extra names to export an item as, if any. pub names: Vec>, } impl<'a> Parse<'a> for InlineExport<'a> { fn parse(parser: Parser<'a>) -> Result { let mut names = Vec::new(); while parser.peek::()? { names.push(parser.parens(|p| { p.parse::()?; p.parse() })?); } Ok(InlineExport { names }) } } impl Peek for InlineExport<'_> { fn peek(cursor: Cursor<'_>) -> Result { let cursor = match cursor.lparen()? { Some(cursor) => cursor, None => return Ok(false), }; let cursor = match cursor.keyword()? { Some(("export", cursor)) => cursor, _ => return Ok(false), }; // (export "foo") if let Some((_, cursor)) = cursor.string()? { return Ok(cursor.rparen()?.is_some()); } // (export (interface "foo")) let cursor = match cursor.lparen()? { Some(cursor) => cursor, None => return Ok(false), }; let cursor = match cursor.keyword()? { Some(("interface", cursor)) => cursor, _ => return Ok(false), }; let cursor = match cursor.string()? { Some((_, cursor)) => cursor, _ => return Ok(false), }; let cursor = match cursor.rparen()? { Some(cursor) => cursor, _ => return Ok(false), }; Ok(cursor.rparen()?.is_some()) } fn display() -> &'static str { "inline export" } }