use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::Index; fn peek(cursor: Cursor) -> Result { // This is a little fancy because when parsing something like: // // (type (component (type $foo))) // // we need to disambiguate that from // // (type (component (type $foo (func)))) // // where the first is a type reference and the second is an inline // component type defining a type internally. The peek here not only // peeks for `K` but also for the index and possibly trailing // strings. // Peek for the given keyword type if !K::peek(cursor)? { return Ok(false); } // Move past the given keyword let cursor = match cursor.keyword()? { Some((_, c)) => c, _ => return Ok(false), }; // Peek an id or integer index, followed by `)` or string to disambiguate let cursor = match cursor.id()? { Some((_, cursor)) => Some(cursor), None => cursor.integer()?.map(|p| p.1), }; Ok(match cursor { Some(cursor) => cursor.rparen()?.is_some() || cursor.string()?.is_some(), None => false, }) } /// Parses core item references. #[derive(Clone, Debug)] pub struct CoreItemRef<'a, K> { /// The item kind being parsed. pub kind: K, /// The item or instance reference. pub idx: Index<'a>, /// Export name to resolve the item from. pub export_name: Option<&'a str>, } impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { // This does not parse the surrounding `(` and `)` because // core prefix is context dependent and only the caller knows if it should be // present for core references; therefore, the caller parses the parens and any core prefix let kind = parser.parse::()?; let idx = parser.parse()?; let export_name = parser.parse()?; Ok(Self { kind, idx, export_name, }) } } impl<'a, K: Peek> Peek for CoreItemRef<'a, K> { fn peek(cursor: Cursor<'_>) -> Result { peek::(cursor) } fn display() -> &'static str { "a core item reference" } } /// Parses component item references. #[derive(Clone, Debug)] pub struct ItemRef<'a, K> { /// The item kind being parsed. pub kind: K, /// The item or instance reference. pub idx: Index<'a>, /// Export names to resolve the item from. pub export_names: Vec<&'a str>, } impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { let kind = parser.parse::()?; let idx = parser.parse()?; let mut export_names = Vec::new(); while !parser.is_empty() { export_names.push(parser.parse()?); } Ok(Self { kind, idx, export_names, }) } } impl<'a, K: Peek> Peek for ItemRef<'a, K> { fn peek(cursor: Cursor<'_>) -> Result { peek::(cursor) } fn display() -> &'static str { "a component item reference" } } /// Convenience structure to parse `$f` or `(item $f)`. #[derive(Clone, Debug)] pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); impl<'a, K> Parse<'a> for IndexOrRef<'a, K> where K: Parse<'a> + Default, { fn parse(parser: Parser<'a>) -> Result { if parser.peek::>()? { Ok(IndexOrRef(ItemRef { kind: K::default(), idx: parser.parse()?, export_names: Vec::new(), })) } else { Ok(IndexOrRef(parser.parens(|p| p.parse())?)) } } } /// Convenience structure to parse `$f` or `(item $f)`. #[derive(Clone, Debug)] pub struct IndexOrCoreRef<'a, K>(pub CoreItemRef<'a, K>); impl<'a, K> Parse<'a> for IndexOrCoreRef<'a, K> where K: Parse<'a> + Default, { fn parse(parser: Parser<'a>) -> Result { if parser.peek::>()? { Ok(IndexOrCoreRef(CoreItemRef { kind: K::default(), idx: parser.parse()?, export_name: None, })) } else { Ok(IndexOrCoreRef(parser.parens(|p| p.parse())?)) } } }