Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include <array> // array
4 : : #include <clocale> // localeconv
5 : : #include <cstddef> // size_t
6 : : #include <cstdio> // snprintf
7 : : #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
8 : : #include <initializer_list> // initializer_list
9 : : #include <string> // char_traits, string
10 : : #include <utility> // move
11 : : #include <vector> // vector
12 : :
13 : : #include <nlohmann/detail/input/input_adapters.hpp>
14 : : #include <nlohmann/detail/input/position_t.hpp>
15 : : #include <nlohmann/detail/macro_scope.hpp>
16 : :
17 : : namespace nlohmann
18 : : {
19 : : namespace detail
20 : : {
21 : : ///////////
22 : : // lexer //
23 : : ///////////
24 : :
25 : : /*!
26 : : @brief lexical analysis
27 : :
28 : : This class organizes the lexical analysis during JSON deserialization.
29 : : */
30 : : template<typename BasicJsonType>
31 : : class lexer
32 : : {
33 : : using number_integer_t = typename BasicJsonType::number_integer_t;
34 : : using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
35 : : using number_float_t = typename BasicJsonType::number_float_t;
36 : : using string_t = typename BasicJsonType::string_t;
37 : :
38 : : public:
39 : : /// token types for the parser
40 : : enum class token_type
41 : : {
42 : : uninitialized, ///< indicating the scanner is uninitialized
43 : : literal_true, ///< the `true` literal
44 : : literal_false, ///< the `false` literal
45 : : literal_null, ///< the `null` literal
46 : : value_string, ///< a string -- use get_string() for actual value
47 : : value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value
48 : : value_integer, ///< a signed integer -- use get_number_integer() for actual value
49 : : value_float, ///< an floating point number -- use get_number_float() for actual value
50 : : begin_array, ///< the character for array begin `[`
51 : : begin_object, ///< the character for object begin `{`
52 : : end_array, ///< the character for array end `]`
53 : : end_object, ///< the character for object end `}`
54 : : name_separator, ///< the name separator `:`
55 : : value_separator, ///< the value separator `,`
56 : : parse_error, ///< indicating a parse error
57 : : end_of_input, ///< indicating the end of the input buffer
58 : : literal_or_value ///< a literal or the begin of a value (only for diagnostics)
59 : : };
60 : :
61 : : /// return name of values of type token_type (only used for errors)
62 : 0 : static const char* token_type_name(const token_type t) noexcept
63 : : {
64 : 0 : switch (t)
65 : : {
66 : : case token_type::uninitialized:
67 : 0 : return "<uninitialized>";
68 : : case token_type::literal_true:
69 : 0 : return "true literal";
70 : : case token_type::literal_false:
71 : 0 : return "false literal";
72 : : case token_type::literal_null:
73 : 0 : return "null literal";
74 : : case token_type::value_string:
75 : 0 : return "string literal";
76 : : case lexer::token_type::value_unsigned:
77 : : case lexer::token_type::value_integer:
78 : : case lexer::token_type::value_float:
79 : 0 : return "number literal";
80 : : case token_type::begin_array:
81 : 0 : return "'['";
82 : : case token_type::begin_object:
83 : 0 : return "'{'";
84 : : case token_type::end_array:
85 : 0 : return "']'";
86 : : case token_type::end_object:
87 : 0 : return "'}'";
88 : : case token_type::name_separator:
89 : 0 : return "':'";
90 : : case token_type::value_separator:
91 : 0 : return "','";
92 : : case token_type::parse_error:
93 : 0 : return "<parse error>";
94 : : case token_type::end_of_input:
95 : 0 : return "end of input";
96 : : case token_type::literal_or_value:
97 : 0 : return "'[', '{', or a literal";
98 : : // LCOV_EXCL_START
99 : : default: // catch non-enum values
100 : : return "unknown token";
101 : : // LCOV_EXCL_STOP
102 : : }
103 : 0 : }
104 : :
105 : 0 : explicit lexer(detail::input_adapter_t&& adapter)
106 : 0 : : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
107 : :
108 : : // delete because of pointer members
109 : : lexer(const lexer&) = delete;
110 : : lexer(lexer&&) = delete;
111 : : lexer& operator=(lexer&) = delete;
112 : : lexer& operator=(lexer&&) = delete;
113 : 0 : ~lexer() = default;
114 : :
115 : : private:
116 : : /////////////////////
117 : : // locales
118 : : /////////////////////
119 : :
120 : : /// return the locale-dependent decimal point
121 : 0 : static char get_decimal_point() noexcept
122 : : {
123 : 0 : const auto loc = localeconv();
124 : 0 : assert(loc != nullptr);
125 : 0 : return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
126 : : }
127 : :
128 : : /////////////////////
129 : : // scan functions
130 : : /////////////////////
131 : :
132 : : /*!
133 : : @brief get codepoint from 4 hex characters following `\u`
134 : :
135 : : For input "\u c1 c2 c3 c4" the codepoint is:
136 : : (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
137 : : = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
138 : :
139 : : Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
140 : : must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
141 : : conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
142 : : between the ASCII value of the character and the desired integer value.
143 : :
144 : : @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
145 : : non-hex character)
146 : : */
147 : 0 : int get_codepoint()
148 : : {
149 : : // this function only makes sense after reading `\u`
150 : 0 : assert(current == 'u');
151 : 0 : int codepoint = 0;
152 : :
153 : 0 : const auto factors = { 12u, 8u, 4u, 0u };
154 : 0 : for (const auto factor : factors)
155 : : {
156 : 0 : get();
157 : :
158 : 0 : if (current >= '0' and current <= '9')
159 : : {
160 : 0 : codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
161 : 0 : }
162 : 0 : else if (current >= 'A' and current <= 'F')
163 : : {
164 : 0 : codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
165 : 0 : }
166 : 0 : else if (current >= 'a' and current <= 'f')
167 : : {
168 : 0 : codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
169 : 0 : }
170 : : else
171 : : {
172 : 0 : return -1;
173 : : }
174 : : }
175 : :
176 : 0 : assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
177 : 0 : return codepoint;
178 : 0 : }
179 : :
180 : : /*!
181 : : @brief check if the next byte(s) are inside a given range
182 : :
183 : : Adds the current byte and, for each passed range, reads a new byte and
184 : : checks if it is inside the range. If a violation was detected, set up an
185 : : error message and return false. Otherwise, return true.
186 : :
187 : : @param[in] ranges list of integers; interpreted as list of pairs of
188 : : inclusive lower and upper bound, respectively
189 : :
190 : : @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
191 : : 1, 2, or 3 pairs. This precondition is enforced by an assertion.
192 : :
193 : : @return true if and only if no range violation was detected
194 : : */
195 : 0 : bool next_byte_in_range(std::initializer_list<int> ranges)
196 : : {
197 : 0 : assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
198 : 0 : add(current);
199 : :
200 : 0 : for (auto range = ranges.begin(); range != ranges.end(); ++range)
201 : : {
202 : 0 : get();
203 : 0 : if (JSON_LIKELY(*range <= current and current <= *(++range)))
204 : : {
205 : 0 : add(current);
206 : 0 : }
207 : : else
208 : : {
209 : 0 : error_message = "invalid string: ill-formed UTF-8 byte";
210 : 0 : return false;
211 : : }
212 : 0 : }
213 : :
214 : 0 : return true;
215 : 0 : }
216 : :
217 : : /*!
218 : : @brief scan a string literal
219 : :
220 : : This function scans a string according to Sect. 7 of RFC 7159. While
221 : : scanning, bytes are escaped and copied into buffer token_buffer. Then the
222 : : function returns successfully, token_buffer is *not* null-terminated (as it
223 : : may contain \0 bytes), and token_buffer.size() is the number of bytes in the
224 : : string.
225 : :
226 : : @return token_type::value_string if string could be successfully scanned,
227 : : token_type::parse_error otherwise
228 : :
229 : : @note In case of errors, variable error_message contains a textual
230 : : description.
231 : : */
232 : 0 : token_type scan_string()
233 : : {
234 : : // reset token_buffer (ignore opening quote)
235 : 0 : reset();
236 : :
237 : : // we entered the function by reading an open quote
238 : 0 : assert(current == '\"');
239 : :
240 : 0 : while (true)
241 : : {
242 : : // get next character
243 : 0 : switch (get())
244 : : {
245 : : // end of file while parsing string
246 : : case std::char_traits<char>::eof():
247 : : {
248 : 0 : error_message = "invalid string: missing closing quote";
249 : 0 : return token_type::parse_error;
250 : : }
251 : :
252 : : // closing quote
253 : : case '\"':
254 : : {
255 : 0 : return token_type::value_string;
256 : : }
257 : :
258 : : // escapes
259 : : case '\\':
260 : : {
261 : 0 : switch (get())
262 : : {
263 : : // quotation mark
264 : : case '\"':
265 : 0 : add('\"');
266 : 0 : break;
267 : : // reverse solidus
268 : : case '\\':
269 : 0 : add('\\');
270 : 0 : break;
271 : : // solidus
272 : : case '/':
273 : 0 : add('/');
274 : 0 : break;
275 : : // backspace
276 : : case 'b':
277 : 0 : add('\b');
278 : 0 : break;
279 : : // form feed
280 : : case 'f':
281 : 0 : add('\f');
282 : 0 : break;
283 : : // line feed
284 : : case 'n':
285 : 0 : add('\n');
286 : 0 : break;
287 : : // carriage return
288 : : case 'r':
289 : 0 : add('\r');
290 : 0 : break;
291 : : // tab
292 : : case 't':
293 : 0 : add('\t');
294 : 0 : break;
295 : :
296 : : // unicode escapes
297 : : case 'u':
298 : : {
299 : 0 : const int codepoint1 = get_codepoint();
300 : 0 : int codepoint = codepoint1; // start with codepoint1
301 : :
302 : 0 : if (JSON_UNLIKELY(codepoint1 == -1))
303 : : {
304 : 0 : error_message = "invalid string: '\\u' must be followed by 4 hex digits";
305 : 0 : return token_type::parse_error;
306 : : }
307 : :
308 : : // check if code point is a high surrogate
309 : 0 : if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
310 : : {
311 : : // expect next \uxxxx entry
312 : 0 : if (JSON_LIKELY(get() == '\\' and get() == 'u'))
313 : : {
314 : 0 : const int codepoint2 = get_codepoint();
315 : :
316 : 0 : if (JSON_UNLIKELY(codepoint2 == -1))
317 : : {
318 : 0 : error_message = "invalid string: '\\u' must be followed by 4 hex digits";
319 : 0 : return token_type::parse_error;
320 : : }
321 : :
322 : : // check if codepoint2 is a low surrogate
323 : 0 : if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
324 : : {
325 : : // overwrite codepoint
326 : 0 : codepoint = static_cast<int>(
327 : : // high surrogate occupies the most significant 22 bits
328 : 0 : (static_cast<unsigned int>(codepoint1) << 10u)
329 : : // low surrogate occupies the least significant 15 bits
330 : 0 : + static_cast<unsigned int>(codepoint2)
331 : : // there is still the 0xD800, 0xDC00 and 0x10000 noise
332 : : // in the result so we have to subtract with:
333 : : // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
334 : 0 : - 0x35FDC00u);
335 : 0 : }
336 : : else
337 : : {
338 : 0 : error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
339 : 0 : return token_type::parse_error;
340 : : }
341 : 0 : }
342 : : else
343 : : {
344 : 0 : error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
345 : 0 : return token_type::parse_error;
346 : : }
347 : 0 : }
348 : : else
349 : : {
350 : 0 : if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
351 : : {
352 : 0 : error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
353 : 0 : return token_type::parse_error;
354 : : }
355 : : }
356 : :
357 : : // result of the above calculation yields a proper codepoint
358 : 0 : assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
359 : :
360 : : // translate codepoint into bytes
361 : 0 : if (codepoint < 0x80)
362 : : {
363 : : // 1-byte characters: 0xxxxxxx (ASCII)
364 : 0 : add(codepoint);
365 : 0 : }
366 : 0 : else if (codepoint <= 0x7FF)
367 : : {
368 : : // 2-byte characters: 110xxxxx 10xxxxxx
369 : 0 : add(static_cast<int>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
370 : 0 : add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
371 : 0 : }
372 : 0 : else if (codepoint <= 0xFFFF)
373 : : {
374 : : // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
375 : 0 : add(static_cast<int>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
376 : 0 : add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
377 : 0 : add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
378 : 0 : }
379 : : else
380 : : {
381 : : // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
382 : 0 : add(static_cast<int>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
383 : 0 : add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
384 : 0 : add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
385 : 0 : add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
386 : : }
387 : :
388 : 0 : break;
389 : : }
390 : :
391 : : // other characters after escape
392 : : default:
393 : 0 : error_message = "invalid string: forbidden character after backslash";
394 : 0 : return token_type::parse_error;
395 : : }
396 : :
397 : 0 : break;
398 : : }
399 : :
400 : : // invalid control characters
401 : : case 0x00:
402 : : {
403 : 0 : error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
404 : 0 : return token_type::parse_error;
405 : : }
406 : :
407 : : case 0x01:
408 : : {
409 : 0 : error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
410 : 0 : return token_type::parse_error;
411 : : }
412 : :
413 : : case 0x02:
414 : : {
415 : 0 : error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
416 : 0 : return token_type::parse_error;
417 : : }
418 : :
419 : : case 0x03:
420 : : {
421 : 0 : error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
422 : 0 : return token_type::parse_error;
423 : : }
424 : :
425 : : case 0x04:
426 : : {
427 : 0 : error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
428 : 0 : return token_type::parse_error;
429 : : }
430 : :
431 : : case 0x05:
432 : : {
433 : 0 : error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
434 : 0 : return token_type::parse_error;
435 : : }
436 : :
437 : : case 0x06:
438 : : {
439 : 0 : error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
440 : 0 : return token_type::parse_error;
441 : : }
442 : :
443 : : case 0x07:
444 : : {
445 : 0 : error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
446 : 0 : return token_type::parse_error;
447 : : }
448 : :
449 : : case 0x08:
450 : : {
451 : 0 : error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
452 : 0 : return token_type::parse_error;
453 : : }
454 : :
455 : : case 0x09:
456 : : {
457 : 0 : error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
458 : 0 : return token_type::parse_error;
459 : : }
460 : :
461 : : case 0x0A:
462 : : {
463 : 0 : error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
464 : 0 : return token_type::parse_error;
465 : : }
466 : :
467 : : case 0x0B:
468 : : {
469 : 0 : error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
470 : 0 : return token_type::parse_error;
471 : : }
472 : :
473 : : case 0x0C:
474 : : {
475 : 0 : error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
476 : 0 : return token_type::parse_error;
477 : : }
478 : :
479 : : case 0x0D:
480 : : {
481 : 0 : error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
482 : 0 : return token_type::parse_error;
483 : : }
484 : :
485 : : case 0x0E:
486 : : {
487 : 0 : error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
488 : 0 : return token_type::parse_error;
489 : : }
490 : :
491 : : case 0x0F:
492 : : {
493 : 0 : error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
494 : 0 : return token_type::parse_error;
495 : : }
496 : :
497 : : case 0x10:
498 : : {
499 : 0 : error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
500 : 0 : return token_type::parse_error;
501 : : }
502 : :
503 : : case 0x11:
504 : : {
505 : 0 : error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
506 : 0 : return token_type::parse_error;
507 : : }
508 : :
509 : : case 0x12:
510 : : {
511 : 0 : error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
512 : 0 : return token_type::parse_error;
513 : : }
514 : :
515 : : case 0x13:
516 : : {
517 : 0 : error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
518 : 0 : return token_type::parse_error;
519 : : }
520 : :
521 : : case 0x14:
522 : : {
523 : 0 : error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
524 : 0 : return token_type::parse_error;
525 : : }
526 : :
527 : : case 0x15:
528 : : {
529 : 0 : error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
530 : 0 : return token_type::parse_error;
531 : : }
532 : :
533 : : case 0x16:
534 : : {
535 : 0 : error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
536 : 0 : return token_type::parse_error;
537 : : }
538 : :
539 : : case 0x17:
540 : : {
541 : 0 : error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
542 : 0 : return token_type::parse_error;
543 : : }
544 : :
545 : : case 0x18:
546 : : {
547 : 0 : error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
548 : 0 : return token_type::parse_error;
549 : : }
550 : :
551 : : case 0x19:
552 : : {
553 : 0 : error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
554 : 0 : return token_type::parse_error;
555 : : }
556 : :
557 : : case 0x1A:
558 : : {
559 : 0 : error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
560 : 0 : return token_type::parse_error;
561 : : }
562 : :
563 : : case 0x1B:
564 : : {
565 : 0 : error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
566 : 0 : return token_type::parse_error;
567 : : }
568 : :
569 : : case 0x1C:
570 : : {
571 : 0 : error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
572 : 0 : return token_type::parse_error;
573 : : }
574 : :
575 : : case 0x1D:
576 : : {
577 : 0 : error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
578 : 0 : return token_type::parse_error;
579 : : }
580 : :
581 : : case 0x1E:
582 : : {
583 : 0 : error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
584 : 0 : return token_type::parse_error;
585 : : }
586 : :
587 : : case 0x1F:
588 : : {
589 : 0 : error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
590 : 0 : return token_type::parse_error;
591 : : }
592 : :
593 : : // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
594 : : case 0x20:
595 : : case 0x21:
596 : : case 0x23:
597 : : case 0x24:
598 : : case 0x25:
599 : : case 0x26:
600 : : case 0x27:
601 : : case 0x28:
602 : : case 0x29:
603 : : case 0x2A:
604 : : case 0x2B:
605 : : case 0x2C:
606 : : case 0x2D:
607 : : case 0x2E:
608 : : case 0x2F:
609 : : case 0x30:
610 : : case 0x31:
611 : : case 0x32:
612 : : case 0x33:
613 : : case 0x34:
614 : : case 0x35:
615 : : case 0x36:
616 : : case 0x37:
617 : : case 0x38:
618 : : case 0x39:
619 : : case 0x3A:
620 : : case 0x3B:
621 : : case 0x3C:
622 : : case 0x3D:
623 : : case 0x3E:
624 : : case 0x3F:
625 : : case 0x40:
626 : : case 0x41:
627 : : case 0x42:
628 : : case 0x43:
629 : : case 0x44:
630 : : case 0x45:
631 : : case 0x46:
632 : : case 0x47:
633 : : case 0x48:
634 : : case 0x49:
635 : : case 0x4A:
636 : : case 0x4B:
637 : : case 0x4C:
638 : : case 0x4D:
639 : : case 0x4E:
640 : : case 0x4F:
641 : : case 0x50:
642 : : case 0x51:
643 : : case 0x52:
644 : : case 0x53:
645 : : case 0x54:
646 : : case 0x55:
647 : : case 0x56:
648 : : case 0x57:
649 : : case 0x58:
650 : : case 0x59:
651 : : case 0x5A:
652 : : case 0x5B:
653 : : case 0x5D:
654 : : case 0x5E:
655 : : case 0x5F:
656 : : case 0x60:
657 : : case 0x61:
658 : : case 0x62:
659 : : case 0x63:
660 : : case 0x64:
661 : : case 0x65:
662 : : case 0x66:
663 : : case 0x67:
664 : : case 0x68:
665 : : case 0x69:
666 : : case 0x6A:
667 : : case 0x6B:
668 : : case 0x6C:
669 : : case 0x6D:
670 : : case 0x6E:
671 : : case 0x6F:
672 : : case 0x70:
673 : : case 0x71:
674 : : case 0x72:
675 : : case 0x73:
676 : : case 0x74:
677 : : case 0x75:
678 : : case 0x76:
679 : : case 0x77:
680 : : case 0x78:
681 : : case 0x79:
682 : : case 0x7A:
683 : : case 0x7B:
684 : : case 0x7C:
685 : : case 0x7D:
686 : : case 0x7E:
687 : : case 0x7F:
688 : : {
689 : 0 : add(current);
690 : 0 : break;
691 : : }
692 : :
693 : : // U+0080..U+07FF: bytes C2..DF 80..BF
694 : : case 0xC2:
695 : : case 0xC3:
696 : : case 0xC4:
697 : : case 0xC5:
698 : : case 0xC6:
699 : : case 0xC7:
700 : : case 0xC8:
701 : : case 0xC9:
702 : : case 0xCA:
703 : : case 0xCB:
704 : : case 0xCC:
705 : : case 0xCD:
706 : : case 0xCE:
707 : : case 0xCF:
708 : : case 0xD0:
709 : : case 0xD1:
710 : : case 0xD2:
711 : : case 0xD3:
712 : : case 0xD4:
713 : : case 0xD5:
714 : : case 0xD6:
715 : : case 0xD7:
716 : : case 0xD8:
717 : : case 0xD9:
718 : : case 0xDA:
719 : : case 0xDB:
720 : : case 0xDC:
721 : : case 0xDD:
722 : : case 0xDE:
723 : : case 0xDF:
724 : : {
725 : 0 : if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
726 : : {
727 : 0 : return token_type::parse_error;
728 : : }
729 : 0 : break;
730 : : }
731 : :
732 : : // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
733 : : case 0xE0:
734 : : {
735 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
736 : : {
737 : 0 : return token_type::parse_error;
738 : : }
739 : 0 : break;
740 : : }
741 : :
742 : : // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
743 : : // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
744 : : case 0xE1:
745 : : case 0xE2:
746 : : case 0xE3:
747 : : case 0xE4:
748 : : case 0xE5:
749 : : case 0xE6:
750 : : case 0xE7:
751 : : case 0xE8:
752 : : case 0xE9:
753 : : case 0xEA:
754 : : case 0xEB:
755 : : case 0xEC:
756 : : case 0xEE:
757 : : case 0xEF:
758 : : {
759 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
760 : : {
761 : 0 : return token_type::parse_error;
762 : : }
763 : 0 : break;
764 : : }
765 : :
766 : : // U+D000..U+D7FF: bytes ED 80..9F 80..BF
767 : : case 0xED:
768 : : {
769 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
770 : : {
771 : 0 : return token_type::parse_error;
772 : : }
773 : 0 : break;
774 : : }
775 : :
776 : : // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
777 : : case 0xF0:
778 : : {
779 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
780 : : {
781 : 0 : return token_type::parse_error;
782 : : }
783 : 0 : break;
784 : : }
785 : :
786 : : // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
787 : : case 0xF1:
788 : : case 0xF2:
789 : : case 0xF3:
790 : : {
791 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
792 : : {
793 : 0 : return token_type::parse_error;
794 : : }
795 : 0 : break;
796 : : }
797 : :
798 : : // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
799 : : case 0xF4:
800 : : {
801 : 0 : if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
802 : : {
803 : 0 : return token_type::parse_error;
804 : : }
805 : 0 : break;
806 : : }
807 : :
808 : : // remaining bytes (80..C1 and F5..FF) are ill-formed
809 : : default:
810 : : {
811 : 0 : error_message = "invalid string: ill-formed UTF-8 byte";
812 : 0 : return token_type::parse_error;
813 : : }
814 : : }
815 : : }
816 : 0 : }
817 : :
818 : : static void strtof(float& f, const char* str, char** endptr) noexcept
819 : : {
820 : : f = std::strtof(str, endptr);
821 : : }
822 : :
823 : 0 : static void strtof(double& f, const char* str, char** endptr) noexcept
824 : : {
825 : 0 : f = std::strtod(str, endptr);
826 : 0 : }
827 : :
828 : : static void strtof(long double& f, const char* str, char** endptr) noexcept
829 : : {
830 : : f = std::strtold(str, endptr);
831 : : }
832 : :
833 : : /*!
834 : : @brief scan a number literal
835 : :
836 : : This function scans a string according to Sect. 6 of RFC 7159.
837 : :
838 : : The function is realized with a deterministic finite state machine derived
839 : : from the grammar described in RFC 7159. Starting in state "init", the
840 : : input is read and used to determined the next state. Only state "done"
841 : : accepts the number. State "error" is a trap state to model errors. In the
842 : : table below, "anything" means any character but the ones listed before.
843 : :
844 : : state | 0 | 1-9 | e E | + | - | . | anything
845 : : ---------|----------|----------|----------|---------|---------|----------|-----------
846 : : init | zero | any1 | [error] | [error] | minus | [error] | [error]
847 : : minus | zero | any1 | [error] | [error] | [error] | [error] | [error]
848 : : zero | done | done | exponent | done | done | decimal1 | done
849 : : any1 | any1 | any1 | exponent | done | done | decimal1 | done
850 : : decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error]
851 : : decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
852 : : exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
853 : : sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
854 : : any2 | any2 | any2 | done | done | done | done | done
855 : :
856 : : The state machine is realized with one label per state (prefixed with
857 : : "scan_number_") and `goto` statements between them. The state machine
858 : : contains cycles, but any cycle can be left when EOF is read. Therefore,
859 : : the function is guaranteed to terminate.
860 : :
861 : : During scanning, the read bytes are stored in token_buffer. This string is
862 : : then converted to a signed integer, an unsigned integer, or a
863 : : floating-point number.
864 : :
865 : : @return token_type::value_unsigned, token_type::value_integer, or
866 : : token_type::value_float if number could be successfully scanned,
867 : : token_type::parse_error otherwise
868 : :
869 : : @note The scanner is independent of the current locale. Internally, the
870 : : locale's decimal point is used instead of `.` to work with the
871 : : locale-dependent converters.
872 : : */
873 : 0 : token_type scan_number() // lgtm [cpp/use-of-goto]
874 : : {
875 : : // reset token_buffer to store the number's bytes
876 : 0 : reset();
877 : :
878 : : // the type of the parsed number; initially set to unsigned; will be
879 : : // changed if minus sign, decimal point or exponent is read
880 : 0 : token_type number_type = token_type::value_unsigned;
881 : :
882 : : // state (init): we just found out we need to scan a number
883 : 0 : switch (current)
884 : : {
885 : : case '-':
886 : : {
887 : 0 : add(current);
888 : 0 : goto scan_number_minus;
889 : : }
890 : :
891 : : case '0':
892 : : {
893 : 0 : add(current);
894 : 0 : goto scan_number_zero;
895 : : }
896 : :
897 : : case '1':
898 : : case '2':
899 : : case '3':
900 : : case '4':
901 : : case '5':
902 : : case '6':
903 : : case '7':
904 : : case '8':
905 : : case '9':
906 : : {
907 : 0 : add(current);
908 : 0 : goto scan_number_any1;
909 : : }
910 : :
911 : : // all other characters are rejected outside scan_number()
912 : : default: // LCOV_EXCL_LINE
913 : : assert(false); // LCOV_EXCL_LINE
914 : : }
915 : :
916 : : scan_number_minus:
917 : : // state: we just parsed a leading minus sign
918 : 0 : number_type = token_type::value_integer;
919 : 0 : switch (get())
920 : : {
921 : : case '0':
922 : : {
923 : 0 : add(current);
924 : 0 : goto scan_number_zero;
925 : : }
926 : :
927 : : case '1':
928 : : case '2':
929 : : case '3':
930 : : case '4':
931 : : case '5':
932 : : case '6':
933 : : case '7':
934 : : case '8':
935 : : case '9':
936 : : {
937 : 0 : add(current);
938 : 0 : goto scan_number_any1;
939 : : }
940 : :
941 : : default:
942 : : {
943 : 0 : error_message = "invalid number; expected digit after '-'";
944 : 0 : return token_type::parse_error;
945 : : }
946 : : }
947 : :
948 : : scan_number_zero:
949 : : // state: we just parse a zero (maybe with a leading minus sign)
950 : 0 : switch (get())
951 : : {
952 : : case '.':
953 : : {
954 : 0 : add(decimal_point_char);
955 : 0 : goto scan_number_decimal1;
956 : : }
957 : :
958 : : case 'e':
959 : : case 'E':
960 : : {
961 : 0 : add(current);
962 : 0 : goto scan_number_exponent;
963 : : }
964 : :
965 : : default:
966 : 0 : goto scan_number_done;
967 : : }
968 : :
969 : : scan_number_any1:
970 : : // state: we just parsed a number 0-9 (maybe with a leading minus sign)
971 : 0 : switch (get())
972 : : {
973 : : case '0':
974 : : case '1':
975 : : case '2':
976 : : case '3':
977 : : case '4':
978 : : case '5':
979 : : case '6':
980 : : case '7':
981 : : case '8':
982 : : case '9':
983 : : {
984 : 0 : add(current);
985 : 0 : goto scan_number_any1;
986 : : }
987 : :
988 : : case '.':
989 : : {
990 : 0 : add(decimal_point_char);
991 : 0 : goto scan_number_decimal1;
992 : : }
993 : :
994 : : case 'e':
995 : : case 'E':
996 : : {
997 : 0 : add(current);
998 : 0 : goto scan_number_exponent;
999 : : }
1000 : :
1001 : : default:
1002 : 0 : goto scan_number_done;
1003 : : }
1004 : :
1005 : : scan_number_decimal1:
1006 : : // state: we just parsed a decimal point
1007 : 0 : number_type = token_type::value_float;
1008 : 0 : switch (get())
1009 : : {
1010 : : case '0':
1011 : : case '1':
1012 : : case '2':
1013 : : case '3':
1014 : : case '4':
1015 : : case '5':
1016 : : case '6':
1017 : : case '7':
1018 : : case '8':
1019 : : case '9':
1020 : : {
1021 : 0 : add(current);
1022 : 0 : goto scan_number_decimal2;
1023 : : }
1024 : :
1025 : : default:
1026 : : {
1027 : 0 : error_message = "invalid number; expected digit after '.'";
1028 : 0 : return token_type::parse_error;
1029 : : }
1030 : : }
1031 : :
1032 : : scan_number_decimal2:
1033 : : // we just parsed at least one number after a decimal point
1034 : 0 : switch (get())
1035 : : {
1036 : : case '0':
1037 : : case '1':
1038 : : case '2':
1039 : : case '3':
1040 : : case '4':
1041 : : case '5':
1042 : : case '6':
1043 : : case '7':
1044 : : case '8':
1045 : : case '9':
1046 : : {
1047 : 0 : add(current);
1048 : 0 : goto scan_number_decimal2;
1049 : : }
1050 : :
1051 : : case 'e':
1052 : : case 'E':
1053 : : {
1054 : 0 : add(current);
1055 : 0 : goto scan_number_exponent;
1056 : : }
1057 : :
1058 : : default:
1059 : 0 : goto scan_number_done;
1060 : : }
1061 : :
1062 : : scan_number_exponent:
1063 : : // we just parsed an exponent
1064 : 0 : number_type = token_type::value_float;
1065 : 0 : switch (get())
1066 : : {
1067 : : case '+':
1068 : : case '-':
1069 : : {
1070 : 0 : add(current);
1071 : 0 : goto scan_number_sign;
1072 : : }
1073 : :
1074 : : case '0':
1075 : : case '1':
1076 : : case '2':
1077 : : case '3':
1078 : : case '4':
1079 : : case '5':
1080 : : case '6':
1081 : : case '7':
1082 : : case '8':
1083 : : case '9':
1084 : : {
1085 : 0 : add(current);
1086 : 0 : goto scan_number_any2;
1087 : : }
1088 : :
1089 : : default:
1090 : : {
1091 : 0 : error_message =
1092 : : "invalid number; expected '+', '-', or digit after exponent";
1093 : 0 : return token_type::parse_error;
1094 : : }
1095 : : }
1096 : :
1097 : : scan_number_sign:
1098 : : // we just parsed an exponent sign
1099 : 0 : switch (get())
1100 : : {
1101 : : case '0':
1102 : : case '1':
1103 : : case '2':
1104 : : case '3':
1105 : : case '4':
1106 : : case '5':
1107 : : case '6':
1108 : : case '7':
1109 : : case '8':
1110 : : case '9':
1111 : : {
1112 : 0 : add(current);
1113 : 0 : goto scan_number_any2;
1114 : : }
1115 : :
1116 : : default:
1117 : : {
1118 : 0 : error_message = "invalid number; expected digit after exponent sign";
1119 : 0 : return token_type::parse_error;
1120 : : }
1121 : : }
1122 : :
1123 : : scan_number_any2:
1124 : : // we just parsed a number after the exponent or exponent sign
1125 : 0 : switch (get())
1126 : : {
1127 : : case '0':
1128 : : case '1':
1129 : : case '2':
1130 : : case '3':
1131 : : case '4':
1132 : : case '5':
1133 : : case '6':
1134 : : case '7':
1135 : : case '8':
1136 : : case '9':
1137 : : {
1138 : 0 : add(current);
1139 : 0 : goto scan_number_any2;
1140 : : }
1141 : :
1142 : : default:
1143 : 0 : goto scan_number_done;
1144 : : }
1145 : :
1146 : : scan_number_done:
1147 : : // unget the character after the number (we only read it to know that
1148 : : // we are done scanning a number)
1149 : 0 : unget();
1150 : :
1151 : 0 : char* endptr = nullptr;
1152 : 0 : errno = 0;
1153 : :
1154 : : // try to parse integers first and fall back to floats
1155 : 0 : if (number_type == token_type::value_unsigned)
1156 : : {
1157 : 0 : const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
1158 : :
1159 : : // we checked the number format before
1160 : 0 : assert(endptr == token_buffer.data() + token_buffer.size());
1161 : :
1162 : 0 : if (errno == 0)
1163 : : {
1164 : 0 : value_unsigned = static_cast<number_unsigned_t>(x);
1165 : 0 : if (value_unsigned == x)
1166 : : {
1167 : 0 : return token_type::value_unsigned;
1168 : : }
1169 : 0 : }
1170 : 0 : }
1171 : 0 : else if (number_type == token_type::value_integer)
1172 : : {
1173 : 0 : const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
1174 : :
1175 : : // we checked the number format before
1176 : 0 : assert(endptr == token_buffer.data() + token_buffer.size());
1177 : :
1178 : 0 : if (errno == 0)
1179 : : {
1180 : 0 : value_integer = static_cast<number_integer_t>(x);
1181 : 0 : if (value_integer == x)
1182 : : {
1183 : 0 : return token_type::value_integer;
1184 : : }
1185 : 0 : }
1186 : 0 : }
1187 : :
1188 : : // this code is reached if we parse a floating-point number or if an
1189 : : // integer conversion above failed
1190 : 0 : strtof(value_float, token_buffer.data(), &endptr);
1191 : :
1192 : : // we checked the number format before
1193 : 0 : assert(endptr == token_buffer.data() + token_buffer.size());
1194 : :
1195 : 0 : return token_type::value_float;
1196 : 0 : }
1197 : :
1198 : : /*!
1199 : : @param[in] literal_text the literal text to expect
1200 : : @param[in] length the length of the passed literal text
1201 : : @param[in] return_type the token type to return on success
1202 : : */
1203 : 0 : token_type scan_literal(const char* literal_text, const std::size_t length,
1204 : : token_type return_type)
1205 : : {
1206 : 0 : assert(current == literal_text[0]);
1207 : 0 : for (std::size_t i = 1; i < length; ++i)
1208 : : {
1209 : 0 : if (JSON_UNLIKELY(get() != literal_text[i]))
1210 : : {
1211 : 0 : error_message = "invalid literal";
1212 : 0 : return token_type::parse_error;
1213 : : }
1214 : 0 : }
1215 : 0 : return return_type;
1216 : 0 : }
1217 : :
1218 : : /////////////////////
1219 : : // input management
1220 : : /////////////////////
1221 : :
1222 : : /// reset token_buffer; current character is beginning of token
1223 : 0 : void reset() noexcept
1224 : : {
1225 : 0 : token_buffer.clear();
1226 : 0 : token_string.clear();
1227 : 0 : token_string.push_back(std::char_traits<char>::to_char_type(current));
1228 : 0 : }
1229 : :
1230 : : /*
1231 : : @brief get next character from the input
1232 : :
1233 : : This function provides the interface to the used input adapter. It does
1234 : : not throw in case the input reached EOF, but returns a
1235 : : `std::char_traits<char>::eof()` in that case. Stores the scanned characters
1236 : : for use in error messages.
1237 : :
1238 : : @return character read from the input
1239 : : */
1240 : 0 : std::char_traits<char>::int_type get()
1241 : : {
1242 : 0 : ++position.chars_read_total;
1243 : 0 : ++position.chars_read_current_line;
1244 : :
1245 : 0 : if (next_unget)
1246 : : {
1247 : : // just reset the next_unget variable and work with current
1248 : 0 : next_unget = false;
1249 : 0 : }
1250 : : else
1251 : : {
1252 : 0 : current = ia->get_character();
1253 : : }
1254 : :
1255 : 0 : if (JSON_LIKELY(current != std::char_traits<char>::eof()))
1256 : : {
1257 : 0 : token_string.push_back(std::char_traits<char>::to_char_type(current));
1258 : 0 : }
1259 : :
1260 : 0 : if (current == '\n')
1261 : : {
1262 : 0 : ++position.lines_read;
1263 : 0 : position.chars_read_current_line = 0;
1264 : 0 : }
1265 : :
1266 : 0 : return current;
1267 : : }
1268 : :
1269 : : /*!
1270 : : @brief unget current character (read it again on next get)
1271 : :
1272 : : We implement unget by setting variable next_unget to true. The input is not
1273 : : changed - we just simulate ungetting by modifying chars_read_total,
1274 : : chars_read_current_line, and token_string. The next call to get() will
1275 : : behave as if the unget character is read again.
1276 : : */
1277 : 0 : void unget()
1278 : : {
1279 : 0 : next_unget = true;
1280 : :
1281 : 0 : --position.chars_read_total;
1282 : :
1283 : : // in case we "unget" a newline, we have to also decrement the lines_read
1284 : 0 : if (position.chars_read_current_line == 0)
1285 : : {
1286 : 0 : if (position.lines_read > 0)
1287 : : {
1288 : 0 : --position.lines_read;
1289 : 0 : }
1290 : 0 : }
1291 : : else
1292 : : {
1293 : 0 : --position.chars_read_current_line;
1294 : : }
1295 : :
1296 : 0 : if (JSON_LIKELY(current != std::char_traits<char>::eof()))
1297 : : {
1298 : 0 : assert(not token_string.empty());
1299 : 0 : token_string.pop_back();
1300 : 0 : }
1301 : 0 : }
1302 : :
1303 : : /// add a character to token_buffer
1304 : 0 : void add(int c)
1305 : : {
1306 : 0 : token_buffer.push_back(std::char_traits<char>::to_char_type(c));
1307 : 0 : }
1308 : :
1309 : : public:
1310 : : /////////////////////
1311 : : // value getters
1312 : : /////////////////////
1313 : :
1314 : : /// return integer value
1315 : 0 : constexpr number_integer_t get_number_integer() const noexcept
1316 : : {
1317 : 0 : return value_integer;
1318 : : }
1319 : :
1320 : : /// return unsigned integer value
1321 : 0 : constexpr number_unsigned_t get_number_unsigned() const noexcept
1322 : : {
1323 : 0 : return value_unsigned;
1324 : : }
1325 : :
1326 : : /// return floating-point value
1327 : 0 : constexpr number_float_t get_number_float() const noexcept
1328 : : {
1329 : 0 : return value_float;
1330 : : }
1331 : :
1332 : : /// return current string value (implicitly resets the token; useful only once)
1333 : 0 : string_t& get_string()
1334 : : {
1335 : 0 : return token_buffer;
1336 : : }
1337 : :
1338 : : /////////////////////
1339 : : // diagnostics
1340 : : /////////////////////
1341 : :
1342 : : /// return position of last read token
1343 : 0 : constexpr position_t get_position() const noexcept
1344 : : {
1345 : 0 : return position;
1346 : : }
1347 : :
1348 : : /// return the last read token (for errors only). Will never contain EOF
1349 : : /// (an arbitrary value that is not a valid char value, often -1), because
1350 : : /// 255 may legitimately occur. May contain NUL, which should be escaped.
1351 : 0 : std::string get_token_string() const
1352 : : {
1353 : : // escape control characters
1354 : 0 : std::string result;
1355 : 0 : for (const auto c : token_string)
1356 : : {
1357 : 0 : if ('\x00' <= c and c <= '\x1F')
1358 : : {
1359 : : // escape control characters
1360 : 0 : std::array<char, 9> cs{{}};
1361 : 0 : (std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c));
1362 : 0 : result += cs.data();
1363 : 0 : }
1364 : : else
1365 : : {
1366 : : // add character as is
1367 : 0 : result.push_back(c);
1368 : : }
1369 : : }
1370 : :
1371 : 0 : return result;
1372 : 0 : }
1373 : :
1374 : : /// return syntax error message
1375 : 0 : constexpr const char* get_error_message() const noexcept
1376 : : {
1377 : 0 : return error_message;
1378 : : }
1379 : :
1380 : : /////////////////////
1381 : : // actual scanner
1382 : : /////////////////////
1383 : :
1384 : : /*!
1385 : : @brief skip the UTF-8 byte order mark
1386 : : @return true iff there is no BOM or the correct BOM has been skipped
1387 : : */
1388 : 0 : bool skip_bom()
1389 : : {
1390 : 0 : if (get() == 0xEF)
1391 : : {
1392 : : // check if we completely parse the BOM
1393 : 0 : return get() == 0xBB and get() == 0xBF;
1394 : : }
1395 : :
1396 : : // the first character is not the beginning of the BOM; unget it to
1397 : : // process is later
1398 : 0 : unget();
1399 : 0 : return true;
1400 : 0 : }
1401 : :
1402 : 0 : token_type scan()
1403 : : {
1404 : : // initially, skip the BOM
1405 : 0 : if (position.chars_read_total == 0 and not skip_bom())
1406 : : {
1407 : 0 : error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
1408 : 0 : return token_type::parse_error;
1409 : : }
1410 : :
1411 : : // read next character and ignore whitespace
1412 : 0 : do
1413 : : {
1414 : 0 : get();
1415 : 0 : }
1416 : 0 : while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
1417 : :
1418 : 0 : switch (current)
1419 : : {
1420 : : // structural characters
1421 : : case '[':
1422 : 0 : return token_type::begin_array;
1423 : : case ']':
1424 : 0 : return token_type::end_array;
1425 : : case '{':
1426 : 0 : return token_type::begin_object;
1427 : : case '}':
1428 : 0 : return token_type::end_object;
1429 : : case ':':
1430 : 0 : return token_type::name_separator;
1431 : : case ',':
1432 : 0 : return token_type::value_separator;
1433 : :
1434 : : // literals
1435 : : case 't':
1436 : 0 : return scan_literal("true", 4, token_type::literal_true);
1437 : : case 'f':
1438 : 0 : return scan_literal("false", 5, token_type::literal_false);
1439 : : case 'n':
1440 : 0 : return scan_literal("null", 4, token_type::literal_null);
1441 : :
1442 : : // string
1443 : : case '\"':
1444 : 0 : return scan_string();
1445 : :
1446 : : // number
1447 : : case '-':
1448 : : case '0':
1449 : : case '1':
1450 : : case '2':
1451 : : case '3':
1452 : : case '4':
1453 : : case '5':
1454 : : case '6':
1455 : : case '7':
1456 : : case '8':
1457 : : case '9':
1458 : 0 : return scan_number();
1459 : :
1460 : : // end of input (the null byte is needed when parsing from
1461 : : // string literals)
1462 : : case '\0':
1463 : : case std::char_traits<char>::eof():
1464 : 0 : return token_type::end_of_input;
1465 : :
1466 : : // error
1467 : : default:
1468 : 0 : error_message = "invalid literal";
1469 : 0 : return token_type::parse_error;
1470 : : }
1471 : 0 : }
1472 : :
1473 : : private:
1474 : : /// input adapter
1475 : : detail::input_adapter_t ia = nullptr;
1476 : :
1477 : : /// the current character
1478 : 0 : std::char_traits<char>::int_type current = std::char_traits<char>::eof();
1479 : :
1480 : : /// whether the next get() call should just return current
1481 : 0 : bool next_unget = false;
1482 : :
1483 : : /// the start position of the current token
1484 : 0 : position_t position {};
1485 : :
1486 : : /// raw input token string (for error messages)
1487 : 0 : std::vector<char> token_string {};
1488 : :
1489 : : /// buffer for variable-length tokens (numbers, strings)
1490 : 0 : string_t token_buffer {};
1491 : :
1492 : : /// a description of occurred lexer errors
1493 : 0 : const char* error_message = "";
1494 : :
1495 : : // number values
1496 : 0 : number_integer_t value_integer = 0;
1497 : 0 : number_unsigned_t value_unsigned = 0;
1498 : 0 : number_float_t value_float = 0;
1499 : :
1500 : : /// the decimal point
1501 : : const char decimal_point_char = '.';
1502 : : };
1503 : : } // namespace detail
1504 : : } // namespace nlohmann
|