diff --git a/mcs/errors/cs1013-2.cs b/mcs/errors/cs1013-2.cs new file mode 100644 index 000000000000..c868cb2a7697 --- /dev/null +++ b/mcs/errors/cs1013-2.cs @@ -0,0 +1,7 @@ +// CS1013: Invalid number +// Line : 6 + +class X +{ + static int i = 0x0_; +} \ No newline at end of file diff --git a/mcs/errors/cs1061-18.cs b/mcs/errors/cs1061-18.cs new file mode 100644 index 000000000000..3ac82b7f2d37 --- /dev/null +++ b/mcs/errors/cs1061-18.cs @@ -0,0 +1,10 @@ +// CS1061: Type `int' does not contain a definition for `__0' and no extension method `__0' of type `int' could be found. Are you missing an assembly reference? +// Line: 8 + +static class C +{ + static void Main () + { + int c = 0.__0; + } +} \ No newline at end of file diff --git a/mcs/errors/cs1644-61.cs b/mcs/errors/cs1644-61.cs new file mode 100644 index 000000000000..d58ba64c7ecd --- /dev/null +++ b/mcs/errors/cs1644-61.cs @@ -0,0 +1,11 @@ +// CS1644: Feature `digit separators' cannot be used because it is not part of the C# 6.0 language specification +// Line: 9 +// Compiler options: -langversion:6 + +class X +{ + int Test () + { + var i = 1_0; + } +} diff --git a/mcs/mcs/cs-tokenizer.cs b/mcs/mcs/cs-tokenizer.cs index dc90fd1020ad..b4a6a6a1dd58 100644 --- a/mcs/mcs/cs-tokenizer.cs +++ b/mcs/mcs/cs-tokenizer.cs @@ -1575,20 +1575,22 @@ bool decimal_digits (int c) Error_NumericConstantTooLong (); number_builder [number_pos++] = (char) c; } - + // // We use peek_char2, because decimal_digits needs to do a // 2-character look-ahead (5.ToString for example). // while ((d = peek_char2 ()) != -1){ - if (d >= '0' && d <= '9'){ + if (d >= '0' && d <= '9') { if (number_pos == MaxNumberLength) Error_NumericConstantTooLong (); - number_builder [number_pos++] = (char) d; + number_builder [number_pos++] = (char)d; get_char (); seen_digits = true; - } else - break; + continue; + } + + break; } return seen_digits; @@ -1718,9 +1720,8 @@ ILiteralConstant adjust_int (int c, Location loc) } catch (OverflowException) { Error_NumericConstantTooLong (); return new IntLiteral (context.BuiltinTypes, 0, loc); - } - catch (FormatException) { - Report.Error (1013, Location, "Invalid number"); + } catch (FormatException) { + Error_InvalidNumber (); return new IntLiteral (context.BuiltinTypes, 0, loc); } } @@ -1759,14 +1760,39 @@ ILiteralConstant handle_hex (Location loc) { int d; ulong ul; + bool digit_separator = false; + int prev = 0; get_char (); while ((d = peek_char ()) != -1){ if (is_hex (d)){ number_builder [number_pos++] = (char) d; get_char (); - } else - break; + + prev = d; + continue; + } + + if (d == '_') { + get_char (); + + if (!digit_separator) { + if (context.Settings.Version < LanguageVersion.V_7) + Report.FeatureIsNotAvailable (context, Location, "digit separators"); + + digit_separator = true; + } + + prev = d; + continue; + } + + break; + } + + if (number_pos == 0 || prev == '_') { + Error_InvalidNumber (); + return new IntLiteral (context.BuiltinTypes, 0, loc); } string s = new String (number_builder, 0, number_pos); @@ -1781,9 +1807,8 @@ ILiteralConstant handle_hex (Location loc) } catch (OverflowException){ Error_NumericConstantTooLong (); return new IntLiteral (context.BuiltinTypes, 0, loc); - } - catch (FormatException) { - Report.Error (1013, Location, "Invalid number"); + } catch (FormatException) { + Error_InvalidNumber (); return new IntLiteral (context.BuiltinTypes, 0, loc); } } @@ -1792,27 +1817,50 @@ ILiteralConstant handle_binary (Location loc) { int d; ulong ul = 0; - - get_char (); + bool digit_separator = false; + int prev = -1; int digits = 0; + + get_char (); while ((d = peek_char ()) != -1){ - if (d == '0' || d == '1'){ + + if (d == '0' || d == '1') { ul = (ul << 1); digits++; if (d == '1') ul |= 1; get_char (); - if (digits > 64){ + if (digits > 64) { Error_NumericConstantTooLong (); return new IntLiteral (context.BuiltinTypes, 0, loc); } - } else - break; + + prev = d; + continue; + } + + if (d == '_') { + get_char (); + + if (!digit_separator) { + if (context.Settings.Version < LanguageVersion.V_7) + Report.FeatureIsNotAvailable (context, Location, "digit separators"); + + digit_separator = true; + } + + prev = d; + continue; + } + + break; } - if (digits == 0){ - Report.Error (1013, Location, "Invalid number"); + + if (digits == 0 || prev == '_') { + Error_InvalidNumber (); return new IntLiteral (context.BuiltinTypes, 0, loc); } + return integer_type_suffix (ul, peek_char (), loc); } @@ -1834,6 +1882,7 @@ int is_number (int c, bool dotLead) #endif number_pos = 0; var loc = Location; + bool digit_separator = false; if (!dotLead){ if (c == '0'){ @@ -1846,11 +1895,12 @@ int is_number (int c, bool dotLead) #endif return Token.LITERAL; - } else if (peek == 'b' || peek == 'B'){ - if (context.Settings.Version < LanguageVersion.V_7){ + } + + if (peek == 'b' || peek == 'B'){ + if (context.Settings.Version < LanguageVersion.V_7) Report.FeatureIsNotAvailable (context, Location, "binary literals"); - return Token.ERROR; - } + val = res = handle_binary (loc); #if FULL_AST res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1); @@ -1859,10 +1909,32 @@ int is_number (int c, bool dotLead) return Token.LITERAL; } } + + digits: decimal_digits (c); c = peek_char (); + + if (c == '_') { + if (!digit_separator) { + if (context.Settings.Version < LanguageVersion.V_7) + Report.FeatureIsNotAvailable (context, Location, "digit separators"); + + digit_separator = true; + } + + do { + get_char (); + c = peek_char (); + } while (c == '_'); + + if (c >= '0' && c <= '9') + goto digits; + } } + //TODO: Implement rejection of trailing digit separators + + // // We need to handle the case of // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER) @@ -1910,9 +1982,28 @@ int is_number (int c, bool dotLead) Error_NumericConstantTooLong (); number_builder [number_pos++] = '+'; } - - decimal_digits (c); + + digits: + bool seen_digits = decimal_digits (c); c = peek_char (); + + if (c == '_' && seen_digits) { + if (!digit_separator) { + if (context.Settings.Version < LanguageVersion.V_7) + Report.FeatureIsNotAvailable (context, Location, "digit separators"); + + digit_separator = true; + } + + do { + get_char (); + c = peek_char (); + } while (c == '_'); + + if (c >= '0' && c <= '9') + goto digits; + } + } var type = real_type_suffix (c); @@ -2985,6 +3076,11 @@ void Error_NumericConstantTooLong () { Report.Error (1021, Location, "Integral constant is too large"); } + + void Error_InvalidNumber () + { + Report.Error (1013, Location, "Invalid number"); + } void Error_InvalidDirective () { diff --git a/mcs/tests/test-950.cs b/mcs/tests/test-950.cs new file mode 100644 index 000000000000..6ac11babea01 --- /dev/null +++ b/mcs/tests/test-950.cs @@ -0,0 +1,12 @@ +using System; + +public class B +{ + public static void Main () + { + int a = 1_0_3; + double b = 0__0e+1_1; + int c = 0b__1_0; + int d = 0x__F_0; + } +} \ No newline at end of file diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index 26430c3e0188..b9f7e8f159b0 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -52849,6 +52849,16 @@ + + + + 26 + + + 7 + + +