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)] #[allow(missing_docs)] 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, true>), ResourceNew(CanonResourceNew<'a>), ResourceDrop(CanonResourceDrop<'a>), ResourceRep(CanonResourceRep<'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::()?; } else if l.peek::()? { return Ok(Self::Alias(parser.parse()?)); } else { return Err(l.error()); } let mut l = parser.lookahead1(); if l.peek::()? { Ok(CoreFuncKind::Lower(parser.parse()?)) } else if l.peek::()? { Ok(CoreFuncKind::ResourceNew(parser.parse()?)) } else if l.peek::()? { Ok(CoreFuncKind::ResourceDrop(parser.parse()?)) } else if l.peek::()? { Ok(CoreFuncKind::ResourceRep(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, false>), } 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::()? { Self::parse_core_func(span, parser, CanonicalFuncKind::Lower) } else if parser.peek::()? { Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceNew) } else if parser.peek::()? { Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceDrop) } else if parser.peek::()? { Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceRep) } else { Err(parser.error("expected `canon lift` or `canon lower`")) } } } impl<'a> CanonicalFunc<'a> { fn parse_core_func( span: Span, parser: Parser<'a>, variant: fn(T) -> CanonicalFuncKind<'a>, ) -> Result where T: Parse<'a>, { 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: variant(info), }) } } /// Possible ways to define a canonical function in the text format. #[derive(Debug)] #[allow(missing_docs)] 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>), ResourceNew(CanonResourceNew<'a>), ResourceDrop(CanonResourceDrop<'a>), ResourceRep(CanonResourceRep<'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(), } } } /// Information relating to the `resource.new` intrinsic. #[derive(Debug)] pub struct CanonResourceNew<'a> { /// The resource type that this intrinsic creates an owned reference to. pub ty: Index<'a>, } impl<'a> Parse<'a> for CanonResourceNew<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; Ok(Self { ty: parser.parse()?, }) } } impl Default for CanonResourceNew<'_> { fn default() -> Self { CanonResourceNew { ty: Index::Num(0, Span::from_offset(0)), } } } /// Information relating to the `resource.drop` intrinsic. #[derive(Debug)] pub struct CanonResourceDrop<'a> { /// The resource type that this intrinsic is dropping. pub ty: Index<'a>, } impl<'a> Parse<'a> for CanonResourceDrop<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; Ok(Self { ty: parser.parse()?, }) } } impl Default for CanonResourceDrop<'_> { fn default() -> Self { CanonResourceDrop { ty: Index::Num(0, Span::from_offset(0)), } } } /// Information relating to the `resource.rep` intrinsic. #[derive(Debug)] pub struct CanonResourceRep<'a> { /// The resource type that this intrinsic is accessing. pub ty: Index<'a>, } impl<'a> Parse<'a> for CanonResourceRep<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; Ok(Self { ty: parser.parse()?, }) } } impl Default for CanonResourceRep<'_> { fn default() -> Self { CanonResourceRep { ty: Index::Num(0, Span::from_offset(0)), } } } #[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) } }