Fix #77035.
[mono.git] / mcs / mcs / cs-tokenizer.cs
index 8ac1b1d13168bc3977cfc97c2b6449388d2be36e..83b92d2f9aa6dd9bab28880a8ea3aa241784e65e 100644 (file)
@@ -32,15 +32,19 @@ namespace Mono.CSharp
        public class Tokenizer : yyParser.yyInput
        {
                SeekableStreamReader reader;
-               public SourceFile ref_name;
-               public SourceFile file_name;
-               public int ref_line = 1;
-               public int line = 1;
-               public int col = 1;
-               public int current_token;
+               SourceFile ref_name;
+               SourceFile file_name;
+               int ref_line = 1;
+               int line = 1;
+               int col = 0;
+               int previous_col;
+               int current_token;
                bool handle_get_set = false;
                bool handle_remove_add = false;
                bool handle_assembly = false;
+               Location current_location;
+               Location current_comment_location = Location.Null;
+               ArrayList escapedIdentifiers = new ArrayList ();
 
                //
                // XML documentation buffer. The save point is used to divide
@@ -151,12 +155,20 @@ namespace Mono.CSharp
                        set {
                                if (value == XmlCommentState.Allowed) {
                                        check_incorrect_doc_comment ();
-                                       consume_doc_comment ();
+                                       reset_doc_comment ();
                                }
                                xmlDocState = value;
                        }
                }
 
+               public bool IsEscapedIdentifier (Location loc)
+               {
+                       foreach (LocatedToken lt in escapedIdentifiers)
+                               if (lt.Location.Equals (loc))
+                                       return true;
+                       return false;
+               }
+
                
                //
                // Class variables
@@ -360,9 +372,7 @@ namespace Mono.CSharp
                }
 
                public Location Location {
-                       get {
-                               return new Location (ref_line);
-                       }
+                       get { return current_location; }
                }
 
                void define (string def)
@@ -395,7 +405,7 @@ namespace Mono.CSharp
                        // FIXME: This could be `Location.Push' but we have to
                        // find out why the MS compiler allows this
                        //
-                       Mono.CSharp.Location.Push (file);
+                       Mono.CSharp.Location.Push (file, 0);
                }
 
                static bool is_identifier_start_character (char c)
@@ -437,8 +447,10 @@ namespace Mono.CSharp
 
                        switch (c){
                        case '{':
+                               val = Location;
                                return Token.OPEN_BRACE;
                        case '}':
+                               val = Location;
                                return Token.CLOSE_BRACE;
                        case '[':
                                // To block doccomment inside attribute declaration.
@@ -457,12 +469,16 @@ namespace Mono.CSharp
 
                                // Save current position and parse next token.
                                int old = reader.Position;
+                               int old_ref_line = ref_line;
+                               int old_col = col;
 
                                // disable preprocessing directives when peeking
                                process_directives = false;
                                int new_token = token ();
                                process_directives = true;
                                reader.Position = old;
+                               ref_line = old_ref_line;
+                               col = old_col;
                                putback_char = -1;
 
                                if (new_token == Token.OPEN_PARENS)
@@ -477,11 +493,11 @@ namespace Mono.CSharp
 
                        case ',':
                                return Token.COMMA;
-                       case ':':
-                               return Token.COLON;
                        case ';':
+                               val = Location;
                                return Token.SEMICOLON;
                        case '~':
+                               val = Location;
                                return Token.TILDE;
                        case '?':
                                return Token.INTERR;
@@ -490,24 +506,32 @@ namespace Mono.CSharp
                        d = peekChar ();
                        if (c == '+'){
                                
-                               if (d == '+')
+                               if (d == '+') {
+                                       val = Location;
                                        t = Token.OP_INC;
+                               }
                                else if (d == '=')
                                        t = Token.OP_ADD_ASSIGN;
-                               else
+                               else {
+                                       val = Location;
                                        return Token.PLUS;
+                               }
                                doread = true;
                                return t;
                        }
                        if (c == '-'){
-                               if (d == '-')
+                               if (d == '-') {
+                                       val = Location;
                                        t = Token.OP_DEC;
+                               }
                                else if (d == '=')
                                        t = Token.OP_SUB_ASSIGN;
                                else if (d == '>')
                                        t = Token.OP_PTR;
-                               else
+                               else {
+                                       val = Location;
                                        return Token.MINUS;
+                               }
                                doread = true;
                                return t;
                        }
@@ -517,6 +541,7 @@ namespace Mono.CSharp
                                        doread = true;
                                        return Token.OP_NE;
                                }
