time_macros/format_description/
ast.rs1use std::iter;
2
3use super::{Error, Location, Spanned, SpannedValue, Unused, lexer, unused};
4use crate::FormatDescriptionVersion;
5use crate::format_description::Span;
6
7pub(super) enum Item<'a> {
8 Literal {
9 version: FormatDescriptionVersion,
10 value: Spanned<&'a [u8]>,
11 },
12 EscapedBracket {
13 _first: Unused<Location>,
14 _second: Unused<Location>,
15 },
16 Component {
17 _opening_bracket: Unused<Location>,
18 _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
19 name: Spanned<&'a [u8]>,
20 modifiers: Box<[Modifier<'a>]>,
21 _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
22 _closing_bracket: Unused<Location>,
23 },
24 Optional {
25 version: FormatDescriptionVersion,
26 opening_bracket: Location,
27 _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
28 _optional_kw: Unused<Spanned<&'a [u8]>>,
29 modifiers: Box<[Modifier<'a>]>,
30 _whitespace_after_modifiers: Unused<Option<Spanned<&'a [u8]>>>,
31 nested_format_description: NestedFormatDescription<'a>,
32 closing_bracket: Location,
33 },
34 First {
35 opening_bracket: Location,
36 _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
37 _first_kw: Unused<Spanned<&'a [u8]>>,
38 modifiers: Box<[Modifier<'a>]>,
39 _whitespace_after_modifiers: Unused<Option<Spanned<&'a [u8]>>>,
40 nested_format_descriptions: Box<[NestedFormatDescription<'a>]>,
41 closing_bracket: Location,
42 },
43}
44
45pub(super) struct NestedFormatDescription<'a> {
46 pub(super) _opening_bracket: Unused<Location>,
47 pub(super) items: Box<[Item<'a>]>,
48 pub(super) _closing_bracket: Unused<Location>,
49 pub(super) _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
50}
51
52#[derive(Debug)]
53pub(super) struct Modifier<'a> {
54 pub(super) _leading_whitespace: Unused<Spanned<&'a [u8]>>,
55 pub(super) key: Spanned<&'a [u8]>,
56 pub(super) _colon: Unused<Location>,
57 pub(super) value: Spanned<&'a [u8]>,
58}
59
60impl<'a> Modifier<'a> {
61 fn from_leading_whitespace_and_token(
62 leading_whitespace: Spanned<&'a [u8]>,
63 token: Spanned<&'a [u8]>,
64 ) -> Result<Self, Error> {
65 let Some(colon_index) = token.iter().position(|&b| b == b':') else {
66 return Err(token.span.error("modifier must be of the form `key:value`"));
67 };
68 let key = &token[..colon_index];
69 let value = &token[colon_index + 1..];
70
71 if key.is_empty() {
72 return Err(token.span.shrink_to_start().error("expected modifier key"));
73 }
74 if value.is_empty() {
75 return Err(token.span.shrink_to_end().error("expected modifier value"));
76 }
77
78 Ok(Self {
79 _leading_whitespace: unused(leading_whitespace),
80 key: key.spanned(token.span),
81 _colon: unused(token.span.start.offset(colon_index as u32)),
82 value: value.spanned(token.span),
83 })
84 }
85
86 pub(super) fn key_value_span(&self) -> Span {
87 self.key.span.start.to(self.value.span.end)
88 }
89}
90
91pub(super) fn parse<'item: 'iter, 'iter, I: Iterator<Item = Result<lexer::Token<'item>, Error>>>(
92 version: FormatDescriptionVersion,
93 tokens: &'iter mut lexer::Lexed<I>,
94) -> impl Iterator<Item = Result<Item<'item>, Error>> + use<'item, 'iter, I> {
95 parse_inner(version, false, tokens)
96}
97
98fn parse_inner<'item, I: Iterator<Item = Result<lexer::Token<'item>, Error>>>(
99 version: FormatDescriptionVersion,
100 nested: bool,
101 tokens: &mut lexer::Lexed<I>,
102) -> impl Iterator<Item = Result<Item<'item>, Error>> + use<'_, 'item, I> {
103 iter::from_fn(move || {
104 if nested && tokens.peek_closing_bracket().is_some() {
105 return None;
106 }
107
108 let next = match tokens.next()? {
109 Ok(token) => token,
110 Err(err) => return Some(Err(err)),
111 };
112
113 Some(match next {
114 lexer::Token::Literal(Spanned { value: _, span: _ }) if nested => {
115 bug!("literal should not be present in nested description")
116 }
117 lexer::Token::Literal(value) => Ok(Item::Literal { version, value }),
118 lexer::Token::Bracket {
119 kind: lexer::BracketKind::Opening,
120 location,
121 } => {
122 if version.is_v1()
123 && let Some(second_location) = tokens.next_if_opening_bracket()
124 {
125 Ok(Item::EscapedBracket {
126 _first: unused(location),
127 _second: unused(second_location),
128 })
129 } else {
130 parse_component(version, location, tokens)
131 }
132 }
133 lexer::Token::Bracket {
134 kind: lexer::BracketKind::Closing,
135 location: _,
136 } if nested => {
137 bug!("closing bracket should be caught by the `if` statement")
138 }
139 lexer::Token::Bracket {
140 kind: lexer::BracketKind::Closing,
141 location: _,
142 } => {
143 bug!("closing bracket should have been consumed by `parse_component`")
144 }
145 lexer::Token::ComponentPart { kind: _, value } if nested => {
146 Ok(Item::Literal { version, value })
147 }
148 lexer::Token::ComponentPart { kind: _, value: _ } => {
149 bug!("component part should have been consumed by `parse_component`")
150 }
151 })
152 })
153}
154
155struct Modifiers<'a> {
156 modifiers: Box<[Modifier<'a>]>,
157 trailing_whitespace: Option<Spanned<&'a [u8]>>,
158}
159
160impl<'a> Modifiers<'a> {
161 fn parse<I>(nested_is_allowed: bool, tokens: &mut lexer::Lexed<I>) -> Result<Self, Error>
162 where
163 I: Iterator<Item = Result<lexer::Token<'a>, Error>>,
164 {
165 let mut modifiers = Vec::new();
166 loop {
167 let Some(whitespace) = tokens.next_if_whitespace() else {
168 return Ok(Self {
169 modifiers: modifiers.into_boxed_slice(),
170 trailing_whitespace: None,
171 });
172 };
173
174 if !nested_is_allowed && let Some(location) = tokens.next_if_opening_bracket() {
177 return Err(location.error("modifier must be of the form `key:value`"));
178 }
179
180 let Some(token) = tokens.next_if_not_whitespace() else {
181 return Ok(Self {
182 modifiers: modifiers.into_boxed_slice(),
183 trailing_whitespace: Some(whitespace),
184 });
185 };
186
187 let modifier = Modifier::from_leading_whitespace_and_token(whitespace, token)?;
188 modifiers.push(modifier);
189 }
190 }
191
192 fn span(&self) -> Span {
193 match &*self.modifiers {
194 [] => self
195 .trailing_whitespace
196 .map(|whitespace| whitespace.span)
197 .unwrap_or_else(Span::dummy),
198 [modifier] => modifier.key.span.start.to(modifier.value.span.end),
199 [first, .., last] => first.key.span.start.to(last.value.span.end),
200 }
201 }
202}
203
204fn parse_component<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>>(
205 version: FormatDescriptionVersion,
206 opening_bracket: Location,
207 tokens: &mut lexer::Lexed<I>,
208) -> Result<Item<'a>, Error> {
209 let leading_whitespace = tokens.next_if_whitespace();
210
211 let Some(name) = tokens.next_if_not_whitespace() else {
212 let span = match leading_whitespace {
213 Some(Spanned { value: _, span }) => span,
214 None => opening_bracket.to(opening_bracket),
215 };
216 return Err(span.error("expected component name"));
217 };
218
219 if *name == b"optional" {
220 let modifiers = Modifiers::parse(true, tokens)?;
221 let nested = parse_nested(version, modifiers.span().end, tokens)?;
222
223 let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
224 return Err(opening_bracket.error("unclosed bracket"));
225 };
226
227 if modifiers.trailing_whitespace.is_none() {
228 if let Some(modifier) = modifiers.modifiers.last() {
229 return Err(modifier
230 .value
231 .span
232 .shrink_to_end()
233 .error("expected whitespace between modifiers and nested description"));
234 } else {
235 return Err(name
236 .span
237 .shrink_to_end()
238 .error("expected whitespace between `optional` and nested description"));
239 }
240 }
241
242 return Ok(Item::Optional {
243 version,
244 opening_bracket,
245 _leading_whitespace: unused(leading_whitespace),
246 _optional_kw: unused(name),
247 modifiers: modifiers.modifiers,
248 _whitespace_after_modifiers: unused(modifiers.trailing_whitespace),
249 nested_format_description: nested,
250 closing_bracket,
251 });
252 }
253
254 if *name == b"first" {
255 let modifiers = Modifiers::parse(true, tokens)?;
256
257 let mut nested_format_descriptions = Vec::new();
258 while let Ok(description) = parse_nested(version, modifiers.span().end, tokens) {
259 nested_format_descriptions.push(description);
260 }
261
262 if version.is_at_least_v3() && nested_format_descriptions.is_empty() {
263 return Err(modifiers
264 .span()
265 .shrink_to_end()
266 .error("expected at least one nested description"));
267 }
268
269 let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
270 return Err(opening_bracket.error("unclosed bracket"));
271 };
272
273 if modifiers.trailing_whitespace.is_none() {
274 if let Some(modifier) = modifiers.modifiers.last() {
275 return Err(modifier
276 .value
277 .span
278 .shrink_to_end()
279 .error("expected whitespace between modifiers and nested descriptions"));
280 } else {
281 return Err(name
282 .span
283 .shrink_to_end()
284 .error("expected whitespace between `first` and nested descriptions"));
285 }
286 }
287
288 return Ok(Item::First {
289 opening_bracket,
290 _leading_whitespace: unused(leading_whitespace),
291 _first_kw: unused(name),
292 modifiers: modifiers.modifiers,
293 _whitespace_after_modifiers: unused(modifiers.trailing_whitespace),
294 nested_format_descriptions: nested_format_descriptions.into_boxed_slice(),
295 closing_bracket,
296 });
297 }
298
299 let Modifiers {
300 modifiers,
301 trailing_whitespace,
302 } = Modifiers::parse(false, tokens)?;
303
304 let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
305 return Err(opening_bracket.error("unclosed bracket"));
306 };
307
308 Ok(Item::Component {
309 _opening_bracket: unused(opening_bracket),
310 _leading_whitespace: unused(leading_whitespace),
311 name,
312 modifiers,
313 _trailing_whitespace: unused(trailing_whitespace),
314 _closing_bracket: unused(closing_bracket),
315 })
316}
317
318fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>>(
319 version: FormatDescriptionVersion,
320 last_location: Location,
321 tokens: &mut lexer::Lexed<I>,
322) -> Result<NestedFormatDescription<'a>, Error> {
323 let Some(opening_bracket) = tokens.next_if_opening_bracket() else {
324 return Err(last_location.error("expected opening bracket"));
325 };
326 let items = parse_inner(version, true, tokens).collect::<Result<_, _>>()?;
327 let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
328 return Err(opening_bracket.error("unclosed bracket"));
329 };
330 let trailing_whitespace = tokens.next_if_whitespace();
331
332 Ok(NestedFormatDescription {
333 _opening_bracket: unused(opening_bracket),
334 items,
335 _closing_bracket: unused(closing_bracket),
336 _trailing_whitespace: unused(trailing_whitespace),
337 })
338}