LCOV - code coverage report
Current view: top level - home/lbartoletti/qgis_coverage_src/external/nlohmann/detail/input - lexer.hpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 416 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           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

Generated by: LCOV version 1.14