+                               val = Location;
                                return Token.BANG;
                        }
 
@@ -536,6 +561,7 @@ namespace Mono.CSharp
                                        doread = true;
                                        return Token.OP_AND_ASSIGN;
                                }
+                               val = Location;
                                return Token.BITWISE_AND;
                        }
 
@@ -555,6 +581,7 @@ namespace Mono.CSharp
                                        doread = true;
                                        return Token.OP_MULT_ASSIGN;
                                }
+                               val = Location;
                                return Token.STAR;
                        }
 
@@ -615,6 +642,15 @@ namespace Mono.CSharp
                                }
                                return Token.OP_GT;
                        }
+                       if (c == ':'){
+                               if (d == ':'){
+                                       doread = true;
+                                       return Token.DOUBLE_COLON;
+                               }
+                               val = Location;
+                               return Token.COLON;
+                       }
+
                        return Token.ERROR;
                }
 
@@ -707,7 +743,7 @@ namespace Mono.CSharp
                                                        // if we have not seen anything in between
                                                        // report this error
                                                        //
-                                                       Report.Warning (78, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
+                                                       Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
                                                }
                                                //
                                                // This goto statement causes the MS CLR 2.0 beta 1 csc to report an error, so
@@ -799,6 +835,11 @@ namespace Mono.CSharp
                                val = 0ul;
                                return Token.LITERAL_INTEGER;
                        }
+                       catch (FormatException) {
+                               Report.Error (1013, Location, "Invalid number");
+                               val = 0ul;
+                               return Token.LITERAL_INTEGER;
+                       }
                }
                
                int adjust_real (int t)
@@ -1041,7 +1082,7 @@ namespace Mono.CSharp
                                        goto default;
                                return v;
                        default:
-                               Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", (char)d);
+                               Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", ((char)d).ToString ());
                                return d;
                        }
                        getChar ();
@@ -1050,13 +1091,22 @@ namespace Mono.CSharp
 
                int getChar ()
                {
-                       if (putback_char != -1){
-                               int x = putback_char;
+                       int x;
+                       if (putback_char != -1) {
+                               x = putback_char;
                                putback_char = -1;
-
-                               return x;
                        }
-                       return reader.Read ();
+                       else
+                               x = reader.Read ();
+                       if (x == '\n') {
+                               line++;
+                               ref_line++;
+                               previous_col = col;
+                               col = 0;
+                       }
+                       else
+                               col++;
+                       return x;
                }
 
                int peekChar ()
@@ -1083,6 +1133,14 @@ namespace Mono.CSharp
                                Console.WriteLine ("Current [{0}] putting back [{1}]  ", putback_char, c);
                                throw new Exception ("This should not happen putback on putback");
                        }
+                       if (c == '\n' || col == 0) {
+                               // It won't happen though.
+                               line--;
+                               ref_line--;
+                               col = previous_col;
+                       }
+                       else
+                               col--;
                        putback_char = c;
                }
 
@@ -1181,22 +1239,16 @@ namespace Mono.CSharp
                        cmd = static_cmd_arg.ToString ();
 
                        if (c == '\n'){
-                               line++;
-                               ref_line++;
                                return;
-                       } else if (c == '\r')
-                               col = 0;
+                       }
 
                        // skip over white space
                        while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
                                ;
 
                        if (c == '\n'){
-                               line++;
-                               ref_line++;
                                return;
                        } else if (c == '\r'){
-                               col = 0;
                                return;
                        } else if (c == -1){
                                arg = "";
@@ -1210,11 +1262,6 @@ namespace Mono.CSharp
                                static_cmd_arg.Append ((char) c);
                        }
 
-                       if (c == '\n'){
-                               line++;
-                               ref_line++;
-                       } else if (c == '\r')
-                               col = 0;
                        arg = static_cmd_arg.ToString ().Trim ();
                }
 
