time_macros/format_description/
ast.rs1use 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}