libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
format_frontend_parser.hpp
1#pragma once
2
11[[nodiscard]] constexpr bool IsDigit(char ch)
12{
13 return ch >= '0' && ch <= '9';
14}
15
21[[nodiscard]] constexpr bool IsAlign(char ch)
22{
23 return ch == '<' || ch == '>' || ch == '^';
24}
25
31[[nodiscard]] constexpr Align ParseAlign(char ch)
32{
33 switch (ch)
34 {
35 case '<':
36 return Align::Left;
37 case '>':
38 return Align::Right;
39 case '^':
40 return Align::Center;
41 default:
42 return Align::None;
43 }
44}
45
51[[nodiscard]] constexpr bool HasEmbeddedNul(std::string_view source)
52{
53 for (char ch : source)
54 {
55 if (ch == '\0')
56 {
57 return true;
58 }
59 }
60 return false;
61}
62
68[[nodiscard]] constexpr bool IsSupportedPresentation(char ch)
69{
70 switch (ch)
71 {
72 case 'd':
73 case 'b':
74 case 'B':
75 case 'o':
76 case 'x':
77 case 'X':
78 case 'c':
79 case 's':
80 case 'p':
81 case 'f':
82 case 'F':
83 case 'e':
84 case 'E':
85 case 'g':
86 case 'G':
87 return true;
88 default:
89 return false;
90 }
91}
92
102template <typename UInt>
103[[nodiscard]] consteval Error ParseUnsigned(std::string_view source, size_t& pos,
104 UInt limit, UInt& value)
105{
106 static_assert(std::is_unsigned_v<UInt>);
107
108 value = 0;
109 if (pos >= source.size() || !IsDigit(source[pos]))
110 {
111 return Error::InvalidSpecifier;
112 }
113
114 while (pos < source.size() && IsDigit(source[pos]))
115 {
116 auto digit = static_cast<UInt>(source[pos] - '0');
117 if (value > static_cast<UInt>((limit - digit) / 10))
118 {
119 return Error::NumberOverflow;
120 }
121 value = static_cast<UInt>(value * 10 + digit);
122 ++pos;
123 }
124
125 return Error::None;
126}
127
132{
133 bool uses_manual = false;
134 bool uses_auto = false;
135 size_t next_auto_index = 0;
136};
137
146[[nodiscard]] consteval Error ParseFieldHead(std::string_view source, size_t& pos,
147 IndexingState& indexing,
148 ParsedField& field)
149{
150 if (pos >= source.size())
151 {
152 return Error::UnexpectedEnd;
153 }
154
155 if (source[pos] == ':' || source[pos] == '}')
156 {
157 if (indexing.uses_manual)
158 {
159 return Error::MixedIndexing;
160 }
161
162 indexing.uses_auto = true;
163 field.arg_index = indexing.next_auto_index++;
164 return Error::None;
165 }
166
167 if (!IsDigit(source[pos]))
168 {
169 return Error::InvalidArgumentIndex;
170 }
171
172 size_t index = 0;
173 auto error =
174 ParseUnsigned(source, pos, std::numeric_limits<size_t>::max(), index);
175 if (error != Error::None)
176 {
177 return error;
178 }
179
180 if (indexing.uses_auto)
181 {
182 return Error::MixedIndexing;
183 }
184
185 if (!Config::enable_explicit_argument_indexing)
186 {
187 return Error::ManualIndexingDisabled;
188 }
189
190 indexing.uses_manual = true;
191 field.arg_index = index;
192 return Error::None;
193}
194
202[[nodiscard]] consteval Error ParseFormatSpec(std::string_view source, size_t& pos,
203 ParsedField& field)
204{
205 if (pos >= source.size())
206 {
207 return Error::UnexpectedEnd;
208 }
209
210 if (pos + 1 < source.size() && IsAlign(source[pos + 1]))
211 {
212 if (source[pos] == '{' || source[pos] == '}')
213 {
214 return Error::InvalidSpecifier;
215 }
216 field.fill = source[pos];
217 field.align = ParseAlign(source[pos + 1]);
218 pos += 2;
219 }
220 else if (IsAlign(source[pos]))
221 {
222 field.align = ParseAlign(source[pos]);
223 ++pos;
224 }
225
226 if (pos < source.size() &&
227 (source[pos] == '+' || source[pos] == '-' || source[pos] == ' '))
228 {
229 field.force_sign = source[pos] == '+';
230 field.space_sign = source[pos] == ' ';
231 ++pos;
232 }
233
234 if (pos < source.size() && source[pos] == '#')
235 {
236 if (!Config::enable_alternate)
237 {
238 return Error::InvalidSpecifier;
239 }
240 field.alternate = true;
241 ++pos;
242 }
243
244 if (pos < source.size() && source[pos] == '0')
245 {
246 field.zero_pad = true;
247 ++pos;
248 }
249
250 if (pos < source.size() && source[pos] == '{')
251 {
252 return Error::DynamicField;
253 }
254
255 if (pos < source.size() && IsDigit(source[pos]))
256 {
257 if (!Config::enable_width)
258 {
259 return Error::InvalidSpecifier;
260 }
261 auto error = ParseUnsigned(source, pos, std::numeric_limits<uint8_t>::max(),
262 field.width);
263 if (error != Error::None)
264 {
265 return error;
266 }
267 }
268
269 if (pos < source.size() && source[pos] == '.')
270 {
271 if (!Config::enable_precision)
272 {
273 return Error::InvalidSpecifier;
274 }
275
276 ++pos;
277 if (pos < source.size() && source[pos] == '{')
278 {
279 return Error::DynamicField;
280 }
281
282 field.has_precision = true;
283 auto error = ParseUnsigned(
284 source, pos, static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - 1),
285 field.precision);
286 if (error != Error::None)
287 {
288 return error;
289 }
290 }
291
292 if (pos < source.size() && source[pos] != '}')
293 {
294 field.presentation = source[pos++];
295 if (!IsSupportedPresentation(field.presentation))
296 {
297 return Error::InvalidPresentation;
298 }
299 }
300
301 return Error::None;
302}
303
312[[nodiscard]] consteval Error ParseField(std::string_view source, size_t& pos,
313 IndexingState& indexing,
314 ParsedField& field)
315{
316 ++pos;
317 if (pos >= source.size())
318 {
319 return Error::UnexpectedEnd;
320 }
321
322 auto error = ParseFieldHead(source, pos, indexing, field);
323 if (error != Error::None)
324 {
325 return error;
326 }
327
328 if (pos < source.size() && source[pos] != ':' && source[pos] != '}')
329 {
330 return Error::InvalidArgumentIndex;
331 }
332
333 if (pos < source.size() && source[pos] == ':')
334 {
335 ++pos;
336 error = ParseFormatSpec(source, pos, field);
337 if (error != Error::None)
338 {
339 return error;
340 }
341 }
342
343 if (pos >= source.size())
344 {
345 return Error::UnexpectedEnd;
346 }
347 if (source[pos] != '}')
348 {
349 return Error::InvalidSpecifier;
350 }
351
352 ++pos;
353 return Error::None;
354}
Error
brace 风格 format 前端的编译期失败类别。 / Compile-time failure categories for the brace-style format frontend.
Align
降为 FormatFlag 位之前的已解析对齐方式。 / Parsed alignment directive before lowering into FormatFlag bits.
brace 字段自动索引与手动索引的源级状态 / Source-level indexing mode for automatic versus manual brace fields
bool uses_auto
automatic field numbering is in use / 正在使用自动编号
size_t next_auto_index
next automatic argument index / 下一个自动参数索引
bool uses_manual
manual field numbering is in use / 正在使用手动编号