Add diagnostics
This commit is contained in:
parent
8be2aec0ab
commit
fe5012bd29
@ -15,7 +15,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[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)
|
||||
{
|
||||
var tokens = ParseText(text);
|
||||
@ -24,7 +26,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[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)
|
||||
{
|
||||
var text = text1 + text2;
|
||||
@ -35,7 +39,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[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)
|
||||
{
|
||||
var text = text1 + separatorText + text2;
|
||||
|
@ -19,6 +19,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||
}
|
||||
|
||||
@ -30,6 +35,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var statement = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||
if (statement is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement).Expression);
|
||||
}
|
||||
|
||||
@ -41,6 +51,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||
}
|
||||
|
||||
@ -50,6 +65,7 @@ namespace Parser.Tests
|
||||
{
|
||||
var sut = GetSut(text);
|
||||
var actual = sut.Parse();
|
||||
var diagnostics = actual.Root.GetDiagnostics();
|
||||
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 actual = sut.Parse();
|
||||
var statement = actual.Root.StatementList[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||
var expression = statement.Expression as BinaryOperationExpressionSyntaxNode;
|
||||
var lhs = expression.Lhs;
|
||||
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||
var lhs = expression!.Lhs;
|
||||
var operation = expression.Operation;
|
||||
var rhs = expression.Rhs;
|
||||
Assert.Equal(0, lhs.Position);
|
||||
|
@ -2,13 +2,16 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
<NullableContextOptions>enable</NullableContextOptions>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||
|
@ -44,7 +44,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[MemberData(nameof(FilesData))]
|
||||
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
public void TestFile(string fileName)
|
||||
{
|
||||
var text = File.ReadAllText(fileName);
|
||||
|
@ -11,6 +11,9 @@ namespace Parser.Internal
|
||||
public TokenKind Kind { get; }
|
||||
public int Slots { get; protected set; }
|
||||
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)
|
||||
{
|
||||
@ -23,6 +26,21 @@ namespace Parser.Internal
|
||||
_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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private SyntaxToken CreateMissingToken(TokenKind kind)
|
||||
{
|
||||
return TokenFactory
|
||||
.CreateMissing(kind, null, null)
|
||||
.WithDiagnostics(TokenDiagnostic.MissingToken(kind));
|
||||
}
|
||||
|
||||
private SyntaxToken EatToken(TokenKind kind)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
if (token.Kind != kind)
|
||||
{
|
||||
Diagnostics.ReportUnexpectedToken(kind, token.Kind);
|
||||
return TokenFactory.CreateMissing(kind, null, null);
|
||||
return CreateMissingToken(kind);
|
||||
}
|
||||
_index++;
|
||||
return token;
|
||||
|
@ -5,7 +5,7 @@ namespace Parser.Internal
|
||||
{
|
||||
internal class SyntaxList : SyntaxNode
|
||||
{
|
||||
private readonly GreenNode[] _elements;
|
||||
internal readonly GreenNode[] _elements;
|
||||
|
||||
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)
|
||||
{
|
||||
return _elements[i];
|
||||
@ -40,5 +53,10 @@ namespace Parser.Internal
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
return (T)_list.GetListSlot(i);
|
||||
@ -32,5 +44,10 @@
|
||||
{
|
||||
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();
|
||||
|
||||
private IEnumerable<SyntaxToken> CalculateChildTokens()
|
||||
@ -57,13 +62,21 @@ namespace Parser.Internal
|
||||
protected StatementSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected StatementSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal abstract class ExpressionSyntaxNode : SyntaxNode
|
||||
{
|
||||
protected ExpressionSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected ExpressionSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode
|
||||
@ -71,6 +84,10 @@ namespace Parser.Internal
|
||||
protected FunctionHandleSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected FunctionHandleSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode
|
||||
@ -78,6 +95,10 @@ namespace Parser.Internal
|
||||
protected MethodDeclarationSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected MethodDeclarationSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class RootSyntaxNode : SyntaxNode
|
||||
@ -91,6 +112,13 @@ namespace Parser.Internal
|
||||
_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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return new Parser.RootSyntaxNode(this, position);
|
||||
|
@ -12,7 +12,7 @@ namespace Parser.Internal
|
||||
internal class SyntaxTokenWithTrivia : SyntaxToken
|
||||
{
|
||||
private readonly string _text;
|
||||
|
||||
|
||||
public SyntaxTokenWithTrivia(
|
||||
TokenKind kind,
|
||||
string text,
|
||||
@ -36,6 +36,31 @@ namespace Parser.Internal
|
||||
_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)
|
||||
{
|
||||
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> TrailingTriviaCore { get; }
|
||||
@ -75,10 +105,27 @@ namespace Parser.Internal
|
||||
_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)
|
||||
{
|
||||
writer.Write(_text);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxTokenWithValue<T>(Kind, _text, _value, diagnostics);
|
||||
}
|
||||
|
||||
public T Value => _value;
|
||||
}
|
||||
|
||||
@ -96,10 +143,23 @@ namespace Parser.Internal
|
||||
_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> TrailingTriviaCore { get; }
|
||||
|
||||
|
||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||
{
|
||||
if (leading)
|
||||
@ -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
|
||||
@ -129,9 +194,21 @@ namespace Parser.Internal
|
||||
writer.Write(_text);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxIdentifier(_text, diagnostics);
|
||||
}
|
||||
|
||||
public SyntaxIdentifier(
|
||||
string text
|
||||
) : base(TokenKind.IdentifierToken)
|
||||
string text) : base(TokenKind.IdentifierToken)
|
||||
{
|
||||
_text = text;
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
}
|
||||
|
||||
public SyntaxIdentifier(
|
||||
string text,
|
||||
TokenDiagnostic[] diagnostics) : base(TokenKind.IdentifierToken, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
@ -142,7 +219,7 @@ namespace Parser.Internal
|
||||
{
|
||||
private readonly IReadOnlyList<SyntaxTrivia> _leadingTrivia;
|
||||
private readonly IReadOnlyList<SyntaxTrivia> _trailingTrivia;
|
||||
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => _leadingTrivia;
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => _trailingTrivia;
|
||||
|
||||
@ -157,6 +234,17 @@ namespace Parser.Internal
|
||||
_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)
|
||||
{
|
||||
if (leading)
|
||||
@ -178,6 +266,11 @@ namespace Parser.Internal
|
||||
|
||||
public override bool IsToken => true;
|
||||
public override bool IsNode => false;
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxIdentifierWithTrivia(Text, _leadingTrivia, _trailingTrivia, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissingTokenWithTrivia : SyntaxTokenWithTrivia
|
||||
@ -191,15 +284,33 @@ namespace Parser.Internal
|
||||
_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 GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new MissingTokenWithTrivia(Kind, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
public virtual int Width => Text.Length;
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
|
||||
|
@ -14,6 +14,11 @@ namespace Parser.Internal
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public SyntaxTrivia(TokenKind kind, string text, TokenDiagnostic[] diagnostics) : base(kind, text.Length, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public override string Text => _text;
|
||||
public int Width => _text.Length;
|
||||
|
||||
@ -35,6 +40,11 @@ namespace Parser.Internal
|
||||
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> 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">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<NullableContextOptions>enable</NullableContextOptions>
|
||||
</PropertyGroup>
|
||||
|
@ -96,6 +96,67 @@ namespace Parser
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||
|
@ -78,8 +78,8 @@ namespace SyntaxGenerator
|
||||
var fieldAssignment = $" _{field.FieldName} = {field.FieldName};\n";
|
||||
return widthAdjustment + fieldAssignment;
|
||||
}
|
||||
|
||||
private static string GenerateInternalConstructor(SyntaxNodeDescription node)
|
||||
|
||||
private static string GenerateInternalConstructorSimple(SyntaxNodeDescription node)
|
||||
{
|
||||
var arguments = string.Join(
|
||||
",",
|
||||
@ -94,6 +94,27 @@ namespace SyntaxGenerator
|
||||
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)
|
||||
{
|
||||
var arguments = "SyntaxNode parent, Internal.GreenNode green, int position";
|
||||
@ -102,6 +123,18 @@ namespace SyntaxGenerator
|
||||
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)
|
||||
{
|
||||
var header = $" public override GreenNode? GetSlot(int i)\n";
|
||||
@ -156,15 +189,17 @@ namespace SyntaxGenerator
|
||||
var fields = string.Join(
|
||||
"",
|
||||
node.Fields.Select(GenerateInternalFieldDeclaration));
|
||||
var constructor = GenerateInternalConstructor(node);
|
||||
var constructor = GenerateInternalConstructors(node);
|
||||
var getSlot = GenerateInternalGetSlot(node);
|
||||
var createRed = GenerateCreateRed(node);
|
||||
var setDiagnostics = GenerateInternalSetDiagnostics(node);
|
||||
return
|
||||
header
|
||||
+ "\n {\n"
|
||||
+ fields + "\n"
|
||||
+ constructor + "\n"
|
||||
+ createRed + "\n"
|
||||
+ setDiagnostics + "\n"
|
||||
+ getSlot + " }\n";
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user