| 1 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
| 2 | use crate::token::Index; |
| 3 | |
| 4 | fn peek<K: Peek>(cursor: Cursor) -> Result<bool> { |
| 5 | // This is a little fancy because when parsing something like: |
| 6 | // |
| 7 | // (type (component (type $foo))) |
| 8 | // |
| 9 | // we need to disambiguate that from |
| 10 | // |
| 11 | // (type (component (type $foo (func)))) |
| 12 | // |
| 13 | // where the first is a type reference and the second is an inline |
| 14 | // component type defining a type internally. The peek here not only |
| 15 | // peeks for `K` but also for the index and possibly trailing |
| 16 | // strings. |
| 17 | |
| 18 | // Peek for the given keyword type |
| 19 | if !K::peek(cursor)? { |
| 20 | return Ok(false); |
| 21 | } |
| 22 | |
| 23 | // Move past the given keyword |
| 24 | let cursor = match cursor.keyword()? { |
| 25 | Some((_, c)) => c, |
| 26 | _ => return Ok(false), |
| 27 | }; |
| 28 | |
| 29 | // Peek an id or integer index, followed by `)` or string to disambiguate |
| 30 | let cursor = match cursor.id()? { |
| 31 | Some((_, cursor)) => Some(cursor), |
| 32 | None => cursor.integer()?.map(|p| p.1), |
| 33 | }; |
| 34 | Ok(match cursor { |
| 35 | Some(cursor) => cursor.rparen()?.is_some() || cursor.string()?.is_some(), |
| 36 | None => false, |
| 37 | }) |
| 38 | } |
| 39 | |
| 40 | /// Parses core item references. |
| 41 | #[derive (Clone, Debug)] |
| 42 | pub struct CoreItemRef<'a, K> { |
| 43 | /// The item kind being parsed. |
| 44 | pub kind: K, |
| 45 | /// The item or instance reference. |
| 46 | pub idx: Index<'a>, |
| 47 | /// Export name to resolve the item from. |
| 48 | pub export_name: Option<&'a str>, |
| 49 | } |
| 50 | |
| 51 | impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> { |
| 52 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 53 | // This does not parse the surrounding `(` and `)` because |
| 54 | // core prefix is context dependent and only the caller knows if it should be |
| 55 | // present for core references; therefore, the caller parses the parens and any core prefix |
| 56 | let kind: K = parser.parse::<K>()?; |
| 57 | let idx: Index<'a> = parser.parse()?; |
| 58 | let export_name: Option<&'a str> = parser.parse()?; |
| 59 | Ok(Self { |
| 60 | kind, |
| 61 | idx, |
| 62 | export_name, |
| 63 | }) |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | impl<'a, K: Peek> Peek for CoreItemRef<'a, K> { |
| 68 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
| 69 | peek::<K>(cursor) |
| 70 | } |
| 71 | |
| 72 | fn display() -> &'static str { |
| 73 | "a core item reference" |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | /// Parses component item references. |
| 78 | #[derive (Clone, Debug)] |
| 79 | pub struct ItemRef<'a, K> { |
| 80 | /// The item kind being parsed. |
| 81 | pub kind: K, |
| 82 | /// The item or instance reference. |
| 83 | pub idx: Index<'a>, |
| 84 | /// Export names to resolve the item from. |
| 85 | pub export_names: Vec<&'a str>, |
| 86 | } |
| 87 | |
| 88 | impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { |
| 89 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 90 | let kind: K = parser.parse::<K>()?; |
| 91 | let idx: Index<'a> = parser.parse()?; |
| 92 | let mut export_names: Vec<&'a str> = Vec::new(); |
| 93 | while !parser.is_empty() { |
| 94 | export_names.push(parser.parse()?); |
| 95 | } |
| 96 | Ok(Self { |
| 97 | kind, |
| 98 | idx, |
| 99 | export_names, |
| 100 | }) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl<'a, K: Peek> Peek for ItemRef<'a, K> { |
| 105 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
| 106 | peek::<K>(cursor) |
| 107 | } |
| 108 | |
| 109 | fn display() -> &'static str { |
| 110 | "a component item reference" |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /// Convenience structure to parse `$f` or `(item $f)`. |
| 115 | #[derive (Clone, Debug)] |
| 116 | pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); |
| 117 | |
| 118 | impl<'a, K> Parse<'a> for IndexOrRef<'a, K> |
| 119 | where |
| 120 | K: Parse<'a> + Default, |
| 121 | { |
| 122 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 123 | if parser.peek::<Index<'_>>()? { |
| 124 | Ok(IndexOrRef(ItemRef { |
| 125 | kind: K::default(), |
| 126 | idx: parser.parse()?, |
| 127 | export_names: Vec::new(), |
| 128 | })) |
| 129 | } else { |
| 130 | Ok(IndexOrRef(parser.parens(|p: Parser<'a>| p.parse())?)) |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /// Convenience structure to parse `$f` or `(item $f)`. |
| 136 | #[derive (Clone, Debug)] |
| 137 | pub struct IndexOrCoreRef<'a, K>(pub CoreItemRef<'a, K>); |
| 138 | |
| 139 | impl<'a, K> Parse<'a> for IndexOrCoreRef<'a, K> |
| 140 | where |
| 141 | K: Parse<'a> + Default, |
| 142 | { |
| 143 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 144 | if parser.peek::<Index<'_>>()? { |
| 145 | Ok(IndexOrCoreRef(CoreItemRef { |
| 146 | kind: K::default(), |
| 147 | idx: parser.parse()?, |
| 148 | export_name: None, |
| 149 | })) |
| 150 | } else { |
| 151 | Ok(IndexOrCoreRef(parser.parens(|p: Parser<'a>| p.parse())?)) |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |