LCOV - code coverage report
Current view: top level - gcc/rust/lex - rust-lex.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 84.3 % 1354 1141
Test Date: 2023-09-09 13:19:57 Functions: 90.0 % 50 45
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2023 Free Software Foundation, Inc.
       2                 :             : 
       3                 :             : // This file is part of GCC.
       4                 :             : 
       5                 :             : // GCC is free software; you can redistribute it and/or modify it under
       6                 :             : // the terms of the GNU General Public License as published by the Free
       7                 :             : // Software Foundation; either version 3, or (at your option) any later
       8                 :             : // version.
       9                 :             : 
      10                 :             : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11                 :             : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12                 :             : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13                 :             : // for more details.
      14                 :             : 
      15                 :             : // You should have received a copy of the GNU General Public License
      16                 :             : // along with GCC; see the file COPYING3.  If not see
      17                 :             : // <http://www.gnu.org/licenses/>.
      18                 :             : 
      19                 :             : #include "rust-system.h"
      20                 :             : #include "rust-lex.h"
      21                 :             : #include "rust-diagnostics.h"
      22                 :             : #include "rust-linemap.h"
      23                 :             : #include "rust-session-manager.h"
      24                 :             : #include "safe-ctype.h"
      25                 :             : 
      26                 :             : namespace Rust {
      27                 :             : // TODO: move to separate compilation unit?
      28                 :             : // overload += for uint32_t to allow 32-bit encoded utf-8 to be added
      29                 :             : std::string &
      30                 :       22090 : operator+= (std::string &str, Codepoint char32)
      31                 :             : {
      32                 :       22090 :   if (char32.value < 0x80)
      33                 :             :     {
      34                 :       22077 :       str += static_cast<char> (char32.value);
      35                 :             :     }
      36                 :          13 :   else if (char32.value < (0x1F + 1) << (1 * 6))
      37                 :             :     {
      38                 :           3 :       str += static_cast<char> (0xC0 | ((char32.value >> 6) & 0x1F));
      39                 :           3 :       str += static_cast<char> (0x80 | ((char32.value >> 0) & 0x3F));
      40                 :             :     }
      41                 :          10 :   else if (char32.value < (0x0F + 1) << (2 * 6))
      42                 :             :     {
      43                 :           4 :       str += static_cast<char> (0xE0 | ((char32.value >> 12) & 0x0F));
      44                 :           4 :       str += static_cast<char> (0x80 | ((char32.value >> 6) & 0x3F));
      45                 :           4 :       str += static_cast<char> (0x80 | ((char32.value >> 0) & 0x3F));
      46                 :             :     }
      47                 :           6 :   else if (char32.value < (0x07 + 1) << (3 * 6))
      48                 :             :     {
      49                 :           2 :       str += static_cast<char> (0xF0 | ((char32.value >> 18) & 0x07));
      50                 :           2 :       str += static_cast<char> (0x80 | ((char32.value >> 12) & 0x3F));
      51                 :           2 :       str += static_cast<char> (0x80 | ((char32.value >> 6) & 0x3F));
      52                 :           2 :       str += static_cast<char> (0x80 | ((char32.value >> 0) & 0x3F));
      53                 :             :     }
      54                 :             :   else
      55                 :             :     {
      56                 :           4 :       rust_debug ("Invalid unicode codepoint found: '%u' ", char32.value);
      57                 :             :     }
      58                 :       22090 :   return str;
      59                 :             : }
      60                 :             : 
      61                 :             : std::string
      62                 :         225 : Codepoint::as_string ()
      63                 :             : {
      64                 :         225 :   std::string str;
      65                 :             : 
      66                 :             :   // str += Codepoint (value);
      67                 :         225 :   str += *this;
      68                 :             : 
      69                 :         225 :   return str;
      70                 :             : }
      71                 :             : 
      72                 :             : /* Includes all allowable float digits EXCEPT _ and . as that needs lookahead
      73                 :             :  * for handling. */
      74                 :             : bool
      75                 :         380 : is_float_digit (char number)
      76                 :             : {
      77                 :         380 :   return ISDIGIT (number) || number == 'E' || number == 'e';
      78                 :             : }
      79                 :             : 
      80                 :             : /* Basically ISXDIGIT from safe-ctype but may change if Rust's encoding or
      81                 :             :  * whatever is different */
      82                 :             : bool
      83                 :         901 : is_x_digit (char number)
      84                 :             : {
      85                 :         901 :   return ISXDIGIT (number);
      86                 :             : }
      87                 :             : 
      88                 :             : bool
      89                 :          53 : is_octal_digit (char number)
      90                 :             : {
      91                 :          53 :   return number >= '0' && number <= '7';
      92                 :             : }
      93                 :             : 
      94                 :             : bool
      95                 :         193 : is_bin_digit (char number)
      96                 :             : {
      97                 :         193 :   return number == '0' || number == '1';
      98                 :             : }
      99                 :             : 
     100                 :             : bool
     101                 :          65 : check_valid_float_dot_end (char character)
     102                 :             : {
     103                 :          65 :   return character != '.' && character != '_' && !ISALPHA (character);
     104                 :             : }
     105                 :             : 
     106                 :             : // ISSPACE from safe-ctype but may change in future
     107                 :             : bool
     108                 :         706 : is_whitespace (char character)
     109                 :             : {
     110                 :         706 :   return ISSPACE (character);
     111                 :             : }
     112                 :             : 
     113                 :             : bool
     114                 :        2147 : is_non_decimal_int_literal_separator (char character)
     115                 :             : {
     116                 :        2147 :   return character == 'x' || character == 'o' || character == 'b';
     117                 :             : }
     118                 :             : 
     119                 :          98 : Lexer::Lexer (const std::string &input)
     120                 :          98 :   : input (RAIIFile::create_error ()), current_line (1), current_column (1),
     121                 :          98 :     line_map (nullptr), dump_lex_out (Optional<std::ofstream &>::none ()),
     122                 :          98 :     raw_input_source (new BufferInputSource (input, 0)),
     123                 :          98 :     input_queue{*raw_input_source}, token_queue (TokenSource (this))
     124                 :          98 : {}
     125                 :             : 
     126                 :        3278 : Lexer::Lexer (const char *filename, RAIIFile file_input, Linemap *linemap,
     127                 :        3278 :               Optional<std::ofstream &> dump_lex_opt)
     128                 :        3278 :   : input (std::move (file_input)), current_line (1), current_column (1),
     129                 :        3278 :     line_map (linemap), dump_lex_out (dump_lex_opt),
     130                 :        3278 :     raw_input_source (new FileInputSource (input.get_raw ())),
     131                 :        3278 :     input_queue{*raw_input_source}, token_queue (TokenSource (this))
     132                 :             : {
     133                 :             :   // inform line_table that file is being entered and is in line 1
     134                 :        3278 :   if (linemap)
     135                 :        3278 :     line_map->start_file (filename, current_line);
     136                 :        3278 : }
     137                 :             : 
     138                 :        3375 : Lexer::~Lexer ()
     139                 :             : {
     140                 :             :   /* ok apparently stop (which is equivalent of original code in destructor) is
     141                 :             :    * meant to be called after all files have finished parsing, for cleanup. On
     142                 :             :    * the other hand, actual code that it calls to leave a certain line map is
     143                 :             :    * mentioned in GCC docs as being useful for "just leaving an included header"
     144                 :             :    * and stuff like that, so this line mapping functionality may need fixing.
     145                 :             :    * FIXME: find out whether this occurs. */
     146                 :             : 
     147                 :             :   // line_map->stop();
     148                 :        3375 : }
     149                 :             : 
     150                 :             : /* TODO: need to optimise somehow to avoid the virtual function call in the
     151                 :             :  * tight loop. Best idea at the moment is CRTP, but that might make lexer
     152                 :             :  * implementation annoying when storing the "base class" (i.e. would need
     153                 :             :  * template parameter everywhere), although in practice it would mostly just
     154                 :             :  * look ugly and make enclosing classes like Parser also require a type
     155                 :             :  * parameter. At this point a macro might be better. OK I guess macros can be
     156                 :             :  * replaced by constexpr if or something if possible. */
     157                 :             : Location
     158                 :      733239 : Lexer::get_current_location ()
     159                 :             : {
     160                 :      733239 :   if (line_map)
     161                 :      732181 :     return line_map->get_location (current_column);
     162                 :             :   else
     163                 :             :     // If we have no linemap, we're lexing something without proper locations
     164                 :        1058 :     return Location ();
     165                 :             : }
     166                 :             : 
     167                 :             : int
     168                 :     1647657 : Lexer::peek_input (int n)
     169                 :             : {
     170                 :     1647657 :   return input_queue.peek (n);
     171                 :             : }
     172                 :             : 
     173                 :             : int
     174                 :     1622643 : Lexer::peek_input ()
     175                 :             : {
     176                 :     1622643 :   return peek_input (0);
     177                 :             : }
     178                 :             : 
     179                 :             : void
     180                 :     1331578 : Lexer::skip_input (int n)
     181                 :             : {
     182                 :     1331578 :   input_queue.skip (n);
     183                 :     1331578 : }
     184                 :             : 
     185                 :             : void
     186                 :     1309780 : Lexer::skip_input ()
     187                 :             : {
     188                 :     1309780 :   skip_input (0);
     189                 :     1309780 : }
     190                 :             : 
     191                 :             : void
     192                 :      304936 : Lexer::skip_token (int n)
     193                 :             : {
     194                 :             :   // dump tokens if dump-lex option is enabled
     195                 :      304936 :   if (dump_lex_out.is_some ())
     196                 :           0 :     dump_and_skip (n);
     197                 :             :   else
     198                 :      304936 :     token_queue.skip (n);
     199                 :      304936 : }
     200                 :             : 
     201                 :             : void
     202                 :           0 : Lexer::dump_and_skip (int n)
     203                 :             : {
     204                 :           0 :   std::ofstream &out = dump_lex_out.get ();
     205                 :           0 :   bool found_eof = false;
     206                 :           0 :   const_TokenPtr tok;
     207                 :           0 :   for (int i = 0; i < n + 1; i++)
     208                 :             :     {
     209                 :           0 :       if (!found_eof)
     210                 :             :         {
     211                 :           0 :           tok = peek_token ();
     212                 :           0 :           found_eof |= tok->get_id () == Rust::END_OF_FILE;
     213                 :             : 
     214                 :           0 :           Location loc = tok->get_locus ();
     215                 :             : 
     216                 :           0 :           out << "<id=";
     217                 :           0 :           out << tok->token_id_to_str ();
     218                 :           0 :           out << (tok->has_str () ? (std::string (", text=") + tok->get_str ()
     219                 :           0 :                                      + std::string (", typehint=")
     220                 :           0 :                                      + std::string (tok->get_type_hint_str ()))
     221                 :             :                                   : "")
     222                 :           0 :               << " ";
     223                 :           0 :           out << get_line_map ()->to_string (loc) << " ";
     224                 :             :         }
     225                 :             : 
     226                 :           0 :       token_queue.skip (0);
     227                 :             :     }
     228                 :           0 : }
     229                 :             : 
     230                 :             : void
     231                 :           0 : Lexer::replace_current_token (TokenPtr replacement)
     232                 :             : {
     233                 :           0 :   token_queue.replace_current_value (replacement);
     234                 :             : 
     235                 :           0 :   rust_debug ("called 'replace_current_token' - this is deprecated");
     236                 :           0 : }
     237                 :             : 
     238                 :             : /* shitty anonymous namespace that can only be accessed inside the compilation
     239                 :             :  * unit - used for classify_keyword binary search in sorted array of keywords
     240                 :             :  * created with x-macros. */
     241                 :             : namespace {
     242                 :             : // TODO: make constexpr when update to c++20
     243                 :             : const std::string keyword_index[] = {
     244                 :             : #define RS_TOKEN(x, y)
     245                 :             : #define RS_TOKEN_KEYWORD(name, keyword) keyword,
     246                 :             :   RS_TOKEN_LIST
     247                 :             : #undef RS_TOKEN_KEYWORD
     248                 :             : #undef RS_TOKEN
     249                 :             : };
     250                 :             : 
     251                 :             : constexpr TokenId keyword_keys[] = {
     252                 :             : #define RS_TOKEN(x, y)
     253                 :             : #define RS_TOKEN_KEYWORD(name, keyword) name,
     254                 :             :   RS_TOKEN_LIST
     255                 :             : #undef RS_TOKEN_KEYWORD
     256                 :             : #undef RS_TOKEN
     257                 :             : };
     258                 :             : 
     259                 :             : constexpr int num_keywords = sizeof (keyword_index) / sizeof (*keyword_index);
     260                 :             : } // namespace
     261                 :             : 
     262                 :             : /* Determines whether the string passed in is a keyword or not. If it is, it
     263                 :             :  * returns the keyword name.  */
     264                 :             : TokenId
     265                 :      127545 : Lexer::classify_keyword (const std::string &str)
     266                 :             : {
     267                 :      127545 :   const std::string *last = keyword_index + num_keywords;
     268                 :      127545 :   const std::string *idx = std::lower_bound (keyword_index, last, str);
     269                 :             : 
     270                 :      127545 :   if (idx == last || str != *idx)
     271                 :             :     return IDENTIFIER;
     272                 :             : 
     273                 :             :   // TODO: possibly replace this x-macro system with something like hash map?
     274                 :             : 
     275                 :             :   // We now have the expected token ID of the reserved keyword. However, some
     276                 :             :   // keywords are reserved starting in certain editions. For example, `try` is
     277                 :             :   // only a reserved keyword in editions >=2018. The language might gain new
     278                 :             :   // reserved keywords in the future.
     279                 :             :   //
     280                 :             :   // https://doc.rust-lang.org/reference/keywords.html#reserved-keywords
     281                 :       44212 :   auto id = keyword_keys[idx - keyword_index];
     282                 :             : 
     283                 :             :   // `try` is not a reserved keyword before 2018
     284                 :       44212 :   if (Session::get_instance ().options.get_edition ()
     285                 :             :         == CompileOptions::Edition::E2015
     286                 :       44212 :       && id == TRY)
     287                 :             :     return IDENTIFIER;
     288                 :             : 
     289                 :             :   return id;
     290                 :             : }
     291                 :             : 
     292                 :             : TokenPtr
     293                 :      309477 : Lexer::build_token ()
     294                 :             : {
     295                 :             :   // loop to go through multiple characters to build a single token
     296                 :      733161 :   while (true)
     297                 :             :     {
     298                 :     1466322 :       Location loc = get_current_location ();
     299                 :      733161 :       current_char = peek_input ();
     300                 :      733161 :       skip_input ();
     301                 :             : 
     302                 :             :       // detect UTF8 bom
     303                 :             :       //
     304                 :             :       // Must be the first thing on the first line.
     305                 :             :       // There might be an optional BOM (Byte Order Mark), which for UTF-8 is
     306                 :             :       // the three bytes 0xEF, 0xBB and 0xBF. These can simply be skipped.
     307                 :        3376 :       if (current_line == 1 && current_column == 1 && current_char == 0xef
     308                 :      733189 :           && peek_input () == 0xbb && peek_input (1) == 0xbf)
     309                 :             :         {
     310                 :          28 :           skip_input (1);
     311                 :          28 :           current_char = peek_input ();
     312                 :          28 :           skip_input ();
     313                 :             :         }
     314                 :             : 
     315                 :             :       // detect shebang
     316                 :             :       // Must be the first thing on the first line, starting with #!
     317                 :             :       // But since an attribute can also start with an #! we don't count it as a
     318                 :             :       // shebang line when after any whitespace or comments there is a [. If it
     319                 :             :       // is a shebang line we simple drop the line. Otherwise we don't consume
     320                 :             :       // any characters and fall through to the real tokenizer.
     321                 :        3376 :       if (current_line == 1 && current_column == 1 && current_char == '#'
     322                 :      733411 :           && peek_input () == '!')
     323                 :             :         {
     324                 :             :           int n = 1;
     325                 :         334 :           while (true)
     326                 :             :             {
     327                 :         334 :               int next_char = peek_input (n);
     328                 :         334 :               if (is_whitespace (next_char))
     329                 :          91 :                 n++;
     330                 :          56 :               else if ((next_char == '/' && peek_input (n + 1) == '/'
     331                 :          21 :                         && peek_input (n + 2) != '!'
     332                 :          21 :                         && peek_input (n + 2) != '/')
     333                 :         278 :                        || (next_char == '/' && peek_input (n + 1) == '/'
     334                 :           0 :                            && peek_input (n + 2) == '/'
     335                 :           0 :                            && peek_input (n + 3) == '/'))
     336                 :             :                 {
     337                 :             :                   // two // or four ////
     338                 :             :                   // A single line comment
     339                 :             :                   // (but not an inner or outer doc comment)
     340                 :          21 :                   n += 2;
     341                 :          21 :                   next_char = peek_input (n);
     342                 :         392 :                   while (next_char != '\n' && next_char != EOF)
     343                 :             :                     {
     344                 :         350 :                       n++;
     345                 :         350 :                       next_char = peek_input (n);
     346                 :             :                     }
     347                 :          21 :                   if (next_char == '\n')
     348                 :          21 :                     n++;
     349                 :             :                 }
     350                 :          35 :               else if (next_char == '/' && peek_input (n + 1) == '*'
     351                 :          14 :                        && peek_input (n + 2) == '*'
     352                 :         222 :                        && peek_input (n + 3) == '/')
     353                 :             :                 {
     354                 :             :                   /**/
     355                 :           0 :                   n += 4;
     356                 :             :                 }
     357                 :          35 :               else if (next_char == '/' && peek_input (n + 1) == '*'
     358                 :          14 :                        && peek_input (n + 2) == '*' && peek_input (n + 3) == '*'
     359                 :         222 :                        && peek_input (n + 4) == '/')
     360                 :             :                 {
     361                 :             :                   /***/
     362                 :           0 :                   n += 5;
     363                 :             :                 }
     364                 :          35 :               else if ((next_char == '/' && peek_input (n + 1) == '*'
     365                 :          14 :                         && peek_input (n + 2) != '*'
     366                 :          14 :                         && peek_input (n + 2) != '!')
     367                 :         243 :                        || (next_char == '/' && peek_input (n + 1) == '*'
     368                 :           0 :                            && peek_input (n + 2) == '*'
     369                 :           0 :                            && peek_input (n + 3) == '*'))
     370                 :             :                 {
     371                 :             :                   // one /* or three /***
     372                 :             :                   // Start of a block comment
     373                 :             :                   // (but not an inner or outer doc comment)
     374                 :          14 :                   n += 2;
     375                 :          14 :                   int level = 1;
     376                 :        1029 :                   while (level > 0)
     377                 :             :                     {
     378                 :        1015 :                       if (peek_input (n) == EOF)
     379                 :             :                         break;
     380                 :        1015 :                       else if (peek_input (n) == '/'
     381                 :        1015 :                                && peek_input (n + 1) == '*')
     382                 :             :                         {
     383                 :           7 :                           n += 2;
     384                 :           7 :                           level += 1;
     385                 :             :                         }
     386                 :        1008 :                       else if (peek_input (n) == '*'
     387                 :        1008 :                                && peek_input (n + 1) == '/')
     388                 :             :                         {
     389                 :          21 :                           n += 2;
     390                 :          21 :                           level -= 1;
     391                 :             :                         }
     392                 :             :                       else
     393                 :         987 :                         n++;
     394                 :             :                     }
     395                 :             :                 }
     396                 :         208 :               else if (next_char != '[')
     397                 :             :                 {
     398                 :             :                   // definitely shebang, ignore the first line
     399                 :         532 :                   while (current_char != '\n' && current_char != EOF)
     400                 :             :                     {
     401                 :         504 :                       current_char = peek_input ();
     402                 :         504 :                       skip_input ();
     403                 :             :                     }
     404                 :             : 
     405                 :             :                   // newline
     406                 :          28 :                   current_line++;
     407                 :          28 :                   current_column = 1;
     408                 :             :                   // tell line_table that new line starts
     409                 :          28 :                   start_line (current_line, max_column_hint);
     410                 :          28 :                   break;
     411                 :             :                 }
     412                 :             :               else
     413                 :             :                 break; /* Definitely not a shebang line. */
     414                 :             :             }
     415                 :             :         }
     416                 :             : 
     417                 :             :       // return end of file token if end of file
     418                 :      733161 :       if (current_char == EOF)
     419                 :        3334 :         return Token::make (END_OF_FILE, loc);
     420                 :             : 
     421                 :             :       // if not end of file, start tokenising
     422                 :      729827 :       switch (current_char)
     423                 :             :         {
     424                 :             :         /* ignore whitespace characters for tokens but continue updating
     425                 :             :          * location */
     426                 :       71884 :         case '\n': // newline
     427                 :       71884 :           current_line++;
     428                 :       71884 :           current_column = 1;
     429                 :             :           // tell line_table that new line starts
     430                 :       71884 :           start_line (current_line, max_column_hint);
     431                 :      733161 :           continue;
     432                 :         252 :         case '\r': // cr
     433                 :             :           // Ignore, we expect a newline (lf) soon.
     434                 :         252 :           continue;
     435                 :      346658 :         case ' ': // space
     436                 :      346658 :           current_column++;
     437                 :      346658 :           continue;
     438                 :         130 :         case '\t': // tab
     439                 :             :           // width of a tab is not well-defined, assume 8 spaces
     440                 :         130 :           current_column += 8;
     441                 :         130 :           continue;
     442                 :             : 
     443                 :             :         // punctuation - actual tokens
     444                 :       13537 :         case '=':
     445                 :       13537 :           if (peek_input () == '>')
     446                 :             :             {
     447                 :             :               // match arm arrow
     448                 :         992 :               skip_input ();
     449                 :         992 :               current_column += 2;
     450                 :         992 :               loc += 1;
     451                 :             : 
     452                 :         992 :               return Token::make (MATCH_ARROW, loc);
     453                 :             :             }
     454                 :       12545 :           else if (peek_input () == '=')
     455                 :             :             {
     456                 :             :               // equality operator
     457                 :         428 :               skip_input ();
     458                 :         428 :               current_column += 2;
     459                 :         428 :               loc += 1;
     460                 :             : 
     461                 :         428 :               return Token::make (EQUAL_EQUAL, loc);
     462                 :             :             }
     463                 :             :           else
     464                 :             :             {
     465                 :             :               // assignment operator
     466                 :       12117 :               current_column++;
     467                 :       12117 :               return Token::make (EQUAL, loc);
     468                 :             :             }
     469                 :       18730 :         case '(':
     470                 :       18730 :           current_column++;
     471                 :       18730 :           return Token::make (LEFT_PAREN, loc);
     472                 :        5482 :         case '-':
     473                 :        5482 :           if (peek_input () == '>')
     474                 :             :             {
     475                 :             :               // return type specifier
     476                 :        4782 :               skip_input ();
     477                 :        4782 :               current_column += 2;
     478                 :        4782 :               loc += 1;
     479                 :             : 
     480                 :        4782 :               return Token::make (RETURN_TYPE, loc);
     481                 :             :             }
     482                 :         700 :           else if (peek_input () == '=')
     483                 :             :             {
     484                 :             :               // minus-assign
     485                 :          14 :               skip_input ();
     486                 :          14 :               current_column += 2;
     487                 :          14 :               loc += 1;
     488                 :             : 
     489                 :          14 :               return Token::make (MINUS_EQ, loc);
     490                 :             :             }
     491                 :             :           else
     492                 :             :             {
     493                 :             :               // minus
     494                 :         686 :               current_column++;
     495                 :         686 :               return Token::make (MINUS, loc);
     496                 :             :             }
     497                 :        1243 :         case '+':
     498                 :        1243 :           if (peek_input () == '=')
     499                 :             :             {
     500                 :             :               // add-assign
     501                 :          50 :               skip_input ();
     502                 :          50 :               current_column += 2;
     503                 :          50 :               loc += 1;
     504                 :             : 
     505                 :          50 :               return Token::make (PLUS_EQ, loc);
     506                 :             :             }
     507                 :             :           else
     508                 :             :             {
     509                 :             :               // add
     510                 :        1193 :               current_column++;
     511                 :        1193 :               return Token::make (PLUS, loc);
     512                 :             :             }
     513                 :       18714 :         case ')':
     514                 :       18714 :           current_column++;
     515                 :       18714 :           return Token::make (RIGHT_PAREN, loc);
     516                 :       19735 :         case ';':
     517                 :       19735 :           current_column++;
     518                 :       19735 :           return Token::make (SEMICOLON, loc);
     519                 :        5231 :         case '*':
     520                 :        5231 :           if (peek_input () == '=')
     521                 :             :             {
     522                 :             :               // multiplication-assign
     523                 :           7 :               skip_input ();
     524                 :           7 :               current_column += 2;
     525                 :           7 :               loc += 1;
     526                 :             : 
     527                 :           7 :               return Token::make (ASTERISK_EQ, loc);
     528                 :             :             }
     529                 :             :           else
     530                 :             :             {
     531                 :             :               // multiplication
     532                 :        5224 :               current_column++;
     533                 :        5224 :               return Token::make (ASTERISK, loc);
     534                 :             :             }
     535                 :        9350 :         case ',':
     536                 :        9350 :           current_column++;
     537                 :        9350 :           return Token::make (COMMA, loc);
     538                 :        5063 :         case '/':
     539                 :        5063 :           if (peek_input () == '=')
     540                 :             :             {
     541                 :             :               // division-assign
     542                 :           7 :               skip_input ();
     543                 :           7 :               current_column += 2;
     544                 :           7 :               loc += 1;
     545                 :             : 
     546                 :           7 :               return Token::make (DIV_EQ, loc);
     547                 :             :             }
     548                 :        9521 :           else if ((peek_input () == '/' && peek_input (1) != '!'
     549                 :        4400 :                     && peek_input (1) != '/')
     550                 :        5223 :                    || (peek_input () == '/' && peek_input (1) == '/'
     551                 :         102 :                        && peek_input (2) == '/'))
     552                 :             :             {
     553                 :             :               // two // or four ////
     554                 :             :               // single line comment
     555                 :             :               // (but not an inner or outer doc comment)
     556                 :        4312 :               skip_input ();
     557                 :        4312 :               current_column += 2;
     558                 :        4312 :               current_char = peek_input ();
     559                 :             : 
     560                 :             :               // basically ignore until line finishes
     561                 :      218231 :               while (current_char != '\n' && current_char != EOF)
     562                 :             :                 {
     563                 :      213919 :                   skip_input ();
     564                 :      213919 :                   current_column++; // not used
     565                 :      213919 :                   current_char = peek_input ();
     566                 :             :                 }
     567                 :        4312 :               continue;
     568                 :             :             }
     569                 :         744 :           else if (peek_input () == '/'
     570                 :         744 :                    && (peek_input (1) == '!' || peek_input (1) == '/'))
     571                 :             :             {
     572                 :             :               /* single line doc comment, inner or outer.  */
     573                 :         153 :               bool is_inner = peek_input (1) == '!';
     574                 :         153 :               skip_input (1);
     575                 :         153 :               current_column += 3;
     576                 :             : 
     577                 :         153 :               std::string str;
     578                 :         153 :               str.reserve (32);
     579                 :         153 :               current_char = peek_input ();
     580                 :        3130 :               while (current_char != '\n')
     581                 :             :                 {
     582                 :        3026 :                   skip_input ();
     583                 :        3026 :                   if (current_char == '\r')
     584                 :             :                     {
     585                 :          51 :                       char next_char = peek_input ();
     586                 :          51 :                       if (next_char == '\n')
     587                 :             :                         {
     588                 :          49 :                           current_char = '\n';
     589                 :          49 :                           break;
     590                 :             :                         }
     591                 :           2 :                       rust_error_at (
     592                 :             :                         loc, "Isolated CR %<\\r%> not allowed in doc comment");
     593                 :           2 :                       current_char = next_char;
     594                 :           2 :                       continue;
     595                 :           2 :                     }
     596                 :        2975 :                   if (current_char == EOF)
     597                 :             :                     {
     598                 :           0 :                       rust_error_at (
     599                 :             :                         loc, "unexpected EOF while looking for end of comment");
     600                 :           0 :                       break;
     601                 :             :                     }
     602                 :        2975 :                   str += current_char;
     603                 :        2975 :                   current_char = peek_input ();
     604                 :             :                 }
     605                 :         153 :               skip_input ();
     606                 :         153 :               current_line++;
     607                 :         153 :               current_column = 1;
     608                 :             :               // tell line_table that new line starts
     609                 :         153 :               start_line (current_line, max_column_hint);
     610                 :             : 
     611                 :         153 :               str.shrink_to_fit ();
     612                 :             : 
     613                 :         153 :               loc += str.size () - 1;
     614                 :         153 :               if (is_inner)
     615                 :          65 :                 return Token::make_inner_doc_comment (loc, std::move (str));
     616                 :             :               else
     617                 :          88 :                 return Token::make_outer_doc_comment (loc, std::move (str));
     618                 :         153 :             }
     619                 :        1154 :           else if (peek_input () == '*' && peek_input (1) == '*'
     620                 :         676 :                    && peek_input (2) == '/')
     621                 :             :             {
     622                 :             :               /**/
     623                 :          14 :               skip_input (2);
     624                 :          14 :               current_column += 4;
     625                 :          14 :               continue;
     626                 :             :             }
     627                 :        1126 :           else if (peek_input () == '*' && peek_input (1) == '*'
     628                 :         648 :                    && peek_input (2) == '*' && peek_input (3) == '/')
     629                 :             :             {
     630                 :             :               /***/
     631                 :          14 :               skip_input (3);
     632                 :          14 :               current_column += 5;
     633                 :          14 :               continue;
     634                 :             :             }
     635                 :        1098 :           else if ((peek_input () == '*' && peek_input (1) != '!'
     636                 :         462 :                     && peek_input (1) != '*')
     637                 :         693 :                    || (peek_input () == '*' && peek_input (1) == '*'
     638                 :          57 :                        && peek_input (2) == '*'))
     639                 :             :             {
     640                 :             :               // one /* or three /***
     641                 :             :               // block comment
     642                 :             :               // (but not an inner or outer doc comment)
     643                 :         419 :               skip_input ();
     644                 :         419 :               current_column += 2;
     645                 :             : 
     646                 :         419 :               int level = 1;
     647                 :       16047 :               while (level > 0)
     648                 :             :                 {
     649                 :       15629 :                   current_char = peek_input ();
     650                 :             : 
     651                 :       15629 :                   if (current_char == EOF)
     652                 :             :                     {
     653                 :           1 :                       rust_error_at (
     654                 :             :                         loc, "unexpected EOF while looking for end of comment");
     655                 :           1 :                       break;
     656                 :             :                     }
     657                 :             : 
     658                 :             :                   // if /* found
     659                 :       15628 :                   if (current_char == '/' && peek_input (1) == '*')
     660                 :             :                     {
     661                 :             :                       // skip /* characters
     662                 :          49 :                       skip_input (1);
     663                 :             : 
     664                 :          49 :                       current_column += 2;
     665                 :             : 
     666                 :          49 :                       level += 1;
     667                 :          49 :                       continue;
     668                 :             :                     }
     669                 :             : 
     670                 :             :                   // ignore until */ is found
     671                 :       15579 :                   if (current_char == '*' && peek_input (1) == '/')
     672                 :             :                     {
     673                 :             :                       // skip */ characters
     674                 :         467 :                       skip_input (1);
     675                 :             : 
     676                 :         467 :                       current_column += 2;
     677                 :             : 
     678                 :         467 :                       level -= 1;
     679                 :         467 :                       continue;
     680                 :             :                     }
     681                 :             : 
     682                 :       15112 :                   if (current_char == '\n')
     683                 :             :                     {
     684                 :         151 :                       skip_input ();
     685                 :         151 :                       current_line++;
     686                 :         151 :                       current_column = 1;
     687                 :             :                       // tell line_table that new line starts
     688                 :         151 :                       start_line (current_line, max_column_hint);
     689                 :         151 :                       continue;
     690                 :             :                     }
     691                 :             : 
     692                 :       14961 :                   skip_input ();
     693                 :       14961 :                   current_column++;
     694                 :             :                 }
     695                 :             : 
     696                 :             :               // refresh new token
     697                 :         419 :               continue;
     698                 :         419 :             }
     699                 :         144 :           else if (peek_input () == '*'
     700                 :         144 :                    && (peek_input (1) == '!' || peek_input (1) == '*'))
     701                 :             :             {
     702                 :             :               // block doc comment, inner /*! or outer /**
     703                 :         116 :               bool is_inner = peek_input (1) == '!';
     704                 :         116 :               skip_input (1);
     705                 :         116 :               current_column += 3;
     706                 :             : 
     707                 :         116 :               std::string str;
     708                 :         116 :               str.reserve (96);
     709                 :             : 
     710                 :         116 :               int level = 1;
     711                 :         116 :               while (level > 0)
     712                 :             :                 {
     713                 :        2685 :                   current_char = peek_input ();
     714                 :             : 
     715                 :        2685 :                   if (current_char == EOF)
     716                 :             :                     {
     717                 :           0 :                       rust_error_at (
     718                 :             :                         loc, "unexpected EOF while looking for end of comment");
     719                 :           0 :                       break;
     720                 :             :                     }
     721                 :             : 
     722                 :             :                   // if /* found
     723                 :        2685 :                   if (current_char == '/' && peek_input (1) == '*')
     724                 :             :                     {
     725                 :             :                       // skip /* characters
     726                 :          84 :                       skip_input (1);
     727                 :          84 :                       current_column += 2;
     728                 :             : 
     729                 :          84 :                       level += 1;
     730                 :          84 :                       str += "/*";
     731                 :          84 :                       continue;
     732                 :             :                     }
     733                 :             : 
     734                 :             :                   // ignore until */ is found
     735                 :        2601 :                   if (current_char == '*' && peek_input (1) == '/')
     736                 :             :                     {
     737                 :             :                       // skip */ characters
     738                 :         200 :                       skip_input (1);
     739                 :         200 :                       current_column += 2;
     740                 :             : 
     741                 :         200 :                       level -= 1;
     742                 :         200 :                       if (level > 0)
     743                 :          84 :                         str += "*/";
     744                 :         200 :                       continue;
     745                 :             :                     }
     746                 :             : 
     747                 :        2401 :                   if (current_char == '\r' && peek_input (1) != '\n')
     748                 :           2 :                     rust_error_at (
     749                 :             :                       loc, "Isolated CR %<\\r%> not allowed in doc comment");
     750                 :             : 
     751                 :        2401 :                   if (current_char == '\n')
     752                 :             :                     {
     753                 :           0 :                       skip_input ();
     754                 :           0 :                       current_line++;
     755                 :           0 :                       current_column = 1;
     756                 :             :                       // tell line_table that new line starts
     757                 :           0 :                       start_line (current_line, max_column_hint);
     758                 :           0 :                       str += '\n';
     759                 :           0 :                       continue;
     760                 :             :                     }
     761                 :             : 
     762                 :        2401 :                   str += current_char;
     763                 :        2401 :                   skip_input ();
     764                 :        2401 :                   current_column++;
     765                 :             :                 }
     766                 :             : 
     767                 :         116 :               str.shrink_to_fit ();
     768                 :             : 
     769                 :         116 :               loc += str.size () - 1;
     770                 :         116 :               if (is_inner)
     771                 :          73 :                 return Token::make_inner_doc_comment (loc, std::move (str));
     772                 :             :               else
     773                 :          43 :                 return Token::make_outer_doc_comment (loc, std::move (str));
     774                 :         116 :             }
     775                 :             :           else
     776                 :             :             {
     777                 :             :               // division
     778                 :          28 :               current_column++;
     779                 :          28 :               return Token::make (DIV, loc);
     780                 :             :             }
     781                 :          42 :         case '%':
     782                 :          42 :           if (peek_input () == '=')
     783                 :             :             {
     784                 :             :               // modulo-assign
     785                 :           7 :               skip_input ();
     786                 :           7 :               current_column += 2;
     787                 :           7 :               loc += 1;
     788                 :             : 
     789                 :           7 :               return Token::make (PERCENT_EQ, loc);
     790                 :             :             }
     791                 :             :           else
     792                 :             :             {
     793                 :             :               // modulo
     794                 :          35 :               current_column++;
     795                 :          35 :               return Token::make (PERCENT, loc);
     796                 :             :             }
     797                 :          21 :         case '^':
     798                 :          21 :           if (peek_input () == '=')
     799                 :             :             {
     800                 :             :               // xor-assign?
     801                 :           7 :               skip_input ();
     802                 :           7 :               current_column += 2;
     803                 :           7 :               loc += 1;
     804                 :             : 
     805                 :           7 :               return Token::make (CARET_EQ, loc);
     806                 :             :             }
     807                 :             :           else
     808                 :             :             {
     809                 :             :               // xor?
     810                 :          14 :               current_column++;
     811                 :          14 :               return Token::make (CARET, loc);
     812                 :             :             }
     813                 :        3894 :         case '<':
     814                 :        3894 :           if (peek_input () == '<')
     815                 :             :             {
     816                 :          23 :               if (peek_input (1) == '=')
     817                 :             :                 {
     818                 :             :                   // left-shift assign
     819                 :           7 :                   skip_input (1);
     820                 :           7 :                   current_column += 3;
     821                 :           7 :                   loc += 2;
     822                 :             : 
     823                 :           7 :                   return Token::make (LEFT_SHIFT_EQ, loc);
     824                 :             :                 }
     825                 :             :               else
     826                 :             :                 {
     827                 :             :                   // left-shift
     828                 :          16 :                   skip_input ();
     829                 :          16 :                   current_column += 2;
     830                 :          16 :                   loc += 1;
     831                 :             : 
     832                 :          16 :                   return Token::make (LEFT_SHIFT, loc);
     833                 :             :                 }
     834                 :             :             }
     835                 :        3871 :           else if (peek_input () == '=')
     836                 :             :             {
     837                 :             :               // smaller than or equal to
     838                 :          49 :               skip_input ();
     839                 :          49 :               current_column += 2;
     840                 :          49 :               loc += 1;
     841                 :             : 
     842                 :          49 :               return Token::make (LESS_OR_EQUAL, loc);
     843                 :             :             }
     844                 :             :           else
     845                 :             :             {
     846                 :             :               // smaller than
     847                 :        3822 :               current_column++;
     848                 :        3822 :               return Token::make (LEFT_ANGLE, loc);
     849                 :             :             }
     850                 :        3966 :           break;
     851                 :        3966 :         case '>':
     852                 :        3966 :           if (peek_input () == '>')
     853                 :             :             {
     854                 :          82 :               if (peek_input (1) == '=')
     855                 :             :                 {
     856                 :             :                   // right-shift-assign
     857                 :           7 :                   skip_input (1);
     858                 :           7 :                   current_column += 3;
     859                 :           7 :                   loc += 2;
     860                 :             : 
     861                 :           7 :                   return Token::make (RIGHT_SHIFT_EQ, loc);
     862                 :             :                 }
     863                 :             :               else
     864                 :             :                 {
     865                 :             :                   // right-shift
     866                 :          75 :                   skip_input ();
     867                 :          75 :                   current_column += 2;
     868                 :          75 :                   loc += 1;
     869                 :             : 
     870                 :          75 :                   return Token::make (RIGHT_SHIFT, loc);
     871                 :             :                 }
     872                 :             :             }
     873                 :        3884 :           else if (peek_input () == '=')
     874                 :             :             {
     875                 :             :               // larger than or equal to
     876                 :          14 :               skip_input ();
     877                 :          14 :               current_column += 2;
     878                 :          14 :               loc += 1;
     879                 :             : 
     880                 :          14 :               return Token::make (GREATER_OR_EQUAL, loc);
     881                 :             :             }
     882                 :             :           else
     883                 :             :             {
     884                 :             :               // larger than
     885                 :        3870 :               current_column++;
     886                 :        3870 :               return Token::make (RIGHT_ANGLE, loc);
     887                 :             :             }
     888                 :       12514 :         case ':':
     889                 :       12514 :           if (peek_input () == ':')
     890                 :             :             {
     891                 :             :               // scope resolution ::
     892                 :        2601 :               skip_input ();
     893                 :        2601 :               current_column += 2;
     894                 :        2601 :               loc += 1;
     895                 :             : 
     896                 :        2601 :               return Token::make (SCOPE_RESOLUTION, loc);
     897                 :             :             }
     898                 :             :           else
     899                 :             :             {
     900                 :             :               // single colon :
     901                 :        9913 :               current_column++;
     902                 :        9913 :               return Token::make (COLON, loc);
     903                 :             :             }
     904                 :        1850 :         case '!':
     905                 :             :           // no special handling for macros in lexer?
     906                 :        1850 :           if (peek_input () == '=')
     907                 :             :             {
     908                 :             :               // not equal boolean operator
     909                 :         106 :               skip_input ();
     910                 :         106 :               current_column += 2;
     911                 :         106 :               loc += 1;
     912                 :             : 
     913                 :         106 :               return Token::make (NOT_EQUAL, loc);
     914                 :             :             }
     915                 :             :           else
     916                 :             :             {
     917                 :             :               // not equal unary operator
     918                 :        1744 :               current_column++;
     919                 :             : 
     920                 :        1744 :               return Token::make (EXCLAM, loc);
     921                 :             :             }
     922                 :          39 :         case '?':
     923                 :          39 :           current_column++;
     924                 :          39 :           return Token::make (QUESTION_MARK, loc);
     925                 :        1323 :         case '#':
     926                 :        1323 :           current_column++;
     927                 :        1323 :           return Token::make (HASH, loc);
     928                 :        2999 :         case '[':
     929                 :        2999 :           current_column++;
     930                 :        2999 :           return Token::make (LEFT_SQUARE, loc);
     931                 :        2992 :         case ']':
     932                 :        2992 :           current_column++;
     933                 :        2992 :           return Token::make (RIGHT_SQUARE, loc);
     934                 :       16418 :         case '{':
     935                 :       16418 :           current_column++;
     936                 :       16418 :           return Token::make (LEFT_CURLY, loc);
     937                 :       16385 :         case '}':
     938                 :       16385 :           current_column++;
     939                 :       16385 :           return Token::make (RIGHT_CURLY, loc);
     940                 :           0 :         case '@':
     941                 :           0 :           current_column++;
     942                 :           0 :           return Token::make (PATTERN_BIND, loc);
     943                 :        1467 :         case '$':
     944                 :        1467 :           current_column++;
     945                 :        1467 :           return Token::make (DOLLAR_SIGN, loc);
     946                 :           0 :         case '~':
     947                 :           0 :           current_column++;
     948                 :           0 :           return Token::make (TILDE, loc);
     949                 :           0 :         case '\\':
     950                 :           0 :           current_column++;
     951                 :           0 :           return Token::make (BACKSLASH, loc);
     952                 :           0 :         case '`':
     953                 :           0 :           current_column++;
     954                 :           0 :           return Token::make (BACKTICK, loc);
     955                 :         124 :         case '|':
     956                 :         124 :           if (peek_input () == '=')
     957                 :             :             {
     958                 :             :               // bitwise or-assign?
     959                 :           7 :               skip_input ();
     960                 :           7 :               current_column += 2;
     961                 :           7 :               loc += 1;
     962                 :             : 
     963                 :           7 :               return Token::make (PIPE_EQ, loc);
     964                 :             :             }
     965                 :         117 :           else if (peek_input () == '|')
     966                 :             :             {
     967                 :             :               // logical or
     968                 :          56 :               skip_input ();
     969                 :          56 :               current_column += 2;
     970                 :          56 :               loc += 1;
     971                 :             : 
     972                 :          56 :               return Token::make (OR, loc);
     973                 :             :             }
     974                 :             :           else
     975                 :             :             {
     976                 :             :               // bitwise or
     977                 :          61 :               current_column++;
     978                 :             : 
     979                 :          61 :               return Token::make (PIPE, loc);
     980                 :             :             }
     981                 :        3503 :         case '&':
     982                 :        3503 :           if (peek_input () == '=')
     983                 :             :             {
     984                 :             :               // bitwise and-assign?
     985                 :          21 :               skip_input ();
     986                 :          21 :               current_column += 2;
     987                 :          21 :               loc += 1;
     988                 :             : 
     989                 :          21 :               return Token::make (AMP_EQ, loc);
     990                 :             :             }
     991                 :        3482 :           else if (peek_input () == '&')
     992                 :             :             {
     993                 :             :               // logical and
     994                 :         342 :               skip_input ();
     995                 :         342 :               current_column += 2;
     996                 :         342 :               loc += 1;
     997                 :             : 
     998                 :         342 :               return Token::make (LOGICAL_AND, loc);
     999                 :             :             }
    1000                 :             :           else
    1001                 :             :             {
    1002                 :             :               // bitwise and/reference
    1003                 :        3140 :               current_column++;
    1004                 :             : 
    1005                 :        3140 :               return Token::make (AMP, loc);
    1006                 :             :             }
    1007                 :        3667 :         case '.':
    1008                 :        3667 :           if (peek_input () == '.')
    1009                 :             :             {
    1010                 :         783 :               if (peek_input (1) == '.')
    1011                 :             :                 {
    1012                 :             :                   // ellipsis
    1013                 :         632 :                   skip_input (1);
    1014                 :         632 :                   current_column += 3;
    1015                 :         632 :                   loc += 2;
    1016                 :             : 
    1017                 :         632 :                   return Token::make (ELLIPSIS, loc);
    1018                 :             :                 }
    1019                 :         151 :               else if (peek_input (1) == '=')
    1020                 :             :                 {
    1021                 :             :                   // ..=
    1022                 :          28 :                   skip_input (1);
    1023                 :          28 :                   current_column += 3;
    1024                 :          28 :                   loc += 2;
    1025                 :             : 
    1026                 :          28 :                   return Token::make (DOT_DOT_EQ, loc);
    1027                 :             :                 }
    1028                 :             :               else
    1029                 :             :                 {
    1030                 :             :                   // ..
    1031                 :         123 :                   skip_input ();
    1032                 :         123 :                   current_column += 2;
    1033                 :         123 :                   loc += 1;
    1034                 :             : 
    1035                 :         123 :                   return Token::make (DOT_DOT, loc);
    1036                 :             :                 }
    1037                 :             :             }
    1038                 :             :           else /*if (!ISDIGIT (peek_input ()))*/
    1039                 :             :             {
    1040                 :             :               // single dot .
    1041                 :             :               // Only if followed by a non-number - otherwise is float
    1042                 :             :               // nope, float cannot start with '.'.
    1043                 :        2884 :               current_column++;
    1044                 :        2884 :               return Token::make (DOT, loc);
    1045                 :             :             }
    1046                 :      418924 :         }
    1047                 :             :       // TODO: special handling of _ in the lexer? instead of being identifier
    1048                 :             : 
    1049                 :             :       // byte character, byte string and raw byte string literals
    1050                 :      142614 :       if (current_char == 'b')
    1051                 :             :         {
    1052                 :        6837 :           if (peek_input () == '\'')
    1053                 :          72 :             return parse_byte_char (loc);
    1054                 :        6765 :           else if (peek_input () == '"')
    1055                 :          47 :             return parse_byte_string (loc);
    1056                 :        6718 :           else if (peek_input () == 'r'
    1057                 :        6718 :                    && (peek_input (1) == '#' || peek_input (1) == '"'))
    1058                 :          24 :             return parse_raw_byte_string (loc);
    1059                 :             :         }
    1060                 :             : 
    1061                 :             :       // raw identifiers and raw strings
    1062                 :      142471 :       if (current_char == 'r')
    1063                 :             :         {
    1064                 :        1887 :           int peek = peek_input ();
    1065                 :        1887 :           int peek1 = peek_input (1);
    1066                 :             : 
    1067                 :        1887 :           if (peek == '#' && (ISALPHA (peek1) || peek1 == '_'))
    1068                 :             :             {
    1069                 :          37 :               TokenPtr raw_ident_ptr = parse_raw_identifier (loc);
    1070                 :          37 :               if (raw_ident_ptr != nullptr)
    1071                 :          36 :                 return raw_ident_ptr;
    1072                 :             :               else
    1073                 :           1 :                 continue; /* input got parsed, it just wasn't valid. An error
    1074                 :             :                              was produced. */
    1075                 :          37 :             }
    1076                 :             :           else
    1077                 :             :             {
    1078                 :        1850 :               TokenPtr maybe_raw_string_ptr = maybe_parse_raw_string (loc);
    1079                 :        1850 :               if (maybe_raw_string_ptr != nullptr)
    1080                 :          23 :                 return maybe_raw_string_ptr;
    1081                 :        1850 :             }
    1082                 :             :         }
    1083                 :             : 
    1084                 :             :       // find identifiers and keywords
    1085                 :      142411 :       if (ISALPHA (current_char) || current_char == '_')
    1086                 :      127834 :         return parse_identifier_or_keyword (loc);
    1087                 :             : 
    1088                 :             :       // int and float literals
    1089                 :       14577 :       if (ISDIGIT (current_char))
    1090                 :             :         { //  _ not allowed as first char
    1091                 :       10922 :           if (current_char == '0'
    1092                 :       10922 :               && is_non_decimal_int_literal_separator (peek_input ()))
    1093                 :             :             {
    1094                 :             :               // handle binary, octal, hex literals
    1095                 :         107 :               TokenPtr non_dec_int_lit_ptr
    1096                 :         107 :                 = parse_non_decimal_int_literals (loc);
    1097                 :         107 :               if (non_dec_int_lit_ptr != nullptr)
    1098                 :         107 :                 return non_dec_int_lit_ptr;
    1099                 :         107 :             }
    1100                 :             :           else
    1101                 :             :             {
    1102                 :             :               // handle decimals (integer or float)
    1103                 :       10815 :               TokenPtr decimal_or_float_ptr = parse_decimal_int_or_float (loc);
    1104                 :       10815 :               if (decimal_or_float_ptr != nullptr)
    1105                 :       10815 :                 return decimal_or_float_ptr;
    1106                 :       10815 :             }
    1107                 :             :         }
    1108                 :             : 
    1109                 :             :       // string literals
    1110                 :        3655 :       if (current_char == '"')
    1111                 :        3233 :         return parse_string (loc);
    1112                 :             : 
    1113                 :             :       // char literals and lifetime names
    1114                 :         422 :       if (current_char == '\'')
    1115                 :             :         {
    1116                 :         422 :           TokenPtr char_or_lifetime_ptr = parse_char_or_lifetime (loc);
    1117                 :         422 :           if (char_or_lifetime_ptr != nullptr)
    1118                 :         422 :             return char_or_lifetime_ptr;
    1119                 :         422 :         }
    1120                 :             : 
    1121                 :             :       // DEBUG: check for specific character problems:
    1122                 :           0 :       if (current_char == '0')
    1123                 :           0 :         rust_debug ("'0' uncaught before unexpected character");
    1124                 :           0 :       else if (current_char == ']')
    1125                 :           0 :         rust_debug ("']' uncaught before unexpected character");
    1126                 :             :       else if (current_char == 0x5d)
    1127                 :             :         rust_debug ("whatever 0x5d is (not '0' or ']') uncaught before "
    1128                 :             :                     "unexpected character");
    1129                 :             : 
    1130                 :             :       // didn't match anything so error
    1131                 :           0 :       rust_error_at (loc, "unexpected character %<%x%>", current_char);
    1132                 :           0 :       current_column++;
    1133                 :             :     }
    1134                 :             : }
    1135                 :             : 
    1136                 :             : // Parses in a type suffix.
    1137                 :             : std::pair<PrimitiveCoreType, int>
    1138                 :       10922 : Lexer::parse_in_type_suffix ()
    1139                 :             : {
    1140                 :       10922 :   std::string suffix;
    1141                 :       10922 :   suffix.reserve (5);
    1142                 :             : 
    1143                 :       10922 :   int additional_length_offset = 0;
    1144                 :             : 
    1145                 :             :   // get suffix
    1146                 :       10922 :   while (ISALPHA (current_char) || ISDIGIT (current_char)
    1147                 :       13792 :          || current_char == '_')
    1148                 :             :     {
    1149                 :        2870 :       if (current_char == '_')
    1150                 :             :         {
    1151                 :             :           // don't add _ to suffix
    1152                 :           0 :           skip_input ();
    1153                 :           0 :           current_char = peek_input ();
    1154                 :             : 
    1155                 :           0 :           additional_length_offset++;
    1156                 :             : 
    1157                 :           0 :           continue;
    1158                 :             :         }
    1159                 :             : 
    1160                 :        2870 :       additional_length_offset++;
    1161                 :             : 
    1162                 :        2870 :       suffix += current_char;
    1163                 :        2870 :       skip_input ();
    1164                 :        2870 :       current_char = peek_input ();
    1165                 :             :     }
    1166                 :             : 
    1167                 :       10922 :   if (suffix.empty ())
    1168                 :             :     {
    1169                 :             :       // no type suffix: do nothing but also no error
    1170                 :        9964 :       return std::make_pair (CORETYPE_UNKNOWN, additional_length_offset);
    1171                 :             :     }
    1172                 :         958 :   else if (suffix == "f32")
    1173                 :             :     {
    1174                 :         495 :       return std::make_pair (CORETYPE_F32, additional_length_offset);
    1175                 :             :     }
    1176                 :         463 :   else if (suffix == "f64")
    1177                 :             :     {
    1178                 :         212 :       return std::make_pair (CORETYPE_F64, additional_length_offset);
    1179                 :             :     }
    1180                 :         251 :   else if (suffix == "i8")
    1181                 :             :     {
    1182                 :          23 :       return std::make_pair (CORETYPE_I8, additional_length_offset);
    1183                 :             :     }
    1184                 :         228 :   else if (suffix == "i16")
    1185                 :             :     {
    1186                 :          15 :       return std::make_pair (CORETYPE_I16, additional_length_offset);
    1187                 :             :     }
    1188                 :         213 :   else if (suffix == "i32")
    1189                 :             :     {
    1190                 :          52 :       return std::make_pair (CORETYPE_I32, additional_length_offset);
    1191                 :             :     }
    1192                 :         161 :   else if (suffix == "i64")
    1193                 :             :     {
    1194                 :          15 :       return std::make_pair (CORETYPE_I64, additional_length_offset);
    1195                 :             :     }
    1196                 :         146 :   else if (suffix == "i128")
    1197                 :             :     {
    1198                 :          15 :       return std::make_pair (CORETYPE_I128, additional_length_offset);
    1199                 :             :     }
    1200                 :         131 :   else if (suffix == "isize")
    1201                 :             :     {
    1202                 :           3 :       return std::make_pair (CORETYPE_ISIZE, additional_length_offset);
    1203                 :             :     }
    1204                 :         128 :   else if (suffix == "u8")
    1205                 :             :     {
    1206                 :          25 :       return std::make_pair (CORETYPE_U8, additional_length_offset);
    1207                 :             :     }
    1208                 :         103 :   else if (suffix == "u16")
    1209                 :             :     {
    1210                 :          22 :       return std::make_pair (CORETYPE_U16, additional_length_offset);
    1211                 :             :     }
    1212                 :          81 :   else if (suffix == "u32")
    1213                 :             :     {
    1214                 :          38 :       return std::make_pair (CORETYPE_U32, additional_length_offset);
    1215                 :             :     }
    1216                 :          43 :   else if (suffix == "u64")
    1217                 :             :     {
    1218                 :          24 :       return std::make_pair (CORETYPE_U64, additional_length_offset);
    1219                 :             :     }
    1220                 :          19 :   else if (suffix == "u128")
    1221                 :             :     {
    1222                 :          15 :       return std::make_pair (CORETYPE_U128, additional_length_offset);
    1223                 :             :     }
    1224                 :           4 :   else if (suffix == "usize")
    1225                 :             :     {
    1226                 :           4 :       return std::make_pair (CORETYPE_USIZE, additional_length_offset);
    1227                 :             :     }
    1228                 :             :   else
    1229                 :             :     {
    1230                 :           0 :       rust_error_at (get_current_location (), "unknown number suffix %qs",
    1231                 :             :                      suffix.c_str ());
    1232                 :             : 
    1233                 :           0 :       return std::make_pair (CORETYPE_UNKNOWN, additional_length_offset);
    1234                 :             :     }
    1235                 :       10922 : }
    1236                 :             : 
    1237                 :             : // Parses in the exponent part (if any) of a float literal.
    1238                 :             : std::pair<std::string, int>
    1239                 :         315 : Lexer::parse_in_exponent_part ()
    1240                 :             : {
    1241                 :         315 :   int additional_length_offset = 0;
    1242                 :         315 :   std::string str;
    1243                 :         315 :   if (current_char == 'E' || current_char == 'e')
    1244                 :             :     {
    1245                 :             :       // add exponent to string as strtod works with it
    1246                 :           0 :       str += current_char;
    1247                 :           0 :       skip_input ();
    1248                 :           0 :       current_char = peek_input ();
    1249                 :             : 
    1250                 :           0 :       additional_length_offset++;
    1251                 :             : 
    1252                 :             :       // special - and + handling
    1253                 :           0 :       if (current_char == '-')
    1254                 :             :         {
    1255                 :           0 :           str += '-';
    1256                 :             : 
    1257                 :           0 :           skip_input ();
    1258                 :           0 :           current_char = peek_input ();
    1259                 :             : 
    1260                 :           0 :           additional_length_offset++;
    1261                 :             :         }
    1262                 :           0 :       else if (current_char == '+')
    1263                 :             :         {
    1264                 :             :           // don't add + but still skip input
    1265                 :           0 :           skip_input ();
    1266                 :           0 :           current_char = peek_input ();
    1267                 :             : 
    1268                 :           0 :           additional_length_offset++;
    1269                 :             :         }
    1270                 :             : 
    1271                 :             :       // parse another decimal number for exponent
    1272                 :           0 :       auto str_length = parse_in_decimal ();
    1273                 :           0 :       str += std::get<0> (str_length);
    1274                 :           0 :       additional_length_offset += std::get<1> (str_length);
    1275                 :           0 :     }
    1276                 :         315 :   return std::make_pair (str, additional_length_offset);
    1277                 :         315 : }
    1278                 :             : 
    1279                 :             : // Parses a decimal integer.
    1280                 :             : std::tuple<std::string, int, bool>
    1281                 :       11130 : Lexer::parse_in_decimal ()
    1282                 :             : {
    1283                 :             :   /* A pure decimal contains only digits.  */
    1284                 :       11130 :   bool pure_decimal = true;
    1285                 :       11130 :   int additional_length_offset = 0;
    1286                 :       11130 :   std::string str;
    1287                 :       16616 :   while (ISDIGIT (current_char) || current_char == '_')
    1288                 :             :     {
    1289                 :        5486 :       if (current_char == '_')
    1290                 :             :         {
    1291                 :           8 :           pure_decimal = false;
    1292                 :             :           // don't add _ to number
    1293                 :           8 :           skip_input ();
    1294                 :           8 :           current_char = peek_input ();
    1295                 :             : 
    1296                 :           8 :           additional_length_offset++;
    1297                 :             : 
    1298                 :           8 :           continue;
    1299                 :             :         }
    1300                 :             : 
    1301                 :        5478 :       additional_length_offset++;
    1302                 :             : 
    1303                 :        5478 :       str += current_char;
    1304                 :        5478 :       skip_input ();
    1305                 :        5478 :       current_char = peek_input ();
    1306                 :             :     }
    1307                 :       11130 :   return std::make_tuple (str, additional_length_offset, pure_decimal);
    1308                 :       11130 : }
    1309                 :             : 
    1310                 :             : /* Parses escapes (and string continues) in "byte" strings and characters. Does
    1311                 :             :  * not support unicode. */
    1312                 :             : std::tuple<char, int, bool>
    1313                 :          53 : Lexer::parse_escape (char opening_char)
    1314                 :             : {
    1315                 :          53 :   int additional_length_offset = 0;
    1316                 :          53 :   char output_char = 0;
    1317                 :             : 
    1318                 :             :   // skip to actual letter
    1319                 :          53 :   skip_input ();
    1320                 :          53 :   current_char = peek_input ();
    1321                 :          53 :   additional_length_offset++;
    1322                 :             : 
    1323                 :          53 :   switch (current_char)
    1324                 :             :     {
    1325                 :          17 :       case 'x': {
    1326                 :          17 :         auto hex_escape_pair = parse_partial_hex_escape ();
    1327                 :          17 :         long hexLong = hex_escape_pair.first;
    1328                 :          17 :         additional_length_offset += hex_escape_pair.second;
    1329                 :             : 
    1330                 :          17 :         if (hexLong > 255 || hexLong < 0)
    1331                 :           0 :           rust_error_at (
    1332                 :             :             get_current_location (),
    1333                 :             :             "byte \\x escape %<\\x%x%> out of range - allows up to %<\\xFF%>",
    1334                 :             :             static_cast<unsigned int> (hexLong));
    1335                 :             :         /* TODO: restore capital for escape output - gcc pretty-printer doesn't
    1336                 :             :          * support %X directly */
    1337                 :          17 :         char hexChar = static_cast<char> (hexLong);
    1338                 :             : 
    1339                 :          17 :         output_char = hexChar;
    1340                 :             :       }
    1341                 :          17 :       break;
    1342                 :             :     case 'n':
    1343                 :             :       output_char = '\n';
    1344                 :             :       break;
    1345                 :           0 :     case 'r':
    1346                 :           0 :       output_char = '\r';
    1347                 :           0 :       break;
    1348                 :           1 :     case 't':
    1349                 :           1 :       output_char = '\t';
    1350                 :           1 :       break;
    1351                 :           8 :     case '\\':
    1352                 :           8 :       output_char = '\\';
    1353                 :           8 :       break;
    1354                 :           1 :     case '0':
    1355                 :           1 :       output_char = '\0';
    1356                 :           1 :       break;
    1357                 :          15 :     case '\'':
    1358                 :          15 :       output_char = '\'';
    1359                 :          15 :       break;
    1360                 :           1 :     case '"':
    1361                 :           1 :       output_char = '"';
    1362                 :           1 :       break;
    1363                 :           2 :     case 'u':
    1364                 :           3 :       rust_error_at (get_current_location (),
    1365                 :             :                      "cannot have a unicode escape \\u in a byte %s",
    1366                 :             :                      opening_char == '\'' ? "character" : "string");
    1367                 :             :       // Try to parse it anyway, just to skip it
    1368                 :           2 :       parse_partial_unicode_escape ();
    1369                 :           2 :       return std::make_tuple (output_char, additional_length_offset, false);
    1370                 :           0 :     case '\r':
    1371                 :           0 :     case '\n':
    1372                 :             :       // string continue
    1373                 :           0 :       return std::make_tuple (0, parse_partial_string_continue (), true);
    1374                 :           1 :     default:
    1375                 :           1 :       rust_error_at (get_current_location (),
    1376                 :             :                      "unknown escape sequence %<\\%c%>", current_char);
    1377                 :             :       // returns false if no parsing could be done
    1378                 :             :       // return false;
    1379                 :           1 :       return std::make_tuple (output_char, additional_length_offset, false);
    1380                 :          50 :       break;
    1381                 :             :     }
    1382                 :             :   // all non-special cases (string continue) should skip their used char
    1383                 :          50 :   skip_input ();
    1384                 :          50 :   current_char = peek_input ();
    1385                 :          50 :   additional_length_offset++;
    1386                 :             : 
    1387                 :             :   // returns true if parsing was successful
    1388                 :             :   // return true;
    1389                 :          50 :   return std::make_tuple (output_char, additional_length_offset, false);
    1390                 :             : }
    1391                 :             : 
    1392                 :             : /* Parses an escape (or string continue) in a string or character. Supports
    1393                 :             :  * unicode escapes. */
    1394                 :             : std::tuple<Codepoint, int, bool>
    1395                 :        2193 : Lexer::parse_utf8_escape ()
    1396                 :             : {
    1397                 :        2193 :   Codepoint output_char;
    1398                 :        2193 :   int additional_length_offset = 0;
    1399                 :             : 
    1400                 :             :   // skip to actual letter
    1401                 :        2193 :   skip_input ();
    1402                 :        2193 :   current_char = peek_input ();
    1403                 :        2193 :   additional_length_offset++;
    1404                 :             : 
    1405                 :        2193 :   switch (current_char)
    1406                 :             :     {
    1407                 :          17 :       case 'x': {
    1408                 :          17 :         auto hex_escape_pair = parse_partial_hex_escape ();
    1409                 :          17 :         long hexLong = hex_escape_pair.first;
    1410                 :          17 :         additional_length_offset += hex_escape_pair.second;
    1411                 :             : 
    1412                 :          17 :         if (hexLong > 127 || hexLong < 0)
    1413                 :           4 :           rust_error_at (
    1414                 :             :             get_current_location (),
    1415                 :             :             "ascii \\x escape %<\\x%x%> out of range - allows up to %<\\x7F%>",
    1416                 :             :             static_cast<unsigned int> (hexLong));
    1417                 :             :         /* TODO: restore capital for escape output - gcc pretty-printer doesn't
    1418                 :             :          * support %X directly */
    1419                 :          17 :         char hexChar = static_cast<char> (hexLong);
    1420                 :             : 
    1421                 :          17 :         output_char = hexChar;
    1422                 :             :       }
    1423                 :          17 :       break;
    1424                 :             :     case 'n':
    1425                 :             :       output_char = '\n';
    1426                 :             :       break;
    1427                 :           0 :     case 'r':
    1428                 :           0 :       output_char = '\r';
    1429                 :           0 :       break;
    1430                 :           1 :     case 't':
    1431                 :           1 :       output_char = '\t';
    1432                 :           1 :       break;
    1433                 :           1 :     case '\\':
    1434                 :           1 :       output_char = '\\';
    1435                 :           1 :       break;
    1436                 :        1036 :     case '0':
    1437                 :        1036 :       output_char = '\0';
    1438                 :        1036 :       break;
    1439                 :           1 :     case '\'':
    1440                 :           1 :       output_char = '\'';
    1441                 :           1 :       break;
    1442                 :           1 :     case '"':
    1443                 :           1 :       output_char = '"';
    1444                 :           1 :       break;
    1445                 :          45 :       case 'u': {
    1446                 :          45 :         auto unicode_escape_pair = parse_partial_unicode_escape ();
    1447                 :          45 :         output_char = unicode_escape_pair.first;
    1448                 :          45 :         additional_length_offset += unicode_escape_pair.second;
    1449                 :             : 
    1450                 :          45 :         return std::make_tuple (output_char, additional_length_offset, false);
    1451                 :             :       }
    1452                 :          28 :       break;
    1453                 :          28 :     case '\r':
    1454                 :          28 :     case '\n':
    1455                 :             :       // string continue
    1456                 :          28 :       return std::make_tuple (0, parse_partial_string_continue (), true);
    1457                 :           1 :     default:
    1458                 :           1 :       rust_error_at (get_current_location (),
    1459                 :             :                      "unknown escape sequence %<\\%c%>", current_char);
    1460                 :             :       // returns false if no parsing could be done
    1461                 :             :       // return false;
    1462                 :           1 :       return std::make_tuple (output_char, additional_length_offset, false);
    1463                 :        2119 :       break;
    1464                 :             :     }
    1465                 :             :   /* all non-special cases (unicode, string continue) should skip their used
    1466                 :             :    * char */
    1467                 :        2119 :   skip_input ();
    1468                 :        2119 :   current_char = peek_input ();
    1469                 :        2119 :   additional_length_offset++;
    1470                 :             : 
    1471                 :             :   // returns true if parsing was successful
    1472                 :             :   // return true;
    1473                 :        2119 :   return std::make_tuple (output_char, additional_length_offset, false);
    1474                 :             : }
    1475                 :             : 
    1476                 :             : // Parses the body of a string continue that has been found in an escape.
    1477                 :             : int
    1478                 :          28 : Lexer::parse_partial_string_continue ()
    1479                 :             : {
    1480                 :          28 :   int additional_length_offset = 1;
    1481                 :             : 
    1482                 :             :   // string continue
    1483                 :         364 :   while (is_whitespace (current_char))
    1484                 :             :     {
    1485                 :         336 :       if (current_char == '\n')
    1486                 :             :         {
    1487                 :          28 :           current_line++;
    1488                 :          28 :           current_column = 1;
    1489                 :             :           // tell line_table that new line starts
    1490                 :          28 :           start_line (current_line, max_column_hint);
    1491                 :             : 
    1492                 :             :           // reset "length"
    1493                 :          28 :           additional_length_offset = 1;
    1494                 :             : 
    1495                 :             :           // get next char
    1496                 :          28 :           skip_input ();
    1497                 :          28 :           current_char = peek_input ();
    1498                 :             : 
    1499                 :          28 :           continue;
    1500                 :             :         }
    1501                 :             : 
    1502                 :         308 :       skip_input ();
    1503                 :         308 :       current_char = peek_input ();
    1504                 :         308 :       additional_length_offset++;
    1505                 :             :     }
    1506                 :             : 
    1507                 :          28 :   return additional_length_offset;
    1508                 :             : }
    1509                 :             : 
    1510                 :             : /* Parses the body of a '\x' escape. Note that it does not check that the number
    1511                 :             :  * is valid and smaller than 255. */
    1512                 :             : std::pair<long, int>
    1513                 :          34 : Lexer::parse_partial_hex_escape ()
    1514                 :             : {
    1515                 :             :   // hex char string (null-terminated)
    1516                 :          34 :   char hexNum[3] = {0, 0, 0};
    1517                 :             : 
    1518                 :             :   // first hex char
    1519                 :          34 :   current_char = peek_input (1);
    1520                 :          34 :   int additional_length_offset = 1;
    1521                 :             : 
    1522                 :          34 :   if (!is_x_digit (current_char))
    1523                 :             :     {
    1524                 :           4 :       rust_error_at (get_current_location (),
    1525                 :             :                      "invalid character %<\\x%c%> in \\x sequence",
    1526                 :             :                      current_char);
    1527                 :           4 :       return std::make_pair (0, 0);
    1528                 :             :     }
    1529                 :          30 :   hexNum[0] = current_char;
    1530                 :             : 
    1531                 :             :   // second hex char
    1532                 :          30 :   skip_input ();
    1533                 :          30 :   current_char = peek_input (1);
    1534                 :          30 :   additional_length_offset++;
    1535                 :             : 
    1536                 :          30 :   if (!is_x_digit (current_char))
    1537                 :             :     {
    1538                 :           2 :       rust_error_at (get_current_location (),
    1539                 :           2 :                      "invalid character %<\\x%c%c%> in \\x sequence", hexNum[0],
    1540                 :             :                      current_char);
    1541                 :           2 :       return std::make_pair (0, 1);
    1542                 :             :     }
    1543                 :          28 :   skip_input ();
    1544                 :          28 :   hexNum[1] = current_char;
    1545                 :             : 
    1546                 :          28 :   long hexLong = std::strtol (hexNum, nullptr, 16);
    1547                 :             : 
    1548                 :          28 :   return std::make_pair (hexLong, additional_length_offset);
    1549                 :             : }
    1550                 :             : 
    1551                 :             : // Parses the body of a unicode escape.
    1552                 :             : std::pair<Codepoint, int>
    1553                 :          47 : Lexer::parse_partial_unicode_escape ()
    1554                 :             : {
    1555                 :          47 :   skip_input ();
    1556                 :          47 :   current_char = peek_input ();
    1557                 :          47 :   int additional_length_offset = 0;
    1558                 :             : 
    1559                 :          47 :   if (current_char != '{')
    1560                 :             :     {
    1561                 :           2 :       rust_error_at (get_current_location (),
    1562                 :             :                      "unicode escape should start with %<{%>");
    1563                 :             :       /* Skip what should probaby have been between brackets.  */
    1564                 :          10 :       while (is_x_digit (current_char) || current_char == '_')
    1565                 :             :         {
    1566                 :           6 :           skip_input ();
    1567                 :           6 :           current_char = peek_input ();
    1568                 :           6 :           additional_length_offset++;
    1569                 :             :         }
    1570                 :           2 :       return std::make_pair (Codepoint (0), additional_length_offset);
    1571                 :             :     }
    1572                 :             : 
    1573                 :          45 :   skip_input ();
    1574                 :          45 :   current_char = peek_input ();
    1575                 :          45 :   additional_length_offset++;
    1576                 :             : 
    1577                 :          45 :   if (current_char == '_')
    1578                 :             :     {
    1579                 :           2 :       rust_error_at (get_current_location (),
    1580                 :             :                      "unicode escape cannot start with %<_%>");
    1581                 :           2 :       skip_input ();
    1582                 :           2 :       current_char = peek_input ();
    1583                 :           2 :       additional_length_offset++;
    1584                 :             :       // fallthrough and try to parse the rest anyway
    1585                 :             :     }
    1586                 :             : 
    1587                 :             :   // parse unicode escape - 1-6 hex digits
    1588                 :          45 :   std::string num_str;
    1589                 :          45 :   num_str.reserve (6);
    1590                 :             : 
    1591                 :             :   // loop through to add entire hex number to string
    1592                 :         296 :   while (is_x_digit (current_char) || current_char == '_')
    1593                 :             :     {
    1594                 :         206 :       if (current_char == '_')
    1595                 :             :         {
    1596                 :             :           // don't add _ to number
    1597                 :          24 :           skip_input ();
    1598                 :          24 :           current_char = peek_input ();
    1599                 :             : 
    1600                 :          24 :           additional_length_offset++;
    1601                 :             : 
    1602                 :          24 :           continue;
    1603                 :             :         }
    1604                 :             : 
    1605                 :         182 :       additional_length_offset++;
    1606                 :             : 
    1607                 :             :       // add raw hex numbers
    1608                 :         182 :       num_str += current_char;
    1609                 :             : 
    1610                 :         182 :       skip_input ();
    1611                 :         182 :       current_char = peek_input ();
    1612                 :             :     }
    1613                 :             : 
    1614                 :          45 :   if (current_char == '}')
    1615                 :             :     {
    1616                 :          43 :       skip_input ();
    1617                 :          43 :       current_char = peek_input ();
    1618                 :          43 :       additional_length_offset++;
    1619                 :             :     }
    1620                 :             :   else
    1621                 :             :     {
    1622                 :             :       // actually an error, but allow propagation anyway Assume that
    1623                 :             :       // wrong bracketm whitespace or single/double quotes are wrong
    1624                 :             :       // termination, otherwise it is a wrong character, then skip to the actual
    1625                 :             :       // terminator.
    1626                 :           2 :       if (current_char == '{' || is_whitespace (current_char)
    1627                 :           4 :           || current_char == '\'' || current_char == '"')
    1628                 :             :         {
    1629                 :           0 :           rust_error_at (get_current_location (),
    1630                 :             :                          "expected terminating %<}%> in unicode escape");
    1631                 :           0 :           return std::make_pair (Codepoint (0), additional_length_offset);
    1632                 :             :         }
    1633                 :             :       else
    1634                 :             :         {
    1635                 :           2 :           rust_error_at (get_current_location (),
    1636                 :             :                          "invalid character %<%c%> in unicode escape",
    1637                 :             :                          current_char);
    1638                 :           2 :           while (current_char != '}' && current_char != '{'
    1639                 :           6 :                  && !is_whitespace (current_char) && current_char != '\''
    1640                 :          14 :                  && current_char != '"')
    1641                 :             :             {
    1642                 :           6 :               skip_input ();
    1643                 :           6 :               current_char = peek_input ();
    1644                 :           6 :               additional_length_offset++;
    1645                 :             :             }
    1646                 :             :           // Consume the actual closing bracket if found
    1647                 :           2 :           if (current_char == '}')
    1648                 :             :             {
    1649                 :           2 :               skip_input ();
    1650                 :           2 :               current_char = peek_input ();
    1651                 :           2 :               additional_length_offset++;
    1652                 :             :             }
    1653                 :           2 :           return std::make_pair (Codepoint (0), additional_length_offset);
    1654                 :             :         }
    1655                 :             :     }
    1656                 :             : 
    1657                 :             :   // ensure 1-6 hex characters
    1658                 :          43 :   if (num_str.length () > 6 || num_str.length () < 1)
    1659                 :             :     {
    1660                 :           4 :       rust_error_at (get_current_location (),
    1661                 :             :                      "unicode escape should be between 1 and 6 hex "
    1662                 :             :                      "characters; it is %lu",
    1663                 :           4 :                      (unsigned long) num_str.length ());
    1664                 :             :       // return false;
    1665                 :           4 :       return std::make_pair (Codepoint (0), additional_length_offset);
    1666                 :             :     }
    1667                 :             : 
    1668                 :          39 :   unsigned long hex_num = std::strtoul (num_str.c_str (), nullptr, 16);
    1669                 :             : 
    1670                 :          39 :   if (hex_num > 0xd7ff && hex_num < 0xe000)
    1671                 :             :     {
    1672                 :           4 :       rust_error_at (
    1673                 :             :         get_current_location (),
    1674                 :             :         "unicode escape cannot be a surrogate value (D800 to DFFF)");
    1675                 :           4 :       return std::make_pair (Codepoint (0), additional_length_offset);
    1676                 :             :     }
    1677                 :             : 
    1678                 :          35 :   if (hex_num > 0x10ffff)
    1679                 :             :     {
    1680                 :           4 :       rust_error_at (get_current_location (),
    1681                 :             :                      "unicode escape cannot be larger than 10FFFF");
    1682                 :           4 :       return std::make_pair (Codepoint (0), additional_length_offset);
    1683                 :             :     }
    1684                 :             : 
    1685                 :             :   // return true;
    1686                 :          31 :   return std::make_pair (Codepoint (static_cast<uint32_t> (hex_num)),
    1687                 :             :                          additional_length_offset);
    1688                 :          45 : }
    1689                 :             : 
    1690                 :             : // Parses a byte character.
    1691                 :             : TokenPtr
    1692                 :          72 : Lexer::parse_byte_char (Location loc)
    1693                 :             : {
    1694                 :          72 :   skip_input ();
    1695                 :          72 :   current_column++;
    1696                 :             :   // make current char the next character
    1697                 :          72 :   current_char = peek_input ();
    1698                 :             : 
    1699                 :          72 :   int length = 1;
    1700                 :             : 
    1701                 :             :   // char to save
    1702                 :          72 :   char byte_char = 0;
    1703                 :             : 
    1704                 :             :   // detect escapes
    1705                 :          72 :   if (current_char == '\\')
    1706                 :             :     {
    1707                 :          30 :       auto escape_length_pair = parse_escape ('\'');
    1708                 :          30 :       byte_char = std::get<0> (escape_length_pair);
    1709                 :          30 :       length += std::get<1> (escape_length_pair);
    1710                 :             : 
    1711                 :          30 :       current_char = peek_input ();
    1712                 :             : 
    1713                 :          30 :       if (current_char != '\'')
    1714                 :             :         {
    1715                 :           0 :           rust_error_at (get_current_location (), "unclosed %<byte char%>");
    1716                 :             :         }
    1717                 :             : 
    1718                 :          30 :       skip_input ();
    1719                 :          30 :       current_char = peek_input ();
    1720                 :          30 :       length++; // go to next char
    1721                 :             :     }
    1722                 :          42 :   else if (current_char != '\'')
    1723                 :             :     {
    1724                 :             :       // otherwise, get character from direct input character
    1725                 :          42 :       byte_char = current_char;
    1726                 :             : 
    1727                 :          42 :       skip_input ();
    1728                 :          42 :       current_char = peek_input ();
    1729                 :          42 :       length++;
    1730                 :             : 
    1731                 :          42 :       if (current_char != '\'')
    1732                 :             :         {
    1733                 :           0 :           rust_error_at (get_current_location (), "unclosed %<byte char%>");
    1734                 :             :         }
    1735                 :             : 
    1736                 :          42 :       skip_input ();
    1737                 :          42 :       current_char = peek_input ();
    1738                 :          42 :       length++; // go to next char
    1739                 :             :     }
    1740                 :             :   else
    1741                 :             :     {
    1742                 :           0 :       rust_error_at (get_current_location (),
    1743                 :             :                      "no character inside %<%> for %<byte char%>");
    1744                 :             :     }
    1745                 :             : 
    1746                 :          72 :   current_column += length;
    1747                 :             : 
    1748                 :          72 :   loc += length - 1;
    1749                 :             : 
    1750                 :          72 :   return Token::make_byte_char (loc, byte_char);
    1751                 :             : }
    1752                 :             : 
    1753                 :             : // Parses a byte string.
    1754                 :             : TokenPtr
    1755                 :          47 : Lexer::parse_byte_string (Location loc)
    1756                 :             : {
    1757                 :             :   // byte string
    1758                 :             : 
    1759                 :             :   // skip quote character
    1760                 :          47 :   skip_input ();
    1761                 :          47 :   current_column++;
    1762                 :             : 
    1763                 :          47 :   std::string str;
    1764                 :          47 :   str.reserve (16); // some sensible default
    1765                 :             : 
    1766                 :          47 :   int length = 1;
    1767                 :          47 :   current_char = peek_input ();
    1768                 :             : 
    1769                 :         277 :   while (current_char != '"' && current_char != EOF)
    1770                 :             :     {
    1771                 :         230 :       if (current_char == '\\')
    1772                 :             :         {
    1773                 :          23 :           auto escape_length_pair = parse_escape ('"');
    1774                 :          23 :           char output_char = std::get<0> (escape_length_pair);
    1775                 :             : 
    1776                 :          23 :           if (output_char == 0 && std::get<2> (escape_length_pair))
    1777                 :           0 :             length = std::get<1> (escape_length_pair) - 1;
    1778                 :             :           else
    1779                 :          23 :             length += std::get<1> (escape_length_pair);
    1780                 :             : 
    1781                 :          23 :           if (output_char != 0 || !std::get<2> (escape_length_pair))
    1782                 :          23 :             str += output_char;
    1783                 :             : 
    1784                 :          23 :           continue;
    1785                 :          23 :         }
    1786                 :             : 
    1787                 :         207 :       length++;
    1788                 :             : 
    1789                 :         207 :       str += current_char;
    1790                 :         207 :       skip_input ();
    1791                 :         207 :       current_char = peek_input ();
    1792                 :             :     }
    1793                 :             : 
    1794                 :          47 :   current_column += length;
    1795                 :             : 
    1796                 :          47 :   if (current_char == '"')
    1797                 :             :     {
    1798                 :          40 :       current_column++;
    1799                 :             : 
    1800                 :          40 :       skip_input ();
    1801                 :          40 :       current_char = peek_input ();
    1802                 :             :     }
    1803                 :           7 :   else if (current_char == EOF)
    1804                 :             :     {
    1805                 :           7 :       rust_error_at (get_current_location (), "unended byte string literal");
    1806                 :           7 :       return Token::make (END_OF_FILE, get_current_location ());
    1807                 :             :     }
    1808                 :             :   else
    1809                 :             :     {
    1810                 :             :       gcc_unreachable ();
    1811                 :             :     }
    1812                 :             : 
    1813                 :          40 :   str.shrink_to_fit ();
    1814                 :          40 :   loc += str.size () - 1;
    1815                 :             : 
    1816                 :          40 :   return Token::make_byte_string (loc, std::move (str));
    1817                 :          47 : }
    1818                 :             : 
    1819                 :             : // Parses a raw byte string.
    1820                 :             : TokenPtr
    1821                 :          24 : Lexer::parse_raw_byte_string (Location loc)
    1822                 :             : {
    1823                 :             :   // raw byte string literals
    1824                 :          24 :   std::string str;
    1825                 :          24 :   str.reserve (16); // some sensible default
    1826                 :             : 
    1827                 :          24 :   int length = 1;
    1828                 :          24 :   int hash_count = 0;
    1829                 :             : 
    1830                 :             :   // get hash count at beginnning
    1831                 :          24 :   skip_input ();
    1832                 :          24 :   current_char = peek_input ();
    1833                 :          24 :   length++;
    1834                 :          31 :   while (current_char == '#')
    1835                 :             :     {
    1836                 :           7 :       hash_count++;
    1837                 :           7 :       length++;
    1838                 :             : 
    1839                 :           7 :       skip_input ();
    1840                 :           7 :       current_char = peek_input ();
    1841                 :             :     }
    1842                 :             : 
    1843                 :          24 :   if (current_char != '"')
    1844                 :             :     {
    1845                 :           0 :       rust_error_at (get_current_location (),
    1846                 :             :                      "raw byte string has no opening %<\"%>");
    1847                 :             :     }
    1848                 :             : 
    1849                 :          24 :   skip_input ();
    1850                 :          24 :   current_char = peek_input ();
    1851                 :          24 :   length++;
    1852                 :             : 
    1853                 :         188 :   while (true)
    1854                 :             :     {
    1855                 :         106 :       if (current_char == '"')
    1856                 :             :         {
    1857                 :          35 :           bool enough_hashes = true;
    1858                 :             : 
    1859                 :          35 :           for (int i = 0; i < hash_count; i++)
    1860                 :             :             {
    1861                 :          11 :               if (peek_input (i + 1) != '#')
    1862                 :             :                 {
    1863                 :             :                   enough_hashes = false;
    1864                 :             :                   break;
    1865                 :             :                 }
    1866                 :             :             }
    1867                 :             : 
    1868                 :          27 :           if (enough_hashes)
    1869                 :             :             {
    1870                 :             :               // skip enough input and peek enough input
    1871                 :          24 :               skip_input (hash_count);
    1872                 :          24 :               current_char = peek_input ();
    1873                 :          24 :               length += hash_count + 1;
    1874                 :          24 :               break;
    1875                 :             :             }
    1876                 :             :         }
    1877                 :             : 
    1878                 :          82 :       if ((unsigned char) current_char > 127)
    1879                 :             :         {
    1880                 :           2 :           rust_error_at (get_current_location (),
    1881                 :             :                          "character %<%c%> in raw byte string out of range",
    1882                 :             :                          current_char);
    1883                 :           2 :           current_char = 0;
    1884                 :             :         }
    1885                 :             : 
    1886                 :          82 :       length++;
    1887                 :             : 
    1888                 :          82 :       str += current_char;
    1889                 :          82 :       skip_input ();
    1890                 :          82 :       current_char = peek_input ();
    1891                 :          82 :     }
    1892                 :             : 
    1893                 :          24 :   current_column += length;
    1894                 :             : 
    1895                 :          24 :   loc += length - 1;
    1896                 :             : 
    1897                 :          24 :   str.shrink_to_fit ();
    1898                 :             : 
    1899                 :          24 :   return Token::make_byte_string (loc, std::move (str));
    1900                 :          24 : }
    1901                 :             : 
    1902                 :             : // Parses a raw identifier.
    1903                 :             : TokenPtr
    1904                 :          37 : Lexer::parse_raw_identifier (Location loc)
    1905                 :             : {
    1906                 :             :   // raw identifier
    1907                 :          37 :   std::string str;
    1908                 :          37 :   str.reserve (16); // default
    1909                 :             : 
    1910                 :          37 :   skip_input ();
    1911                 :          37 :   current_char = peek_input ();
    1912                 :             : 
    1913                 :          37 :   current_column += 2;
    1914                 :             : 
    1915                 :          37 :   bool first_is_underscore = current_char == '_';
    1916                 :             : 
    1917                 :          37 :   int length = 0;
    1918                 :          37 :   current_char = peek_input ();
    1919                 :             :   // loop through entire name
    1920                 :          37 :   while (ISALPHA (current_char) || ISDIGIT (current_char)
    1921                 :         218 :          || current_char == '_')
    1922                 :             :     {
    1923                 :         181 :       length++;
    1924                 :             : 
    1925                 :         181 :       str += current_char;
    1926                 :         181 :       skip_input ();
    1927                 :         181 :       current_char = peek_input ();
    1928                 :             :     }
    1929                 :             : 
    1930                 :          37 :   current_column += length;
    1931                 :             : 
    1932                 :             :   // if just a single underscore, not an identifier
    1933                 :          37 :   if (first_is_underscore && length == 1)
    1934                 :           1 :     rust_error_at (get_current_location (),
    1935                 :             :                    "%<_%> is not a valid raw identifier");
    1936                 :             : 
    1937                 :          36 :   if (str == "crate" || str == "extern" || str == "self" || str == "super"
    1938                 :          73 :       || str == "Self")
    1939                 :             :     {
    1940                 :           1 :       rust_error_at (get_current_location (),
    1941                 :             :                      "%qs is a forbidden raw identifier", str.c_str ());
    1942                 :             : 
    1943                 :           1 :       return nullptr;
    1944                 :             :     }
    1945                 :             :   else
    1946                 :             :     {
    1947                 :          36 :       str.shrink_to_fit ();
    1948                 :          36 :       loc += length - 1;
    1949                 :             : 
    1950                 :          36 :       return Token::make_identifier (loc, std::move (str));
    1951                 :             :     }
    1952                 :          37 : }
    1953                 :             : 
    1954                 :             : // skip broken string input (unterminated strings)
    1955                 :             : void
    1956                 :           0 : Lexer::skip_broken_string_input (int current_char)
    1957                 :             : {
    1958                 :           0 :   while (current_char != '"' && current_char != EOF)
    1959                 :             :     {
    1960                 :           0 :       if (current_char == '\n')
    1961                 :             :         {
    1962                 :           0 :           current_line++;
    1963                 :           0 :           current_column = 1;
    1964                 :             :         }
    1965                 :             :       else
    1966                 :             :         {
    1967                 :           0 :           current_column++;
    1968                 :             :         }
    1969                 :           0 :       skip_input ();
    1970                 :           0 :       current_char = peek_input ();
    1971                 :             :     }
    1972                 :           0 :   if (current_char == '"')
    1973                 :             :     {
    1974                 :           0 :       current_column++;
    1975                 :             : 
    1976                 :           0 :       skip_input ();
    1977                 :           0 :       current_char = peek_input ();
    1978                 :             :     }
    1979                 :           0 :   rust_debug ("skipped to %d:%d due to bad quotes", current_line,
    1980                 :             :               current_column);
    1981                 :           0 : }
    1982                 :             : 
    1983                 :             : // Parses a unicode string.
    1984                 :             : TokenPtr
    1985                 :        3233 : Lexer::parse_string (Location loc)
    1986                 :             : {
    1987                 :        3233 :   Codepoint current_char32;
    1988                 :             : 
    1989                 :        3233 :   std::string str;
    1990                 :        3233 :   str.reserve (16); // some sensible default
    1991                 :             : 
    1992                 :        3233 :   int length = 1;
    1993                 :        3233 :   current_char32 = peek_codepoint_input ();
    1994                 :             : 
    1995                 :             :   // FIXME: This fails if the input ends. How do we check for EOF?
    1996                 :       24856 :   while (current_char32.value != '"' && !current_char32.is_eof ())
    1997                 :             :     {
    1998                 :       21623 :       if (current_char32.value == '\\')
    1999                 :             :         {
    2000                 :             :           // parse escape
    2001                 :        2171 :           auto utf8_escape_pair = parse_utf8_escape ();
    2002                 :        2171 :           current_char32 = std::get<0> (utf8_escape_pair);
    2003                 :             : 
    2004                 :        2171 :           if (current_char32 == Codepoint (0) && std::get<2> (utf8_escape_pair))
    2005                 :          28 :             length = std::get<1> (utf8_escape_pair) - 1;
    2006                 :             :           else
    2007                 :        2143 :             length += std::get<1> (utf8_escape_pair);
    2008                 :             : 
    2009                 :        2171 :           if (current_char32 != Codepoint (0)
    2010                 :        2171 :               || !std::get<2> (utf8_escape_pair))
    2011                 :        2143 :             str += current_char32;
    2012                 :             : 
    2013                 :             :           // required as parsing utf8 escape only changes current_char
    2014                 :        2171 :           current_char32 = peek_codepoint_input ();
    2015                 :             : 
    2016                 :        2171 :           continue;
    2017                 :        2171 :         }
    2018                 :             : 
    2019                 :       19452 :       length += get_input_codepoint_length ();
    2020                 :             : 
    2021                 :       19452 :       str += current_char32;
    2022                 :       19452 :       skip_codepoint_input ();
    2023                 :       19452 :       current_char32 = peek_codepoint_input ();
    2024                 :             :     }
    2025                 :             : 
    2026                 :        3233 :   current_column += length;
    2027                 :             : 
    2028                 :        3233 :   if (current_char32.value == '"')
    2029                 :             :     {
    2030                 :        3219 :       current_column++;
    2031                 :             : 
    2032                 :        3219 :       skip_input ();
    2033                 :        3219 :       current_char = peek_input ();
    2034                 :             :     }
    2035                 :          14 :   else if (current_char32.is_eof ())
    2036                 :             :     {
    2037                 :          14 :       rust_error_at (get_current_location (), "unended string literal");
    2038                 :          14 :       return Token::make (END_OF_FILE, get_current_location ());
    2039                 :             :     }
    2040                 :             :   else
    2041                 :             :     {
    2042                 :             :       gcc_unreachable ();
    2043                 :             :     }
    2044                 :             : 
    2045                 :        3219 :   str.shrink_to_fit ();
    2046                 :        3219 :   loc += length - 1;
    2047                 :             : 
    2048                 :        3219 :   return Token::make_string (loc, std::move (str));
    2049                 :        3233 : }
    2050                 :             : 
    2051                 :             : // Parses an identifier or keyword.
    2052                 :             : TokenPtr
    2053                 :      127834 : Lexer::parse_identifier_or_keyword (Location loc)
    2054                 :             : {
    2055                 :      127834 :   std::string str;
    2056                 :      127834 :   str.reserve (16); // default
    2057                 :      127834 :   str += current_char;
    2058                 :             : 
    2059                 :      127834 :   bool first_is_underscore = current_char == '_';
    2060                 :             : 
    2061                 :      127834 :   int length = 1;
    2062                 :      127834 :   current_char = peek_input ();
    2063                 :             :   // loop through entire name
    2064                 :      127834 :   while (ISALPHA (current_char) || ISDIGIT (current_char)
    2065                 :      435850 :          || current_char == '_')
    2066                 :             :     {
    2067                 :      308016 :       length++;
    2068                 :             : 
    2069                 :      308016 :       str += current_char;
    2070                 :      308016 :       skip_input ();
    2071                 :      308016 :       current_char = peek_input ();
    2072                 :             :     }
    2073                 :             : 
    2074                 :      127834 :   current_column += length;
    2075                 :             : 
    2076                 :             :   // if just a single underscore, not an identifier
    2077                 :      127834 :   if (first_is_underscore && length == 1)
    2078                 :         289 :     return Token::make (UNDERSCORE, loc);
    2079                 :             : 
    2080                 :      127545 :   str.shrink_to_fit ();
    2081                 :             : 
    2082                 :      127545 :   loc += length - 1;
    2083                 :             : 
    2084                 :      127545 :   TokenId keyword = classify_keyword (str);
    2085                 :      127545 :   if (keyword == IDENTIFIER)
    2086                 :       83334 :     return Token::make_identifier (loc, std::move (str));
    2087                 :             :   else
    2088                 :       44211 :     return Token::make (keyword, loc);
    2089                 :      127834 : }
    2090                 :             : 
    2091                 :             : // Possibly returns a raw string token if it exists - otherwise returns null.
    2092                 :             : TokenPtr
    2093                 :        1850 : Lexer::maybe_parse_raw_string (Location loc)
    2094                 :             : {
    2095                 :        1850 :   int peek_index = 0;
    2096                 :        1857 :   while (peek_input (peek_index) == '#')
    2097                 :           7 :     peek_index++;
    2098                 :             : 
    2099                 :        1850 :   if (peek_input (peek_index) == '"')
    2100                 :          23 :     return parse_raw_string (loc, peek_index);
    2101                 :             :   else
    2102                 :        1827 :     return nullptr;
    2103                 :             : }
    2104                 :             : 
    2105                 :             : // Returns a raw string token.
    2106                 :             : TokenPtr
    2107                 :          23 : Lexer::parse_raw_string (Location loc, int initial_hash_count)
    2108                 :             : {
    2109                 :             :   // raw string literals
    2110                 :          23 :   std::string str;
    2111                 :          23 :   str.reserve (16); // some sensible default
    2112                 :             : 
    2113                 :          23 :   int length = 1 + initial_hash_count;
    2114                 :             : 
    2115                 :          23 :   if (initial_hash_count > 0)
    2116                 :           5 :     skip_input (initial_hash_count - 1);
    2117                 :             : 
    2118                 :          23 :   current_char = peek_input ();
    2119                 :             : 
    2120                 :          23 :   if (current_char != '"')
    2121                 :           0 :     rust_error_at (get_current_location (), "raw string has no opening %<\"%>");
    2122                 :             : 
    2123                 :          23 :   length++;
    2124                 :          23 :   skip_input ();
    2125                 :          23 :   Codepoint current_char32 = peek_codepoint_input ();
    2126                 :             : 
    2127                 :          96 :   while (!current_char32.is_eof ())
    2128                 :             :     {
    2129                 :          96 :       if (current_char32.value == '"')
    2130                 :             :         {
    2131                 :          34 :           bool enough_hashes = true;
    2132                 :             : 
    2133                 :          34 :           for (int i = 0; i < initial_hash_count; i++)
    2134                 :             :             {
    2135                 :          11 :               if (peek_input (i + 1) != '#')
    2136                 :             :                 {
    2137                 :             :                   enough_hashes = false;
    2138                 :             :                   break;
    2139                 :             :                 }
    2140                 :             :             }
    2141                 :             : 
    2142                 :          26 :           if (enough_hashes)
    2143                 :             :             {
    2144                 :             :               // skip enough input and peek enough input
    2145                 :          23 :               skip_input (initial_hash_count);
    2146                 :          23 :               current_char = peek_input ();
    2147                 :          23 :               length += initial_hash_count + 1;
    2148                 :          23 :               break;
    2149                 :             :             }
    2150                 :             :         }
    2151                 :             : 
    2152                 :          73 :       length++;
    2153                 :             : 
    2154                 :          73 :       str += current_char32;
    2155                 :          73 :       skip_codepoint_input ();
    2156                 :          73 :       current_char32 = peek_codepoint_input ();
    2157                 :             :     }
    2158                 :             : 
    2159                 :          23 :   current_column += length;
    2160                 :             : 
    2161                 :          23 :   loc += length - 1;
    2162                 :             : 
    2163                 :          23 :   str.shrink_to_fit ();
    2164                 :             : 
    2165                 :          23 :   return Token::make_string (loc, std::move (str));
    2166                 :          23 : }
    2167                 :             : 
    2168                 :             : template <typename IsDigitFunc>
    2169                 :             : TokenPtr
    2170                 :         107 : Lexer::parse_non_decimal_int_literal (Location loc, IsDigitFunc is_digit_func,
    2171                 :             :                                       std::string existent_str, int base)
    2172                 :             : {
    2173                 :         107 :   int length = 1;
    2174                 :             : 
    2175                 :         107 :   skip_input ();
    2176                 :         107 :   current_char = peek_input ();
    2177                 :             : 
    2178                 :         107 :   length++;
    2179                 :             : 
    2180                 :             :   // loop through to add entire number to string
    2181                 :         824 :   while (is_digit_func (current_char) || current_char == '_')
    2182                 :             :     {
    2183                 :         717 :       if (current_char == '_')
    2184                 :             :         {
    2185                 :             :           // don't add _ to number
    2186                 :          21 :           skip_input ();
    2187                 :          21 :           current_char = peek_input ();
    2188                 :             : 
    2189                 :          21 :           length++;
    2190                 :             : 
    2191                 :          21 :           continue;
    2192                 :             :         }
    2193                 :             : 
    2194                 :         696 :       length++;
    2195                 :             : 
    2196                 :             :       // add raw numbers
    2197                 :         696 :       existent_str += current_char;
    2198                 :         696 :       skip_input ();
    2199                 :         696 :       current_char = peek_input ();
    2200                 :             :     }
    2201                 :             : 
    2202                 :             :   // convert value to decimal representation
    2203                 :         107 :   long dec_num = std::strtol (existent_str.c_str (), nullptr, base);
    2204                 :             : 
    2205                 :         107 :   existent_str = std::to_string (dec_num);
    2206                 :             : 
    2207                 :             :   // parse in type suffix if it exists
    2208                 :         107 :   auto type_suffix_pair = parse_in_type_suffix ();
    2209                 :         107 :   PrimitiveCoreType type_hint = type_suffix_pair.first;
    2210                 :         107 :   length += type_suffix_pair.second;
    2211                 :             : 
    2212                 :         107 :   current_column += length;
    2213                 :             : 
    2214                 :         107 :   if (type_hint == CORETYPE_F32 || type_hint == CORETYPE_F64)
    2215                 :             :     {
    2216                 :           0 :       rust_error_at (get_current_location (),
    2217                 :             :                      "invalid type suffix %qs for integer (%s) literal",
    2218                 :             :                      get_type_hint_string (type_hint),
    2219                 :             :                      base == 16
    2220                 :             :                        ? "hex"
    2221                 :             :                        : (base == 8 ? "octal"
    2222                 :             :                                     : (base == 2 ? "binary"
    2223                 :             :                                                  : "<insert unknown base>")));
    2224                 :           0 :       return nullptr;
    2225                 :             :     }
    2226                 :             : 
    2227                 :         107 :   loc += length - 1;
    2228                 :             : 
    2229                 :         107 :   return Token::make_int (loc, std::move (existent_str), type_hint);
    2230                 :             : }
    2231                 :             : 
    2232                 :             : // Parses a hex, binary or octal int literal.
    2233                 :             : TokenPtr
    2234                 :         107 : Lexer::parse_non_decimal_int_literals (Location loc)
    2235                 :             : {
    2236                 :         107 :   std::string str;
    2237                 :         107 :   str.reserve (16); // some sensible default
    2238                 :         107 :   str += current_char;
    2239                 :             : 
    2240                 :         107 :   current_char = peek_input ();
    2241                 :             : 
    2242                 :         107 :   if (current_char == 'x')
    2243                 :             :     {
    2244                 :             :       // hex (integer only)
    2245                 :          75 :       return parse_non_decimal_int_literal (loc, is_x_digit, str + "x", 16);
    2246                 :             :     }
    2247                 :          32 :   else if (current_char == 'o')
    2248                 :             :     {
    2249                 :             :       // octal (integer only)
    2250                 :          16 :       return parse_non_decimal_int_literal (loc, is_octal_digit,
    2251                 :          16 :                                             std::move (str), 8);
    2252                 :             :     }
    2253                 :          16 :   else if (current_char == 'b')
    2254                 :             :     {
    2255                 :             :       // binary (integer only)
    2256                 :          16 :       return parse_non_decimal_int_literal (loc, is_bin_digit, std::move (str),
    2257                 :          16 :                                             2);
    2258                 :             :     }
    2259                 :             :   else
    2260                 :             :     {
    2261                 :           0 :       return nullptr;
    2262                 :             :     }
    2263                 :         107 : }
    2264                 :             : 
    2265                 :             : // Parses a decimal-based int literal or float literal.
    2266                 :             : TokenPtr
    2267                 :       10815 : Lexer::parse_decimal_int_or_float (Location loc)
    2268                 :             : {
    2269                 :       10815 :   std::string str;
    2270                 :       10815 :   str.reserve (16); // some sensible default
    2271                 :       10815 :   str += current_char;
    2272                 :             : 
    2273                 :       10815 :   int length = 1;
    2274                 :       10815 :   bool first_zero = current_char == '0';
    2275                 :             : 
    2276                 :       10815 :   current_char = peek_input ();
    2277                 :             : 
    2278                 :             :   // parse initial decimal integer (or first integer part of float) literal
    2279                 :       10815 :   auto initial_decimal = parse_in_decimal ();
    2280                 :       10815 :   str += std::get<0> (initial_decimal);
    2281                 :       10815 :   length += std::get<1> (initial_decimal);
    2282                 :             : 
    2283                 :             :   // detect float literal
    2284                 :       10815 :   if (current_char == '.' && is_float_digit (peek_input (1)))
    2285                 :             :     {
    2286                 :             :       // float with a '.', parse another decimal into it
    2287                 :             : 
    2288                 :             :       // add . to str
    2289                 :         315 :       str += current_char;
    2290                 :         315 :       skip_input ();
    2291                 :         315 :       current_char = peek_input ();
    2292                 :         315 :       length++;
    2293                 :             : 
    2294                 :             :       // parse another decimal number for float
    2295                 :         315 :       auto second_decimal = parse_in_decimal ();
    2296                 :         315 :       str += std::get<0> (second_decimal);
    2297                 :         315 :       length += std::get<1> (second_decimal);
    2298                 :             : 
    2299                 :             :       // parse in exponent part if it exists
    2300                 :         315 :       auto exponent_pair = parse_in_exponent_part ();
    2301                 :         315 :       str += exponent_pair.first;
    2302                 :         315 :       length += exponent_pair.second;
    2303                 :             : 
    2304                 :             :       // parse in type suffix if it exists
    2305                 :         315 :       auto type_suffix_pair = parse_in_type_suffix ();
    2306                 :         315 :       PrimitiveCoreType type_hint = type_suffix_pair.first;
    2307                 :         315 :       length += type_suffix_pair.second;
    2308                 :             : 
    2309                 :         315 :       if (type_hint != CORETYPE_F32 && type_hint != CORETYPE_F64
    2310                 :         315 :           && type_hint != CORETYPE_UNKNOWN)
    2311                 :             :         {
    2312                 :           0 :           rust_error_at (get_current_location (),
    2313                 :             :                          "invalid type suffix %qs for floating-point literal",
    2314                 :             :                          get_type_hint_string (type_hint));
    2315                 :             :           // ignore invalid type suffix as everything else seems fine
    2316                 :           0 :           type_hint = CORETYPE_UNKNOWN;
    2317                 :             :         }
    2318                 :             : 
    2319                 :         315 :       current_column += length;
    2320                 :             : 
    2321                 :         315 :       loc += length - 1;
    2322                 :             : 
    2323                 :         315 :       str.shrink_to_fit ();
    2324                 :         315 :       return Token::make_float (loc, std::move (str), type_hint);
    2325                 :         315 :     }
    2326                 :       10500 :   else if (current_char == '.' && check_valid_float_dot_end (peek_input (1)))
    2327                 :             :     {
    2328                 :             :       // float that is just an integer with a terminating '.' character
    2329                 :             : 
    2330                 :             :       // add . to str
    2331                 :           0 :       str += current_char;
    2332                 :           0 :       skip_input ();
    2333                 :           0 :       current_char = peek_input ();
    2334                 :           0 :       length++;
    2335                 :             : 
    2336                 :             :       // add a '0' after the . to prevent ambiguity
    2337                 :           0 :       str += '0';
    2338                 :             : 
    2339                 :             :       // type hint not allowed
    2340                 :             : 
    2341                 :           0 :       current_column += length;
    2342                 :             : 
    2343                 :           0 :       loc += length - 1;
    2344                 :             : 
    2345                 :           0 :       str.shrink_to_fit ();
    2346                 :           0 :       return Token::make_float (loc, std::move (str), CORETYPE_UNKNOWN);
    2347                 :             :     }
    2348                 :       10500 :   else if (current_char == 'E' || current_char == 'e')
    2349                 :             :     {
    2350                 :             :       // exponent float with no '.' character
    2351                 :             : 
    2352                 :             :       // parse exponent part
    2353                 :           0 :       auto exponent_pair = parse_in_exponent_part ();
    2354                 :           0 :       str += exponent_pair.first;
    2355                 :           0 :       length += exponent_pair.second;
    2356                 :             : 
    2357                 :             :       // parse in type suffix if it exists
    2358                 :           0 :       auto type_suffix_pair = parse_in_type_suffix ();
    2359                 :           0 :       PrimitiveCoreType type_hint = type_suffix_pair.first;
    2360                 :           0 :       length += type_suffix_pair.second;
    2361                 :             : 
    2362                 :           0 :       if (type_hint != CORETYPE_F32 && type_hint != CORETYPE_F64
    2363                 :           0 :           && type_hint != CORETYPE_UNKNOWN)
    2364                 :             :         {
    2365                 :           0 :           rust_error_at (get_current_location (),
    2366                 :             :                          "invalid type suffix %qs for floating-point literal",
    2367                 :             :                          get_type_hint_string (type_hint));
    2368                 :             :           // ignore invalid type suffix as everything else seems fine
    2369                 :           0 :           type_hint = CORETYPE_UNKNOWN;
    2370                 :             :         }
    2371                 :             : 
    2372                 :           0 :       current_column += length;
    2373                 :             : 
    2374                 :           0 :       loc += length - 1;
    2375                 :             : 
    2376                 :           0 :       str.shrink_to_fit ();
    2377                 :           0 :       return Token::make_float (loc, std::move (str), type_hint);
    2378                 :           0 :     }
    2379                 :             :   else
    2380                 :             :     {
    2381                 :             :       // is an integer
    2382                 :             : 
    2383                 :             :       // parse in type suffix if it exists
    2384                 :       10500 :       auto type_suffix_pair = parse_in_type_suffix ();
    2385                 :       10500 :       PrimitiveCoreType type_hint = type_suffix_pair.first;
    2386                 :             :       /* A "real" pure decimal doesn't have a suffix and no zero prefix.  */
    2387                 :       10500 :       if (type_hint == CORETYPE_UNKNOWN)
    2388                 :             :         {
    2389                 :        9599 :           bool pure_decimal = std::get<2> (initial_decimal);
    2390                 :        9599 :           if (pure_decimal && (!first_zero || str.size () == 1))
    2391                 :             :             type_hint = CORETYPE_PURE_DECIMAL;
    2392                 :             :         }
    2393                 :       10500 :       length += type_suffix_pair.second;
    2394                 :             : 
    2395                 :       10500 :       current_column += length;
    2396                 :             : 
    2397                 :       10500 :       loc += length - 1;
    2398                 :             : 
    2399                 :       10500 :       str.shrink_to_fit ();
    2400                 :       10500 :       return Token::make_int (loc, std::move (str), type_hint);
    2401                 :             :     }
    2402                 :       10815 : }
    2403                 :             : 
    2404                 :             : TokenPtr
    2405                 :         422 : Lexer::parse_char_or_lifetime (Location loc)
    2406                 :             : {
    2407                 :         422 :   Codepoint current_char32;
    2408                 :             : 
    2409                 :         422 :   int length = 1;
    2410                 :             : 
    2411                 :         422 :   current_char32 = peek_codepoint_input ();
    2412                 :         422 :   if (current_char32.is_eof ())
    2413                 :           0 :     return nullptr;
    2414                 :             : 
    2415                 :             :   // parse escaped char literal
    2416                 :         422 :   if (current_char32.value == '\\')
    2417                 :             :     {
    2418                 :             :       // parse escape
    2419                 :          22 :       auto utf8_escape_pair = parse_utf8_escape ();
    2420                 :          22 :       current_char32 = std::get<0> (utf8_escape_pair);
    2421                 :          22 :       length += std::get<1> (utf8_escape_pair);
    2422                 :             : 
    2423                 :          22 :       if (peek_codepoint_input ().value != '\'')
    2424                 :             :         {
    2425                 :           0 :           rust_error_at (get_current_location (), "unended character literal");
    2426                 :             :         }
    2427                 :             :       else
    2428                 :             :         {
    2429                 :          22 :           skip_codepoint_input ();
    2430                 :          22 :           current_char = peek_input ();
    2431                 :          22 :           length++;
    2432                 :             :         }
    2433                 :             : 
    2434                 :          22 :       current_column += length;
    2435                 :             : 
    2436                 :          22 :       loc += length - 1;
    2437                 :             : 
    2438                 :          22 :       return Token::make_char (loc, current_char32);
    2439                 :             :     }
    2440                 :             :   else
    2441                 :             :     {
    2442                 :         400 :       skip_codepoint_input ();
    2443                 :             : 
    2444                 :         400 :       if (peek_codepoint_input ().value == '\'')
    2445                 :             :         {
    2446                 :             :           // parse non-escaped char literal
    2447                 :             : 
    2448                 :             :           // skip the ' character
    2449                 :         203 :           skip_input ();
    2450                 :         203 :           current_char = peek_input ();
    2451                 :             : 
    2452                 :             :           // TODO fix due to different widths of utf-8 chars?
    2453                 :         203 :           current_column += 3;
    2454                 :             : 
    2455                 :         203 :           loc += 2;
    2456                 :             : 
    2457                 :         203 :           return Token::make_char (loc, current_char32);
    2458                 :             :         }
    2459                 :         197 :       else if (ISDIGIT (current_char32.value) || ISALPHA (current_char32.value)
    2460                 :           0 :                || current_char32.value == '_')
    2461                 :             :         {
    2462                 :             :           // parse lifetime name
    2463                 :         197 :           std::string str;
    2464                 :         197 :           str += current_char32;
    2465                 :         197 :           length++;
    2466                 :             : 
    2467                 :         197 :           current_char = peek_input ();
    2468                 :         197 :           while (ISDIGIT (current_char) || ISALPHA (current_char)
    2469                 :         281 :                  || current_char == '_')
    2470                 :             :             {
    2471                 :          84 :               str += current_char;
    2472                 :          84 :               skip_input ();
    2473                 :          84 :               current_char = peek_input ();
    2474                 :          84 :               length++;
    2475                 :             :             }
    2476                 :             : 
    2477                 :         197 :           current_column += length;
    2478                 :             : 
    2479                 :         197 :           loc += length - 1;
    2480                 :             : 
    2481                 :         197 :           str.shrink_to_fit ();
    2482                 :         197 :           return Token::make_lifetime (loc, std::move (str));
    2483                 :         197 :         }
    2484                 :             :       else
    2485                 :             :         {
    2486                 :           0 :           rust_error_at (
    2487                 :             :             get_current_location (),
    2488                 :             :             "expected %' after character constant in character literal");
    2489                 :           0 :           return nullptr;
    2490                 :             :         }
    2491                 :             :     }
    2492                 :             : }
    2493                 :             : 
    2494                 :             : // Returns the length of the codepoint at the current position.
    2495                 :             : int
    2496                 :       39399 : Lexer::get_input_codepoint_length ()
    2497                 :             : {
    2498                 :       39399 :   uint8_t input = peek_input ();
    2499                 :             : 
    2500                 :       39399 :   if ((int8_t) input == EOF)
    2501                 :             :     return 0;
    2502                 :             : 
    2503                 :       39399 :   if (input < 128)
    2504                 :             :     {
    2505                 :             :       // ascii -- 1 byte
    2506                 :             :       // return input;
    2507                 :             : 
    2508                 :             :       return 1;
    2509                 :             :     }
    2510                 :           1 :   else if ((input & 0xC0) == 0x80)
    2511                 :             :     {
    2512                 :             :       // invalid (continuation; can't be first char)
    2513                 :             :       // return 0xFFFE;
    2514                 :             : 
    2515                 :             :       return 0;
    2516                 :             :     }
    2517                 :           1 :   else if ((input & 0xE0) == 0xC0)
    2518                 :             :     {
    2519                 :             :       // 2 bytes
    2520                 :           1 :       uint8_t input2 = peek_input (1);
    2521                 :           1 :       if ((input2 & 0xC0) != 0x80)
    2522                 :             :         return 0;
    2523                 :             :       // return 0xFFFE;
    2524                 :             : 
    2525                 :             :       // uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0);
    2526                 :             :       // return output;
    2527                 :             :       return 2;
    2528                 :             :     }
    2529                 :           0 :   else if ((input & 0xF0) == 0xE0)
    2530                 :             :     {
    2531                 :             :       // 3 bytes
    2532                 :           0 :       uint8_t input2 = peek_input (1);
    2533                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2534                 :             :         return 0;
    2535                 :             :       // return 0xFFFE;
    2536                 :             : 
    2537                 :           0 :       uint8_t input3 = peek_input (2);
    2538                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2539                 :             :         return 0;
    2540                 :             :       // return 0xFFFE;
    2541                 :             : 
    2542                 :             :       /*uint32_t output
    2543                 :             :         = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 & 0x3F) <<
    2544                 :             :       0); return output;*/
    2545                 :             :       return 3;
    2546                 :             :     }
    2547                 :           0 :   else if ((input & 0xF8) == 0xF0)
    2548                 :             :     {
    2549                 :             :       // 4 bytes
    2550                 :           0 :       uint8_t input2 = peek_input (1);
    2551                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2552                 :             :         return 0;
    2553                 :             :       // return 0xFFFE;
    2554                 :             : 
    2555                 :           0 :       uint8_t input3 = peek_input (2);
    2556                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2557                 :             :         return 0;
    2558                 :             :       // return 0xFFFE;
    2559                 :             : 
    2560                 :           0 :       uint8_t input4 = peek_input (3);
    2561                 :           0 :       if ((input4 & 0xC0) != 0x80)
    2562                 :             :         return 0;
    2563                 :             :       // return 0xFFFE;
    2564                 :             : 
    2565                 :             :       /*uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12)
    2566                 :             :                         | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0);
    2567                 :             :       return output;*/
    2568                 :             :       return 4;
    2569                 :             :     }
    2570                 :             :   else
    2571                 :             :     {
    2572                 :           0 :       rust_error_at (get_current_location (),
    2573                 :             :                      "invalid UTF-8 [FIRST] (too long)");
    2574                 :           0 :       return 0;
    2575                 :             :     }
    2576                 :             : }
    2577                 :             : 
    2578                 :             : // Returns the codepoint at the current position.
    2579                 :             : Codepoint
    2580                 :       25796 : Lexer::peek_codepoint_input ()
    2581                 :             : {
    2582                 :       25796 :   uint8_t input = peek_input ();
    2583                 :             : 
    2584                 :       25796 :   if ((int8_t) input == EOF)
    2585                 :          14 :     return Codepoint::eof ();
    2586                 :             : 
    2587                 :       25782 :   if (input < 128)
    2588                 :             :     {
    2589                 :             :       // ascii -- 1 byte
    2590                 :       25781 :       return {input};
    2591                 :             :     }
    2592                 :           1 :   else if ((input & 0xC0) == 0x80)
    2593                 :             :     {
    2594                 :             :       // invalid (continuation; can't be first char)
    2595                 :           0 :       return {0xFFFE};
    2596                 :             :     }
    2597                 :           1 :   else if ((input & 0xE0) == 0xC0)
    2598                 :             :     {
    2599                 :             :       // 2 bytes
    2600                 :           1 :       uint8_t input2 = peek_input (1);
    2601                 :           1 :       if ((input2 & 0xC0) != 0x80)
    2602                 :           0 :         return {0xFFFE};
    2603                 :             : 
    2604                 :           1 :       uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0);
    2605                 :           1 :       return {output};
    2606                 :             :     }
    2607                 :           0 :   else if ((input & 0xF0) == 0xE0)
    2608                 :             :     {
    2609                 :             :       // 3 bytes
    2610                 :           0 :       uint8_t input2 = peek_input (1);
    2611                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2612                 :           0 :         return {0xFFFE};
    2613                 :             : 
    2614                 :           0 :       uint8_t input3 = peek_input (2);
    2615                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2616                 :           0 :         return {0xFFFE};
    2617                 :             : 
    2618                 :           0 :       uint32_t output = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6)
    2619                 :           0 :                         | ((input3 & 0x3F) << 0);
    2620                 :           0 :       return {output};
    2621                 :             :     }
    2622                 :           0 :   else if ((input & 0xF8) == 0xF0)
    2623                 :             :     {
    2624                 :             :       // 4 bytes
    2625                 :           0 :       uint8_t input2 = peek_input (1);
    2626                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2627                 :           0 :         return {0xFFFE};
    2628                 :             : 
    2629                 :           0 :       uint8_t input3 = peek_input (2);
    2630                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2631                 :           0 :         return {0xFFFE};
    2632                 :             : 
    2633                 :           0 :       uint8_t input4 = peek_input (3);
    2634                 :           0 :       if ((input4 & 0xC0) != 0x80)
    2635                 :           0 :         return {0xFFFE};
    2636                 :             : 
    2637                 :           0 :       uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12)
    2638                 :           0 :                         | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0);
    2639                 :           0 :       return {output};
    2640                 :             :     }
    2641                 :             :   else
    2642                 :             :     {
    2643                 :           0 :       rust_error_at (get_current_location (),
    2644                 :             :                      "invalid UTF-8 [SECND] (too long)");
    2645                 :           0 :       return {0xFFFE};
    2646                 :             :     }
    2647                 :             : }
    2648                 :             : 
    2649                 :             : void
    2650                 :       19947 : Lexer::skip_codepoint_input ()
    2651                 :             : {
    2652                 :       19947 :   int toSkip = get_input_codepoint_length ();
    2653                 :       19947 :   gcc_assert (toSkip >= 1);
    2654                 :             : 
    2655                 :       19947 :   skip_input (toSkip - 1);
    2656                 :       19947 : }
    2657                 :             : 
    2658                 :             : int
    2659                 :           0 : Lexer::test_get_input_codepoint_n_length (int n_start_offset)
    2660                 :             : {
    2661                 :           0 :   uint8_t input = peek_input (n_start_offset);
    2662                 :             : 
    2663                 :           0 :   if (input < 128)
    2664                 :             :     {
    2665                 :             :       // ascii -- 1 byte
    2666                 :             :       // return input;
    2667                 :             :       return 1;
    2668                 :             :     }
    2669                 :           0 :   else if ((input & 0xC0) == 0x80)
    2670                 :             :     {
    2671                 :             :       // invalid (continuation; can't be first char)
    2672                 :             :       // return 0xFFFE;
    2673                 :             :       return 0;
    2674                 :             :     }
    2675                 :           0 :   else if ((input & 0xE0) == 0xC0)
    2676                 :             :     {
    2677                 :             :       // 2 bytes
    2678                 :           0 :       uint8_t input2 = peek_input (n_start_offset + 1);
    2679                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2680                 :             :         // return 0xFFFE;
    2681                 :             :         return 0;
    2682                 :             : 
    2683                 :             :       // uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0);
    2684                 :             :       // return output;
    2685                 :             :       return 2;
    2686                 :             :     }
    2687                 :           0 :   else if ((input & 0xF0) == 0xE0)
    2688                 :             :     {
    2689                 :             :       // 3 bytes
    2690                 :           0 :       uint8_t input2 = peek_input (n_start_offset + 1);
    2691                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2692                 :             :         // return 0xFFFE;
    2693                 :             :         return 0;
    2694                 :             : 
    2695                 :           0 :       uint8_t input3 = peek_input (n_start_offset + 2);
    2696                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2697                 :             :         // return 0xFFFE;
    2698                 :             :         return 0;
    2699                 :             : 
    2700                 :             :       /*uint32_t output
    2701                 :             :         = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 & 0x3F) <<
    2702                 :             :       0); return output;*/
    2703                 :             :       return 3;
    2704                 :             :     }
    2705                 :           0 :   else if ((input & 0xF8) == 0xF0)
    2706                 :             :     {
    2707                 :             :       // 4 bytes
    2708                 :           0 :       uint8_t input2 = peek_input (n_start_offset + 1);
    2709                 :           0 :       if ((input2 & 0xC0) != 0x80)
    2710                 :             :         // return 0xFFFE;
    2711                 :             :         return 0;
    2712                 :             : 
    2713                 :           0 :       uint8_t input3 = peek_input (n_start_offset + 2);
    2714                 :           0 :       if ((input3 & 0xC0) != 0x80)
    2715                 :             :         // return 0xFFFE;
    2716                 :             :         return 0;
    2717                 :             : 
    2718                 :           0 :       uint8_t input4 = peek_input (n_start_offset + 3);
    2719                 :           0 :       if ((input4 & 0xC0) != 0x80)
    2720                 :             :         // return 0xFFFE;
    2721                 :             :         return 0;
    2722                 :             : 
    2723                 :             :       /*uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12)
    2724                 :             :                         | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0);
    2725                 :             :       return output;*/
    2726                 :             :       return 4;
    2727                 :             :     }
    2728                 :             :   else
    2729                 :             :     {
    2730                 :           0 :       rust_error_at (get_current_location (),
    2731                 :             :                      "invalid UTF-8 [THIRD] (too long)");
    2732                 :           0 :       return 0;
    2733                 :             :     }
    2734                 :             : }
    2735                 :             : 
    2736                 :             : // peeks the codepoint input at n codepoints ahead of current codepoint - try
    2737                 :             : // not to use
    2738                 :             : Codepoint
    2739                 :           0 : Lexer::test_peek_codepoint_input (int n)
    2740                 :             : {
    2741                 :           0 :   int totalOffset = 0;
    2742                 :             : 
    2743                 :             :   // add up all offsets into total offset? does this do what I want?
    2744                 :           0 :   for (int i = 0; i < n; i++)
    2745                 :             :     {
    2746                 :           0 :       totalOffset += test_get_input_codepoint_n_length (totalOffset);
    2747                 :             :     }
    2748                 :             :   // issues: this would have (at least) O(n) lookup time, not O(1) like the
    2749                 :             :   // rest?
    2750                 :             : 
    2751                 :             :   // TODO: implement if still needed
    2752                 :             : 
    2753                 :             :   // error out of function as it is not implemented
    2754                 :           0 :   gcc_assert (1 == 0);
    2755                 :             :   return {0};
    2756                 :             :   /*
    2757                 :             :           uint8_t input = peek_input();
    2758                 :             : 
    2759                 :             :           if (input < 128) {
    2760                 :             :               // ascii -- 1 byte
    2761                 :             :               return input;
    2762                 :             :           } else if ((input & 0xC0) == 0x80) {
    2763                 :             :               // invalid (continuation; can't be first char)
    2764                 :             :               return 0xFFFE;
    2765                 :             :           } else if ((input & 0xE0) == 0xC0) {
    2766                 :             :               // 2 bytes
    2767                 :             :               uint8_t input2 = peek_input(1);
    2768                 :             :               if ((input2 & 0xC0) != 0x80)
    2769                 :             :                   return 0xFFFE;
    2770                 :             : 
    2771                 :             :               uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0);
    2772                 :             :               return output;
    2773                 :             :           } else if ((input & 0xF0) == 0xE0) {
    2774                 :             :               // 3 bytes
    2775                 :             :               uint8_t input2 = peek_input(1);
    2776                 :             :               if ((input2 & 0xC0) != 0x80)
    2777                 :             :                   return 0xFFFE;
    2778                 :             : 
    2779                 :             :               uint8_t input3 = peek_input(2);
    2780                 :             :               if ((input3 & 0xC0) != 0x80)
    2781                 :             :                   return 0xFFFE;
    2782                 :             : 
    2783                 :             :               uint32_t output
    2784                 :             :                 = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 &
    2785                 :             :      0x3F) << 0); return output; } else if ((input & 0xF8) == 0xF0) {
    2786                 :             :               // 4 bytes
    2787                 :             :               uint8_t input2 = peek_input(1);
    2788                 :             :               if ((input2 & 0xC0) != 0x80)
    2789                 :             :                   return 0xFFFE;
    2790                 :             : 
    2791                 :             :               uint8_t input3 = peek_input(2);
    2792                 :             :               if ((input3 & 0xC0) != 0x80)
    2793                 :             :                   return 0xFFFE;
    2794                 :             : 
    2795                 :             :               uint8_t input4 = peek_input(3);
    2796                 :             :               if ((input4 & 0xC0) != 0x80)
    2797                 :             :                   return 0xFFFE;
    2798                 :             : 
    2799                 :             :               uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12)
    2800                 :             :                                 | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) <<
    2801                 :             :      0); return output; } else { rust_error_at(get_current_location(), "invalid
    2802                 :             :      UTF-8 (too long)"); return 0xFFFE;
    2803                 :             :           }*/
    2804                 :             : }
    2805                 :             : 
    2806                 :             : void
    2807                 :          61 : Lexer::split_current_token (TokenId new_left, TokenId new_right)
    2808                 :             : {
    2809                 :             :   /* TODO: assert that this TokenId is a "simple token" like punctuation and not
    2810                 :             :    * like "IDENTIFIER"? */
    2811                 :          61 :   Location current_loc = peek_token ()->get_locus ();
    2812                 :          61 :   TokenPtr new_left_tok = Token::make (new_left, current_loc);
    2813                 :          61 :   TokenPtr new_right_tok = Token::make (new_right, current_loc + 1);
    2814                 :             : 
    2815                 :          61 :   token_queue.replace_current_value (std::move (new_left_tok));
    2816                 :          61 :   token_queue.insert (1, std::move (new_right_tok));
    2817                 :          61 : }
    2818                 :             : 
    2819                 :             : void
    2820                 :       72244 : Lexer::start_line (int current_line, int current_column)
    2821                 :             : {
    2822                 :       72244 :   if (line_map)
    2823                 :       72124 :     line_map->start_line (current_line, current_column);
    2824                 :       72244 : }
    2825                 :             : 
    2826                 :             : } // namespace Rust
        

Generated by: LCOV version 2.0-1

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.