@@ -1229,7 +1276,7 @@ namespace Mono.CSharp
                        if (arg == "default"){
                                ref_line = line;
                                ref_name = file_name;
-                               Location.Push (ref_name);
+                               Location.Push (ref_name, line);
                                return true;
                        } else if (arg == "hidden"){
                                //
@@ -1251,7 +1298,7 @@ namespace Mono.CSharp
                                        ref_name = Location.LookupFile (name);
                                        file_name.HasLineDirective = true;
                                        ref_name.HasLineDirective = true;
-                                       Location.Push (ref_name);
+                                       Location.Push (ref_name, ref_line);
                                } else {
                                        ref_line = System.Int32.Parse (arg);
                                }
@@ -1333,7 +1380,7 @@ namespace Mono.CSharp
                                Hashtable w_table = Report.warning_ignore_table;
                                foreach (int code in codes) {
                                        if (w_table != null && w_table.Contains (code))
-                                               Report.Warning (1635, 1, Location, "Cannot restore warning 'CS{0:0000}' because it was disabled globally", code);
+                                               Report.Warning (1635, 1, Location, String.Format ("Cannot restore warning `CS{0:0000}' because it was disabled globally", code));
                                        Report.RegisterWarningRegion (Location).WarningEnable (Location, code);
                                }
                                return;
@@ -1357,7 +1404,7 @@ namespace Mono.CSharp
                                        values[index++] = int.Parse (string_code, System.Globalization.CultureInfo.InvariantCulture);
                                }
                                catch (FormatException) {
-                                       Report.Warning (1692, Location, "Invalid number");
+                                       Report.Warning (1692, 1, Location, "Invalid number");
                                }
                        }
                        return values;
@@ -1745,7 +1792,7 @@ namespace Mono.CSharp
                                return true;
 
                        case "warning":
-                               Report.Warning (1030, Location, "#warning: `{0}'", arg);
+                               Report.Warning (1030, 1, Location, "#warning: `{0}'", arg);
                                return true;
                        }
 
@@ -1774,11 +1821,7 @@ namespace Mono.CSharp
                                if (c == '\n'){
                                        if (!quoted)
                                                Report.Error (1010, Location, "Newline in constant");
-                                       line++;
-                                       ref_line++;
-                                       col = 0;
-                               } else
-                                       col++;
+                               }
 
                                if (!quoted){
                                        c = escape (c);
@@ -1809,6 +1852,8 @@ namespace Mono.CSharp
                                // Save current position and parse next token.
                                int old = reader.Position;
                                int old_putback = putback_char;
+                               int old_ref_line = ref_line;
+                               int old_col = col;
 
                                putback_char = -1;
 
@@ -1819,12 +1864,14 @@ namespace Mono.CSharp
                                        (next_token == Token.ENUM); // "partial" is a keyword in 'partial enum', even though it's not valid
 
                                reader.Position = old;
+                               ref_line = old_ref_line;
+                               col = old_col;
                                putback_char = old_putback;
 
                                if (ok)
                                        return res;
                                else {
-                                       val = "partial";
+                                       val = new LocatedToken (Location, "partial");
                                        return Token.IDENTIFIER;
                                }
                        }
