Skip to content

Commit

Permalink
Do not lex .. as a single DotDotToken (#75549)
Browse files Browse the repository at this point in the history
* Add failing test

* WorkItem :)

* Renames and docs

* Update tests

* Do not have lexer produce .. token

* Move error

* Docs

* Advance

* Place at the same locaiton

* Cleanup and consistency

* Break apart numerics

* in progress

* Lexer work

* restore

* Update src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs

* Simplify

* Update quick scanner as well

* More cases

* Consequence parsing

* Fixup test

* More precise errors

* Specialized error message

* Simplify expression parsing

* Extract helper

* simplify

* simplify

* simplify

* inline

* Simplify token merging

* Fix

* Simplify

* Simplify

* Simplify

* Update src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

Co-authored-by: Rikki Gibson <rikkigibson@gmail.com>

* Tweak comment

* Grammar

* Update src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

* Lower value slightly

* Fix

* Clean up usings

* Add tests

* Simplify

* Add tests

* Add tests

---------

Co-authored-by: Rekkonnect <8298332+Rekkonnect@users.noreply.github.com>
Co-authored-by: Rikki Gibson <rikkigibson@gmail.com>
  • Loading branch information
3 people authored Oct 25, 2024
1 parent cd336d2 commit 09a7b38
Show file tree
Hide file tree
Showing 13 changed files with 726 additions and 132 deletions.
4 changes: 1 addition & 3 deletions src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@

using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
Expand Down Expand Up @@ -307,6 +304,7 @@ internal static bool IsFabricatedToken(SyntaxKind kind)
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
case SyntaxKind.DotDotToken:
return true;
default:
return SyntaxFacts.IsContextualKeyword(kind);
Expand Down
3 changes: 0 additions & 3 deletions src/Compilers/CSharp/Portable/Parser/Blender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
Expand Down
161 changes: 91 additions & 70 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,12 @@ private PatternSyntax ParsePrimaryPattern(Precedence precedence, bool afterIs, b
{
case SyntaxKind.OpenBracketToken:
return this.ParseListPattern(inSwitchArmPattern);
case SyntaxKind.DotDotToken:
return _syntaxFactory.SlicePattern(EatToken(),
IsPossibleSubpatternElement() ? ParsePattern(precedence, afterIs: false, inSwitchArmPattern) : null);
case SyntaxKind.DotToken when IsAtDotDotToken():
return _syntaxFactory.SlicePattern(
EatDotDotToken(),
IsPossibleSubpatternElement()
? ParsePattern(precedence, afterIs: false, inSwitchArmPattern)
: null);
case SyntaxKind.LessThanToken:
case SyntaxKind.LessThanEqualsToken:
case SyntaxKind.GreaterThanToken:
Expand Down
43 changes: 29 additions & 14 deletions src/Compilers/CSharp/Portable/Parser/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ internal enum XmlDocCommentStyle
Delimited = 1
}

internal partial class Lexer : AbstractLexer
internal sealed partial class Lexer : AbstractLexer
{
private const int TriviaListInitialCapacity = 8;

Expand Down Expand Up @@ -459,26 +459,41 @@ private void ScanSyntaxToken(ref TokenInfo info)
break;

case '.':
if (!this.ScanNumericLiteral(ref info))
if (this.TextWindow.PeekChar(1) is >= '0' and <= '9')
{
TextWindow.AdvanceChar();
if (TextWindow.TryAdvance('.'))
var atDotPosition = this.TextWindow.Position;
if (atDotPosition >= 1 &&
atDotPosition == this.TextWindow.LexemeStartPosition)
{
if (TextWindow.PeekChar() == '.')
// We have something like: .0
//
// This could be a fp number *except* the case where we have `..0` in that case, we want two
// dots followed by an integer (which will be treated as a range expression).
//
// Move back one space to see what's before this dot and adjust accordingly.

this.TextWindow.Reset(atDotPosition - 1);
var priorCharacterIsDot = this.TextWindow.PeekChar() is '.';
this.TextWindow.Reset(atDotPosition);

if (priorCharacterIsDot)
{
// Triple-dot: explicitly reject this, to allow triple-dot
// to be added to the language without a breaking change.
// (without this, 0...2 would parse as (0)..(.2), i.e. a range from 0 to 0.2)
this.AddError(ErrorCode.ERR_TripleDotNotAllowed);
// We have two dots in a row. Treat the second dot as a dot, not the start of a number literal.
TextWindow.AdvanceChar();
info.Kind = SyntaxKind.DotToken;
break;
}

info.Kind = SyntaxKind.DotDotToken;
}
else
{
info.Kind = SyntaxKind.DotToken;
// Fall through naturally and scan the number out as a floating point number.
}
}

if (!this.ScanNumericLiteral(ref info))
{
TextWindow.AdvanceChar();
info.Kind = SyntaxKind.DotToken;
}

break;

case ',':
Expand Down
5 changes: 1 addition & 4 deletions src/Compilers/CSharp/Portable/Parser/QuickScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

using System;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
Expand Down Expand Up @@ -152,7 +149,7 @@ private enum CharFlags : byte
(byte)QuickScanState.FollowingCR, // CR
(byte)QuickScanState.DoneAfterNext, // LF
(byte)QuickScanState.Done, // Letter
(byte)QuickScanState.Number, // Digit
(byte)QuickScanState.Bad, // Dot followed by number. Could be a fp `.0` or could be a range + num `..0`. Can't tell here.
(byte)QuickScanState.Done, // Punct
(byte)QuickScanState.Bad, // Dot (DotDot range token, exit so that we handle it in subsequent scanning code)
(byte)QuickScanState.Done, // Compound
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ protected SyntaxToken CurrentToken
{
get
{
return _currentToken ?? (_currentToken = this.FetchCurrentToken());
return _currentToken ??= this.FetchCurrentToken();
}
}

Expand Down
Loading

0 comments on commit 09a7b38

Please sign in to comment.