diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs index 20f83b0622ce6..d771636a1d563 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs @@ -971,16 +971,16 @@ private void ScanNumericLiteralSingleInteger(ref bool underscoreInWrongPlace, re TextWindow.AdvanceChar(); } - if (lastCharWasUnderscore && !firstCharWasUnderscore) - { - underscoreInWrongPlace = true; - } - else if (firstCharWasUnderscore) + if (firstCharWasUnderscore) { CheckFeatureAvailability(MessageID.IDS_FeatureLeadingDigitSeparator); // No need for cascading feature error usedUnderscore = false; } + else if (lastCharWasUnderscore) + { + underscoreInWrongPlace = true; + } } private bool ScanNumericLiteral(ref TokenInfo info) diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs index 628597a9e1f8f..84f0f568fae73 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs @@ -2689,6 +2689,16 @@ public void TestNumericWithLeadingUnderscoresWithoutFeatureFlag() Assert.Equal(1, errors.Length); Assert.Equal((int)ErrorCode.ERR_FeatureNotAvailableInVersion6, errors[0].Code); Assert.Equal(text, token.Text); + + text = "0x_123_456_789_ABC_DEF_123"; + token = LexToken(text, _options6); + + Assert.Equal(SyntaxKind.NumericLiteralToken, token.Kind()); + errors = token.Errors(); + Assert.Equal(2, errors.Length); + Assert.Equal((int)ErrorCode.ERR_FeatureNotAvailableInVersion6, errors[0].Code); + Assert.Equal((int)ErrorCode.ERR_IntOverflow, errors[1].Code); + Assert.Equal(text, token.Text); } [Fact] @@ -2804,6 +2814,40 @@ public void TestNumericWithBadUnderscores() Assert.Equal((int)ErrorCode.ERR_InvalidNumber, errors[0].Code); Assert.Equal("error CS1013: Invalid number", errors[0].ToString(EnsureEnglishUICulture.PreferredOrNull)); Assert.Equal(text, token.Text); + + text = "1E+_2"; + token = LexToken(text, _options72); + + Assert.NotNull(token); + Assert.Equal(SyntaxKind.NumericLiteralToken, token.Kind()); + errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_InvalidNumber, errors[0].Code); + Assert.Equal("error CS1013: Invalid number", errors[0].ToString(EnsureEnglishUICulture.PreferredOrNull)); + Assert.Equal(text, token.Text); + + text = "1E-_2"; + token = LexToken(text, _options72); + + Assert.NotNull(token); + Assert.Equal(SyntaxKind.NumericLiteralToken, token.Kind()); + errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_InvalidNumber, errors[0].Code); + Assert.Equal("error CS1013: Invalid number", errors[0].ToString(EnsureEnglishUICulture.PreferredOrNull)); + Assert.Equal(text, token.Text); + + text = "1E_"; + token = LexToken(text, _options72); + + Assert.NotNull(token); + Assert.Equal(SyntaxKind.NumericLiteralToken, token.Kind()); + errors = token.Errors(); + Assert.Equal(2, errors.Length); + Assert.Equal((int)ErrorCode.ERR_InvalidNumber, errors[0].Code); + Assert.Equal((int)ErrorCode.ERR_FloatOverflow, errors[1].Code); + Assert.Equal("error CS1013: Invalid number", errors[0].ToString(EnsureEnglishUICulture.PreferredOrNull)); + Assert.Equal(text, token.Text); } [Fact] diff --git a/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb b/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb index e0e6443976740..d02ac85b7dbb9 100644 --- a/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb +++ b/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb @@ -1696,7 +1696,7 @@ FullWidthRepeat: IntegerLiteralStart = Here Base = LiteralBase.Hexadecimal - If (CanGet(Here) AndAlso Peek(Here) = "_"c) Then + If CanGet(Here) AndAlso Peek(Here) = "_"c Then LeadingUnderscoreUsed = True End If @@ -1717,7 +1717,7 @@ FullWidthRepeat: IntegerLiteralStart = Here Base = LiteralBase.Binary - If (CanGet(Here) AndAlso Peek(Here) = "_"c) Then + If CanGet(Here) AndAlso Peek(Here) = "_"c Then LeadingUnderscoreUsed = True End If @@ -1738,7 +1738,7 @@ FullWidthRepeat: IntegerLiteralStart = Here Base = LiteralBase.Octal - If (CanGet(Here) AndAlso Peek(Here) = "_"c) Then + If CanGet(Here) AndAlso Peek(Here) = "_"c Then LeadingUnderscoreUsed = True End If @@ -2095,7 +2095,9 @@ FullWidthRepeat2: If Overflows Then result = DirectCast(result.AddError(ErrorFactory.ErrorInfo(ERRID.ERR_Overflow)), SyntaxToken) - ElseIf UnderscoreInWrongPlace Then + End If + + If UnderscoreInWrongPlace Then result = DirectCast(result.AddError(ErrorFactory.ErrorInfo(ERRID.ERR_Syntax)), SyntaxToken) ElseIf LeadingUnderscoreUsed Then result = CheckFeatureAvailability(result, Feature.LeadingDigitSeparator) @@ -2106,6 +2108,7 @@ FullWidthRepeat2: If Base = LiteralBase.Binary Then result = CheckFeatureAvailability(result, Feature.BinaryLiterals) End If + Return result End Function diff --git a/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb index 9c0e13d8b3d62..018b31297bc74 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb @@ -1071,21 +1071,21 @@ End If]]>.Value, tk = ScanOnce(Str) Assert.Equal(SyntaxKind.IntegerLiteralToken, tk.Kind) Assert.Equal(LiteralBase.Hexadecimal, tk.GetBase()) - Assert.Equal(&H1, tk.Value) + Assert.Equal(&H11L, tk.Value) Assert.Equal(" &H__1_1L ", tk.ToFullString()) Str = " &B__1_1L " tk = ScanOnce(Str) Assert.Equal(SyntaxKind.IntegerLiteralToken, tk.Kind) Assert.Equal(LiteralBase.Binary, tk.GetBase()) - Assert.Equal(&B11, tk.Value) + Assert.Equal(&B11L, tk.Value) Assert.Equal(" &B__1_1L ", tk.ToFullString()) Str = " &O__1_1L " tk = ScanOnce(Str) Assert.Equal(SyntaxKind.IntegerLiteralToken, tk.Kind) Assert.Equal(LiteralBase.Octal, tk.GetBase()) - Assert.Equal(&O11, tk.Value) + Assert.Equal(&O11L, tk.Value) Assert.Equal(" &O__1_1L ", tk.ToFullString()) Str = " &H42L &H42& " @@ -1309,6 +1309,15 @@ End If]]>.Value, Assert.Equal(1, errors.Count) Assert.Equal(36716, errors.First().Code) Assert.Equal(1, CInt(tk.Value)) + + Str = "&H_123_456_789_ABC_DEF_123" + tk = ScanOnce(Str, LanguageVersion.VisualBasic14) + Assert.Equal(SyntaxKind.IntegerLiteralToken, tk.Kind) + errors = tk.Errors() + Assert.Equal(2, errors.Count) + Assert.Equal(30036, errors.ElementAt(0).Code) + Assert.Equal(36716, errors.ElementAt(1).Code) + Assert.Equal(0, CInt(tk.Value)) End Sub @@ -1810,4 +1819,17 @@ Module SyntaxDiagnosticInfoListExtensions Throw New InvalidOperationException() End Function + + + Public Function ElementAt(list As SyntaxDiagnosticInfoList, index As Integer) As DiagnosticInfo + Dim i = 0 + For Each v In list + If i = index Then + Return v + End If + i += 1 + Next + + Throw New IndexOutOfRangeException() + End Function End Module