Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / mcs / cs-tokenizer.cs
index 6f0097e4b2a6dddda69a3441083ce75a1c4dffb2..e07fdcaf6e6437c1a4a39bb53cfc2283bdb25918 100644 (file)
@@ -240,6 +240,8 @@ namespace Mono.CSharp
                public bool parsing_catch_when;
 
                int parsing_string_interpolation;
+               int string_interpolation_section;
+               Stack<bool> parsing_string_interpolation_quoted;
 
                public bool parsing_interpolation_format;
 
@@ -409,6 +411,9 @@ namespace Mono.CSharp
                        public int parsing_generic_less_than;
                        public int current_token;
                        public object val;
+                       public int parsing_string_interpolation;
+                       public int string_interpolation_section;
+                       public Stack<bool> parsing_string_interpolation_quoted;
 
                        public Position (Tokenizer t)
                        {
@@ -427,8 +432,16 @@ namespace Mono.CSharp
                                        ifstack = new Stack<int> (clone);
                                }
                                parsing_generic_less_than = t.parsing_generic_less_than;
+                               string_interpolation_section = t.string_interpolation_section;
                                current_token = t.current_token;
                                val = t.val;
+                               parsing_string_interpolation = t.parsing_string_interpolation;
+                               string_interpolation_section = t.string_interpolation_section;
+                               if (t.parsing_string_interpolation_quoted != null && t.parsing_string_interpolation_quoted.Count != 0) {
+                                       var clone = t.parsing_string_interpolation_quoted.ToArray ();
+                                       Array.Reverse (clone);
+                                       parsing_string_interpolation_quoted = new Stack<bool> (clone);
+                               }
                        }
                }
 
@@ -471,6 +484,8 @@ namespace Mono.CSharp
                        previous_col = p.previous_col;
                        ifstack = p.ifstack;
                        parsing_generic_less_than = p.parsing_generic_less_than;
+                       parsing_string_interpolation = p.parsing_string_interpolation;
+                       parsing_string_interpolation_quoted = p.parsing_string_interpolation_quoted;
                        current_token = p.current_token;
                        val = p.val;
                }
@@ -925,7 +940,13 @@ namespace Mono.CSharp
 
                static bool is_identifier_start_character (int c)
                {
-                       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Char.IsLetter ((char)c);
+                       if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
+                               return true;
+
+                       if (c < 0x80)
+                               return false;
+
+                       return is_identifier_start_character_slow_part ((char) c);
                }
 
                static bool is_identifier_part_character (char c)
@@ -945,21 +966,46 @@ namespace Mono.CSharp
                        return is_identifier_part_character_slow_part (c);
                }
 
-               static bool is_identifier_part_character_slow_part (char c)
+               static bool is_identifier_start_character_slow_part (char c)
                {
-                       if (Char.IsLetter (c))
+                       switch (Char.GetUnicodeCategory (c)) {
+                       case UnicodeCategory.LetterNumber:
+                       case UnicodeCategory.UppercaseLetter:
+                       case UnicodeCategory.LowercaseLetter:
+                       case UnicodeCategory.TitlecaseLetter:
+                       case UnicodeCategory.ModifierLetter:
+                       case UnicodeCategory.OtherLetter:
                                return true;
+                       }
+                       return false;
+               }
 
