1 | use std::iter; |
2 | |
3 | use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused}; |
4 | |
5 | pub(super) enum Item<'a> { |
6 | Literal(Spanned<&'a [u8]>), |
7 | EscapedBracket { |
8 | _first: Unused<Location>, |
9 | _second: Unused<Location>, |
10 | }, |
11 | Component { |
12 | _opening_bracket: Unused<Location>, |
13 | _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, |
14 | name: Spanned<&'a [u8]>, |
15 | modifiers: Box<[Modifier<'a>]>, |
16 | _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, |
17 | _closing_bracket: Unused<Location>, |
18 | }, |
19 | Optional { |
20 | opening_bracket: Location, |
21 | _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, |
22 | _optional_kw: Unused<Spanned<&'a [u8]>>, |
23 | _whitespace: Unused<Spanned<&'a [u8]>>, |
24 | nested_format_description: NestedFormatDescription<'a>, |
25 | closing_bracket: Location, |
26 | }, |
27 | First { |
28 | opening_bracket: Location, |
29 | _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, |
30 | _first_kw: Unused<Spanned<&'a [u8]>>, |
31 | _whitespace: Unused<Spanned<&'a [u8]>>, |
32 | nested_format_descriptions: Box<[NestedFormatDescription<'a>]>, |
33 | closing_bracket: Location, |
34 | }, |
35 | } |
36 | |
37 | pub(super) struct NestedFormatDescription<'a> { |
38 | pub(super) _opening_bracket: Unused<Location>, |
39 | pub(super) items: Box<[Item<'a>]>, |
40 | pub(super) _closing_bracket: Unused<Location>, |
41 | pub(super) _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, |
42 | } |
43 | |
44 | pub(super) struct Modifier<'a> { |
45 | pub(super) _leading_whitespace: Unused<Spanned<&'a [u8]>>, |
46 | pub(super) key: Spanned<&'a [u8]>, |
47 | pub(super) _colon: Unused<Location>, |
48 | pub(super) value: Spanned<&'a [u8]>, |
49 | } |
50 | |
51 | pub(super) fn parse< |
52 | 'item: 'iter, |
53 | 'iter, |
54 | I: Iterator<Item = Result<lexer::Token<'item>, Error>>, |
55 | const VERSION: u8, |
56 | >( |
57 | tokens: &'iter mut lexer::Lexed<I>, |
58 | ) -> impl Iterator<Item = Result<Item<'item>, Error>> + 'iter { |
59 | assert!(version!(1..=2)); |
60 | parse_inner::<_, false, VERSION>(tokens) |
61 | } |
62 | |
63 | fn parse_inner< |
64 | 'item, |
65 | I: Iterator<Item = Result<lexer::Token<'item>, Error>>, |
66 | const NESTED: bool, |
67 | const VERSION: u8, |
68 | >( |
69 | tokens: &mut lexer::Lexed<I>, |
70 | ) -> impl Iterator<Item = Result<Item<'item>, Error>> + '_ { |
71 | iter::from_fn(move || { |
72 | if NESTED && tokens.peek_closing_bracket().is_some() { |
73 | return None; |
74 | } |
75 | |
76 | let next = match tokens.next()? { |
77 | Ok(token) => token, |
78 | Err(err) => return Some(Err(err)), |
79 | }; |
80 | |
81 | Some(match next { |
82 | lexer::Token::Literal(Spanned { value: _, span: _ }) if NESTED => { |
83 | bug!("literal should not be present in nested description" ) |
84 | } |
85 | lexer::Token::Literal(value) => Ok(Item::Literal(value)), |
86 | lexer::Token::Bracket { |
87 | kind: lexer::BracketKind::Opening, |
88 | location, |
89 | } => { |
90 | if version!(..=1) { |
91 | if let Some(second_location) = tokens.next_if_opening_bracket() { |
92 | Ok(Item::EscapedBracket { |
93 | _first: unused(location), |
94 | _second: unused(second_location), |
95 | }) |
96 | } else { |
97 | parse_component::<_, VERSION>(location, tokens) |
98 | } |
99 | } else { |
100 | parse_component::<_, VERSION>(location, tokens) |
101 | } |
102 | } |
103 | lexer::Token::Bracket { |
104 | kind: lexer::BracketKind::Closing, |
105 | location: _, |
106 | } if NESTED => { |
107 | bug!("closing bracket should be caught by the `if` statement" ) |
108 | } |
109 | lexer::Token::Bracket { |
110 | kind: lexer::BracketKind::Closing, |
111 | location: _, |
112 | } => { |
113 | bug!("closing bracket should have been consumed by `parse_component`" ) |
114 | } |
115 | lexer::Token::ComponentPart { kind: _, value } if NESTED => Ok(Item::Literal(value)), |
116 | lexer::Token::ComponentPart { kind: _, value: _ } => { |
117 | bug!("component part should have been consumed by `parse_component`" ) |
118 | } |
119 | }) |
120 | }) |
121 | } |
122 | |
123 | fn parse_component<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: u8>( |
124 | opening_bracket: Location, |
125 | tokens: &mut lexer::Lexed<I>, |
126 | ) -> Result<Item<'a>, Error> { |
127 | let leading_whitespace = tokens.next_if_whitespace(); |
128 | |
129 | let Some(name) = tokens.next_if_not_whitespace() else { |
130 | let span = match leading_whitespace { |
131 | Some(Spanned { value: _, span }) => span, |
132 | None => opening_bracket.to(opening_bracket), |
133 | }; |
134 | return Err(span.error("expected component name" )); |
135 | }; |
136 | |
137 | if *name == b"optional" { |
138 | let Some(whitespace) = tokens.next_if_whitespace() else { |
139 | return Err(name.span.error("expected whitespace after `optional`" )); |
140 | }; |
141 | |
142 | let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; |
143 | |
144 | let Some(closing_bracket) = tokens.next_if_closing_bracket() else { |
145 | return Err(opening_bracket.error("unclosed bracket" )); |
146 | }; |
147 | |
148 | return Ok(Item::Optional { |
149 | opening_bracket, |
150 | _leading_whitespace: unused(leading_whitespace), |
151 | _optional_kw: unused(name), |
152 | _whitespace: unused(whitespace), |
153 | nested_format_description: nested, |
154 | closing_bracket, |
155 | }); |
156 | } |
157 | |
158 | if *name == b"first" { |
159 | let Some(whitespace) = tokens.next_if_whitespace() else { |
160 | return Err(name.span.error("expected whitespace after `first`" )); |
161 | }; |
162 | |
163 | let mut nested_format_descriptions = Vec::new(); |
164 | while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { |
165 | nested_format_descriptions.push(description); |
166 | } |
167 | |
168 | let Some(closing_bracket) = tokens.next_if_closing_bracket() else { |
169 | return Err(opening_bracket.error("unclosed bracket" )); |
170 | }; |
171 | |
172 | return Ok(Item::First { |
173 | opening_bracket, |
174 | _leading_whitespace: unused(leading_whitespace), |
175 | _first_kw: unused(name), |
176 | _whitespace: unused(whitespace), |
177 | nested_format_descriptions: nested_format_descriptions.into_boxed_slice(), |
178 | closing_bracket, |
179 | }); |
180 | } |
181 | |
182 | let mut modifiers = Vec::new(); |
183 | let trailing_whitespace = loop { |
184 | let Some(whitespace) = tokens.next_if_whitespace() else { |
185 | break None; |
186 | }; |
187 | |
188 | if let Some(location) = tokens.next_if_opening_bracket() { |
189 | return Err(location |
190 | .to(location) |
191 | .error("modifier must be of the form `key:value`" )); |
192 | } |
193 | |
194 | let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { |
195 | break Some(whitespace); |
196 | }; |
197 | |
198 | let Some(colon_index) = value.iter().position(|&b| b == b':' ) else { |
199 | return Err(span.error("modifier must be of the form `key:value`" )); |
200 | }; |
201 | let key = &value[..colon_index]; |
202 | let value = &value[colon_index + 1..]; |
203 | |
204 | if key.is_empty() { |
205 | return Err(span.shrink_to_start().error("expected modifier key" )); |
206 | } |
207 | if value.is_empty() { |
208 | return Err(span.shrink_to_end().error("expected modifier value" )); |
209 | } |
210 | |
211 | modifiers.push(Modifier { |
212 | _leading_whitespace: unused(whitespace), |
213 | key: key.spanned(span.shrink_to_before(colon_index as _)), |
214 | _colon: unused(span.start.offset(colon_index as _)), |
215 | value: value.spanned(span.shrink_to_after(colon_index as _)), |
216 | }); |
217 | }; |
218 | |
219 | let Some(closing_bracket) = tokens.next_if_closing_bracket() else { |
220 | return Err(opening_bracket.error("unclosed bracket" )); |
221 | }; |
222 | |
223 | Ok(Item::Component { |
224 | _opening_bracket: unused(opening_bracket), |
225 | _leading_whitespace: unused(leading_whitespace), |
226 | name, |
227 | modifiers: modifiers.into_boxed_slice(), |
228 | _trailing_whitespace: unused(trailing_whitespace), |
229 | _closing_bracket: unused(closing_bracket), |
230 | }) |
231 | } |
232 | |
233 | fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: u8>( |
234 | last_location: Location, |
235 | tokens: &mut lexer::Lexed<I>, |
236 | ) -> Result<NestedFormatDescription<'a>, Error> { |
237 | let Some(opening_bracket: Location) = tokens.next_if_opening_bracket() else { |
238 | return Err(last_location.error(message:"expected opening bracket" )); |
239 | }; |
240 | let items: Box<[Item<'_>]> = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?; |
241 | let Some(closing_bracket: Location) = tokens.next_if_closing_bracket() else { |
242 | return Err(opening_bracket.error(message:"unclosed bracket" )); |
243 | }; |
244 | let trailing_whitespace: Option> = tokens.next_if_whitespace(); |
245 | |
246 | Ok(NestedFormatDescription { |
247 | _opening_bracket: unused(opening_bracket), |
248 | items, |
249 | _closing_bracket: unused(closing_bracket), |
250 | _trailing_whitespace: unused(trailing_whitespace), |
251 | }) |
252 | } |
253 | |