6
6
#include " fly/types/string/detail/format_parse_context.hpp"
7
7
#include " fly/types/string/detail/format_specifier.hpp"
8
8
#include " fly/types/string/detail/traits.hpp"
9
+ #include " fly/types/string/formatters.hpp"
9
10
#include " fly/types/string/lexer.hpp"
10
11
#include " fly/types/string/literals.hpp"
11
12
12
13
#include < array>
13
14
#include < cstdint>
14
15
#include < optional>
16
+ #include < tuple>
15
17
#include < type_traits>
16
18
17
19
namespace fly ::detail {
@@ -68,19 +70,15 @@ class BasicFormatString
68
70
constexpr FormatSpecifier parse_specifier ();
69
71
70
72
/* *
71
- * Parse a replacement field for a user-defined type.
73
+ * Parse a replacement field for a user-defined type. If the formatter for the user-defined type
74
+ * defines a |parse| method, it is invoked to parse any formatting options. Otherwise, it is an
75
+ * error if any formatting options are specified.
72
76
*
73
77
* @param specifier The replacement field being parsed.
74
78
*/
79
+ template <std::size_t N = 0 >
75
80
constexpr void parse_user_defined_specifier (FormatSpecifier &specifier);
76
81
77
- /* *
78
- * Parse a replacement field for a standard type.
79
- *
80
- * @param specifier The replacement field being parsed.
81
- */
82
- constexpr void parse_standard_specifier (FormatSpecifier &specifier);
83
-
84
82
static constexpr const auto s_left_brace = FLY_CHR(CharType, ' {' );
85
83
static constexpr const auto s_right_brace = FLY_CHR(CharType, ' }' );
86
84
static constexpr const auto s_colon = FLY_CHR(CharType, ' :' );
@@ -164,13 +162,22 @@ constexpr auto BasicFormatString<CharType, ParameterTypes...>::parse_specifier()
164
162
FormatSpecifier specifier (m_context);
165
163
specifier.m_parse_index = m_context.lexer ().position ();
166
164
167
- if (m_context.parameter_type (specifier. m_position ) == ParameterType::UserDefined )
165
+ if (m_context.lexer (). consume_if (s_colon) )
168
166
{
169
- parse_user_defined_specifier (specifier);
167
+ specifier.m_parse_index = m_context.lexer ().position ();
168
+
169
+ if (m_context.parameter_type (specifier.m_position ) == ParameterType::UserDefined)
170
+ {
171
+ parse_user_defined_specifier (specifier);
172
+ }
173
+ else
174
+ {
175
+ specifier.parse (m_context);
176
+ }
170
177
}
171
- else
178
+ else if (!m_context. lexer (). consume_if (s_right_brace))
172
179
{
173
- parse_standard_specifier (specifier );
180
+ m_context. on_error ( " Detected unclosed replacement field - must end with } " );
174
181
}
175
182
176
183
specifier.m_size = m_context.lexer ().position () - starting_position;
@@ -179,62 +186,35 @@ constexpr auto BasicFormatString<CharType, ParameterTypes...>::parse_specifier()
179
186
180
187
// ==================================================================================================
181
188
template <fly::StandardCharacter CharType, typename ... ParameterTypes>
189
+ template <std::size_t N>
182
190
constexpr void BasicFormatString<CharType, ParameterTypes...>::parse_user_defined_specifier(
183
191
FormatSpecifier &specifier)
184
192
{
185
- // Replacement fields for user-defined types are parsed at runtime.
186
- //
187
- // TODO: Formatters that inherit from standard formatters might be parsed at compile time.
188
- // TODO: Allow nested format specifiers.
189
- std::size_t expected_close_brace_count = 1 ;
190
- std::size_t nested_specifier_count = 0 ;
191
-
192
- while (expected_close_brace_count != 0 )
193
+ if constexpr (N < sizeof ...(ParameterTypes))
193
194
{
194
- if (auto ch = m_context. lexer (). consume (); ch )
195
+ if (N != specifier. m_position )
195
196
{
196
- if (ch == s_right_brace)
197
- {
198
- --expected_close_brace_count;
199
- }
200
- else if (ch == s_left_brace)
201
- {
202
- ++expected_close_brace_count;
203
- ++nested_specifier_count;
204
- }
205
- else if (ch == s_colon)
206
- {
207
- specifier.m_parse_index = m_context.lexer ().position ();
208
- }
197
+ parse_user_defined_specifier<N + 1 >(specifier);
198
+ return ;
199
+ }
200
+
201
+ using T = std::tuple_element_t <N, std::tuple<std::remove_cvref_t <ParameterTypes>...>>;
202
+ using Formatter = fly::Formatter<T, CharType>;
203
+
204
+ if constexpr (fly::FormattableWithParsing<FormatParseContext, Formatter>)
205
+ {
206
+ Formatter formatter;
207
+ formatter.parse (m_context);
209
208
}
210
209
else
211
210
{
212
- m_context.on_error (" Detected unclosed replacement field - must end with }" );
213
- expected_close_brace_count = 0 ;
211
+ if (!m_context.lexer ().consume_if (s_right_brace))
212
+ {
213
+ m_context.on_error (
214
+ " User-defined formatter without a parser may not have formatting options" );
215
+ }
214
216
}
215
217
}
216
-
217
- if (nested_specifier_count != 0 )
218
- {
219
- m_context.on_error (" Nested replacement fields are not allowed in user-defined formatters" );
220
- }
221
- }
222
-
223
- // ==================================================================================================
224
- template <fly::StandardCharacter CharType, typename ... ParameterTypes>
225
- constexpr void
226
- BasicFormatString<CharType, ParameterTypes...>::parse_standard_specifier(FormatSpecifier &specifier)
227
- {
228
- if (m_context.lexer ().consume_if (s_colon))
229
- {
230
- specifier.m_parse_index = m_context.lexer ().position ();
231
- specifier.parse (m_context);
232
- }
233
-
234
- if (!m_context.has_error () && !m_context.lexer ().consume_if (s_right_brace))
235
- {
236
- m_context.on_error (" Detected unclosed replacement field - must end with }" );
237
- }
238
218
}
239
219
240
220
} // namespace fly::detail
0 commit comments