+               static bool is_identifier_part_character_slow_part (char c)
+               {
                        switch (Char.GetUnicodeCategory (c)) {
-                               case UnicodeCategory.ConnectorPunctuation:
-
-                               // combining-character: A Unicode character of classes Mn or Mc
-                               case UnicodeCategory.NonSpacingMark:
-                               case UnicodeCategory.SpacingCombiningMark:
-
-                               // decimal-digit-character: A Unicode character of the class Nd 
-                               case UnicodeCategory.DecimalDigitNumber:
+                       // connecting-character:  A Unicode character of the class Pc
+                       case UnicodeCategory.ConnectorPunctuation:
+
+                       // combining-character: A Unicode character of classes Mn or Mc
+                       case UnicodeCategory.NonSpacingMark:
+                       case UnicodeCategory.SpacingCombiningMark:
+
+                       // decimal-digit-character: A Unicode character of the class Nd 
+                       case UnicodeCategory.DecimalDigitNumber:
+
+                       // plus is_identifier_start_character_slow_part
+                       case UnicodeCategory.LetterNumber:
+                       case UnicodeCategory.UppercaseLetter:
+                       case UnicodeCategory.LowercaseLetter:
+                       case UnicodeCategory.TitlecaseLetter:
+                       case UnicodeCategory.ModifierLetter:
+                       case UnicodeCategory.OtherLetter:
                                return true;
+
+                       // formatting-character: A Unicode character of the class Cf
+                       case UnicodeCategory.Format:
+                               // csc bug compatibility which recognizes it as a whitespace
+                               return c != 0xFEFF;
                        }
 
                        return false;
@@ -1049,6 +1095,7 @@ namespace Mono.CSharp
                                                case Token.DECIMAL:
                                                case Token.BOOL:
                                                case Token.STRING:
+                                               case Token.SBYTE:
                                                        return Token.OPEN_PARENS_CAST;
                                                }
                                        }
@@ -1296,6 +1343,7 @@ namespace Mono.CSharp
                        case Token.NULL:
                        case Token.THIS:
                        case Token.NEW:
+                       case Token.INTERPOLATED_STRING:
                                next_token = Token.INTERR;
                                break;
                                
@@ -2405,6 +2453,34 @@ namespace Mono.CSharp
                        return true;
                }
 
