Add diagnostics
This commit is contained in:
parent
8be2aec0ab
commit
fe5012bd29
@ -15,7 +15,9 @@ namespace Parser.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
[MemberData(nameof(SingleTokensData))]
|
[MemberData(nameof(SingleTokensData))]
|
||||||
|
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
public void MLexerGreen_Parses_Token(TokenKind kind, string text)
|
public void MLexerGreen_Parses_Token(TokenKind kind, string text)
|
||||||
{
|
{
|
||||||
var tokens = ParseText(text);
|
var tokens = ParseText(text);
|
||||||
@ -24,7 +26,9 @@ namespace Parser.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
[MemberData(nameof(PairTokensData))]
|
[MemberData(nameof(PairTokensData))]
|
||||||
|
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
public void MLexerGreen_Parses_PairOfTokens(TokenKind kind1, string text1, TokenKind kind2, string text2)
|
public void MLexerGreen_Parses_PairOfTokens(TokenKind kind1, string text1, TokenKind kind2, string text2)
|
||||||
{
|
{
|
||||||
var text = text1 + text2;
|
var text = text1 + text2;
|
||||||
@ -35,7 +39,9 @@ namespace Parser.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
[MemberData(nameof(PairTokensWithSeparatorData))]
|
[MemberData(nameof(PairTokensWithSeparatorData))]
|
||||||
|
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
public void MLexerGreen_Parses_PairOfTokensWithSeparator(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)
|
public void MLexerGreen_Parses_PairOfTokensWithSeparator(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)
|
||||||
{
|
{
|
||||||
var text = text1 + separatorText + text2;
|
var text = text1 + separatorText + text2;
|
||||||
|
@ -19,6 +19,11 @@ namespace Parser.Tests
|
|||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var assignment = actual.Root.StatementList[0].AsNode();
|
var assignment = actual.Root.StatementList[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||||
|
if (assignment is null)
|
||||||
|
{
|
||||||
|
throw new System.Exception();
|
||||||
|
}
|
||||||
|
|
||||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +35,11 @@ namespace Parser.Tests
|
|||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.StatementList[0].AsNode();
|
var statement = actual.Root.StatementList[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||||
|
if (statement is null)
|
||||||
|
{
|
||||||
|
throw new System.Exception();
|
||||||
|
}
|
||||||
|
|
||||||
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement).Expression);
|
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement).Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +51,11 @@ namespace Parser.Tests
|
|||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var assignment = actual.Root.StatementList[0].AsNode();
|
var assignment = actual.Root.StatementList[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||||
|
if (assignment is null)
|
||||||
|
{
|
||||||
|
throw new System.Exception();
|
||||||
|
}
|
||||||
|
|
||||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +65,7 @@ namespace Parser.Tests
|
|||||||
{
|
{
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
|
var diagnostics = actual.Root.GetDiagnostics();
|
||||||
Assert.Collection(actual.Diagnostics, item => Assert.Equal("Unexpected token 'SemicolonToken', expected 'IdentifierToken'.", item.Message));
|
Assert.Collection(actual.Diagnostics, item => Assert.Equal("Unexpected token 'SemicolonToken', expected 'IdentifierToken'.", item.Message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +76,8 @@ namespace Parser.Tests
|
|||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.StatementList[0].AsNode() as ExpressionStatementSyntaxNode;
|
var statement = actual.Root.StatementList[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||||
var expression = statement.Expression as BinaryOperationExpressionSyntaxNode;
|
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||||
var lhs = expression.Lhs;
|
var lhs = expression!.Lhs;
|
||||||
var operation = expression.Operation;
|
var operation = expression.Operation;
|
||||||
var rhs = expression.Rhs;
|
var rhs = expression.Rhs;
|
||||||
Assert.Equal(0, lhs.Position);
|
Assert.Equal(0, lhs.Position);
|
||||||
|
@ -2,13 +2,16 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
<NullableContextOptions>enable</NullableContextOptions>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.3.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -44,7 +44,9 @@ namespace Parser.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
[MemberData(nameof(FilesData))]
|
[MemberData(nameof(FilesData))]
|
||||||
|
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||||
public void TestFile(string fileName)
|
public void TestFile(string fileName)
|
||||||
{
|
{
|
||||||
var text = File.ReadAllText(fileName);
|
var text = File.ReadAllText(fileName);
|
||||||
|
@ -11,6 +11,9 @@ namespace Parser.Internal
|
|||||||
public TokenKind Kind { get; }
|
public TokenKind Kind { get; }
|
||||||
public int Slots { get; protected set; }
|
public int Slots { get; protected set; }
|
||||||
public abstract GreenNode? GetSlot(int i);
|
public abstract GreenNode? GetSlot(int i);
|
||||||
|
public bool HasDiagnostics { get; }
|
||||||
|
private static Dictionary<GreenNode, TokenDiagnostic[]> diagnosticsTable = new Dictionary<GreenNode, TokenDiagnostic[]>();
|
||||||
|
private static TokenDiagnostic[] emptyDiagnostics = Array.Empty<TokenDiagnostic>();
|
||||||
|
|
||||||
public GreenNode(TokenKind kind)
|
public GreenNode(TokenKind kind)
|
||||||
{
|
{
|
||||||
@ -23,6 +26,21 @@ namespace Parser.Internal
|
|||||||
_fullWidth = fullWidth;
|
_fullWidth = fullWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GreenNode(TokenKind kind, TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
HasDiagnostics = true;
|
||||||
|
diagnosticsTable[this] = diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GreenNode(TokenKind kind, int fullWidth, TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
_fullWidth = fullWidth;
|
||||||
|
HasDiagnostics = true;
|
||||||
|
diagnosticsTable[this] = diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position);
|
internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position);
|
||||||
|
|
||||||
protected int _fullWidth;
|
protected int _fullWidth;
|
||||||
@ -225,5 +243,17 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics);
|
||||||
|
|
||||||
|
internal TokenDiagnostic[] GetDiagnostics()
|
||||||
|
{
|
||||||
|
if (diagnosticsTable.TryGetValue(this, out var diags))
|
||||||
|
{
|
||||||
|
return diags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyDiagnostics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
14
Parser/Internal/GreenNodeExtensions.cs
Normal file
14
Parser/Internal/GreenNodeExtensions.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Parser.Internal
|
||||||
|
{
|
||||||
|
internal static class GreenNodeExtensions
|
||||||
|
{
|
||||||
|
public static TNode WithDiagnostics<TNode>(this TNode node, params TokenDiagnostic[] diagnostics)
|
||||||
|
where TNode : GreenNode
|
||||||
|
{
|
||||||
|
return (TNode)node.SetDiagnostics(diagnostics.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,13 +28,20 @@ namespace Parser.Internal
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SyntaxToken CreateMissingToken(TokenKind kind)
|
||||||
|
{
|
||||||
|
return TokenFactory
|
||||||
|
.CreateMissing(kind, null, null)
|
||||||
|
.WithDiagnostics(TokenDiagnostic.MissingToken(kind));
|
||||||
|
}
|
||||||
|
|
||||||
private SyntaxToken EatToken(TokenKind kind)
|
private SyntaxToken EatToken(TokenKind kind)
|
||||||
{
|
{
|
||||||
var token = CurrentToken;
|
var token = CurrentToken;
|
||||||
if (token.Kind != kind)
|
if (token.Kind != kind)
|
||||||
{
|
{
|
||||||
Diagnostics.ReportUnexpectedToken(kind, token.Kind);
|
Diagnostics.ReportUnexpectedToken(kind, token.Kind);
|
||||||
return TokenFactory.CreateMissing(kind, null, null);
|
return CreateMissingToken(kind);
|
||||||
}
|
}
|
||||||
_index++;
|
_index++;
|
||||||
return token;
|
return token;
|
||||||
|
@ -5,7 +5,7 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
internal class SyntaxList : SyntaxNode
|
internal class SyntaxList : SyntaxNode
|
||||||
{
|
{
|
||||||
private readonly GreenNode[] _elements;
|
internal readonly GreenNode[] _elements;
|
||||||
|
|
||||||
protected SyntaxList(GreenNode[] elements) : base(TokenKind.List)
|
protected SyntaxList(GreenNode[] elements) : base(TokenKind.List)
|
||||||
{
|
{
|
||||||
@ -17,6 +17,19 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SyntaxList(
|
||||||
|
GreenNode[] elements,
|
||||||
|
TokenDiagnostic[] diagnostics)
|
||||||
|
: base(TokenKind.List, diagnostics)
|
||||||
|
{
|
||||||
|
Slots = elements.Length;
|
||||||
|
_elements = elements;
|
||||||
|
foreach (var element in elements)
|
||||||
|
{
|
||||||
|
this.AdjustWidth(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public GreenNode GetListSlot(int i)
|
public GreenNode GetListSlot(int i)
|
||||||
{
|
{
|
||||||
return _elements[i];
|
return _elements[i];
|
||||||
@ -40,5 +53,10 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxList(_elements, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
namespace Parser.Internal
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Parser.Internal
|
||||||
{
|
{
|
||||||
internal class SyntaxList<T> : SyntaxNode where T : GreenNode
|
internal class SyntaxList<T> : SyntaxNode where T : GreenNode
|
||||||
{
|
{
|
||||||
@ -14,6 +16,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SyntaxList(T[] list, TokenDiagnostic[] diagnostics) : base(TokenKind.List, diagnostics)
|
||||||
|
{
|
||||||
|
Slots = list.Length;
|
||||||
|
_list = SyntaxList.List(list);
|
||||||
|
foreach (var element in list)
|
||||||
|
{
|
||||||
|
this.AdjustWidth(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
return (T)_list.GetListSlot(i);
|
return (T)_list.GetListSlot(i);
|
||||||
@ -32,5 +44,10 @@
|
|||||||
{
|
{
|
||||||
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxList<T>(_list._elements.Select(x => (T)x).ToArray(), diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,11 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics)
|
||||||
|
: base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<SyntaxToken> DescendantTokens => CalculateChildTokens();
|
public IEnumerable<SyntaxToken> DescendantTokens => CalculateChildTokens();
|
||||||
|
|
||||||
private IEnumerable<SyntaxToken> CalculateChildTokens()
|
private IEnumerable<SyntaxToken> CalculateChildTokens()
|
||||||
@ -57,6 +62,10 @@ namespace Parser.Internal
|
|||||||
protected StatementSyntaxNode(TokenKind kind) : base(kind)
|
protected StatementSyntaxNode(TokenKind kind) : base(kind)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected StatementSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class ExpressionSyntaxNode : SyntaxNode
|
internal abstract class ExpressionSyntaxNode : SyntaxNode
|
||||||
@ -64,6 +73,10 @@ namespace Parser.Internal
|
|||||||
protected ExpressionSyntaxNode(TokenKind kind) : base(kind)
|
protected ExpressionSyntaxNode(TokenKind kind) : base(kind)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ExpressionSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode
|
internal abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode
|
||||||
@ -71,6 +84,10 @@ namespace Parser.Internal
|
|||||||
protected FunctionHandleSyntaxNode(TokenKind kind) : base(kind)
|
protected FunctionHandleSyntaxNode(TokenKind kind) : base(kind)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FunctionHandleSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode
|
internal abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode
|
||||||
@ -78,6 +95,10 @@ namespace Parser.Internal
|
|||||||
protected MethodDeclarationSyntaxNode(TokenKind kind) : base(kind)
|
protected MethodDeclarationSyntaxNode(TokenKind kind) : base(kind)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected MethodDeclarationSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class RootSyntaxNode : SyntaxNode
|
internal class RootSyntaxNode : SyntaxNode
|
||||||
@ -91,6 +112,13 @@ namespace Parser.Internal
|
|||||||
_file = file;
|
_file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RootSyntaxNode(FileSyntaxNode file, TokenDiagnostic[] diagnostics) : base(TokenKind.Root, diagnostics)
|
||||||
|
{
|
||||||
|
Slots = 1;
|
||||||
|
this.AdjustWidth(file);
|
||||||
|
_file = file;
|
||||||
|
}
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
switch (i)
|
switch (i)
|
||||||
@ -100,6 +128,11 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new RootSyntaxNode(this._file, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
||||||
{
|
{
|
||||||
return new Parser.RootSyntaxNode(this, position);
|
return new Parser.RootSyntaxNode(this, position);
|
||||||
|
@ -36,6 +36,31 @@ namespace Parser.Internal
|
|||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxTokenWithTrivia(
|
||||||
|
TokenKind kind,
|
||||||
|
string text,
|
||||||
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
|
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
LeadingTriviaCore = leadingTrivia;
|
||||||
|
TrailingTriviaCore = trailingTrivia;
|
||||||
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyntaxTokenWithTrivia(
|
||||||
|
TokenKind kind,
|
||||||
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
|
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
_text = base.Text;
|
||||||
|
LeadingTriviaCore = leadingTrivia;
|
||||||
|
TrailingTriviaCore = trailingTrivia;
|
||||||
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
if (leading)
|
if (leading)
|
||||||
@ -55,6 +80,11 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxTokenWithTrivia(Kind, _text, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
||||||
@ -75,10 +105,27 @@ namespace Parser.Internal
|
|||||||
_fullWidth = text?.Length ?? 0;
|
_fullWidth = text?.Length ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxTokenWithValue(
|
||||||
|
TokenKind kind,
|
||||||
|
string text,
|
||||||
|
T value,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
_value = value;
|
||||||
|
_fullWidth = text?.Length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
writer.Write(_text);
|
writer.Write(_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxTokenWithValue<T>(Kind, _text, _value, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
public T Value => _value;
|
public T Value => _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +143,19 @@ namespace Parser.Internal
|
|||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxTokenWithValueAndTrivia(
|
||||||
|
TokenKind kind,
|
||||||
|
string text,
|
||||||
|
T value,
|
||||||
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
|
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(kind, text, value, diagnostics)
|
||||||
|
{
|
||||||
|
LeadingTriviaCore = leadingTrivia;
|
||||||
|
TrailingTriviaCore = trailingTrivia;
|
||||||
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
||||||
@ -118,6 +178,11 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxTokenWithValueAndTrivia<T>(Kind, _text, Value, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SyntaxIdentifier : SyntaxToken
|
internal class SyntaxIdentifier : SyntaxToken
|
||||||
@ -129,9 +194,21 @@ namespace Parser.Internal
|
|||||||
writer.Write(_text);
|
writer.Write(_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxIdentifier(_text, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
public SyntaxIdentifier(
|
public SyntaxIdentifier(
|
||||||
string text
|
string text) : base(TokenKind.IdentifierToken)
|
||||||
) : base(TokenKind.IdentifierToken)
|
{
|
||||||
|
_text = text;
|
||||||
|
_fullWidth = text?.Length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyntaxIdentifier(
|
||||||
|
string text,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(TokenKind.IdentifierToken, diagnostics)
|
||||||
{
|
{
|
||||||
_text = text;
|
_text = text;
|
||||||
_fullWidth = text?.Length ?? 0;
|
_fullWidth = text?.Length ?? 0;
|
||||||
@ -157,6 +234,17 @@ namespace Parser.Internal
|
|||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxIdentifierWithTrivia(
|
||||||
|
string text,
|
||||||
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
|
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(text, diagnostics)
|
||||||
|
{
|
||||||
|
_leadingTrivia = leadingTrivia;
|
||||||
|
_trailingTrivia = trailingTrivia;
|
||||||
|
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
if (leading)
|
if (leading)
|
||||||
@ -178,6 +266,11 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public override bool IsToken => true;
|
public override bool IsToken => true;
|
||||||
public override bool IsNode => false;
|
public override bool IsNode => false;
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxIdentifierWithTrivia(Text, _leadingTrivia, _trailingTrivia, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MissingTokenWithTrivia : SyntaxTokenWithTrivia
|
internal class MissingTokenWithTrivia : SyntaxTokenWithTrivia
|
||||||
@ -191,13 +284,31 @@ namespace Parser.Internal
|
|||||||
_isMissing = true;
|
_isMissing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MissingTokenWithTrivia(
|
||||||
|
TokenKind kind,
|
||||||
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
|
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||||
|
TokenDiagnostic[] diagnostics) : base(kind, leadingTrivia, trailingTrivia, diagnostics)
|
||||||
|
{
|
||||||
|
_isMissing = true;
|
||||||
|
}
|
||||||
|
|
||||||
public override string Text => "";
|
public override string Text => "";
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new MissingTokenWithTrivia(Kind, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SyntaxToken(TokenKind kind) : base(kind)
|
protected SyntaxToken(TokenKind kind) : base(kind)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SyntaxToken(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
||||||
|
|
||||||
public virtual int Width => Text.Length;
|
public virtual int Width => Text.Length;
|
||||||
|
@ -14,6 +14,11 @@ namespace Parser.Internal
|
|||||||
_text = text;
|
_text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxTrivia(TokenKind kind, string text, TokenDiagnostic[] diagnostics) : base(kind, text.Length, diagnostics)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
}
|
||||||
|
|
||||||
public override string Text => _text;
|
public override string Text => _text;
|
||||||
public int Width => _text.Length;
|
public int Width => _text.Length;
|
||||||
|
|
||||||
@ -35,6 +40,11 @@ namespace Parser.Internal
|
|||||||
writer.Write(_text);
|
writer.Write(_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new SyntaxTrivia(Kind, _text, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>();
|
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>();
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>();
|
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>();
|
||||||
}
|
}
|
||||||
|
24
Parser/Internal/TokenDiagnostic.cs
Normal file
24
Parser/Internal/TokenDiagnostic.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace Parser.Internal
|
||||||
|
{
|
||||||
|
public class TokenDiagnostic
|
||||||
|
{
|
||||||
|
protected TokenDiagnostic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenDiagnostic MissingToken(TokenKind kind)
|
||||||
|
{
|
||||||
|
return new MissingTokenDiagnostic(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MissingTokenDiagnostic : TokenDiagnostic
|
||||||
|
{
|
||||||
|
internal MissingTokenDiagnostic(TokenKind kind)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenKind Kind { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<NullableContextOptions>enable</NullableContextOptions>
|
<NullableContextOptions>enable</NullableContextOptions>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -96,6 +96,67 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Accept(SyntaxVisitor visitor);
|
public abstract void Accept(SyntaxVisitor visitor);
|
||||||
|
|
||||||
|
public SyntaxDiagnostic[] GetDiagnostics()
|
||||||
|
{
|
||||||
|
return GetDiagnosticsRecursive(_green, Position).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<SyntaxDiagnostic> GetDiagnosticsRecursive(Internal.GreenNode node, int position)
|
||||||
|
{
|
||||||
|
if (node.HasDiagnostics)
|
||||||
|
{
|
||||||
|
foreach (var diagnostic in node.GetDiagnostics())
|
||||||
|
{
|
||||||
|
yield return SyntaxDiagnostic.From(diagnostic, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < node.Slots; i++)
|
||||||
|
{
|
||||||
|
var maybeChild = node.GetSlot(i);
|
||||||
|
if (maybeChild is Internal.GreenNode child) {
|
||||||
|
foreach (var diagnostic in GetDiagnosticsRecursive(child, position))
|
||||||
|
{
|
||||||
|
yield return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
position += child.FullWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SyntaxDiagnostic
|
||||||
|
{
|
||||||
|
public int Position { get; }
|
||||||
|
|
||||||
|
public static SyntaxDiagnostic From(Internal.TokenDiagnostic diagnostic, int Position)
|
||||||
|
{
|
||||||
|
switch (diagnostic)
|
||||||
|
{
|
||||||
|
case Internal.MissingTokenDiagnostic missingToken:
|
||||||
|
return new MissingTokenSyntaxDiagnostic(Position, missingToken.Kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new System.ArgumentOutOfRangeException(nameof(diagnostic));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SyntaxDiagnostic(int position)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MissingTokenSyntaxDiagnostic : SyntaxDiagnostic
|
||||||
|
{
|
||||||
|
public TokenKind Kind { get; }
|
||||||
|
|
||||||
|
internal MissingTokenSyntaxDiagnostic(int position, TokenKind tokenKind)
|
||||||
|
: base(position)
|
||||||
|
{
|
||||||
|
Kind = tokenKind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class StatementSyntaxNode : SyntaxNode
|
public abstract class StatementSyntaxNode : SyntaxNode
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -79,7 +79,7 @@ namespace SyntaxGenerator
|
|||||||
return widthAdjustment + fieldAssignment;
|
return widthAdjustment + fieldAssignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateInternalConstructor(SyntaxNodeDescription node)
|
private static string GenerateInternalConstructorSimple(SyntaxNodeDescription node)
|
||||||
{
|
{
|
||||||
var arguments = string.Join(
|
var arguments = string.Join(
|
||||||
",",
|
",",
|
||||||
@ -94,6 +94,27 @@ namespace SyntaxGenerator
|
|||||||
return header + "\n {\n" + slotsAssignment + "\n" + assignments + " }\n";
|
return header + "\n {\n" + slotsAssignment + "\n" + assignments + " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GenerateInternalConstructorWithDiagnostics(SyntaxNodeDescription node)
|
||||||
|
{
|
||||||
|
var arguments = string.Join(
|
||||||
|
",",
|
||||||
|
node.Fields
|
||||||
|
.Select(field => $"\n {FullFieldType(field)} {field.FieldName}")
|
||||||
|
.Concat(new[] { $"\n TokenDiagnostic[] diagnostics" }));
|
||||||
|
var header =
|
||||||
|
$" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName}, diagnostics)";
|
||||||
|
var slotsAssignment = $" Slots = {node.Fields.Length};";
|
||||||
|
var assignments = string.Join(
|
||||||
|
"",
|
||||||
|
node.Fields.Select(GenerateFieldAssignmentInsideConstructor));
|
||||||
|
return header + "\n {\n" + slotsAssignment + "\n" + assignments + " }\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateInternalConstructors(SyntaxNodeDescription node)
|
||||||
|
{
|
||||||
|
return GenerateInternalConstructorSimple(node) + "\n" + GenerateInternalConstructorWithDiagnostics(node);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateConstructor(SyntaxNodeDescription node)
|
private static string GenerateConstructor(SyntaxNodeDescription node)
|
||||||
{
|
{
|
||||||
var arguments = "SyntaxNode parent, Internal.GreenNode green, int position";
|
var arguments = "SyntaxNode parent, Internal.GreenNode green, int position";
|
||||||
@ -102,6 +123,18 @@ namespace SyntaxGenerator
|
|||||||
return header + " {\n }\n";
|
return header + " {\n }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GenerateInternalSetDiagnostics(SyntaxNodeDescription node)
|
||||||
|
{
|
||||||
|
var header = $" public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)";
|
||||||
|
var arguments = string.Join(
|
||||||
|
", ",
|
||||||
|
node.Fields
|
||||||
|
.Select(field => "_" + field.FieldName)
|
||||||
|
.Concat(new[] { "diagnostics" }));
|
||||||
|
var text = $" return new {node.ClassName}({arguments});";
|
||||||
|
return header + "\n {\n" + text + "\n }\n";
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateInternalGetSlot(SyntaxNodeDescription node)
|
private static string GenerateInternalGetSlot(SyntaxNodeDescription node)
|
||||||
{
|
{
|
||||||
var header = $" public override GreenNode? GetSlot(int i)\n";
|
var header = $" public override GreenNode? GetSlot(int i)\n";
|
||||||
@ -156,15 +189,17 @@ namespace SyntaxGenerator
|
|||||||
var fields = string.Join(
|
var fields = string.Join(
|
||||||
"",
|
"",
|
||||||
node.Fields.Select(GenerateInternalFieldDeclaration));
|
node.Fields.Select(GenerateInternalFieldDeclaration));
|
||||||
var constructor = GenerateInternalConstructor(node);
|
var constructor = GenerateInternalConstructors(node);
|
||||||
var getSlot = GenerateInternalGetSlot(node);
|
var getSlot = GenerateInternalGetSlot(node);
|
||||||
var createRed = GenerateCreateRed(node);
|
var createRed = GenerateCreateRed(node);
|
||||||
|
var setDiagnostics = GenerateInternalSetDiagnostics(node);
|
||||||
return
|
return
|
||||||
header
|
header
|
||||||
+ "\n {\n"
|
+ "\n {\n"
|
||||||
+ fields + "\n"
|
+ fields + "\n"
|
||||||
+ constructor + "\n"
|
+ constructor + "\n"
|
||||||
+ createRed + "\n"
|
+ createRed + "\n"
|
||||||
|
+ setDiagnostics + "\n"
|
||||||
+ getSlot + " }\n";
|
+ getSlot + " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user