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 | |