+               bool ScanClosingInterpolationBrace ()
+               {
+                       PushPosition ();
+
+                       bool? res = null;
+                       int str_quote = 0;
+                       do {
+                               var c = reader.Read ();
+                               switch (c) {
+                               case '\"':
+                                       ++str_quote;
+                                       break;
+                               case -1:
+                                       res = false;
+                                       break;
+                               case '}':
+                                       if (str_quote % 2 == 1) {
+                                               res = true;
+                                       }
+
+                                       break;
+                               }
+                       } while (res == null);
+
+                       PopPosition ();
+                       return res.Value;
+               }
+
                int TokenizeNumber (int value)
                {
                        number_pos = 0;
@@ -3153,9 +3229,14 @@ namespace Mono.CSharp
                        if (c == '\\') {
                                int surrogate;
                                c = escape (c, out surrogate);
-                               if (surrogate != 0) {
-                                       id_builder [pos++] = (char) c;
+                               if (quoted || is_identifier_start_character (c)) {
+                                       // it's added bellow
+                               } else if (surrogate != 0) {
+                                       id_builder [pos++] = (char)c;
                                        c = surrogate;
+                               } else {
+                                       Report.Error (1056, Location, "Unexpected character `\\{0}'", c.ToString ("x4"));
+                                       return Token.ERROR;
                                }
                        }
 
@@ -3176,9 +3257,18 @@ namespace Mono.CSharp
                                                        c = escape (c, out surrogate);
                                                        if (is_identifier_part_character ((char) c))
                                                                id_builder[pos++] = (char) c;
-
-                                                       if (surrogate != 0) {
+                                                       else if (surrogate != 0) {
                                                                c = surrogate;
+                                                       } else {
+                                                               switch (c) {
+                                                               // TODO: Probably need more whitespace characters
+                                                               case 0xFEFF:
+                                                                       putback_char = c;
+                                                                       break;
+                                                               default:
+                                                                       Report.Error (1056, Location, "Unexpected character `\\{0}'", c.ToString ("x4"));
+                                                                       return Token.ERROR;
+                                                               }
                                                        }
 
                                                        continue;
@@ -3288,15 +3378,26 @@ namespace Mono.CSharp
 
                                case '{':
                                        val = ltb.Create (current_source, ref_line, col);
+
+                                       if (parsing_string_interpolation > 0)
+                                               ++string_interpolation_section;
+
                                        return Token.OPEN_BRACE;
                                case '}':
                                        if (parsing_string_interpolation > 0) {
-                                               if (peek_char () != '}') {
+                                               if (string_interpolation_section == 0) {
                                                        --parsing_string_interpolation;
-                                                       return TokenizeInterpolatedString ();
+                                                       bool quoted;
+                                                       if (parsing_string_interpolation_quoted != null && parsing_string_interpolation_quoted.Count > 0) {
+                                                               quoted = parsing_string_interpolation_quoted.Pop ();
+                                                       } else {
+                                                               quoted = false;
+                                                       }
+
+                                                       return TokenizeInterpolatedString (quoted);
                                                }
 
-                                               continue;
+                                               --string_interpolation_section;
                                        }
 
                                        val = ltb.Create (current_source, ref_line, col);
@@ -3691,10 +3792,10 @@ namespace Mono.CSharp
                                        return Token.EOF;
                                
                                case '"':
-                                       if (parsing_string_interpolation > 0) {
+                                       if (parsing_string_interpolation > 0 && !ScanClosingInterpolationBrace ()) {
                                                parsing_string_interpolation = 0;
                                                Report.Error (8076, Location, "Missing close delimiter `}' for interpolated expression");
-                                               val = null;
+                                               val = new StringLiteral (context.BuiltinTypes, "", Location);
                                                return Token.INTERPOLATED_STRING_END;
                                        }
 
@@ -3718,9 +3819,18 @@ namespace Mono.CSharp
                                        return Token.ERROR;
 
                                case '$':
-                                       if (peek_char () == '"') {
+                                       switch (peek_char ()) {
+                                       case '"':
+                                               get_char ();
+                                               return TokenizeInterpolatedString (false);
+                                       case '@':
                                                get_char ();
-                                               return TokenizeInterpolatedString ();
+                                               if (peek_char () == '"') {
+                                                       get_char ();
+                                                       return TokenizeInterpolatedString (true);
+                                               }
+
+                                               break;
                                        }
 
                                        break;
@@ -3849,7 +3959,7 @@ namespace Mono.CSharp
                        return Token.OP_LT;
                }
 
-               int TokenizeInterpolatedString ()
+               int TokenizeInterpolatedString (bool quoted)
                {
                        int pos = 0;
                        var start_location = Location;
@@ -3858,6 +3968,11 @@ namespace Mono.CSharp
                                var ch = get_char ();
                                switch (ch) {
                                case '"':
+                                       if (quoted && peek_char () == '"') {
+                                               get_char ();
+                                               break;
+                                       }
+
                                        val = new StringLiteral (context.BuiltinTypes, CreateStringFromBuilder (pos), start_location);
                                        return Token.INTERPOLATED_STRING_END;
                                case '{':
@@ -3868,9 +3983,21 @@ namespace Mono.CSharp
                                        }
 
                                        ++parsing_string_interpolation;
+                                       if (quoted) {
+                                               if (parsing_string_interpolation_quoted == null)
+                                                       parsing_string_interpolation_quoted = new Stack<bool> ();
+                                       }
+
+                                       if (parsing_string_interpolation_quoted != null) {
+                                               parsing_string_interpolation_quoted.Push (quoted);
+                                       }
+
                                        val = new StringLiteral (context.BuiltinTypes, CreateStringFromBuilder (pos), start_location);
                                        return Token.INTERPOLATED_STRING;
                                case '\\':
+                                       if (quoted)
+                                               break;
+                                       
                                        ++col;
                                        int surrogate;
                                        ch = escape (ch, out surrogate);
@@ -3885,6 +4012,9 @@ namespace Mono.CSharp
                                                if (pos == value_builder.Length)
                                                        Array.Resize (ref value_builder, pos * 2);
 
+                                               if (pos == value_builder.Length)
+                                                       Array.Resize (ref value_builder, pos * 2);
+
                                                value_builder [pos++] = (char)ch;
                                                ch = surrogate;
                                        }
@@ -3895,6 +4025,9 @@ namespace Mono.CSharp
                                }
 
                                ++col;
+                               if (pos == value_builder.Length)
+                                       Array.Resize (ref value_builder, pos * 2);
+
                                value_builder[pos++] = (char) ch;
                        }
                }
@@ -3969,8 +4102,6 @@ namespace Mono.CSharp
                private void handle_one_line_xml_comment ()
                {
                        int c;
-                       while ((c = peek_char ()) == ' ')
-                               get_char (); // skip heading whitespaces.
                        while ((c = peek_char ()) != -1 && c != '\n' && c != '\r') {
                                xml_comment_buffer.Append ((char) get_char ());
                        }