time_macros/format_description/
ast.rs

1use std::iter;
2
3use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused};
4
5pub(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
37pub(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
44pub(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
51pub(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
63fn 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
123fn 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
233fn 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) = tokens.next_if_opening_bracket() else {
238        return Err(last_location.error("expected opening bracket"));
239    };
240    let items = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?;
241    let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
242        return Err(opening_bracket.error("unclosed bracket"));
243    };
244    let trailing_whitespace = 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}