use crate::component::*; use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; /// A declared core function. /// /// This is a member of both the core alias and canon sections. #[derive(Debug)] pub struct CoreFunc<'a> { /// Where this `core func` was defined. pub span: Span, /// An identifier that this function is resolved with (optionally) for name /// resolution. pub id: Option>, /// An optional name for this function stored in the custom `name` section. pub name: Option>, /// The kind of core function. pub kind: CoreFuncKind<'a>, } impl<'a> Parse<'a> for CoreFunc<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; parser.parse::()?; let id = parser.parse()?; let name = parser.parse()?; let kind = parser.parse()?; Ok(Self { span, id, name, kind, }) } } /// Represents the kind of core functions. #[derive(Debug)] pub enum CoreFuncKind<'a> { /// The core function is defined in terms of lowering a component function. /// /// The core function is actually a member of the canon section. Lower(CanonLower<'a>), /// The core function is defined in terms of aliasing a module instance export. /// /// The core function is actually a member of the core alias section. Alias(InlineExportAlias<'a>), } impl<'a> Parse<'a> for CoreFuncKind<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let mut l = parser.lookahead1(); if l.peek::() { parser.parse::()?; Ok(Self::Lower(parser.parse()?)) } else if l.peek::() { Ok(Self::Alias(parser.parse()?)) } else { Err(l.error()) } }) } } /// A declared component function. /// /// This may be a member of the import, alias, or canon sections. #[derive(Debug)] pub struct Func<'a> { /// Where this `func` was defined. pub span: Span, /// An identifier that this function is resolved with (optionally) for name /// resolution. pub id: Option>, /// An optional name for this function stored in the custom `name` section. pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. pub exports: InlineExport<'a>, /// The kind of function. pub kind: FuncKind<'a>, } impl<'a> Parse<'a> for Func<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; let exports = parser.parse()?; let kind = parser.parse()?; Ok(Self { span, id, name, exports, kind, }) } } /// Represents the kind of component functions. #[derive(Debug)] pub enum FuncKind<'a> { /// A function which is actually defined as an import, such as: /// /// ```text /// (func (import "foo") (param string)) /// ``` Import { /// The import name of this import. import: InlineImport<'a>, /// The type that this function will have. ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, }, /// The function is defined in terms of lifting a core function. /// /// The function is actually a member of the canon section. Lift { /// The lifted function's type. ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, /// Information relating to the lifting of the core function. info: CanonLift<'a>, }, /// The function is defined in terms of aliasing a component instance export. /// /// The function is actually a member of the alias section. Alias(InlineExportAlias<'a>), } impl<'a> Parse<'a> for FuncKind<'a> { fn parse(parser: Parser<'a>) -> Result { if let Some(import) = parser.parse()? { Ok(Self::Import { import, ty: parser.parse()?, }) } else if parser.peek::() && parser.peek2::() { parser.parens(|parser| Ok(Self::Alias(parser.parse()?))) } else { Ok(Self::Lift { ty: parser.parse()?, info: parser.parens(|parser| { parser.parse::()?; parser.parse() })?, }) } } } /// A WebAssembly canonical function to be inserted into a component. /// /// This is a member of the canonical section. #[derive(Debug)] pub struct CanonicalFunc<'a> { /// Where this `func` was defined. pub span: Span, /// An identifier that this function is resolved with (optionally) for name /// resolution. pub id: Option>, /// An optional name for this function stored in the custom `name` section. pub name: Option>, /// What kind of function this is, be it a lowered or lifted function. pub kind: CanonicalFuncKind<'a>, } impl<'a> Parse<'a> for CanonicalFunc<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; if parser.peek::() { let info = parser.parse()?; let (id, name, ty) = parser.parens(|parser| { parser.parse::()?; let id = parser.parse()?; let name = parser.parse()?; let ty = parser.parse()?; Ok((id, name, ty)) })?; Ok(Self { span, id, name, kind: CanonicalFuncKind::Lift { info, ty }, }) } else if parser.peek::() { let info = parser.parse()?; let (id, name) = parser.parens(|parser| { parser.parse::()?; parser.parse::()?; let id = parser.parse()?; let name = parser.parse()?; Ok((id, name)) })?; Ok(Self { span, id, name, kind: CanonicalFuncKind::Lower(info), }) } else { Err(parser.error("expected `canon lift` or `canon lower`")) } } } /// Possible ways to define a canonical function in the text format. #[derive(Debug)] pub enum CanonicalFuncKind<'a> { /// A canonical function that is defined in terms of lifting a core function. Lift { /// The lifted function's type. ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, /// Information relating to the lifting of the core function. info: CanonLift<'a>, }, /// A canonical function that is defined in terms of lowering a component function. Lower(CanonLower<'a>), } /// Information relating to lifting a core function. #[derive(Debug)] pub struct CanonLift<'a> { /// The core function being lifted. pub func: CoreItemRef<'a, kw::func>, /// The canonical options for the lifting. pub opts: Vec>, } impl<'a> Parse<'a> for CanonLift<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; Ok(Self { func: parser.parens(|parser| { parser.parse::()?; parser.parse() })?, opts: parser.parse()?, }) } } impl Default for CanonLift<'_> { fn default() -> Self { let span = Span::from_offset(0); Self { func: CoreItemRef { kind: kw::func(span), idx: Index::Num(0, span), export_name: None, }, opts: Vec::new(), } } } /// Information relating to lowering a component function. #[derive(Debug)] pub struct CanonLower<'a> { /// The function being lowered. pub func: ItemRef<'a, kw::func>, /// The canonical options for the lowering. pub opts: Vec>, } impl<'a> Parse<'a> for CanonLower<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; Ok(Self { func: parser.parens(|parser| parser.parse())?, opts: parser.parse()?, }) } } impl Default for CanonLower<'_> { fn default() -> Self { let span = Span::from_offset(0); Self { func: ItemRef { kind: kw::func(span), idx: Index::Num(0, span), export_names: Vec::new(), }, opts: Vec::new(), } } } #[derive(Debug)] /// Canonical ABI options. pub enum CanonOpt<'a> { /// Encode strings as UTF-8. StringUtf8, /// Encode strings as UTF-16. StringUtf16, /// Encode strings as "compact UTF-16". StringLatin1Utf16, /// Use the specified memory for canonical ABI memory access. Memory(CoreItemRef<'a, kw::memory>), /// Use the specified reallocation function for memory allocations. Realloc(CoreItemRef<'a, kw::func>), /// Call the specified function after the lifted function has returned. PostReturn(CoreItemRef<'a, kw::func>), } impl<'a> Parse<'a> for CanonOpt<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::() { parser.parse::()?; Ok(Self::StringUtf8) } else if l.peek::() { parser.parse::()?; Ok(Self::StringUtf16) } else if l.peek::() { parser.parse::()?; Ok(Self::StringLatin1Utf16) } else if l.peek::() { parser.parens(|parser| { let mut l = parser.lookahead1(); if l.peek::() { let span = parser.parse::()?.0; Ok(CanonOpt::Memory(parse_trailing_item_ref( kw::memory(span), parser, )?)) } else if l.peek::() { parser.parse::()?; Ok(CanonOpt::Realloc( parser.parse::>()?.0, )) } else if l.peek::() { parser.parse::()?; Ok(CanonOpt::PostReturn( parser.parse::>()?.0, )) } else { Err(l.error()) } }) } else { Err(l.error()) } } } fn parse_trailing_item_ref(kind: T, parser: Parser) -> Result> { Ok(CoreItemRef { kind, idx: parser.parse()?, export_name: parser.parse()?, }) } impl<'a> Parse<'a> for Vec> { fn parse(parser: Parser<'a>) -> Result { let mut funcs = Vec::new(); while !parser.is_empty() { funcs.push(parser.parse()?); } Ok(funcs) } }