@@ -1835,11 +1882,13 @@ namespace Mono.CSharp
                private int consume_identifier (int s, bool quoted) 
                {
                        int pos = 1;
-                       int c;
+                       int c = -1;
                        
                        id_builder [0] = (char) s;
 
-                       while ((c = reader.Read ()) != -1) {
+                       current_location = new Location (ref_line, Col);
+
+                       while ((c = getChar ()) != -1) {
                                if (is_identifier_part_character ((char) c)){
                                        if (pos == max_id_size){
                                                Report.Error (645, Location, "Identifier too long (limit is 512 chars)");
@@ -1847,10 +1896,10 @@ namespace Mono.CSharp
                                        }
                                        
                                        id_builder [pos++] = (char) c;
-                                       putback_char = -1;
-                                       col++;
+//                                     putback_char = -1;
                                } else {
-                                       putback_char = c;
+//                                     putback_char = c;
+                                       putback (c);
                                        break;
                                }
                        }
@@ -1861,8 +1910,10 @@ namespace Mono.CSharp
                        //
                        if (!quoted && (s >= 'a' || s == '_')){
                                int keyword = GetKeyword (id_builder, pos);
-                               if (keyword != -1)
+                               if (keyword != -1) {
+                                       val = Location;
                                        return keyword;
+                               }
                        }
 
                        //
@@ -1873,6 +1924,9 @@ namespace Mono.CSharp
                        if (identifiers [pos] != null) {
                                val = identifiers [pos][id_builder];
                                if (val != null) {
+                                       val = new LocatedToken (Location, (string) val);
+                                       if (quoted)
+                                               escapedIdentifiers.Add (val);
                                        return Token.IDENTIFIER;
                                }
                        }
@@ -1880,12 +1934,24 @@ namespace Mono.CSharp
                                identifiers [pos] = new CharArrayHashtable (pos);
 
                        val = new String (id_builder, 0, pos);
+                       if (RootContext.Version == LanguageVersion.ISO_1) {
+                               for (int i = 1; i < id_builder.Length; i += 3) {
+                                       if (id_builder [i] == '_' && (id_builder [i - 1] == '_' || id_builder [i + 1] == '_')) {
+                                               Report.Error (1638, Location, 
+                                                       "`{0}': Any identifier with double underscores cannot be used when ISO language version mode is specified", val.ToString ());
+                                               break;
+                                       }
+                               }
+                       }
 
                        char [] chars = new char [pos];
                        Array.Copy (id_builder, chars, pos);
 
                        identifiers [pos] [chars] = val;
 
+                       val = new LocatedToken (Location, (string) val);
+                       if (quoted)
+                               escapedIdentifiers.Add (val);
                        return Token.IDENTIFIER;
                }
                
@@ -1900,12 +1966,11 @@ namespace Mono.CSharp
                        
                        val = null;
                        // optimization: eliminate col and implement #directive semantic correctly.
-                       for (;(c = getChar ()) != -1; col++) {
+                       for (;(c = getChar ()) != -1;) {
                                if (c == ' ')
                                        continue;
                                
                                if (c == '\t') {
-                                       col = (((col + 8) / 8) * 8) - 1;
                                        continue;
                                }
                                
@@ -1916,9 +1981,6 @@ namespace Mono.CSharp
                                        if (peekChar () == '\n')
                                                getChar ();
 
-                                       line++;
-                                       ref_line++;
-                                       col = 0;
                                        any_token_seen |= tokens_seen;
                                        tokens_seen = false;
                                        comments_seen = false;
@@ -1935,6 +1997,7 @@ namespace Mono.CSharp
                                                        getChar ();
                                                        // Don't allow ////.
                                                        if ((d = peekChar ()) != '/') {
+                                                               update_comment_location ();
                                                                if (doc_state == XmlCommentState.Allowed)
                                                                        handle_one_line_xml_comment ();
                                                                else if (doc_state == XmlCommentState.NotAllowed)
@@ -1942,11 +2005,7 @@ namespace Mono.CSharp
                                                        }
                                                }
                                                while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')
-                                                       col++;
                                                if (d == '\n'){
-                                                       line++;
-                                                       ref_line++;
-                                                       col = 0;
                                                }
                                                any_token_seen |= tokens_seen;
                                                tokens_seen = false;
@@ -1957,6 +2016,7 @@ namespace Mono.CSharp
                                                bool docAppend = false;
                                                if (RootContext.Documentation != null && peekChar () == '*') {
                                                        getChar ();
+                                                       update_comment_location ();
                                                        // But when it is /**/, just do nothing.
                                                        if (peekChar () == '/') {
                                                                getChar ();
@@ -1979,7 +2039,6 @@ namespace Mono.CSharp
                                                while ((d = getChar ()) != -1){
                                                        if (d == '*' && peekChar () == '/'){
                                                                getChar ();
-                                                               col++;
                                                                comments_seen = true;
                                                                break;
                                                        }
@@ -1987,9 +2046,6 @@ namespace Mono.CSharp
                                                                xml_comment_buffer.Append ((char) d);
                                                        
                                                        if (d == '\n'){
-                                                               line++;
-                                                               ref_line++;
-                                                               col = 0;
                                                                any_token_seen |= tokens_seen;
                                                                tokens_seen = false;
                                                                // 
@@ -2016,20 +2072,17 @@ namespace Mono.CSharp
                                }
 
                        is_punct_label:
+                               current_location = new Location (ref_line, Col);
                                if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){
                                        tokens_seen = true;
                                        if (doread){
                                                getChar ();
-                                               col++;
                                        }
                                        return t;
                                }
 
                                // white space
                                if (c == '\n'){
-                                       line++;
-                                       ref_line++;
-                                       col = 0;
                                        any_token_seen |= tokens_seen;
                                        tokens_seen = false;
                                        comments_seen = false;
@@ -2072,17 +2125,12 @@ namespace Mono.CSharp
                                        cont = handle_preprocessing_directive (cont);
 
                                        if (cont){
-                                               col = 0;
                                                continue;
                                        }
-                                       col = 1;
 
                                        bool skipping = false;
-                                       for (;(c = getChar ()) != -1; col++){
+                                       for (;(c = getChar ()) != -1;){
                                                if (c == '\n'){
-                                                       col = 0;
-                                                       line++;
-                                                       ref_line++;
                                                        skipping = false;
                                                } else if (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0)
                                                        continue;
@@ -2109,6 +2157,10 @@ namespace Mono.CSharp
                                                Report.Error (1011, Location, error_details);
                                                return Token.ERROR;
                                        }
+                                       if (c == '\r' || c == '\n') {
+                                               Report.Error (1010, Location, "Newline in constant");
+                                               return Token.ERROR;
+                                       }
                                        c = escape (c);
                                        if (c == -1)
                                                return Token.ERROR;
@@ -2122,14 +2174,11 @@ namespace Mono.CSharp
 
                                                // Try to recover, read until newline or next "'"
                                                while ((c = getChar ()) != -1){
-                                                       if (c == '\n' || c == '\''){
-                                                               line++;
-                                                               ref_line++;
-                                                               col = 0;
+                                                       if (c == '\n'){
+                                                               break;
+                                                       }
+                                                       else if (c == '\'')
                                                                break;
-                                                       } else
-                                                               col++;
-                                                       
                                                }
                                                return Token.ERROR;
                                        }
@@ -2165,7 +2214,6 @@ namespace Mono.CSharp
                        while ((c = peekChar ()) == ' ')
                                getChar (); // skip heading whitespaces.
                        while ((c = peekChar ()) != -1 && c != '\n' && c != '\r') {
-                               col++;
                                xml_comment_buffer.Append ((char) getChar ());
                        }
                        if (c == '\r' || c == '\n')
@@ -2203,6 +2251,18 @@ namespace Mono.CSharp
                        xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
                }
 
+               //
+               // Updates current comment location.
+               //
+               private void update_comment_location ()
+               {
+                       if (current_comment_location.IsNull) {
+                               // "-2" is for heading "//" or "/*"
+                               current_comment_location =
+                                       new Location (ref_line, col - 2);
+                       }
+               }
+
                //
                // Checks if there was incorrect doc comments and raise
                // warnings.
@@ -2219,10 +2279,13 @@ namespace Mono.CSharp
                //
                private void warn_incorrect_doc_comment ()
                {
-                       doc_state = XmlCommentState.Error;
-                       // in csc, it is 'XML comment is not placed on a valid 
-                       // language element'. But that does not make sense.
-                       Report.Warning (1587, 2, Location, "XML comment is not placed on a valid language element");
+                       if (doc_state != XmlCommentState.Error) {
+                               doc_state = XmlCommentState.Error;
+                               // in csc, it is 'XML comment is not placed on 
+                               // a valid language element'. But that does not
+                               // make sense.
+                               Report.Warning (1587, 2, Location, "XML comment is not placed on a valid language element");
+                       }
                }
 
                //
@@ -2233,12 +2296,18 @@ namespace Mono.CSharp
                {
                        if (xml_comment_buffer.Length > 0) {
                                string ret = xml_comment_buffer.ToString ();
-                               xml_comment_buffer.Length = 0;
+                               reset_doc_comment ();
                                return ret;
                        }
                        return null;
                }
 
+               void reset_doc_comment ()
+               {
+                       xml_comment_buffer.Length = 0;
+                       current_comment_location = Location.Null;
+               }
+
                public void cleanup ()
                {
                        if (ifstack != null && ifstack.Count >= 1) {
@@ -2246,7 +2315,7 @@ namespace Mono.CSharp
                                if ((state & REGION) != 0)
                                        Report.Error (1038, Location, "#endregion directive expected");
                                else 
-                                       Report.Error (1027, "Expected `#endif' directive");
+                                       Report.Error (1027, Location, "Expected `#endif' directive");
                        }
                                
                }