LCOV - code coverage report
Current view: top level - vala - valascanner.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 91.2 % 865 789
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valascanner.vala
       2              :  *
       3              :  * Copyright (C) 2008-2012  Jürg Billeter
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Lesser General Public
       7              :  * License as published by the Free Software Foundation; either
       8              :  * version 2.1 of the License, or (at your option) any later version.
       9              : 
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Lesser General Public License for more details.
      14              : 
      15              :  * You should have received a copy of the GNU Lesser General Public
      16              :  * License along with this library; if not, write to the Free Software
      17              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  *      Jukka-Pekka Iivonen <jp0409@jippii.fi>
      22              :  */
      23              : 
      24              : using GLib;
      25              : 
      26              : /**
      27              :  * Lexical scanner for Vala source files.
      28              :  */
      29        14750 : public class Vala.Scanner {
      30    102775645 :         public SourceFile source_file { get; private set; }
      31              : 
      32              :         TokenType previous;
      33              :         char* current;
      34              :         char* end;
      35              : 
      36              :         int line;
      37              :         int column;
      38              : 
      39         6606 :         Comment _comment;
      40              : 
      41         6606 :         Conditional[] conditional_stack;
      42              : 
      43              :         struct Conditional {
      44              :                 public bool matched;
      45              :                 public bool else_found;
      46              :                 public bool skip_section;
      47              :         }
      48              : 
      49         6606 :         State[] state_stack;
      50              : 
      51              :         enum State {
      52              :                 PARENS,
      53              :                 BRACE,
      54              :                 BRACKET,
      55              :                 TEMPLATE,
      56              :                 TEMPLATE_PART,
      57              :                 REGEX_LITERAL,
      58              :                 VERBATIM_TEMPLATE
      59              :         }
      60              : 
      61        13212 :         public Scanner (SourceFile source_file) {
      62         6606 :                 this.source_file = source_file;
      63              : 
      64         6606 :                 char* begin = source_file.get_mapped_contents ();
      65         6606 :                 end = begin + source_file.get_mapped_length ();
      66              : 
      67         6606 :                 current = begin;
      68              : 
      69         6606 :                 line = 1;
      70         6606 :                 column = 1;
      71              :         }
      72              : 
      73            8 :         public void seek (SourceLocation location) {
      74            8 :                 current = location.pos;
      75            8 :                 line = location.line;
      76            8 :                 column = location.column;
      77              : 
      78            8 :                 conditional_stack = null;
      79            8 :                 state_stack = null;
      80              :         }
      81              : 
      82    193748544 :         inline bool in_template () {
      83    193748544 :                 return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE);
      84              :         }
      85              : 
      86    193748557 :         inline bool in_verbatim_template () {
      87    193748557 :                 return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.VERBATIM_TEMPLATE);
      88              :         }
      89              : 
      90    179617845 :         inline bool in_template_part () {
      91    179617845 :                 return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE_PART);
      92              :         }
      93              : 
      94    179617827 :         inline bool in_regex_literal () {
      95    179617827 :                 return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.REGEX_LITERAL);
      96              :         }
      97              : 
      98    684065374 :         inline bool is_ident_char (char c) {
      99    684065374 :                 return (c.isalnum () || c == '_');
     100              :         }
     101              : 
     102         9916 :         SourceReference get_source_reference (int offset, int length = 0) {
     103         9916 :                 return new SourceReference (source_file, SourceLocation (current, line, column + offset), SourceLocation (current + length, line, column + offset + length));
     104              :         }
     105              : 
     106           60 :         public TokenType read_regex_token (out SourceLocation token_begin, out SourceLocation token_end) {
     107              :                 TokenType type;
     108           60 :                 char* begin = current;
     109           60 :                 token_begin = SourceLocation (begin, line, column);
     110              : 
     111           60 :                 int token_length_in_chars = -1;
     112              : 
     113           60 :                 if (current >= end) {
     114              :                         type = TokenType.EOF;
     115              :                 } else {
     116           60 :                         switch (current[0]) {
     117              :                         case '/':
     118           30 :                                 type = TokenType.CLOSE_REGEX_LITERAL;
     119           30 :                                 current++;
     120           30 :                                 state_stack.length--;
     121           30 :                                 var fl_i = false;
     122           30 :                                 var fl_s = false;
     123           30 :                                 var fl_m = false;
     124           30 :                                 var fl_x = false;
     125           30 :                                 var fl_o = false;
     126           52 :                                 while (current[0] == 'i' || current[0] == 's' || current[0] == 'm' || current[0] == 'x' || current[0] == 'o') {
     127           22 :                                         switch (current[0]) {
     128              :                                         case 'i':
     129            7 :                                                 if (fl_i) {
     130            1 :                                                         Report.error (get_source_reference (token_length_in_chars), "modifier 'i' used more than once");
     131              :                                                 }
     132              :                                                 fl_i = true;
     133              :                                                 break;
     134              :                                         case 's':
     135            8 :                                                 if (fl_s) {
     136            1 :                                                         Report.error (get_source_reference (token_length_in_chars), "modifier 's' used more than once");
     137              :                                                 }
     138              :                                                 fl_s = true;
     139              :                                                 break;
     140              :                                         case 'm':
     141            2 :                                                 if (fl_m) {
     142            1 :                                                         Report.error (get_source_reference (token_length_in_chars), "modifier 'm' used more than once");
     143              :                                                 }
     144              :                                                 fl_m = true;
     145              :                                                 break;
     146              :                                         case 'x':
     147            2 :                                                 if (fl_x) {
     148            1 :                                                         Report.error (get_source_reference (token_length_in_chars), "modifier 'x' used more than once");
     149              :                                                 }
     150              :                                                 fl_x = true;
     151              :                                                 break;
     152              :                                         case 'o':
     153            3 :                                                 if (fl_o) {
     154            1 :                                                         Report.error (get_source_reference (token_length_in_chars), "modifier 'o' used more than once");
     155              :                                                 }
     156              :                                                 fl_o = true;
     157              :                                                 break;
     158              :                                         }
     159           22 :                                         current++;
     160           22 :                                         token_length_in_chars++;
     161              :                                 }
     162              :                                 break;
     163              :                         default:
     164          512 :                                 type = TokenType.REGEX_LITERAL;
     165              :                                 token_length_in_chars = 0;
     166          512 :                                 while (current < end && current[0] != '/') {
     167          482 :                                         if (current[0] == '\\') {
     168           68 :                                                 current++;
     169           68 :                                                 token_length_in_chars++;
     170           68 :                                                 if (current >= end) {
     171              :                                                         break;
     172              :                                                 }
     173              : 
     174           68 :                                                 switch (current[0]) {
     175              :                                                 case '\'':
     176              :                                                 case '"':
     177              :                                                 case '\\':
     178              :                                                 case '/':
     179              :                                                 case '^':
     180              :                                                 case '$':
     181              :                                                 case '.':
     182              :                                                 case '[':
     183              :                                                 case ']':
     184              :                                                 case '{':
     185              :                                                 case '}':
     186              :                                                 case '(':
     187              :                                                 case ')':
     188              :                                                 case '?':
     189              :                                                 case '*':
     190              :                                                 case '+':
     191              :                                                 case '-':
     192              :                                                 case '#':
     193              :                                                 case '&':
     194              :                                                 case '~':
     195              :                                                 case ':':
     196              :                                                 case ';':
     197              :                                                 case '<':
     198              :                                                 case '>':
     199              :                                                 case '|':
     200              :                                                 case '%':
     201              :                                                 case '=':
     202              :                                                 case '@':
     203              :                                                 case '0':
     204              :                                                 case 'b':
     205              :                                                 case 'B':
     206              :                                                 case 'f':
     207              :                                                 case 'n':
     208              :                                                 case 'N':
     209              :                                                 case 'r':
     210              :                                                 case 'R':
     211              :                                                 case 't':
     212              :                                                 case 'v':
     213              :                                                 case 'a':
     214              :                                                 case 'A':
     215              :                                                 case 'p':
     216              :                                                 case 'P':
     217              :                                                 case 'e':
     218              :                                                 case 'd':
     219              :                                                 case 'D':
     220              :                                                 case 's':
     221              :                                                 case 'S':
     222              :                                                 case 'w':
     223              :                                                 case 'W':
     224              :                                                 case 'G':
     225              :                                                 case 'z':
     226              :                                                 case 'Z':
     227           58 :                                                         current++;
     228           58 :                                                         token_length_in_chars++;
     229           58 :                                                         break;
     230              :                                                 case 'u':
     231              :                                                         // u escape character has four hex digits
     232            2 :                                                         current++;
     233            2 :                                                         token_length_in_chars++;
     234              :                                                         int digit_length;
     235            5 :                                                         for (digit_length = 0; current < end && current[0].isxdigit (); digit_length++) {
     236            3 :                                                                 current++;
     237            3 :                                                                 token_length_in_chars++;
     238              :                                                         }
     239            2 :                                                         if (digit_length < 1) {
     240            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\u used with no following hex digits");
     241            1 :                                                         } else if (digit_length < 4) {
     242            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "incomplete universal character name");
     243              :                                                         }
     244              :                                                         break;
     245              :                                                 case 'x':
     246              :                                                         // hexadecimal escape character requires two hex digits
     247            5 :                                                         current++;
     248            5 :                                                         token_length_in_chars++;
     249              :                                                         int digit_length;
     250            5 :                                                         bool empty = true;
     251           16 :                                                         for (digit_length = 0; current < end && current[0].isxdigit ();) {
     252           11 :                                                                 if (current[0] != '0') {
     253            6 :                                                                         digit_length++;
     254              :                                                                 } else {
     255              :                                                                         empty = false;
     256              :                                                                 }
     257           11 :                                                                 current++;
     258           11 :                                                                 token_length_in_chars++;
     259              :                                                         }
     260            5 :                                                         if (empty && digit_length < 1) {
     261            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\x used with no following hex digits");
     262            4 :                                                         } else if (digit_length > 2) {
     263            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "hex escape sequence out of range");
     264              :                                                         }
     265              :                                                         break;
     266              :                                                 default:
     267              :                                                         // back references \1 through \99
     268            3 :                                                         if (current[0].isdigit ()) {
     269            2 :                                                                 current++;
     270            2 :                                                                 token_length_in_chars++;
     271            2 :                                                                 if (current[0].isdigit ()) {
     272            1 :                                                                         current++;
     273            1 :                                                                         token_length_in_chars++;
     274              :                                                                 }
     275              :                                                         } else {
     276            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "invalid escape sequence");
     277              :                                                         }
     278              :                                                         break;
     279              :                                                 }
     280          414 :                                         } else if (current[0] == '\n') {
     281              :                                                 break;
     282              :                                         } else {
     283          414 :                                                 unichar u = ((string) current).get_char_validated ((long) (end - current));
     284          414 :                                                 if (u != (unichar) (-1)) {
     285          414 :                                                         current += u.to_utf8 (null);
     286          414 :                                                         token_length_in_chars++;
     287              :                                                 } else {
     288            0 :                                                         current++;
     289            0 :                                                         Report.error (get_source_reference (token_length_in_chars), "invalid UTF-8 character");
     290              :                                                 }
     291              :                                         }
     292              :                                 }
     293           30 :                                 if (current >= end || current[0] == '\n') {
     294            0 :                                         Report.error (get_source_reference (token_length_in_chars), "syntax error, expected \"");
     295            0 :                                         state_stack.length--;
     296            0 :                                         return read_token (out token_begin, out token_end);
     297              :                                 }
     298              :                                 break;
     299              :                         }
     300              :                 }
     301              : 
     302           60 :                 if (token_length_in_chars < 0) {
     303           13 :                         column += (int) (current - begin);
     304              :                 } else {
     305           47 :                         column += token_length_in_chars;
     306              :                 }
     307              : 
     308           60 :                 token_end = SourceLocation (current, line, column - 1);
     309              : 
     310           60 :                 return type;
     311              :         }
     312              : 
     313              :         public static TokenType get_identifier_or_keyword (char* begin, int len) {
     314     83183156 :                 switch (len) {
     315              :                 case 2:
     316       298664 :                         switch (begin[0]) {
     317              :                         case 'a':
     318          698 :                                 if (matches (begin, "as")) return TokenType.AS;
     319              :                                 break;
     320              :                         case 'd':
     321         4027 :                                 if (matches (begin, "do")) return TokenType.DO;
     322              :                                 break;
     323              :                         case 'i':
     324        85434 :                                 switch (begin[1]) {
     325              :                                 case 'f':
     326     83183156 :                                         return TokenType.IF;
     327              :                                 case 'n':
     328          772 :                                         return TokenType.IN;
     329              :                                 case 's':
     330         1370 :                                         return TokenType.IS;
     331              :                                 }
     332              :                                 break;
     333              :                         }
     334              :                         break;
     335              :                 case 3:
     336      3996653 :                         switch (begin[0]) {
     337              :                         case 'f':
     338        18222 :                                 if (matches (begin, "for")) return TokenType.FOR;
     339              :                                 break;
     340              :                         case 'g':
     341       438879 :                                 if (matches (begin, "get")) return TokenType.GET;
     342              :                                 break;
     343              :                         case 'n':
     344        35056 :                                 if (matches (begin, "new")) return TokenType.NEW;
     345              :                                 break;
     346              :                         case 'o':
     347       535774 :                                 if (matches (begin, "out")) return TokenType.OUT;
     348              :                                 break;
     349              :                         case 'r':
     350       126182 :                                 if (matches (begin, "ref")) return TokenType.REF;
     351              :                                 break;
     352              :                         case 's':
     353       380400 :                                 if (matches (begin, "set")) return TokenType.SET;
     354              :                                 break;
     355              :                         case 't':
     356        21066 :                                 if (matches (begin, "try")) return TokenType.TRY;
     357              :                                 break;
     358              :                         case 'v':
     359        66465 :                                 if (matches (begin, "var")) return TokenType.VAR;
     360              :                                 break;
     361              :                         }
     362              :                         break;
     363              :                 case 4:
     364     14453470 :                         switch (begin[0]) {
     365              :                         case 'b':
     366      1575842 :                                 if (matches (begin, "base")) return TokenType.BASE;
     367              :                                 break;
     368              :                         case 'c':
     369       300588 :                                 if (matches (begin, "case")) return TokenType.CASE;
     370              :                                 break;
     371              :                         case 'e':
     372       320613 :                                 switch (begin[1]) {
     373              :                                 case 'l':
     374        52949 :                                         if (matches (begin, "else")) return TokenType.ELSE;
     375              :                                         break;
     376              :                                 case 'n':
     377       221364 :                                         if (matches (begin, "enum")) return TokenType.ENUM;
     378              :                                         break;
     379              :                                 }
     380              :                                 break;
     381              :                         case 'l':
     382       175609 :                                 if (matches (begin, "lock")) return TokenType.LOCK;
     383              :                                 break;
     384              :                         case 'n':
     385      1188753 :                                 if (matches (begin, "null")) return TokenType.NULL;
     386              :                                 break;
     387              :                         case 't':
     388       895642 :                                 switch (begin[1]) {
     389              :                                 case 'h':
     390       125375 :                                         if (matches (begin, "this")) return TokenType.THIS;
     391              :                                         break;
     392              :                                 case 'r':
     393       422578 :                                         if (matches (begin, "true")) return TokenType.TRUE;
     394              :                                         break;
     395              :                                 }
     396              :                                 break;
     397              :                         case 'v':
     398      2224518 :                                 if (matches (begin, "void")) return TokenType.VOID;
     399              :                                 break;
     400              :                         case 'w':
     401        70673 :                                 switch (begin[1]) {
     402              :                                 case 'e':
     403        59444 :                                         if (matches (begin, "weak")) return TokenType.WEAK;
     404              :                                         break;
     405              :                                 case 'i':
     406          150 :                                         if (matches (begin, "with")) return TokenType.WITH;
     407              :                                         break;
     408              :                                 }
     409              :                                 break;
     410              :                         }
     411              :                         break;
     412              :                 case 5:
     413     14525277 :                         switch (begin[0]) {
     414              :                         case 'a':
     415       257731 :                                 if (matches (begin, "async")) return TokenType.ASYNC;
     416              :                                 break;
     417              :                         case 'b':
     418        91252 :                                 if (matches (begin, "break")) return TokenType.BREAK;
     419              :                                 break;
     420              :                         case 'c':
     421      2829211 :                                 switch (begin[1]) {
     422              :                                 case 'a':
     423         6347 :                                         if (matches (begin, "catch")) return TokenType.CATCH;
     424              :                                         break;
     425              :                                 case 'l':
     426       443689 :                                         if (matches (begin, "class")) return TokenType.CLASS;
     427              :                                         break;
     428              :                                 case 'o':
     429       667893 :                                         if (matches (begin, "const")) return TokenType.CONST;
     430              :                                         break;
     431              :                                 }
     432              :                                 break;
     433              :                         case 'f':
     434      1571095 :                                 if (matches (begin, "false")) return TokenType.FALSE;
     435              :                                 break;
     436              :                         case 'o':
     437       405801 :                                 if (matches (begin, "owned")) return TokenType.OWNED;
     438              :                                 break;
     439              :                         case 't':
     440        25857 :                                 if (matches (begin, "throw")) return TokenType.THROW;
     441              :                                 break;
     442              :                         case 'u':
     443       359808 :                                 if (matches (begin, "using")) return TokenType.USING;
     444              :                                 break;
     445              :                         case 'w':
     446        21956 :                                 if (matches (begin, "while")) return TokenType.WHILE;
     447              :                                 break;
     448              :                         case 'y':
     449         4849 :                                 if (matches (begin, "yield")) return TokenType.YIELD;
     450              :                                 break;
     451              :                         }
     452              :                         break;
     453              :                 case 6:
     454     19237716 :                         switch (begin[0]) {
     455              :                         case 'd':
     456       453281 :                                 if (matches (begin, "delete")) return TokenType.DELETE;
     457              :                                 break;
     458              :                         case 'e':
     459       117590 :                                 if (matches (begin, "extern")) return TokenType.EXTERN;
     460              :                                 break;
     461              :                         case 'i':
     462        74011 :                                 if (matches (begin, "inline")) return TokenType.INLINE;
     463              :                                 break;
     464              :                         case 'p':
     465      9266082 :                                 switch (begin[1]) {
     466              :                                 case 'a':
     467        16215 :                                         if (matches (begin, "params")) return TokenType.PARAMS;
     468              :                                         break;
     469              :                                 case 'u':
     470      9223572 :                                         if (matches (begin, "public")) return TokenType.PUBLIC;
     471              :                                         break;
     472              :                                 }
     473              :                                 break;
     474              :                         case 'r':
     475       333447 :                                 if (matches (begin, "return")) return TokenType.RETURN;
     476              :                                 break;
     477              :                         case 's':
     478      6061002 :                                 switch (begin[1]) {
     479              :                                 case 'e':
     480        77403 :                                         if (matches (begin, "sealed")) return TokenType.SEALED;
     481              :                                         break;
     482              :                                 case 'i':
     483       444335 :                                         switch (begin[2]) {
     484              :                                         case 'g':
     485       144239 :                                                 if (matches (begin, "signal")) return TokenType.SIGNAL;
     486              :                                                 break;
     487              :                                         case 'z':
     488       296868 :                                                 if (matches (begin, "sizeof")) return TokenType.SIZEOF;
     489              :                                                 break;
     490              :                                         }
     491              :                                         break;
     492              :                                 case 't':
     493      5456217 :                                         switch (begin[2]) {
     494              :                                         case 'a':
     495      1590722 :                                                 if (matches (begin, "static")) return TokenType.STATIC;
     496              :                                                 break;
     497              :                                         case 'r':
     498      3862127 :                                                 if (matches (begin, "struct")) return TokenType.STRUCT;
     499              :                                                 break;
     500              :                                         }
     501              :                                         break;
     502              :                                 case 'w':
     503          115 :                                         if (matches (begin, "switch")) return TokenType.SWITCH;
     504              :                                         break;
     505              :                                 }
     506              :                                 break;
     507              :                         case 't':
     508       952806 :                                 switch (begin[1]) {
     509              :                                 case 'h':
     510       888172 :                                         if (matches (begin, "throws")) return TokenType.THROWS;
     511              :                                         break;
     512              :                                 case 'y':
     513          150 :                                         if (matches (begin, "typeof")) return TokenType.TYPEOF;
     514              :                                         break;
     515              :                                 }
     516              :                                 break;
     517              :                         case 'u':
     518       319771 :                                 if (matches (begin, "unlock")) return TokenType.UNLOCK;
     519              :                                 break;
     520              :                         }
     521              :                         break;
     522              :                 case 7:
     523      6977012 :                         switch (begin[0]) {
     524              :                         case 'd':
     525        30086 :                                 switch (begin[1]) {
     526              :                                 case 'e':
     527        17587 :                                         if (matches (begin, "default")) return TokenType.DEFAULT;
     528              :                                         break;
     529              :                                 case 'y':
     530           22 :                                         if (matches (begin, "dynamic")) return TokenType.DYNAMIC;
     531              :                                         break;
     532              :                                 }
     533              :                                 break;
     534              :                         case 'e':
     535        41623 :                                 if (matches (begin, "ensures")) return TokenType.ENSURES;
     536              :                                 break;
     537              :                         case 'f':
     538        27229 :                                 switch (begin[1]) {
     539              :                                 case 'i':
     540         4671 :                                         if (matches (begin, "finally")) return TokenType.FINALLY;
     541              :                                         break;
     542              :                                 case 'o':
     543         9943 :                                         if (matches (begin, "foreach")) return TokenType.FOREACH;
     544              :                                         break;
     545              :                                 }
     546              :                                 break;
     547              :                         case 'p':
     548        52610 :                                 switch (begin[1]) {
     549              :                                 case 'r':
     550        32641 :                                         if (matches (begin, "private")) return TokenType.PRIVATE;
     551              :                                         break;
     552              :                                 case 'a':
     553        10110 :                                         if (matches (begin, "partial")) return TokenType.PARTIAL;
     554              :                                         break;
     555              :                                 }
     556              :                                 break;
     557              :                         case 'u':
     558       948178 :                                 if (matches (begin, "unowned")) return TokenType.UNOWNED;
     559              :                                 break;
     560              :                         case 'v':
     561       520915 :                                 if (matches (begin, "virtual")) return TokenType.VIRTUAL;
     562              :                                 break;
     563              :                         }
     564              :                         break;
     565              :                 case 8:
     566      2714164 :                         switch (begin[0]) {
     567              :                         case 'a':
     568       446108 :                                 if (matches (begin, "abstract")) return TokenType.ABSTRACT;
     569              :                                 break;
     570              :                         case 'c':
     571        86401 :                                 if (matches (begin, "continue")) return TokenType.CONTINUE;
     572              :                                 break;
     573              :                         case 'd':
     574       219752 :                                 if (matches (begin, "delegate")) return TokenType.DELEGATE;
     575              :                                 break;
     576              :                         case 'i':
     577       142205 :                                 if (matches (begin, "internal")) return TokenType.INTERNAL;
     578              :                                 break;
     579              :                         case 'o':
     580        42443 :                                 if (matches (begin, "override")) return TokenType.OVERRIDE;
     581              :                                 break;
     582              :                         case 'r':
     583        19242 :                                 if (matches (begin, "requires")) return TokenType.REQUIRES;
     584              :                                 break;
     585              :                         case 'v':
     586        44766 :                                 if (matches (begin, "volatile")) return TokenType.VOLATILE;
     587              :                                 break;
     588              :                         }
     589              :                         break;
     590              :                 case 9:
     591      2153566 :                         switch (begin[0]) {
     592              :                         case 'c':
     593       311328 :                                 if (matches (begin, "construct")) return TokenType.CONSTRUCT;
     594              :                                 break;
     595              :                         case 'i':
     596       115955 :                                 if (matches (begin, "interface")) return TokenType.INTERFACE;
     597              :                                 break;
     598              :                         case 'n':
     599        95184 :                                 if (matches (begin, "namespace")) return TokenType.NAMESPACE;
     600              :                                 break;
     601              :                         case 'p':
     602       114022 :                                 if (matches (begin, "protected")) return TokenType.PROTECTED;
     603              :                                 break;
     604              :                         }
     605              :                         break;
     606              :                 case 11:
     607      3319252 :                         if (matches (begin, "errordomain")) return TokenType.ERRORDOMAIN;
     608              :                         break;
     609              :                 }
     610              :                 return TokenType.IDENTIFIER;
     611              :         }
     612              : 
     613       683103 :         TokenType read_number () {
     614       683103 :                 var type = TokenType.INTEGER_LITERAL;
     615              : 
     616              :                 // integer part
     617       683103 :                 if (current < end - 2 && current[0] == '0') {
     618       213252 :                         switch (current[1]) {
     619              :                         case 'x':
     620              :                         case 'X':
     621              :                                 // hexadecimal literal
     622         6191 :                                 current += 2;
     623        18602 :                                 while (current < end && current[0].isxdigit ()) {
     624        12411 :                                         current++;
     625              :                                 }
     626              :                                 // fractional part
     627              :                                 // hexadecimal fractional part
     628         6191 :                                 if (current < end - 1 && current[0] == '.' && current[1].isxdigit ()) {
     629           12 :                                         type = TokenType.REAL_LITERAL;
     630           12 :                                         current++;
     631           36 :                                         while (current < end && current[0].isxdigit ()) {
     632           24 :                                                 current++;
     633              :                                         }
     634              :                                 }
     635              :                                 // hexadecimal exponent part
     636         6191 :                                 if (current < end && current[0].tolower () == 'p') {
     637           10 :                                         type = TokenType.REAL_LITERAL;
     638           10 :                                         current++;
     639           10 :                                         if (current < end && (current[0] == '+' || current[0] == '-')) {
     640            0 :                                                 current++;
     641              :                                         }
     642           19 :                                         while (current < end && current[0].isdigit ()) {
     643            9 :                                                 current++;
     644              :                                         }
     645         6181 :                                 } else if (type == TokenType.REAL_LITERAL) {
     646            2 :                                         Report.error (get_source_reference (1), "hexadecimal floating constants require an exponent");
     647              :                                 }
     648              :                                 break;
     649              :                         case 'b':
     650              :                         case 'B':
     651              :                         case 'o':
     652              :                         case 'O':
     653              :                                 // binary integer literal or octal integer literal
     654           17 :                                 current += 2;
     655          365 :                                 while (current < end && current[0].isdigit ()) {
     656          348 :                                         current++;
     657              :                                 }
     658              :                                 break;
     659              :                         default:
     660              :                                 // decimal number (also may be octal integer)
     661       418726 :                                 while (current < end && current[0].isdigit ()) {
     662       211682 :                                         current++;
     663              :                                 }
     664              :                                 break;
     665              :                         }
     666              :                 } else {
     667              :                         // decimal number
     668      1015117 :                         while (current < end && current[0].isdigit ()) {
     669       545266 :                                 current++;
     670              :                         }
     671              :                 }
     672              : 
     673              :                 // fractional part
     674       683103 :                 if (current < end - 1 && current[0] == '.' && current[1].isdigit ()) {
     675       276580 :                         type = TokenType.REAL_LITERAL;
     676       276580 :                         current++;
     677       649924 :                         while (current < end && current[0].isdigit ()) {
     678       373344 :                                 current++;
     679              :                         }
     680              :                 }
     681              : 
     682              :                 // exponent part
     683       683103 :                 if (current < end && current[0].tolower () == 'e') {
     684            7 :                         type = TokenType.REAL_LITERAL;
     685            7 :                         current++;
     686            7 :                         if (current < end && (current[0] == '+' || current[0] == '-')) {
     687            6 :                                 current++;
     688              :                         }
     689           12 :                         while (current < end && current[0].isdigit ()) {
     690            5 :                                 current++;
     691              :                         }
     692              :                 }
     693              : 
     694              :                 // type suffix
     695       683103 :                 if (current < end) {
     696       683103 :                         bool real_literal = (type == TokenType.REAL_LITERAL);
     697              : 
     698       683103 :                         switch (current[0]) {
     699              :                         case 'l':
     700              :                         case 'L':
     701           26 :                                 if (type == TokenType.INTEGER_LITERAL) {
     702           26 :                                         current++;
     703           26 :                                         if (current < end && current[0].tolower () == 'l') {
     704           24 :                                                 current++;
     705              :                                         }
     706              :                                 }
     707              :                                 break;
     708              :                         case 'u':
     709              :                         case 'U':
     710         4641 :                                 if (type == TokenType.INTEGER_LITERAL) {
     711         4641 :                                         current++;
     712         4641 :                                         if (current < end && current[0].tolower () == 'l') {
     713            6 :                                                 current++;
     714            6 :                                                 if (current < end && current[0].tolower () == 'l') {
     715            3 :                                                         current++;
     716              :                                                 }
     717              :                                         }
     718              :                                 }
     719              :                                 break;
     720              :                         case 'f':
     721              :                         case 'F':
     722              :                         case 'd':
     723              :                         case 'D':
     724          128 :                                 type = TokenType.REAL_LITERAL;
     725          128 :                                 current++;
     726          128 :                                 break;
     727              :                         }
     728              : 
     729       683103 :                         if (!real_literal && is_ident_char (current[0])) {
     730              :                                 // allow identifiers to start with a digit
     731              :                                 // as long as they contain at least one char
     732           11 :                                 while (current < end && is_ident_char (current[0])) {
     733            8 :                                         current++;
     734              :                                 }
     735              :                                 type = TokenType.IDENTIFIER;
     736              :                         }
     737              :                 }
     738              : 
     739              :                 return type;
     740              :         }
     741              : 
     742           28 :         public TokenType read_template_token (out SourceLocation token_begin, out SourceLocation token_end) {
     743           28 :                 bool is_verbatim = in_verbatim_template ();
     744              :                 TokenType type;
     745           28 :                 char* begin = current;
     746           28 :                 token_begin = SourceLocation (begin, line, column);
     747              : 
     748           28 :                 int token_length_in_chars = -1;
     749              : 
     750           28 :                 if (current >= end) {
     751              :                         type = TokenType.EOF;
     752              :                 } else {
     753           28 :                         switch (current[0]) {
     754              :                         case '"':
     755            8 :                                 if (is_verbatim) {
     756            4 :                                         if (current < end -2 && current[1] == '"' && current[2] == '"' && current[3] != '"') {
     757            4 :                                                 type = TokenType.CLOSE_TEMPLATE;
     758            4 :                                                 current += 3;
     759            4 :                                                 state_stack.length--;
     760              :                                         } else {
     761            0 :                                                 type = TokenType.VERBATIM_TEMPLATE_STRING_LITERAL;
     762            0 :                                                 current++;
     763            0 :                                                 token_length_in_chars++;
     764            0 :                                                 state_stack += State.TEMPLATE_PART;
     765              :                                         }
     766              :                                 } else {
     767            4 :                                         type = TokenType.CLOSE_TEMPLATE;
     768            4 :                                         current++;
     769            4 :                                         state_stack.length--;
     770              :                                 }
     771              :                                 break;
     772              :                         case '$':
     773           10 :                                 token_begin.pos++; // $ is not part of following token
     774           10 :                                 current++;
     775           10 :                                 if (current[0].isalpha () || current[0] == '_') {
     776              :                                         int len = 0;
     777           20 :                                         while (current < end && is_ident_char (current[0])) {
     778           14 :                                                 current++;
     779           14 :                                                 len++;
     780              :                                         }
     781            6 :                                         type = TokenType.IDENTIFIER;
     782            6 :                                         state_stack += State.TEMPLATE_PART;
     783            4 :                                 } else if (current[0] == '(') {
     784            2 :                                         current++;
     785            2 :                                         column += 2;
     786            4 :                                         state_stack += State.PARENS;
     787            2 :                                         return read_token (out token_begin, out token_end);
     788            2 :                                 } else if (current[0] == '$') {
     789            2 :                                         type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
     790            2 :                                         current++;
     791            2 :                                         state_stack += State.TEMPLATE_PART;
     792              :                                 } else {
     793            0 :                                         Report.error (get_source_reference (1), "unexpected character");
     794            0 :                                         return read_template_token (out token_begin, out token_end);
     795              :                                 }
     796              :                                 break;
     797              :                         default:
     798           10 :                                 type = is_verbatim ? TokenType.VERBATIM_TEMPLATE_STRING_LITERAL : TokenType.TEMPLATE_STRING_LITERAL;
     799           10 :                                 token_length_in_chars = 0;
     800           29 :                                 while (current < end && current[0] != '"' && current[0] != '$') {
     801           19 :                                         if (current[0] == '\\' && !is_verbatim) {
     802            0 :                                                 current++;
     803            0 :                                                 token_length_in_chars++;
     804            0 :                                                 if (current >= end) {
     805              :                                                         break;
     806              :                                                 }
     807              : 
     808            0 :                                                 switch (current[0]) {
     809              :                                                 case '\'':
     810              :                                                 case '"':
     811              :                                                 case '\\':
     812              :                                                 case '0':
     813              :                                                 case 'b':
     814              :                                                 case 'f':
     815              :                                                 case 'n':
     816              :                                                 case 'r':
     817              :                                                 case 't':
     818              :                                                 case 'v':
     819            0 :                                                         current++;
     820            0 :                                                         token_length_in_chars++;
     821            0 :                                                         break;
     822              :                                                 case 'u':
     823              :                                                         // u escape character has four hex digits
     824            0 :                                                         current++;
     825            0 :                                                         token_length_in_chars++;
     826              :                                                         int digit_length;
     827            0 :                                                         for (digit_length = 0; current < end && current[0].isxdigit (); digit_length++) {
     828            0 :                                                                 current++;
     829            0 :                                                                 token_length_in_chars++;
     830              :                                                         }
     831            0 :                                                         if (digit_length < 1) {
     832            0 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\u used with no following hex digits");
     833            0 :                                                         } else if (digit_length < 4) {
     834            0 :                                                                 Report.error (get_source_reference (token_length_in_chars), "incomplete universal character name");
     835              :                                                         }
     836              :                                                         break;
     837              :                                                 case 'x':
     838              :                                                         // hexadecimal escape character requires two hex digits
     839            0 :                                                         current++;
     840            0 :                                                         token_length_in_chars++;
     841              :                                                         int digit_length;
     842            0 :                                                         bool empty = true;
     843            0 :                                                         for (digit_length = 0; current < end && current[0].isxdigit ();) {
     844            0 :                                                                 if (current[0] != '0') {
     845            0 :                                                                         digit_length++;
     846              :                                                                 } else {
     847              :                                                                         empty = false;
     848              :                                                                 }
     849            0 :                                                                 current++;
     850            0 :                                                                 token_length_in_chars++;
     851              :                                                         }
     852            0 :                                                         if (empty && digit_length < 1) {
     853            0 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\x used with no following hex digits");
     854            0 :                                                         } else if (digit_length > 2) {
     855            0 :                                                                 Report.error (get_source_reference (token_length_in_chars), "hex escape sequence out of range");
     856              :                                                         }
     857              :                                                         break;
     858              :                                                 default:
     859            0 :                                                         Report.error (get_source_reference (token_length_in_chars), "invalid escape sequence");
     860              :                                                         break;
     861              :                                                 }
     862           19 :                                         } else if (current[0] == '\n') {
     863            3 :                                                 current++;
     864            3 :                                                 line++;
     865            3 :                                                 column = 1;
     866            3 :                                                 token_length_in_chars = 1;
     867              :                                         } else {
     868           16 :                                                 unichar u = ((string) current).get_char_validated ((long) (end - current));
     869           16 :                                                 if (u != (unichar) (-1)) {
     870           16 :                                                         current += u.to_utf8 (null);
     871           16 :                                                         token_length_in_chars++;
     872              :                                                 } else {
     873            0 :                                                         current++;
     874            0 :                                                         Report.error (get_source_reference (token_length_in_chars), "invalid UTF-8 character");
     875              :                                                 }
     876              :                                         }
     877              :                                 }
     878           10 :                                 if (current >= end) {
     879            0 :                                         Report.error (get_source_reference (token_length_in_chars), "syntax error, expected \"");
     880            0 :                                         state_stack.length--;
     881            0 :                                         return read_token (out token_begin, out token_end);
     882              :                                 }
     883           20 :                                 state_stack += State.TEMPLATE_PART;
     884           10 :                                 break;
     885              :                         }
     886              :                 }
     887              : 
     888           26 :                 if (token_length_in_chars < 0) {
     889           16 :                         column += (int) (current - begin);
     890              :                 } else {
     891           10 :                         column += token_length_in_chars;
     892              :                 }
     893              : 
     894           26 :                 token_end = SourceLocation (current, line, column - 1);
     895              : 
     896           26 :                 return type;
     897              :         }
     898              : 
     899    179617873 :         public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
     900    179617873 :                 if (in_template () || in_verbatim_template ()) {
     901           28 :                         return read_template_token (out token_begin, out token_end);
     902    179617845 :                 } else if (in_template_part ()) {
     903           18 :                         state_stack.length--;
     904              : 
     905           18 :                         token_begin = SourceLocation (current, line, column);
     906           18 :                         token_end = SourceLocation (current, line, column - 1);
     907              : 
     908           18 :                         return TokenType.COMMA;
     909    179617827 :                 } else if (in_regex_literal ()) {
     910           60 :                         return read_regex_token (out token_begin, out token_end);
     911              :                 }
     912              : 
     913    179617767 :                 space ();
     914              : 
     915              :                 TokenType type;
     916    179617767 :                 char* begin = current;
     917    179617767 :                 token_begin = SourceLocation (begin, line, column);
     918              : 
     919    179617767 :                 int token_length_in_chars = -1;
     920              : 
     921    179617767 :                 if (current >= end) {
     922              :                         type = TokenType.EOF;
     923    179611160 :                 } else if (current[0].isalpha () || current[0] == '_') {
     924              :                         int len = 0;
     925    682472661 :                         while (current < end && is_ident_char (current[0])) {
     926    599323761 :                                 current++;
     927    599323761 :                                 len++;
     928              :                         }
     929     83148900 :                         type = get_identifier_or_keyword (begin, len);
     930     96462260 :                 } else if (current[0] == '@') {
     931       163298 :                         if (current < end - 1 && current[1] == '"') {
     932            8 :                                 current += 1;
     933            8 :                                 if (current < end - 5 && current[1] == '"' && current[2] == '"') {
     934            4 :                                         current += 3;
     935            8 :                                         state_stack += State.VERBATIM_TEMPLATE;
     936              :                                 } else {
     937            4 :                                         current += 1;
     938            8 :                                         state_stack += State.TEMPLATE;
     939              :                                 }
     940              :                                 type = TokenType.OPEN_TEMPLATE;
     941              :                         } else {
     942       163290 :                                 token_begin.pos++; // @ is not part of the identifier
     943       163290 :                                 current++;
     944       163290 :                                 int len = 0;
     945       842558 :                                 while (current < end && is_ident_char (current[0])) {
     946       679268 :                                         current++;
     947       679268 :                                         len++;
     948              :                                 }
     949              :                                 type = TokenType.IDENTIFIER;
     950              :                         }
     951     96298962 :                 } else if (current[0].isdigit ()) {
     952       683103 :                         type = read_number ();
     953              :                 } else {
     954     95615859 :                         switch (current[0]) {
     955              :                         case '{':
     956      1623611 :                                 type = TokenType.OPEN_BRACE;
     957      1623611 :                                 current++;
     958      1623611 :                                 state_stack += State.BRACE;
     959      1623611 :                                 break;
     960              :                         case '}':
     961      1623610 :                                 type = TokenType.CLOSE_BRACE;
     962      1623610 :                                 current++;
     963      1623610 :                                 if (state_stack.length > 0) {
     964      1623603 :                                         state_stack.length--;
     965              :                                 }
     966              :                                 break;
     967              :                         case '(':
     968     14130669 :                                 type = TokenType.OPEN_PARENS;
     969     14130669 :                                 current++;
     970     14130669 :                                 state_stack += State.PARENS;
     971     14130669 :                                 break;
     972              :                         case ')':
     973     14130671 :                                 type = TokenType.CLOSE_PARENS;
     974     14130671 :                                 current++;
     975     14130671 :                                 if (state_stack.length > 0) {
     976     14130671 :                                         state_stack.length--;
     977              :                                 }
     978     14130671 :                                 if (in_template () || in_verbatim_template ()) {
     979              :                                         type = TokenType.COMMA;
     980              :                                 }
     981              :                                 break;
     982              :                         case '[':
     983      7942299 :                                 type = TokenType.OPEN_BRACKET;
     984      7942299 :                                 current++;
     985      7942299 :                                 state_stack += State.BRACKET;
     986      7942299 :                                 break;
     987              :                         case ']':
     988      7942299 :                                 type = TokenType.CLOSE_BRACKET;
     989      7942299 :                                 current++;
     990      7942299 :                                 if (state_stack.length > 0) {
     991      7942299 :                                         state_stack.length--;
     992              :                                 }
     993              :                                 break;
     994              :                         case '.':
     995      5711673 :                                 type = TokenType.DOT;
     996      5711673 :                                 current++;
     997      5711673 :                                 if (current < end - 1) {
     998      5711673 :                                         if (current[0] == '.' && current[1] == '.') {
     999       126668 :                                                 type = TokenType.ELLIPSIS;
    1000       126668 :                                                 current += 2;
    1001              :                                         }
    1002              :                                 }
    1003              :                                 break;
    1004              :                         case ':':
    1005       304799 :                                 type = TokenType.COLON;
    1006       304799 :                                 current++;
    1007       304799 :                                 if (current < end && current[0] == ':') {
    1008           18 :                                         type = TokenType.DOUBLE_COLON;
    1009           18 :                                         current++;
    1010              :                                 }
    1011              :                                 break;
    1012              :                         case ',':
    1013      9526910 :                                 type = TokenType.COMMA;
    1014      9526910 :                                 current++;
    1015      9526910 :                                 break;
    1016              :                         case ';':
    1017      9245971 :                                 type = TokenType.SEMICOLON;
    1018      9245971 :                                 current++;
    1019      9245971 :                                 break;
    1020              :                         case '#':
    1021            2 :                                 type = TokenType.HASH;
    1022            2 :                                 current++;
    1023            2 :                                 break;
    1024              :                         case '?':
    1025      1919944 :                                 type = TokenType.INTERR;
    1026      1919944 :                                 current++;
    1027      1919944 :                                 if (current < end && current[0] == '?') {
    1028           62 :                                         type = TokenType.OP_COALESCING;
    1029           62 :                                         current++;
    1030              :                                 }
    1031              :                                 break;
    1032              :                         case '|':
    1033        11622 :                                 type = TokenType.BITWISE_OR;
    1034        11622 :                                 current++;
    1035        11622 :                                 if (current < end) {
    1036        11622 :                                         switch (current[0]) {
    1037              :                                         case '=':
    1038          100 :                                                 type = TokenType.ASSIGN_BITWISE_OR;
    1039          100 :                                                 current++;
    1040          100 :                                                 break;
    1041              :                                         case '|':
    1042        11445 :                                                 type = TokenType.OP_OR;
    1043        11445 :                                                 current++;
    1044        11445 :                                                 break;
    1045              :                                         }
    1046              :                                 }
    1047              :                                 break;
    1048              :                         case '&':
    1049        33853 :                                 type = TokenType.BITWISE_AND;
    1050        33853 :                                 current++;
    1051        33853 :                                 if (current < end) {
    1052        33853 :                                         switch (current[0]) {
    1053              :                                         case '=':
    1054            2 :                                                 type = TokenType.ASSIGN_BITWISE_AND;
    1055            2 :                                                 current++;
    1056            2 :                                                 break;
    1057              :                                         case '&':
    1058        30727 :                                                 type = TokenType.OP_AND;
    1059        30727 :                                                 current++;
    1060        30727 :                                                 break;
    1061              :                                         }
    1062              :                                 }
    1063              :                                 break;
    1064              :                         case '^':
    1065            7 :                                 type = TokenType.CARRET;
    1066            7 :                                 current++;
    1067            7 :                                 if (current < end && current[0] == '=') {
    1068            2 :                                         type = TokenType.ASSIGN_BITWISE_XOR;
    1069            2 :                                         current++;
    1070              :                                 }
    1071              :                                 break;
    1072              :                         case '~':
    1073           27 :                                 type = TokenType.TILDE;
    1074           27 :                                 current++;
    1075           27 :                                 break;
    1076              :                         case '=':
    1077     11008861 :                                 type = TokenType.ASSIGN;
    1078     11008861 :                                 current++;
    1079     11008861 :                                 if (current < end) {
    1080     11008861 :                                         switch (current[0]) {
    1081              :                                         case '=':
    1082        52315 :                                                 type = TokenType.OP_EQ;
    1083        52315 :                                                 current++;
    1084        52315 :                                                 break;
    1085              :                                         case '>':
    1086         6475 :                                                 type = TokenType.LAMBDA;
    1087         6475 :                                                 current++;
    1088         6475 :                                                 break;
    1089              :                                         }
    1090              :                                 }
    1091              :                                 break;
    1092              :                         case '<':
    1093       697421 :                                 type = TokenType.OP_LT;
    1094       697421 :                                 current++;
    1095       697421 :                                 if (current < end) {
    1096       697421 :                                         switch (current[0]) {
    1097              :                                         case '=':
    1098        18455 :                                                 type = TokenType.OP_LE;
    1099        18455 :                                                 current++;
    1100        18455 :                                                 break;
    1101              :                                         case '<':
    1102           24 :                                                 type = TokenType.OP_SHIFT_LEFT;
    1103           24 :                                                 current++;
    1104           24 :                                                 if (current < end && current[0] == '=') {
    1105            2 :                                                         type = TokenType.ASSIGN_SHIFT_LEFT;
    1106            2 :                                                         current++;
    1107              :                                                 }
    1108              :                                                 break;
    1109              :                                         }
    1110              :                                 }
    1111              :                                 break;
    1112              :                         case '>':
    1113       682134 :                                 type = TokenType.OP_GT;
    1114       682134 :                                 current++;
    1115       682134 :                                 if (current < end && current[0] == '=') {
    1116        16876 :                                         type = TokenType.OP_GE;
    1117        16876 :                                         current++;
    1118              :                                 }
    1119              :                                 break;
    1120              :                         case '!':
    1121       114968 :                                 type = TokenType.OP_NEG;
    1122       114968 :                                 current++;
    1123       114968 :                                 if (current < end && current[0] == '=') {
    1124        66338 :                                         type = TokenType.OP_NE;
    1125        66338 :                                         current++;
    1126              :                                 }
    1127              :                                 break;
    1128              :                         case '+':
    1129        80933 :                                 type = TokenType.PLUS;
    1130        80933 :                                 current++;
    1131        80933 :                                 if (current < end) {
    1132        80933 :                                         switch (current[0]) {
    1133              :                                         case '=':
    1134         6285 :                                                 type = TokenType.ASSIGN_ADD;
    1135         6285 :                                                 current++;
    1136         6285 :                                                 break;
    1137              :                                         case '+':
    1138         5036 :                                                 type = TokenType.OP_INC;
    1139         5036 :                                                 current++;
    1140         5036 :                                                 break;
    1141              :                                         }
    1142              :                                 }
    1143              :                                 break;
    1144              :                         case '-':
    1145       169379 :                                 type = TokenType.MINUS;
    1146       169379 :                                 current++;
    1147       169379 :                                 if (current < end) {
    1148       169379 :                                         switch (current[0]) {
    1149              :                                         case '=':
    1150           14 :                                                 type = TokenType.ASSIGN_SUB;
    1151           14 :                                                 current++;
    1152           14 :                                                 break;
    1153              :                                         case '-':
    1154         1629 :                                                 type = TokenType.OP_DEC;
    1155         1629 :                                                 current++;
    1156         1629 :                                                 break;
    1157              :                                         case '>':
    1158         1538 :                                                 type = TokenType.OP_PTR;
    1159         1538 :                                                 current++;
    1160         1538 :                                                 break;
    1161              :                                         }
    1162              :                                 }
    1163              :                                 break;
    1164              :                         case '*':
    1165       633903 :                                 type = TokenType.STAR;
    1166       633903 :                                 current++;
    1167       633903 :                                 if (current < end && current[0] == '=') {
    1168            6 :                                         type = TokenType.ASSIGN_MUL;
    1169            6 :                                         current++;
    1170              :                                 }
    1171              :                                 break;
    1172              :                         case '/':
    1173           47 :                                 switch (previous) {
    1174              :                                 case TokenType.ASSIGN:
    1175              :                                 case TokenType.COMMA:
    1176              :                                 case TokenType.MINUS:
    1177              :                                 case TokenType.OP_AND:
    1178              :                                 case TokenType.OP_COALESCING:
    1179              :                                 case TokenType.OP_EQ:
    1180              :                                 case TokenType.OP_GE:
    1181              :                                 case TokenType.OP_GT:
    1182              :                                 case TokenType.OP_LE:
    1183              :                                 case TokenType.OP_LT:
    1184              :                                 case TokenType.OP_NE:
    1185              :                                 case TokenType.OP_NEG:
    1186              :                                 case TokenType.OP_OR:
    1187              :                                 case TokenType.OPEN_BRACE:
    1188              :                                 case TokenType.OPEN_PARENS:
    1189              :                                 case TokenType.PLUS:
    1190              :                                 case TokenType.RETURN:
    1191           30 :                                         type = TokenType.OPEN_REGEX_LITERAL;
    1192           60 :                                         state_stack += State.REGEX_LITERAL;
    1193           30 :                                         current++;
    1194           30 :                                         break;
    1195              :                                 default:
    1196           17 :                                         type = TokenType.DIV;
    1197           17 :                                         current++;
    1198           17 :                                         if (current < end && current[0] == '=') {
    1199            5 :                                                 type = TokenType.ASSIGN_DIV;
    1200            5 :                                                 current++;
    1201              :                                         }
    1202              :                                         break;
    1203              :                                 }
    1204              :                                 break;
    1205              :                         case '%':
    1206           16 :                                 type = TokenType.PERCENT;
    1207           16 :                                 current++;
    1208           16 :                                 if (current < end && current[0] == '=') {
    1209            5 :                                         type = TokenType.ASSIGN_PERCENT;
    1210            5 :                                         current++;
    1211              :                                 }
    1212              :                                 break;
    1213              :                         case '\'':
    1214              :                         case '"':
    1215      8080230 :                                 if (begin[0] == '\'') {
    1216              :                                         type = TokenType.CHARACTER_LITERAL;
    1217      8075054 :                                 } else if (current < end - 6 && begin[1] == '"' && begin[2] == '"') {
    1218           28 :                                         type = TokenType.VERBATIM_STRING_LITERAL;
    1219           28 :                                         token_length_in_chars = 6;
    1220           28 :                                         current += 3;
    1221         2789 :                                         while (current < end - 4) {
    1222         2789 :                                                 if (current[0] == '"' && current[1] == '"' && current[2] == '"' && current[3] != '"') {
    1223              :                                                         break;
    1224         2761 :                                                 } else if (current[0] == '\n') {
    1225           44 :                                                         current++;
    1226           44 :                                                         line++;
    1227           44 :                                                         column = 1;
    1228           44 :                                                         token_length_in_chars = 3;
    1229              :                                                 } else {
    1230         2717 :                                                         unichar u = ((string) current).get_char_validated ((long) (end - current));
    1231         2717 :                                                         if (u != (unichar) (-1)) {
    1232         2717 :                                                                 current += u.to_utf8 (null);
    1233         2717 :                                                                 token_length_in_chars++;
    1234              :                                                         } else {
    1235            0 :                                                                 Report.error (get_source_reference (token_length_in_chars), "invalid UTF-8 character");
    1236              :                                                         }
    1237              :                                                 }
    1238              :                                         }
    1239           28 :                                         if (current[0] == '"' && current[1] == '"' && current[2] == '"') {
    1240           28 :                                                 current += 3;
    1241              :                                         } else {
    1242            0 :                                                 Report.error (get_source_reference (token_length_in_chars), "syntax error, expected \"\"\"");
    1243              :                                         }
    1244              :                                         break;
    1245              :                                 } else {
    1246              :                                         type = TokenType.STRING_LITERAL;
    1247              :                                 }
    1248      8080202 :                                 token_length_in_chars = 2;
    1249      8080202 :                                 current++;
    1250     95603178 :                                 while (current < end && current[0] != begin[0]) {
    1251     87522976 :                                         if (current[0] == '\\') {
    1252        15096 :                                                 current++;
    1253        15096 :                                                 token_length_in_chars++;
    1254        15096 :                                                 if (current >= end) {
    1255              :                                                         break;
    1256              :                                                 }
    1257              : 
    1258        15096 :                                                 switch (current[0]) {
    1259              :                                                 case '\'':
    1260              :                                                 case '"':
    1261              :                                                 case '\\':
    1262              :                                                 case '0':
    1263              :                                                 case 'b':
    1264              :                                                 case 'f':
    1265              :                                                 case 'n':
    1266              :                                                 case 'r':
    1267              :                                                 case 't':
    1268              :                                                 case 'v':
    1269              :                                                 case '$':
    1270        15077 :                                                         current++;
    1271        15077 :                                                         token_length_in_chars++;
    1272        15077 :                                                         break;
    1273              :                                                 case 'u':
    1274              :                                                         // u escape character has four hex digits
    1275            3 :                                                         current++;
    1276            3 :                                                         token_length_in_chars++;
    1277              :                                                         int digit_length;
    1278           10 :                                                         for (digit_length = 0; current < end && current[0].isxdigit (); digit_length++) {
    1279            7 :                                                                 current++;
    1280            7 :                                                                 token_length_in_chars++;
    1281              :                                                         }
    1282            3 :                                                         if (digit_length < 1) {
    1283            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\u used with no following hex digits");
    1284            2 :                                                         } else if (digit_length < 4) {
    1285            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "incomplete universal character name");
    1286              :                                                         }
    1287              :                                                         break;
    1288              :                                                 case 'x':
    1289              :                                                         // hexadecimal escape character requires two hex digits
    1290           16 :                                                         current++;
    1291           16 :                                                         token_length_in_chars++;
    1292              :                                                         int digit_length;
    1293           16 :                                                         bool empty = true;
    1294           48 :                                                         for (digit_length = 0; current < end && current[0].isxdigit ();) {
    1295           32 :                                                                 if (current[0] != '0') {
    1296           26 :                                                                         digit_length++;
    1297              :                                                                 } else {
    1298              :                                                                         empty = false;
    1299              :                                                                 }
    1300           32 :                                                                 current++;
    1301           32 :                                                                 token_length_in_chars++;
    1302              :                                                         }
    1303           16 :                                                         if (empty && digit_length < 1) {
    1304            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "\\x used with no following hex digits");
    1305           15 :                                                         } else if (digit_length > 2) {
    1306            1 :                                                                 Report.error (get_source_reference (token_length_in_chars), "hex escape sequence out of range");
    1307              :                                                         }
    1308              :                                                         break;
    1309              :                                                 default:
    1310            0 :                                                         Report.error (get_source_reference (token_length_in_chars), "invalid escape sequence");
    1311              :                                                         break;
    1312              :                                                 }
    1313     87507880 :                                         } else if (current[0] == '\n') {
    1314            0 :                                                 current++;
    1315            0 :                                                 line++;
    1316            0 :                                                 column = 1;
    1317            0 :                                                 token_length_in_chars = 1;
    1318              :                                         } else {
    1319     87507880 :                                                 unichar u = ((string) current).get_char_validated ((long) (end - current));
    1320     87507880 :                                                 if (u != (unichar) (-1)) {
    1321     87507880 :                                                         current += u.to_utf8 (null);
    1322     87507880 :                                                         token_length_in_chars++;
    1323              :                                                 } else {
    1324            0 :                                                         current++;
    1325            0 :                                                         Report.error (get_source_reference (token_length_in_chars), "invalid UTF-8 character");
    1326              :                                                 }
    1327              :                                         }
    1328     87522976 :                                         if (current < end && begin[0] == '\'' && current[0] != '\'') {
    1329              :                                                 // multiple characters in single character literal
    1330            0 :                                                 Report.error (get_source_reference (token_length_in_chars), "invalid character literal");
    1331              :                                         }
    1332              :                                 }
    1333      8080202 :                                 if (current < end) {
    1334      8080202 :                                         current++;
    1335              :                                 } else {
    1336            0 :                                         Report.error (get_source_reference (token_length_in_chars), "syntax error, expected %c", begin[0]);
    1337              :                                 }
    1338              :                                 break;
    1339              :                         default:
    1340            0 :                                 unichar u = ((string) current).get_char_validated ((long) (end - current));
    1341            0 :                                 if (u != (unichar) (-1)) {
    1342            0 :                                         current += u.to_utf8 (null);
    1343            0 :                                         Report.error (get_source_reference (0), "syntax error, unexpected character");
    1344              :                                 } else {
    1345            0 :                                         current++;
    1346            0 :                                         Report.error (get_source_reference (0), "invalid UTF-8 character");
    1347              :                                 }
    1348            0 :                                 column++;
    1349            0 :                                 return read_token (out token_begin, out token_end);
    1350              :                         }
    1351              :                 }
    1352              : 
    1353    179617767 :                 if (token_length_in_chars < 0) {
    1354    171537537 :                         column += (int) (current - begin);
    1355              :                 } else {
    1356      8080230 :                         column += token_length_in_chars;
    1357              :                 }
    1358              : 
    1359    179617767 :                 token_end = SourceLocation (current, line, column - 1);
    1360    179617767 :                 previous = type;
    1361              : 
    1362    179617767 :                 return type;
    1363              :         }
    1364              : 
    1365     35892440 :         static bool matches (char* begin, string keyword) {
    1366     35892440 :                 char* keyword_array = (char*) keyword;
    1367     35892440 :                 long len = keyword.length;
    1368    179788670 :                 for (int i = 0; i < len; i++) {
    1369    157367985 :                         if (begin[i] != keyword_array[i]) {
    1370              :                                 return false;
    1371              :                         }
    1372              :                 }
    1373              :                 return true;
    1374              :         }
    1375              : 
    1376       347163 :         bool pp_whitespace () {
    1377              :                 bool found = false;
    1378       379310 :                 while (current < end && current[0].isspace () && current[0] != '\n') {
    1379        32147 :                         found = true;
    1380        32147 :                         current++;
    1381        32147 :                         column++;
    1382              :                 }
    1383              :                 return found;
    1384              :         }
    1385              : 
    1386       315016 :         void pp_space () {
    1387       347163 :                 while (pp_whitespace () || comment ()) {
    1388              :                 }
    1389              :         }
    1390              : 
    1391        93203 :         void pp_directive () {
    1392              :                 // hash sign
    1393        93203 :                 current++;
    1394        93203 :                 column++;
    1395              : 
    1396        93203 :                 if (line == 1 && column == 2 && current < end && current[0] == '!') {
    1397              :                         // hash bang: #!
    1398              :                         // skip until end of line or end of file
    1399            0 :                         while (current < end && current[0] != '\n') {
    1400            0 :                                 current++;
    1401              :                         }
    1402              :                         return;
    1403              :                 }
    1404              : 
    1405        93203 :                 pp_space ();
    1406              : 
    1407        93203 :                 char* begin = current;
    1408        93203 :                 int len = 0;
    1409       433937 :                 while (current < end && current[0].isalnum ()) {
    1410       340734 :                         current++;
    1411       340734 :                         column++;
    1412       340734 :                         len++;
    1413              :                 }
    1414              : 
    1415        93203 :                 if (len == 2 && matches (begin, "if")) {
    1416        32078 :                         parse_pp_if ();
    1417        61125 :                 } else if (len == 4 && matches (begin, "elif")) {
    1418           55 :                         parse_pp_elif ();
    1419        61070 :                 } else if (len == 4 && matches (begin, "else")) {
    1420        28990 :                         parse_pp_else ();
    1421        32080 :                 } else if (len == 5 && matches (begin, "endif")) {
    1422        32079 :                         parse_pp_endif ();
    1423              :                 } else {
    1424            1 :                         Report.error (get_source_reference (-len, len), "syntax error, invalid preprocessing directive");
    1425              :                 }
    1426              : 
    1427        93203 :                 if (conditional_stack.length > 0
    1428        61121 :                     && conditional_stack[conditional_stack.length - 1].skip_section) {
    1429              :                         // skip lines until next preprocessing directive
    1430              :                         bool bol = false;
    1431      6188178 :                         while (current < end) {
    1432      6188178 :                                 if (bol && current[0] == '#') {
    1433              :                                         // go back to begin of line
    1434        30594 :                                         current -= (column - 1);
    1435        30594 :                                         column = 1;
    1436        30594 :                                         return;
    1437              :                                 }
    1438      6157584 :                                 if (current[0] == '\n') {
    1439       153628 :                                         line++;
    1440       153628 :                                         column = 0;
    1441       153628 :                                         bol = true;
    1442      6003956 :                                 } else if (!current[0].isspace ()) {
    1443      5173897 :                                         bol = false;
    1444              :                                 }
    1445      6157584 :                                 current++;
    1446      6157584 :                                 column++;
    1447              :                         }
    1448              :                 }
    1449              :         }
    1450              : 
    1451        93202 :         void pp_eol () {
    1452        93202 :                 pp_space ();
    1453        93202 :                 if (current >= end || current[0] != '\n') {
    1454            0 :                         Report.error (get_source_reference (0), "syntax error, expected newline");
    1455              :                 }
    1456              :         }
    1457              : 
    1458        32078 :         void parse_pp_if () {
    1459        32078 :                 pp_space ();
    1460              : 
    1461        32078 :                 bool condition = parse_pp_expression ();
    1462              : 
    1463        32078 :                 pp_eol ();
    1464              : 
    1465        64156 :                 conditional_stack += Conditional ();
    1466              : 
    1467        32078 :                 if (condition && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
    1468              :                         // condition true => process code within if
    1469        13682 :                         conditional_stack[conditional_stack.length - 1].matched = true;
    1470              :                 } else {
    1471              :                         // skip lines until next preprocessing directive
    1472        18396 :                         conditional_stack[conditional_stack.length - 1].skip_section = true;
    1473              :                 }
    1474              :         }
    1475              : 
    1476           55 :         void parse_pp_elif () {
    1477           55 :                 pp_space ();
    1478              : 
    1479           55 :                 bool condition = parse_pp_expression ();
    1480              : 
    1481           55 :                 pp_eol ();
    1482              : 
    1483           55 :                 if (conditional_stack.length == 0 || conditional_stack[conditional_stack.length - 1].else_found) {
    1484            1 :                         Report.error (get_source_reference (0), "syntax error, unexpected #elif");
    1485            1 :                         return;
    1486              :                 }
    1487              : 
    1488           54 :                 if (condition && !conditional_stack[conditional_stack.length - 1].matched
    1489            0 :                     && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
    1490              :                         // condition true => process code within if
    1491            0 :                         conditional_stack[conditional_stack.length - 1].matched = true;
    1492            0 :                         conditional_stack[conditional_stack.length - 1].skip_section = false;
    1493              :                 } else {
    1494              :                         // skip lines until next preprocessing directive
    1495           54 :                         conditional_stack[conditional_stack.length - 1].skip_section = true;
    1496              :                 }
    1497              :         }
    1498              : 
    1499        28991 :         void parse_pp_else () {
    1500        28990 :                 pp_eol ();
    1501              : 
    1502        28990 :                 if (conditional_stack.length == 0 || conditional_stack[conditional_stack.length - 1].else_found) {
    1503            1 :                         Report.error (get_source_reference (0), "syntax error, unexpected #else");
    1504            1 :                         return;
    1505              :                 }
    1506              : 
    1507        28989 :                 if (!conditional_stack[conditional_stack.length - 1].matched
    1508        16845 :                     && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
    1509              :                         // condition true => process code within if
    1510        16845 :                         conditional_stack[conditional_stack.length - 1].matched = true;
    1511        16845 :                         conditional_stack[conditional_stack.length - 1].skip_section = false;
    1512              :                 } else {
    1513              :                         // skip lines until next preprocessing directive
    1514        12144 :                         conditional_stack[conditional_stack.length - 1].skip_section = true;
    1515              :                 }
    1516              :         }
    1517              : 
    1518        32079 :         void parse_pp_endif () {
    1519        32079 :                 pp_eol ();
    1520              : 
    1521        32079 :                 if (conditional_stack.length == 0) {
    1522            1 :                         Report.error (get_source_reference (0), "syntax error, unexpected #endif");
    1523            1 :                         return;
    1524              :                 }
    1525              : 
    1526        32078 :                 conditional_stack.length--;
    1527              :         }
    1528              : 
    1529        32140 :         bool parse_pp_symbol () {
    1530              :                 int len = 0;
    1531       311470 :                 while (current < end && is_ident_char (current[0])) {
    1532       279330 :                         current++;
    1533       279330 :                         column++;
    1534       279330 :                         len++;
    1535              :                 }
    1536              : 
    1537        32140 :                 if (len == 0) {
    1538            0 :                         Report.error (get_source_reference (0), "syntax error, expected identifier");
    1539            0 :                         return false;
    1540              :                 }
    1541              : 
    1542        32140 :                 string identifier = ((string) (current - len)).substring (0, len);
    1543              :                 bool defined;
    1544        32140 :                 if (identifier == "true") {
    1545              :                         defined = true;
    1546        32140 :                 } else if (identifier == "false") {
    1547              :                         defined = false;
    1548              :                 } else {
    1549        32140 :                         defined = source_file.context.is_defined (identifier);
    1550              :                 }
    1551              : 
    1552        32140 :                 return defined;
    1553              :         }
    1554              : 
    1555        32143 :         bool parse_pp_primary_expression () {
    1556        32143 :                 if (current >= end) {
    1557            0 :                         Report.error (get_source_reference (0), "syntax error, expected identifier");
    1558        32143 :                 } else if (is_ident_char (current[0])) {
    1559        32140 :                         return parse_pp_symbol ();
    1560            3 :                 } else if (current[0] == '(') {
    1561            3 :                         current++;
    1562            3 :                         column++;
    1563            3 :                         pp_space ();
    1564            3 :                         bool result = parse_pp_expression ();
    1565            3 :                         pp_space ();
    1566            3 :                         if (current < end && current[0] ==  ')') {
    1567            2 :                                 current++;
    1568            2 :                                 column++;
    1569              :                         } else {
    1570            1 :                                 Report.error (get_source_reference (0), "syntax error, expected `)'");
    1571              :                         }
    1572            3 :                         return result;
    1573              :                 } else {
    1574            0 :                         Report.error (get_source_reference (0), "syntax error, expected identifier");
    1575              :                 }
    1576        32143 :                 return false;
    1577              :         }
    1578              : 
    1579        32194 :         bool parse_pp_unary_expression () {
    1580        32194 :                 if (current < end && current[0] == '!') {
    1581           51 :                         current++;
    1582           51 :                         column++;
    1583           51 :                         pp_space ();
    1584           51 :                         return !parse_pp_unary_expression ();
    1585              :                 }
    1586              : 
    1587        32143 :                 return parse_pp_primary_expression ();
    1588              :         }
    1589              : 
    1590        32141 :         bool parse_pp_equality_expression () {
    1591        32141 :                 bool left = parse_pp_unary_expression ();
    1592        32141 :                 pp_space ();
    1593        32143 :                 while (true) {
    1594        32143 :                         if (current < end - 1 && current[0] == '=' && current[1] == '=') {
    1595            1 :                                 current += 2;
    1596            1 :                                 column += 2;
    1597            1 :                                 pp_space ();
    1598            1 :                                 bool right = parse_pp_unary_expression ();
    1599            1 :                                 left = (left == right);
    1600        32142 :                         } else if (current < end - 1 && current[0] == '!' && current[1] == '=') {
    1601            1 :                                 current += 2;
    1602            1 :                                 column += 2;
    1603            1 :                                 pp_space ();
    1604            1 :                                 bool right = parse_pp_unary_expression ();
    1605            1 :                                 left = (left != right);
    1606              :                         } else {
    1607              :                                 break;
    1608              :                         }
    1609              :                 }
    1610              :                 return left;
    1611              :         }
    1612              : 
    1613        32137 :         bool parse_pp_and_expression () {
    1614        32137 :                 bool left = parse_pp_equality_expression ();
    1615        32137 :                 pp_space ();
    1616        32141 :                 while (current < end - 1 && current[0] == '&' && current[1] == '&') {
    1617            4 :                         current += 2;
    1618            4 :                         column += 2;
    1619            4 :                         pp_space ();
    1620            4 :                         bool right = parse_pp_equality_expression ();
    1621            4 :                         left = left && right;
    1622              :                 }
    1623              :                 return left;
    1624              :         }
    1625              : 
    1626        32136 :         bool parse_pp_or_expression () {
    1627        32136 :                 bool left = parse_pp_and_expression ();
    1628        32136 :                 pp_space ();
    1629        32137 :                 while (current < end - 1 && current[0] == '|' && current[1] == '|') {
    1630            1 :                         current += 2;
    1631            1 :                         column += 2;
    1632            1 :                         pp_space ();
    1633            1 :                         bool right = parse_pp_and_expression ();
    1634            1 :                         left = left || right;
    1635              :                 }
    1636              :                 return left;
    1637              :         }
    1638              : 
    1639        32136 :         bool parse_pp_expression () {
    1640        32136 :                 return parse_pp_or_expression ();
    1641              :         }
    1642              : 
    1643    283233314 :         bool whitespace () {
    1644    283233314 :                 bool found = false;
    1645    283233314 :                 bool bol = (column == 1);
    1646    424287980 :                 while (current < end && current[0].isspace ()) {
    1647    141054666 :                         if (current[0] == '\n') {
    1648     21296941 :                                 line++;
    1649     21296941 :                                 column = 0;
    1650     21296941 :                                 bol = true;
    1651              :                         }
    1652    141054666 :                         found = true;
    1653    141054666 :                         current++;
    1654    141054666 :                         column++;
    1655              :                 }
    1656    283233314 :                 if (bol && current < end && current[0] == '#') {
    1657        93203 :                         pp_directive ();
    1658        93203 :                         return true;
    1659              :                 }
    1660    283233314 :                 return found;
    1661              :         }
    1662              : 
    1663    180204249 :         bool comment (bool file_comment = false) {
    1664    180204249 :                 if (current == null
    1665    180204249 :                     || current > end - 2
    1666    180197632 :                     || current[0] != '/'
    1667       264926 :                     || (current[1] != '/' && current[1] != '*')) {
    1668    179939388 :                         return false;
    1669              :                 }
    1670              : 
    1671       274766 :                 if (current[1] == '/') {
    1672        23960 :                         SourceReference source_reference = null;
    1673        23960 :                         if (file_comment) {
    1674            6 :                                 source_reference = get_source_reference (0);
    1675              :                         }
    1676              : 
    1677              :                         // single-line comment
    1678        23960 :                         current += 2;
    1679        23960 :                         char* begin = current;
    1680              : 
    1681              :                         // skip until end of line or end of file
    1682      1016250 :                         while (current < end && current[0] != '\n') {
    1683       992290 :                                 current++;
    1684              :                         }
    1685              : 
    1686        23960 :                         if (source_reference != null) {
    1687            6 :                                 push_comment (((string) begin).substring (0, (long) (current - begin)), source_reference, file_comment);
    1688              :                         }
    1689              :                 } else {
    1690       240919 :                         SourceReference source_reference = null;
    1691              : 
    1692       240919 :                         if (file_comment && current[2] == '*') {
    1693    179939388 :                                 return false;
    1694              :                         }
    1695              : 
    1696       240901 :                         if (current[2] == '*' || file_comment) {
    1697         9888 :                                 source_reference = get_source_reference (0);
    1698              :                         }
    1699              : 
    1700       240901 :                         current += 2;
    1701       240901 :                         column += 2;
    1702              : 
    1703       240901 :                         char* begin = current;
    1704      7875370 :                         while (current < end - 1
    1705      7875369 :                                && (current[0] != '*' || current[1] != '/')) {
    1706      7634469 :                                 if (current[0] == '\n') {
    1707       109750 :                                         line++;
    1708       109750 :                                         column = 0;
    1709              :                                 }
    1710      7634469 :                                 current++;
    1711      7634469 :                                 column++;
    1712              :                         }
    1713              : 
    1714       240901 :                         if (current == end - 1) {
    1715            1 :                                 Report.error (get_source_reference (0), "syntax error, expected */");
    1716            1 :                                 return true;
    1717              :                         }
    1718              : 
    1719       240900 :                         if (source_reference != null) {
    1720         9887 :                                 push_comment (((string) begin).substring (0, (long) (current - begin)), source_reference, file_comment);
    1721              :                         }
    1722              : 
    1723       240900 :                         current += 2;
    1724       240900 :                         column += 2;
    1725              :                 }
    1726              : 
    1727    180204249 :                 return true;
    1728              :         }
    1729              : 
    1730    179617767 :         void space () {
    1731    283216181 :                 while (whitespace () || comment ()) {
    1732              :                 }
    1733              :         }
    1734              : 
    1735         6605 :         public void parse_file_comments () {
    1736        17133 :                 while (whitespace () || comment (true)) {
    1737              :                 }
    1738              :         }
    1739              : 
    1740         9893 :         void push_comment (string comment_item, SourceReference source_reference, bool file_comment) {
    1741         9893 :                 if (comment_item[0] == '*') {
    1742         4661 :                         if (_comment != null) {
    1743              :                                 // extra doc comment, add it to source file comments
    1744            0 :                                 source_file.add_comment (_comment);
    1745              :                         }
    1746         4661 :                         _comment = new Comment (comment_item, source_reference);
    1747              :                 }
    1748              : 
    1749         9893 :                 if (file_comment) {
    1750         5232 :                         source_file.add_comment (new Comment (comment_item, source_reference));
    1751         5232 :                         _comment = null;
    1752              :                 }
    1753              :         }
    1754              : 
    1755              :         /**
    1756              :          * Clears and returns the content of the comment stack.
    1757              :          *
    1758              :          * @return saved comment
    1759              :          */
    1760     12942471 :         public Comment? pop_comment () {
    1761     12942471 :                 if (_comment == null) {
    1762     12937810 :                         return null;
    1763              :                 }
    1764              : 
    1765         4661 :                 var comment = _comment;
    1766         4661 :                 _comment = null;
    1767         4661 :                 return comment;
    1768              :         }
    1769              : }
    1770              : 
        

Generated by: LCOV version 2.0-1