Merge pull request #1 from mahalex/nullable-reference-types

Nullable reference types
This commit is contained in:
Alexander Luzgarev 2020-07-04 12:45:30 +02:00 committed by GitHub
commit 9f84f64a58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2362 additions and 660 deletions

View File

@ -196,7 +196,12 @@ namespace ProjectConsole
Visit(node.InputDescription); Visit(node.InputDescription);
Visit(node.Commas); Visit(node.Commas);
Visit(node.Body); Visit(node.Body);
OutputKeyword(node.EndKeyword); Visit(node.EndKeyword);
}
public override void VisitEndKeyword(EndKeywordSyntaxNode node)
{
OutputKeyword(node.EndKeyword);
} }
public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node) public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node)
@ -207,7 +212,7 @@ namespace ProjectConsole
Visit(node.InputDescription); Visit(node.InputDescription);
Visit(node.Commas); Visit(node.Commas);
Visit(node.Body); Visit(node.Body);
OutputKeyword(node.EndKeyword); Visit(node.EndKeyword);
} }
public override void VisitIfStatement(IfStatementSyntaxNode node) public override void VisitIfStatement(IfStatementSyntaxNode node)

View File

@ -0,0 +1,47 @@
using System.Linq;
namespace Parser.Tests
{
public static class DiagnosticExtensions
{
public static bool IsEquivalentTo(this SyntaxDiagnostic[] actualSequence, params SyntaxDiagnostic[] expectedSequence)
{
if (actualSequence.Length != expectedSequence.Length)
{
return false;
}
var actualSorted = actualSequence.OrderBy(x => x.Position).ToArray();
var expectedSorted = expectedSequence.OrderBy(x => x.Position).ToArray();
for (var i = 0; i < expectedSequence.Length; i++)
{
var expected = expectedSequence[i];
var actual = actualSequence[i];
if (expected.Position != actual.Position)
{
return false;
}
if (expected is MissingTokenSyntaxDiagnostic expectedMissingToken)
{
if (!(actual is MissingTokenSyntaxDiagnostic actualMissingToken))
{
return false;
}
if (expectedMissingToken.Kind != actualMissingToken.Kind)
{
return false;
}
}
}
return true;
}
public static MissingTokenSyntaxDiagnostic MissingToken(int position, TokenKind kind)
{
return new MissingTokenSyntaxDiagnostic(position, kind);
}
}
}

View File

@ -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;
@ -78,17 +84,17 @@ namespace Parser.Tests
public static IEnumerable<(TokenKind kind, string text)> GetTokens() public static IEnumerable<(TokenKind kind, string text)> GetTokens()
{ {
var fixedTokens = Enum.GetValues(typeof(TokenKind)) var fixedTokens =
.Cast<TokenKind>() from TokenKind kind in Enum.GetValues(typeof(TokenKind))
.Select(k => (kind: k, text: SyntaxFacts.GetText(k))) let text = SyntaxFacts.GetText(kind)
.Where(t => !(t.text is null)) where !(text is null)
.Where(t => !(SyntaxFacts.IsUnaryTokenKind(t.kind) where !(SyntaxFacts.IsUnaryTokenKind(kind)
|| SyntaxFacts.IsOpeningToken(t.kind) || SyntaxFacts.IsOpeningToken(kind)
|| SyntaxFacts.IsClosingToken(t.kind) || SyntaxFacts.IsClosingToken(kind)
|| t.kind == TokenKind.ApostropheToken)); || kind == TokenKind.ApostropheToken)
select (kind, text);
var dynamicTokens = new[] var dynamicTokens = new[]
{ {
(TokenKind.IdentifierToken, "a"), (TokenKind.IdentifierToken, "a"),
(TokenKind.IdentifierToken, "abc"), (TokenKind.IdentifierToken, "abc"),
@ -105,33 +111,21 @@ namespace Parser.Tests
public static IEnumerable<(TokenKind kind1, string text1, TokenKind kind2, string text2)> GetPairsOfTokens() public static IEnumerable<(TokenKind kind1, string text1, TokenKind kind2, string text2)> GetPairsOfTokens()
{ {
foreach (var token1 in GetTokens()) return
{ from token1 in GetTokens()
foreach (var token2 in GetTokens()) from token2 in GetTokens()
{ where !RequiresSeparator(token1.kind, token2.kind)
if (!RequiresSeparator(token1.kind, token2.kind)) select (token1.kind, token1.text, token2.kind, token2.text);
{
yield return (token1.kind, token1.text, token2.kind, token2.text);
}
}
}
} }
public static IEnumerable<(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)> GetPairsOfTokensWithSeparators() public static IEnumerable<(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)> GetPairsOfTokensWithSeparators()
{ {
foreach (var token1 in GetTokens()) return
{ from token1 in GetTokens()
foreach (var token2 in GetTokens()) from token2 in GetTokens()
{ where RequiresSeparator(token1.kind, token2.kind)
if (RequiresSeparator(token1.kind, token2.kind)) from separatorText in GetSeparators()
{ select (token1.kind, token1.text, separatorText, token2.kind, token2.text);
foreach (var separatorText in GetSeparators())
{
yield return (token1.kind, token1.text, separatorText, token2.kind, token2.text);
}
}
}
}
} }
private static bool RequiresSeparator(TokenKind kind1, TokenKind kind2) private static bool RequiresSeparator(TokenKind kind1, TokenKind kind2)

View File

@ -2,6 +2,8 @@
namespace Parser.Tests namespace Parser.Tests
{ {
using static DiagnosticExtensions;
public class MParserShould public class MParserShould
{ {
private static MParser GetSut(string text) private static MParser GetSut(string text)
@ -19,6 +21,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 +37,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 +53,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,7 +67,8 @@ namespace Parser.Tests
{ {
var sut = GetSut(text); var sut = GetSut(text);
var actual = sut.Parse(); var actual = sut.Parse();
Assert.Collection(actual.Diagnostics, item => Assert.Equal("Unexpected token 'SemicolonToken', expected 'IdentifierToken'.", item.Message)); var diagnostics = actual.Root.GetDiagnostics();
Assert.True(diagnostics.IsEquivalentTo(MissingToken(4, TokenKind.IdentifierToken)));
} }
[Fact] [Fact]
@ -60,8 +78,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);

View File

@ -2,11 +2,16 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<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" />

View File

@ -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);

View File

@ -68,7 +68,7 @@ namespace Parser
internal SyntaxNodeOrToken ThisInternal(int index) internal SyntaxNodeOrToken ThisInternal(int index)
{ {
var currentSlotIndex = 0; var currentSlotIndex = 0;
GreenNode currentSlot = null; GreenNode? currentSlot = null;
while (true) while (true)
{ {
currentSlot = _node._green.GetSlot(currentSlotIndex); currentSlot = _node._green.GetSlot(currentSlotIndex);
@ -84,13 +84,17 @@ namespace Parser
if (currentSlot.IsList) if (currentSlot.IsList)
{ {
var listSlot = _node.GetNode(currentSlotIndex); var listSlot = _node.GetNode(currentSlotIndex);
if (listSlot is null)
{
throw new Exception($"Unexpected null in list slot.");
}
var red = listSlot.GetNode(index); var red = listSlot.GetNode(index);
if (red != null) if (!(red is null))
{ {
return red; return red;
} }
// this is a token // this is a token
return new SyntaxToken(listSlot, listSlot._green.GetSlot(index), _node.GetChildPosition(index)); return new SyntaxToken(listSlot, listSlot._green.GetSlot(index)!, _node.GetChildPosition(index));
} }
else else
{ {
@ -100,7 +104,7 @@ namespace Parser
return red; return red;
} }
// this is a token // this is a token
return new SyntaxToken(_node, _node._green.GetSlot(currentSlotIndex), _node.GetChildPosition(currentSlotIndex)); return new SyntaxToken(_node, _node._green.GetSlot(currentSlotIndex)!, _node.GetChildPosition(currentSlotIndex));
} }
} }

View File

@ -4,7 +4,7 @@ namespace Parser.Internal
{ {
public class Diagnostic public class Diagnostic
{ {
public TextSpan Span { get; } public TextSpan? Span { get; }
public string Message { get; } public string Message { get; }
public Diagnostic(TextSpan span, string message) public Diagnostic(TextSpan span, string message)
@ -12,5 +12,10 @@ namespace Parser.Internal
Span = span; Span = span;
Message = message ?? throw new ArgumentNullException(nameof(message)); Message = message ?? throw new ArgumentNullException(nameof(message));
} }
public Diagnostic(string message)
{
Message = message ?? throw new ArgumentNullException(nameof(message));
}
} }
} }

View File

@ -26,6 +26,12 @@ namespace Parser.Internal
_diagnostics.Add(diagnostic); _diagnostics.Add(diagnostic);
} }
private void Report(string message)
{
var diagnostic = new Diagnostic(message);
_diagnostics.Add(diagnostic);
}
internal void ReportUnexpectedEndOfFile(TextSpan span) internal void ReportUnexpectedEndOfFile(TextSpan span)
{ {
Report(span, "Unexpected end of file."); Report(span, "Unexpected end of file.");
@ -46,9 +52,9 @@ namespace Parser.Internal
Report(span, $"Unknown symbol '{c}'."); Report(span, $"Unknown symbol '{c}'.");
} }
internal void ReportUnexpectedToken(TextSpan span, TokenKind expected, TokenKind actual) internal void ReportUnexpectedToken(TokenKind expected, TokenKind actual)
{ {
Report(span, $"Unexpected token '{actual}', expected '{expected}'."); Report($"Unexpected token '{actual}', expected '{expected}'.");
} }
public IEnumerator<Diagnostic> GetEnumerator() public IEnumerator<Diagnostic> GetEnumerator()

View File

@ -10,7 +10,10 @@ 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,13 +26,28 @@ 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;
public int FullWidth => _fullWidth; public int FullWidth => _fullWidth;
protected void AdjustWidth(GreenNode node) protected void AdjustWidth(GreenNode? node)
{ {
if (!(node is null)) if (!(node is null))
{ {
@ -56,11 +74,6 @@ namespace Parser.Internal
internal bool IsMissing => _isMissing; internal bool IsMissing => _isMissing;
public override string ToString()
{
return base.ToString();
}
private void WriteTo(TextWriter writer, bool leading, bool trailing) private void WriteTo(TextWriter writer, bool leading, bool trailing)
{ {
var stack = new Stack<(GreenNode node, bool leading, bool trailing)>(); var stack = new Stack<(GreenNode node, bool leading, bool trailing)>();
@ -109,12 +122,12 @@ namespace Parser.Internal
return -1; return -1;
} }
private GreenNode GetFirstTerminal() private GreenNode? GetFirstTerminal()
{ {
var current = this; var current = this;
while (true) while (true)
{ {
GreenNode next = null; GreenNode? next = null;
if (current.Slots == 0) if (current.Slots == 0)
{ {
return current; return current;
@ -141,12 +154,12 @@ namespace Parser.Internal
} }
} }
private GreenNode GetLastTerminal() private GreenNode? GetLastTerminal()
{ {
var current = this; var current = this;
while (true) while (true)
{ {
GreenNode next = null; GreenNode? next = null;
if (current.Slots == 0) if (current.Slots == 0)
{ {
return current; return current;
@ -225,5 +238,17 @@ namespace Parser.Internal
} }
} }
} }
public abstract GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics);
internal TokenDiagnostic[] GetDiagnostics()
{
if (diagnosticsTable.TryGetValue(this, out var diags))
{
return diags;
}
return emptyDiagnostics;
}
} }
} }

View 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());
}
}
}

View File

@ -9,9 +9,9 @@ namespace Parser.Internal
{ {
private class TokenInfo private class TokenInfo
{ {
public TokenKind Kind { get; set; } public TokenKind Kind { get; set; } = TokenKind.None;
public string Text { get; set; } public string Text { get; set; } = "";
public string StringValue { get; set; } public string StringValue { get; set; } = "";
public double DoubleValue { get; set; } public double DoubleValue { get; set; }
} }
@ -25,6 +25,7 @@ namespace Parser.Internal
public MLexerGreen(ITextWindow window) public MLexerGreen(ITextWindow window)
{ {
Window = window; Window = window;
LastToken = SyntaxToken.NoneToken;
TokenStack = new Stack<TokenKind>(); TokenStack = new Stack<TokenKind>();
} }

View File

@ -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(token.Span, kind, token.Kind); Diagnostics.ReportUnexpectedToken(kind, token.Kind);
return TokenFactory.CreateMissing(kind, null, null); return CreateMissingToken(kind);
} }
_index++; _index++;
return token; return token;
@ -55,13 +62,13 @@ namespace Parser.Internal
var token = CurrentToken; var token = CurrentToken;
if (token.Kind != TokenKind.IdentifierToken) if (token.Kind != TokenKind.IdentifierToken)
{ {
Diagnostics.ReportUnexpectedToken(token.Span, TokenKind.IdentifierToken, token.Kind); Diagnostics.ReportUnexpectedToken(TokenKind.IdentifierToken, token.Kind);
return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null); return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null);
} }
if (token.Text != s) if (token.Text != s)
{ {
Diagnostics.ReportUnexpectedToken(token.Span, TokenKind.IdentifierToken, token.Kind); Diagnostics.ReportUnexpectedToken(TokenKind.IdentifierToken, token.Kind);
return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null); return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null);
} }
@ -69,7 +76,7 @@ namespace Parser.Internal
return token; return token;
} }
private SyntaxToken PossiblyEatIdentifier(string s) private SyntaxToken? PossiblyEatIdentifier(string s)
{ {
var token = CurrentToken; var token = CurrentToken;
if (token.Kind == TokenKind.IdentifierToken && token.Text == s) if (token.Kind == TokenKind.IdentifierToken && token.Text == s)
@ -94,7 +101,7 @@ namespace Parser.Internal
new List<SyntaxTrivia>()); new List<SyntaxTrivia>());
} }
private SyntaxList ParseFunctionOutputList() private SyntaxList? ParseFunctionOutputList()
{ {
var outputs = new SyntaxListBuilder(); var outputs = new SyntaxListBuilder();
var firstToken = true; var firstToken = true;
@ -112,7 +119,7 @@ namespace Parser.Internal
return outputs.ToList(); return outputs.ToList();
} }
private FunctionOutputDescriptionSyntaxNode ParseFunctionOutputDescription() private FunctionOutputDescriptionSyntaxNode? ParseFunctionOutputDescription()
{ {
SyntaxToken assignmentSign; SyntaxToken assignmentSign;
var builder = new SyntaxListBuilder(); var builder = new SyntaxListBuilder();
@ -180,7 +187,7 @@ namespace Parser.Internal
return builder.ToList(); return builder.ToList();
} }
private FunctionInputDescriptionSyntaxNode ParseFunctionInputDescription() private FunctionInputDescriptionSyntaxNode? ParseFunctionInputDescription()
{ {
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
@ -206,7 +213,8 @@ namespace Parser.Internal
var inputDescription = ParseFunctionInputDescription(); var inputDescription = ParseFunctionInputDescription();
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var body = ParseStatementList(); var body = ParseStatementList();
var endKeyword = EatPossiblyMissingIdentifier("end"); var endKeyword = ParseEndKeyword();
//var endKeyword =
return Factory.FunctionDeclarationSyntax( return Factory.FunctionDeclarationSyntax(
functionKeyword, functionKeyword,
outputDescription, outputDescription,
@ -216,7 +224,13 @@ namespace Parser.Internal
body, body,
endKeyword); endKeyword);
} }
private EndKeywordSyntaxNode? ParseEndKeyword()
{
var keyword = EatPossiblyMissingIdentifier("end");
return keyword is null ? null : Factory.EndKeywordSyntax(keyword);
}
internal struct ParseOptions internal struct ParseOptions
{ {
public bool ParsingArrayElements { get; set; } public bool ParsingArrayElements { get; set; }
@ -224,12 +238,12 @@ namespace Parser.Internal
public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false }; public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false };
} }
private ExpressionSyntaxNode ParseExpression() private ExpressionSyntaxNode? ParseExpression()
{ {
return ParseExpression(ParseOptions.Default); return ParseExpression(ParseOptions.Default);
} }
private ExpressionSyntaxNode ParseExpression(ParseOptions options) private ExpressionSyntaxNode? ParseExpression(ParseOptions options)
{ {
return ParseSubExpression(options, SyntaxFacts.Precedence.Expression); return ParseSubExpression(options, SyntaxFacts.Precedence.Expression);
} }
@ -286,10 +300,10 @@ namespace Parser.Internal
return builder.ToList(); return builder.ToList();
} }
private ExpressionSyntaxNode ParseTerm(ParseOptions options) private ExpressionSyntaxNode? ParseTerm(ParseOptions options)
{ {
var token = CurrentToken; var token = CurrentToken;
ExpressionSyntaxNode expression = null; ExpressionSyntaxNode? expression = null;
switch (token.Kind) switch (token.Kind)
{ {
case TokenKind.NumberLiteralToken: case TokenKind.NumberLiteralToken:
@ -410,6 +424,11 @@ namespace Parser.Internal
return Factory.CommandExpressionSyntax(idNameNode, builder.ToList()); return Factory.CommandExpressionSyntax(idNameNode, builder.ToList());
} }
if (expression is null)
{
throw new Exception("Command expression identifier cannot be empty.");
}
throw new ParsingException($"Unexpected token \"{CurrentToken}\" while parsing expression \"{expression.FullText}\" at {CurrentPosition}."); throw new ParsingException($"Unexpected token \"{CurrentToken}\" while parsing expression \"{expression.FullText}\" at {CurrentPosition}.");
} }
@ -420,6 +439,10 @@ namespace Parser.Internal
{ {
var atToken = EatToken(); var atToken = EatToken();
var baseClassNameWithArguments = ParseExpression(); var baseClassNameWithArguments = ParseExpression();
if (baseClassNameWithArguments is null)
{
throw new Exception($"Base class name cannot be empty.");
}
return Factory.BaseClassInvokationSyntax(methodName, atToken, baseClassNameWithArguments); return Factory.BaseClassInvokationSyntax(methodName, atToken, baseClassNameWithArguments);
} }
if (expression is MemberAccessSyntaxNode memberAccess if (expression is MemberAccessSyntaxNode memberAccess
@ -427,6 +450,10 @@ namespace Parser.Internal
{ {
var atToken = EatToken(); var atToken = EatToken();
var baseClassNameWithArguments = ParseExpression(); var baseClassNameWithArguments = ParseExpression();
if (baseClassNameWithArguments is null)
{
throw new Exception($"Base class name cannot be empty.");
}
return Factory.BaseClassInvokationSyntax(memberAccess, atToken, baseClassNameWithArguments); return Factory.BaseClassInvokationSyntax(memberAccess, atToken, baseClassNameWithArguments);
} }
throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}."); throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}.");
@ -442,6 +469,10 @@ namespace Parser.Internal
{ {
var openingBracket = EatToken(); var openingBracket = EatToken();
var indirectMember = ParseExpression(); var indirectMember = ParseExpression();
if (indirectMember is null)
{
throw new Exception("Indirect member invokation cannot be empty.");
}
var closingBracket = EatToken(TokenKind.CloseParenthesisToken); var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
return Factory.IndirectMemberAccessSyntax( return Factory.IndirectMemberAccessSyntax(
openingBracket, openingBracket,
@ -466,7 +497,12 @@ namespace Parser.Internal
firstToken = false; firstToken = false;
} }
builder.Add(ParseExpression()); var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Function call parameter cannot be empty.");
}
builder.Add(expression);
} }
return builder.ToList(); return builder.ToList();
@ -476,6 +512,10 @@ namespace Parser.Internal
{ {
var openParen = EatToken(TokenKind.OpenParenthesisToken); var openParen = EatToken(TokenKind.OpenParenthesisToken);
var expression = ParseExpression(); var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Parenthesized expression cannot be empty.");
}
var closeParen = EatToken(TokenKind.CloseParenthesisToken); var closeParen = EatToken(TokenKind.CloseParenthesisToken);
return Factory.ParenthesizedExpressionSyntax( return Factory.ParenthesizedExpressionSyntax(
openParen, openParen,
@ -514,17 +554,25 @@ namespace Parser.Internal
else if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) else if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
var inputs = ParseFunctionInputDescription(); var inputs = ParseFunctionInputDescription();
if (inputs is null)
{
throw new Exception($"Lambda expression inputs cannot be empty.");
}
var body = ParseExpression(); var body = ParseExpression();
if (body is null)
{
throw new Exception($"Lambda expression body cannot be empty.");
}
return Factory.LambdaSyntax(atSign, inputs, body); return Factory.LambdaSyntax(atSign, inputs, body);
} }
throw new ParsingException($"Unexpected token {CurrentToken} while parsing function handle at {CurrentPosition}."); throw new ParsingException($"Unexpected token {CurrentToken} while parsing function handle at {CurrentPosition}.");
} }
private ExpressionSyntaxNode ParseSubExpression( private ExpressionSyntaxNode? ParseSubExpression(
ParseOptions options, ParseOptions options,
SyntaxFacts.Precedence precedence) SyntaxFacts.Precedence precedence)
{ {
ExpressionSyntaxNode lhs; ExpressionSyntaxNode? lhs;
if (SyntaxFacts.IsUnaryOperator(CurrentToken.Kind)) if (SyntaxFacts.IsUnaryOperator(CurrentToken.Kind))
{ {
var operation = EatToken(); var operation = EatToken();
@ -551,6 +599,10 @@ namespace Parser.Internal
else else
{ {
lhs = ParseTerm(options); lhs = ParseTerm(options);
if (lhs is null)
{
throw new Exception("Left-hand side in subexpression cannot be empty.");
}
} }
while (true) while (true)
@ -579,9 +631,10 @@ namespace Parser.Internal
} }
else else
{ {
rhs = null; throw new Exception("Right-hand side in subexpression cannot be empty.");
} }
} }
if (token.Kind == TokenKind.EqualsToken) if (token.Kind == TokenKind.EqualsToken)
{ {
lhs = Factory.AssignmentExpressionSyntax(lhs, token, rhs); lhs = Factory.AssignmentExpressionSyntax(lhs, token, rhs);
@ -627,6 +680,10 @@ namespace Parser.Internal
{ {
var caseKeyword = EatIdentifier("case"); var caseKeyword = EatIdentifier("case");
var caseId = ParseExpression(); var caseId = ParseExpression();
if (caseId is null)
{
throw new Exception("Case label cannot be empty.");
}
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var statementList = ParseStatementList(); var statementList = ParseStatementList();
return Factory.SwitchCaseSyntax(caseKeyword, caseId, commas, statementList); return Factory.SwitchCaseSyntax(caseKeyword, caseId, commas, statementList);
@ -636,6 +693,10 @@ namespace Parser.Internal
{ {
var switchKeyword = EatIdentifier("switch"); var switchKeyword = EatIdentifier("switch");
var expression = ParseExpression(); var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Match expression in switch statement cannot be empty.");
}
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var builder = new SyntaxListBuilder<SwitchCaseSyntaxNode>(); var builder = new SyntaxListBuilder<SwitchCaseSyntaxNode>();
while (IsIdentifier(CurrentToken, "case")) while (IsIdentifier(CurrentToken, "case"))
@ -655,6 +716,11 @@ namespace Parser.Internal
{ {
var whileKeyword = EatIdentifier("while"); var whileKeyword = EatIdentifier("while");
var condition = ParseExpression(); var condition = ParseExpression();
if (condition is null)
{
throw new Exception("Condition in while statement cannot be empty.");
}
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var body = ParseStatementList(); var body = ParseStatementList();
var endKeyword = EatIdentifier("end"); var endKeyword = EatIdentifier("end");
@ -670,6 +736,10 @@ namespace Parser.Internal
{ {
var elseifKeyword = EatIdentifier("elseif"); var elseifKeyword = EatIdentifier("elseif");
var condition = ParseExpression(); var condition = ParseExpression();
if (condition is null)
{
throw new Exception("Condition in elseif clause cannot be empty.");
}
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var body = ParseStatementList(); var body = ParseStatementList();
return Factory.ElseifClause(elseifKeyword, condition, commas, body); return Factory.ElseifClause(elseifKeyword, condition, commas, body);
@ -686,10 +756,14 @@ namespace Parser.Internal
{ {
var ifKeyword = EatIdentifier(); var ifKeyword = EatIdentifier();
var condition = ParseExpression(); var condition = ParseExpression();
if (condition is null)
{
throw new Exception("Condition in if statement cannot be empty.");
}
var commas = ParseOptionalSemicolonsOrCommas(); var commas = ParseOptionalSemicolonsOrCommas();
var body = ParseStatementList(); var body = ParseStatementList();
var elseifClauses = new SyntaxListBuilder<ElseifClause>(); var elseifClauses = new SyntaxListBuilder<ElseifClause>();
ElseClause elseClause = null; ElseClause? elseClause = null;
while (true) while (true)
{ {
var token = CurrentToken; var token = CurrentToken;
@ -740,7 +814,7 @@ namespace Parser.Internal
endKeyword); endKeyword);
} }
private CatchClauseSyntaxNode ParseCatchClause() private CatchClauseSyntaxNode? ParseCatchClause()
{ {
if (IsIdentifier(CurrentToken, "catch")) if (IsIdentifier(CurrentToken, "catch"))
{ {
@ -766,15 +840,24 @@ namespace Parser.Internal
private ExpressionStatementSyntaxNode ParseExpressionStatement() private ExpressionStatementSyntaxNode ParseExpressionStatement()
{ {
var expression = ParseExpression(); var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Expression statement cannot be empty.");
}
return Factory.ExpressionStatementSyntax(expression); return Factory.ExpressionStatementSyntax(expression);
} }
private AttributeAssignmentSyntaxNode ParseAttributeAssignment() private AttributeAssignmentSyntaxNode? ParseAttributeAssignment()
{ {
if (CurrentToken.Kind == TokenKind.EqualsToken) if (CurrentToken.Kind == TokenKind.EqualsToken)
{ {
var assignmentSign = EatToken(); var assignmentSign = EatToken();
var value = ParseExpression(); var value = ParseExpression();
if (value is null)
{
throw new Exception("Right-hand side in attribute assignment cannot be empty.");
}
return Factory.AttributeAssignmentSyntax(assignmentSign, value); return Factory.AttributeAssignmentSyntax(assignmentSign, value);
} }
@ -845,7 +928,7 @@ namespace Parser.Internal
var inputDescription = ParseFunctionInputDescription(); var inputDescription = ParseFunctionInputDescription();
var commas = ParseOptionalCommas(); var commas = ParseOptionalCommas();
var body = ParseStatementList(); var body = ParseStatementList();
var endKeyword = PossiblyEatIdentifier("end"); var endKeyword = ParseEndKeyword();
return Factory.MethodDefinitionSyntax( return Factory.MethodDefinitionSyntax(
functionKeyword, functionKeyword,
outputDescription, outputDescription,
@ -859,7 +942,7 @@ namespace Parser.Internal
private MethodsListSyntaxNode ParseMethods() private MethodsListSyntaxNode ParseMethods()
{ {
var methodsKeyword = EatToken(); var methodsKeyword = EatToken();
AttributeListSyntaxNode attributes = null; AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
attributes = ParseAttributesList(); attributes = ParseAttributesList();
@ -876,7 +959,7 @@ namespace Parser.Internal
return Factory.MethodsListSyntax(methodsKeyword, attributes, builder.ToList(), endKeyword); return Factory.MethodsListSyntax(methodsKeyword, attributes, builder.ToList(), endKeyword);
} }
private GreenNode ParsePropertyDeclaration() private GreenNode? ParsePropertyDeclaration()
{ {
if (CurrentToken.Kind == TokenKind.CommaToken) if (CurrentToken.Kind == TokenKind.CommaToken)
{ {
@ -885,7 +968,7 @@ namespace Parser.Internal
return ParseStatement(); return ParseStatement();
} }
private SyntaxNode ParseEventDeclaration() private SyntaxNode? ParseEventDeclaration()
{ {
return ParseStatement(); return ParseStatement();
} }
@ -893,7 +976,7 @@ namespace Parser.Internal
private PropertiesListSyntaxNode ParseProperties() private PropertiesListSyntaxNode ParseProperties()
{ {
var propertiesKeyword = EatToken(); var propertiesKeyword = EatToken();
AttributeListSyntaxNode attributes = null; AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
attributes = ParseAttributesList(); attributes = ParseAttributesList();
@ -902,14 +985,19 @@ namespace Parser.Internal
var builder = new SyntaxListBuilder(); var builder = new SyntaxListBuilder();
while (!IsIdentifier(CurrentToken, "end")) while (!IsIdentifier(CurrentToken, "end"))
{ {
builder.Add(ParsePropertyDeclaration()); var declaration = ParsePropertyDeclaration();
if (declaration is null)
{
throw new Exception("Property declaration cannot be null.");
}
builder.Add(declaration);
} }
var endKeyword = EatToken(); var endKeyword = EatToken();
return Factory.PropertiesListSyntax(propertiesKeyword, attributes, builder.ToList(), endKeyword); return Factory.PropertiesListSyntax(propertiesKeyword, attributes, builder.ToList(), endKeyword);
} }
private EnumerationItemValueSyntaxNode ParseEnumerationValue() private EnumerationItemValueSyntaxNode? ParseEnumerationValue()
{ {
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
@ -920,7 +1008,12 @@ namespace Parser.Internal
while (CurrentToken.Kind == TokenKind.CommaToken) while (CurrentToken.Kind == TokenKind.CommaToken)
{ {
builder.Add(EatToken()); builder.Add(EatToken());
builder.Add(ParseExpression()); var nextExpression = ParseExpression();
if (nextExpression is null)
{
throw new Exception("Enumeration identifier cannot be empty.");
}
builder.Add(nextExpression);
} }
var closingBracket = EatToken(TokenKind.CloseParenthesisToken); var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
return Factory.EnumerationItemValueSyntax(openingBracket, builder.ToList(), closingBracket); return Factory.EnumerationItemValueSyntax(openingBracket, builder.ToList(), closingBracket);
@ -940,7 +1033,7 @@ namespace Parser.Internal
{ {
var enumerationKeyword = EatToken(); var enumerationKeyword = EatToken();
var builder = new SyntaxListBuilder<EnumerationItemSyntaxNode>(); var builder = new SyntaxListBuilder<EnumerationItemSyntaxNode>();
AttributeListSyntaxNode attributes = null; AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
attributes = ParseAttributesList(); attributes = ParseAttributesList();
@ -962,7 +1055,7 @@ namespace Parser.Internal
private SyntaxNode ParseEvents() private SyntaxNode ParseEvents()
{ {
var eventsKeyword = EatToken(); var eventsKeyword = EatToken();
AttributeListSyntaxNode attributes = null; AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
attributes = ParseAttributesList(); attributes = ParseAttributesList();
@ -971,7 +1064,12 @@ namespace Parser.Internal
var builder = new SyntaxListBuilder(); var builder = new SyntaxListBuilder();
while (!IsIdentifier(CurrentToken, "end")) while (!IsIdentifier(CurrentToken, "end"))
{ {
builder.Add(ParseEventDeclaration()); var eventDeclaration = ParseEventDeclaration();
if (eventDeclaration is null)
{
throw new Exception("Event declaration cannot be empty.");
}
builder.Add(eventDeclaration);
} }
var endKeyword = EatToken(); var endKeyword = EatToken();
@ -1001,13 +1099,13 @@ namespace Parser.Internal
private StatementSyntaxNode ParseClassDeclaration() private StatementSyntaxNode ParseClassDeclaration()
{ {
var classdefKeyword = EatToken(); var classdefKeyword = EatToken();
AttributeListSyntaxNode attributes = null; AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken) if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{ {
attributes = ParseAttributesList(); attributes = ParseAttributesList();
} }
var className = Factory.IdentifierNameSyntax(EatToken(TokenKind.IdentifierToken)); var className = Factory.IdentifierNameSyntax(EatToken(TokenKind.IdentifierToken));
BaseClassListSyntaxNode baseClassList = null; BaseClassListSyntaxNode? baseClassList = null;
if (CurrentToken.Kind == TokenKind.LessToken) if (CurrentToken.Kind == TokenKind.LessToken)
{ {
baseClassList = ParseBaseClassList(); baseClassList = ParseBaseClassList();
@ -1052,7 +1150,7 @@ namespace Parser.Internal
endKeyword); endKeyword);
} }
private StatementSyntaxNode ParseStatement() private StatementSyntaxNode? ParseStatement()
{ {
if (CurrentToken.Kind == TokenKind.IdentifierToken) if (CurrentToken.Kind == TokenKind.IdentifierToken)
{ {
@ -1120,5 +1218,11 @@ namespace Parser.Internal
var endOfFileToken = EatToken(); var endOfFileToken = EatToken();
return Factory.FileSyntax(statementList, endOfFileToken); return Factory.FileSyntax(statementList, endOfFileToken);
} }
public RootSyntaxNode ParseRoot()
{
var file = ParseFile();
return Factory.RootSyntax(file);
}
} }
} }

View File

@ -1,3 +1,4 @@
#nullable enable
namespace Parser.Internal namespace Parser.Internal
{ {
internal partial class SyntaxFactory internal partial class SyntaxFactory
@ -13,12 +14,12 @@ namespace Parser.Internal
public FunctionDeclarationSyntaxNode FunctionDeclarationSyntax( public FunctionDeclarationSyntaxNode FunctionDeclarationSyntax(
SyntaxToken functionKeyword, SyntaxToken functionKeyword,
FunctionOutputDescriptionSyntaxNode outputDescription, FunctionOutputDescriptionSyntaxNode? outputDescription,
SyntaxToken name, SyntaxToken name,
FunctionInputDescriptionSyntaxNode inputDescription, FunctionInputDescriptionSyntaxNode? inputDescription,
SyntaxList<SyntaxToken> commas, SyntaxList<SyntaxToken> commas,
SyntaxList body, SyntaxList body,
SyntaxToken endKeyword) EndKeywordSyntaxNode? endKeyword)
{ {
return new FunctionDeclarationSyntaxNode( return new FunctionDeclarationSyntaxNode(
functionKeyword, functionKeyword,
@ -121,7 +122,7 @@ namespace Parser.Internal
SyntaxList<SyntaxToken> optionalCommas, SyntaxList<SyntaxToken> optionalCommas,
SyntaxList body, SyntaxList body,
SyntaxList<ElseifClause> elseifClauses, SyntaxList<ElseifClause> elseifClauses,
ElseClause elseClause, ElseClause? elseClause,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
return new IfStatementSyntaxNode( return new IfStatementSyntaxNode(
@ -172,7 +173,7 @@ namespace Parser.Internal
public TryCatchStatementSyntaxNode TryCatchStatementSyntax( public TryCatchStatementSyntaxNode TryCatchStatementSyntax(
SyntaxToken tryKeyword, SyntaxToken tryKeyword,
SyntaxList tryBody, SyntaxList tryBody,
CatchClauseSyntaxNode catchClause, CatchClauseSyntaxNode? catchClause,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
return new TryCatchStatementSyntaxNode( return new TryCatchStatementSyntaxNode(
@ -404,7 +405,7 @@ namespace Parser.Internal
public AttributeSyntaxNode AttributeSyntax( public AttributeSyntaxNode AttributeSyntax(
IdentifierNameSyntaxNode name, IdentifierNameSyntaxNode name,
AttributeAssignmentSyntaxNode assignment) AttributeAssignmentSyntaxNode? assignment)
{ {
return new AttributeSyntaxNode( return new AttributeSyntaxNode(
name, name,
@ -424,12 +425,12 @@ namespace Parser.Internal
public MethodDefinitionSyntaxNode MethodDefinitionSyntax( public MethodDefinitionSyntaxNode MethodDefinitionSyntax(
SyntaxToken functionKeyword, SyntaxToken functionKeyword,
FunctionOutputDescriptionSyntaxNode outputDescription, FunctionOutputDescriptionSyntaxNode? outputDescription,
CompoundNameSyntaxNode name, CompoundNameSyntaxNode name,
FunctionInputDescriptionSyntaxNode inputDescription, FunctionInputDescriptionSyntaxNode? inputDescription,
SyntaxList<SyntaxToken> commas, SyntaxList<SyntaxToken> commas,
SyntaxList body, SyntaxList body,
SyntaxToken endKeyword) EndKeywordSyntaxNode? endKeyword)
{ {
return new MethodDefinitionSyntaxNode( return new MethodDefinitionSyntaxNode(
functionKeyword, functionKeyword,
@ -442,9 +443,9 @@ namespace Parser.Internal
} }
public AbstractMethodDeclarationSyntaxNode AbstractMethodDeclarationSyntax( public AbstractMethodDeclarationSyntaxNode AbstractMethodDeclarationSyntax(
FunctionOutputDescriptionSyntaxNode outputDescription, FunctionOutputDescriptionSyntaxNode? outputDescription,
CompoundNameSyntaxNode name, CompoundNameSyntaxNode name,
FunctionInputDescriptionSyntaxNode inputDescription) FunctionInputDescriptionSyntaxNode? inputDescription)
{ {
return new AbstractMethodDeclarationSyntaxNode( return new AbstractMethodDeclarationSyntaxNode(
outputDescription, outputDescription,
@ -454,7 +455,7 @@ namespace Parser.Internal
public MethodsListSyntaxNode MethodsListSyntax( public MethodsListSyntaxNode MethodsListSyntax(
SyntaxToken methodsKeyword, SyntaxToken methodsKeyword,
AttributeListSyntaxNode attributes, AttributeListSyntaxNode? attributes,
SyntaxList methods, SyntaxList methods,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
@ -467,7 +468,7 @@ namespace Parser.Internal
public PropertiesListSyntaxNode PropertiesListSyntax( public PropertiesListSyntaxNode PropertiesListSyntax(
SyntaxToken propertiesKeyword, SyntaxToken propertiesKeyword,
AttributeListSyntaxNode attributes, AttributeListSyntaxNode? attributes,
SyntaxList properties, SyntaxList properties,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
@ -489,9 +490,9 @@ namespace Parser.Internal
public ClassDeclarationSyntaxNode ClassDeclarationSyntax( public ClassDeclarationSyntaxNode ClassDeclarationSyntax(
SyntaxToken classdefKeyword, SyntaxToken classdefKeyword,
AttributeListSyntaxNode attributes, AttributeListSyntaxNode? attributes,
IdentifierNameSyntaxNode className, IdentifierNameSyntaxNode className,
BaseClassListSyntaxNode baseClassList, BaseClassListSyntaxNode? baseClassList,
SyntaxList nodes, SyntaxList nodes,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
@ -517,7 +518,7 @@ namespace Parser.Internal
public EnumerationItemSyntaxNode EnumerationItemSyntax( public EnumerationItemSyntaxNode EnumerationItemSyntax(
IdentifierNameSyntaxNode name, IdentifierNameSyntaxNode name,
EnumerationItemValueSyntaxNode values, EnumerationItemValueSyntaxNode? values,
SyntaxList<SyntaxToken> commas) SyntaxList<SyntaxToken> commas)
{ {
return new EnumerationItemSyntaxNode( return new EnumerationItemSyntaxNode(
@ -528,7 +529,7 @@ namespace Parser.Internal
public EnumerationListSyntaxNode EnumerationListSyntax( public EnumerationListSyntaxNode EnumerationListSyntax(
SyntaxToken enumerationKeyword, SyntaxToken enumerationKeyword,
AttributeListSyntaxNode attributes, AttributeListSyntaxNode? attributes,
SyntaxList<EnumerationItemSyntaxNode> items, SyntaxList<EnumerationItemSyntaxNode> items,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
@ -541,7 +542,7 @@ namespace Parser.Internal
public EventsListSyntaxNode EventsListSyntax( public EventsListSyntaxNode EventsListSyntax(
SyntaxToken eventsKeyword, SyntaxToken eventsKeyword,
AttributeListSyntaxNode attributes, AttributeListSyntaxNode? attributes,
SyntaxList events, SyntaxList events,
SyntaxToken endKeyword) SyntaxToken endKeyword)
{ {
@ -551,5 +552,12 @@ namespace Parser.Internal
events, events,
endKeyword); endKeyword);
} }
public EndKeywordSyntaxNode EndKeywordSyntax(
SyntaxToken endKeyword)
{
return new EndKeywordSyntaxNode(
endKeyword);
}
} }
} }

View File

@ -2,5 +2,9 @@
{ {
internal partial class SyntaxFactory internal partial class SyntaxFactory
{ {
public RootSyntaxNode RootSyntax(FileSyntaxNode file)
{
return new RootSyntaxNode(file);
}
} }
} }

View File

@ -155,7 +155,7 @@ namespace Parser.Internal
} }
} }
private static readonly string[] StringFromKind = private static readonly string?[] StringFromKind =
{ {
null, // None = 0, null, // None = 0,
null, // BadToken = 1, null, // BadToken = 1,
@ -210,7 +210,7 @@ namespace Parser.Internal
"?", // UnaryQuestionMark = 60, "?", // UnaryQuestionMark = 60,
}; };
public static string GetText(TokenKind kind) public static string? GetText(TokenKind kind)
{ {
if ((int) kind < (int) TokenKind.File) if ((int) kind < (int) TokenKind.File)
{ {

View File

@ -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,21 +17,46 @@ namespace Parser.Internal
} }
} }
public override GreenNode GetSlot(int i) 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]; return _elements[i];
} }
public override GreenNode? GetSlot(int i)
{
return GetListSlot(i);
}
public static SyntaxList List(GreenNode[] elements) public static SyntaxList List(GreenNode[] elements)
{ {
return new SyntaxList(elements); return new SyntaxList(elements);
} }
public static SyntaxList EmptyList { get; } = new SyntaxList(new GreenNode[] { });
public override bool IsList => true; public override bool IsList => true;
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position) internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
{ {
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);
}
} }
} }

View File

@ -20,14 +20,14 @@ namespace Parser.Internal
{ {
for (var i = 0; i < list.Slots; i++) for (var i = 0; i < list.Slots; i++)
{ {
var element = list.GetSlot(i); var element = list.GetListSlot(i);
_list.Add(element); _list.Add(element);
} }
} }
public SyntaxList ToList() public SyntaxList ToList()
{ {
return _list.Count == 0 ? null : SyntaxList.List(_list.ToArray()); return _list.Count == 0 ? SyntaxList.EmptyList : SyntaxList.List(_list.ToArray());
} }
} }
} }

View File

@ -18,7 +18,7 @@ namespace Parser.Internal
public SyntaxList<T> ToList() public SyntaxList<T> ToList()
{ {
return _list.Count == 0 ? null : SyntaxList<T>.List(_list.ToArray()); return _list.Count == 0 ? SyntaxList<T>.Empty : SyntaxList<T>.List(_list.ToArray());
} }
} }

View File

@ -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,9 +16,19 @@
} }
} }
public override GreenNode GetSlot(int i) protected SyntaxList(T[] list, TokenDiagnostic[] diagnostics) : base(TokenKind.List, diagnostics)
{ {
return (T)_list.GetSlot(i); 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);
} }
public static SyntaxList<T> List(T[] elements) public static SyntaxList<T> List(T[] elements)
@ -24,11 +36,18 @@
return new SyntaxList<T>(elements); return new SyntaxList<T>(elements);
} }
public static SyntaxList<T> Empty => new SyntaxList<T>(new T[] { });
public override bool IsList => true; public override bool IsList => true;
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position) internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
{ {
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

View File

@ -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,13 +62,21 @@ 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
{ {
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,5 +95,47 @@ 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 readonly FileSyntaxNode _file;
public RootSyntaxNode(FileSyntaxNode file) : base(TokenKind.Root)
{
Slots = 1;
this.AdjustWidth(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)
{
switch (i)
{
case 0: return _file;
default: return null;
}
}
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);
}
} }
} }

View File

@ -7,12 +7,12 @@ namespace Parser.Internal
{ {
internal abstract class SyntaxToken : GreenNode internal abstract class SyntaxToken : GreenNode
{ {
public TextSpan Span { get; } internal static IReadOnlyList<SyntaxTrivia> s_EmptySyntaxTriviaList = new List<SyntaxTrivia>();
internal class SyntaxTokenWithTrivia : SyntaxToken internal class SyntaxTokenWithTrivia : SyntaxToken
{ {
private readonly string _text; private readonly string _text;
public SyntaxTokenWithTrivia( public SyntaxTokenWithTrivia(
TokenKind kind, TokenKind kind,
string text, 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); _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,10 +143,23 @@ 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; }
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
{ {
if (leading) 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 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;
@ -142,7 +219,7 @@ namespace Parser.Internal
{ {
private readonly IReadOnlyList<SyntaxTrivia> _leadingTrivia; private readonly IReadOnlyList<SyntaxTrivia> _leadingTrivia;
private readonly IReadOnlyList<SyntaxTrivia> _trailingTrivia; private readonly IReadOnlyList<SyntaxTrivia> _trailingTrivia;
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => _leadingTrivia; public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => _leadingTrivia;
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => _trailingTrivia; 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); _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,19 +284,39 @@ 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);
public virtual int Width => Text.Length; public virtual int Width => Text.Length;
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>(); public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>(); public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => s_EmptySyntaxTriviaList;
public override GreenNode GetSlot(int i) public override GreenNode? GetSlot(int i)
{ {
throw new System.InvalidOperationException(); throw new System.InvalidOperationException();
} }

View File

@ -14,10 +14,15 @@ 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;
public override GreenNode GetSlot(int i) public override GreenNode? GetSlot(int i)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
@ -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>();
} }

View 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; }
}
}

View File

@ -51,10 +51,10 @@ namespace Parser.Internal
public static SyntaxToken CreateMissing( public static SyntaxToken CreateMissing(
TokenKind kind, TokenKind kind,
IReadOnlyList<SyntaxTrivia> leadingTrivia, IReadOnlyList<SyntaxTrivia>? leadingTrivia,
IReadOnlyList<SyntaxTrivia> trailingTrivia) IReadOnlyList<SyntaxTrivia>? trailingTrivia)
{ {
return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia, trailingTrivia); return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList, trailingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList);
} }
} }
} }

View File

@ -20,23 +20,24 @@ namespace Parser
var lexerDiagnostics = lexer.Diagnostics; var lexerDiagnostics = lexer.Diagnostics;
var tokens = lexer.ParseAll(); var tokens = lexer.ParseAll();
var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory()); var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory());
var green = parser.ParseFile(); var green = parser.ParseRoot();
var parserDiagnostics = parser.Diagnostics; var parserDiagnostics = parser.Diagnostics;
var totalDiagnostics = new DiagnosticsBag(lexerDiagnostics.Concat(parserDiagnostics)); var totalDiagnostics = new DiagnosticsBag(lexerDiagnostics.Concat(parserDiagnostics));
var root = new FileSyntaxNode(null, green, 0); var root = new RootSyntaxNode(green, 0);
return new SyntaxTree(root, totalDiagnostics); return new SyntaxTree(root, totalDiagnostics);
} }
} }
public class SyntaxTree public class SyntaxTree
{ {
public SyntaxTree(FileSyntaxNode root, DiagnosticsBag diagnostics) public SyntaxTree(RootSyntaxNode nullRoot, DiagnosticsBag diagnostics)
{ {
Root = root ?? throw new ArgumentNullException(nameof(root)); NullRoot = nullRoot ?? throw new ArgumentNullException(nameof(nullRoot));
Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics)); Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
} }
public FileSyntaxNode Root { get; } public RootSyntaxNode NullRoot { get; }
public FileSyntaxNode Root => NullRoot.File;
public DiagnosticsBag Diagnostics { get; } public DiagnosticsBag Diagnostics { get; }
} }

View File

@ -0,0 +1,13 @@
namespace Parser
{
public class MissingTokenSyntaxDiagnostic : SyntaxDiagnostic
{
public TokenKind Kind { get; }
public MissingTokenSyntaxDiagnostic(int position, TokenKind tokenKind)
: base(position)
{
Kind = tokenKind;
}
}
}

View File

@ -1,6 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" /> <PackageReference Include="System.Collections.Immutable" Version="1.5.0" />

View File

@ -2,7 +2,7 @@
{ {
public struct Position public struct Position
{ {
public string FileName { get; set; } public string? FileName { get; set; }
public int Line { get; set; } public int Line { get; set; }
public int Column { get; set; } public int Column { get; set; }
public int Offset { get; set; } public int Offset { get; set; }

View File

@ -0,0 +1,23 @@
namespace Parser
{
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;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ namespace Parser
public abstract class SyntaxNode public abstract class SyntaxNode
{ {
private readonly SyntaxNode _parent; private readonly SyntaxNode _parent;
internal readonly Internal.GreenNode _green; internal readonly Internal.GreenNode _green;
internal SyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) internal SyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position)
{ {
_parent = parent; _parent = parent;
@ -15,6 +15,13 @@ namespace Parser
Position = position; Position = position;
} }
private protected SyntaxNode(Internal.GreenNode green, int position)
{
_parent = this;
_green = green;
Position = position;
}
public TokenKind Kind => _green.Kind; public TokenKind Kind => _green.Kind;
public SyntaxNode Parent => _parent; public SyntaxNode Parent => _parent;
@ -43,9 +50,9 @@ namespace Parser
return result; return result;
} }
internal abstract SyntaxNode GetNode(int index); internal abstract SyntaxNode? GetNode(int index);
internal SyntaxNode GetRed(ref SyntaxNode field, int slot) internal SyntaxNode? GetRed(ref SyntaxNode? field, int slot)
{ {
if (field == null) if (field == null)
{ {
@ -89,6 +96,35 @@ 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 abstract class StatementSyntaxNode : SyntaxNode public abstract class StatementSyntaxNode : SyntaxNode
@ -119,4 +155,35 @@ namespace Parser
} }
} }
public class RootSyntaxNode : SyntaxNode
{
private SyntaxNode? _file;
internal RootSyntaxNode(Internal.GreenNode green, int position) : base(green, position)
{
}
internal override SyntaxNode? GetNode(int index)
{
throw new System.NotImplementedException();
}
public override void Accept(SyntaxVisitor visitor)
{
throw new System.NotImplementedException();
}
public FileSyntaxNode File
{
get
{
var red = this.GetRed(ref this._file, 0);
if (red != null)
return (FileSyntaxNode)red;
throw new System.Exception("file cannot be null");
}
}
}
} }

View File

@ -2,7 +2,7 @@
{ {
public struct SyntaxNodeOrToken public struct SyntaxNodeOrToken
{ {
private readonly Internal.GreenNode _token; private readonly Internal.GreenNode? _token;
private readonly SyntaxNode _nodeOrParent; private readonly SyntaxNode _nodeOrParent;
private readonly bool _isToken; private readonly bool _isToken;
@ -27,7 +27,7 @@
public int Position { get; } public int Position { get; }
public SyntaxNode AsNode() public SyntaxNode? AsNode()
{ {
if (_isToken) if (_isToken)
{ {
@ -43,7 +43,7 @@
{ {
return default(SyntaxToken); return default(SyntaxToken);
} }
return new SyntaxToken(_nodeOrParent, _token, Position); return new SyntaxToken(_nodeOrParent, _token!, Position);
} }
public static implicit operator SyntaxNodeOrToken(SyntaxToken token) public static implicit operator SyntaxNodeOrToken(SyntaxToken token)

View File

@ -24,7 +24,7 @@ namespace Parser
} }
else else
{ {
return green.CreateRed(this, this.GetChildPosition(index)); return green!.CreateRed(this, this.GetChildPosition(index));
} }
} }
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@ -81,7 +81,7 @@ namespace Parser
public int Count => _green.Slots; public int Count => _green.Slots;
internal override SyntaxNode GetNode(int index) internal override SyntaxNode? GetNode(int index)
{ {
if (index < _green.Slots) if (index < _green.Slots)
{ {

View File

@ -12,7 +12,7 @@ namespace Parser
public TokenKind Kind => _token.Kind; public TokenKind Kind => _token.Kind;
public override string ToString() public override string? ToString()
{ {
return _token.ToString(); return _token.ToString();
} }
@ -34,7 +34,7 @@ namespace Parser
return Equals(_parent, other._parent) && Equals(_token, other._token); return Equals(_parent, other._parent) && Equals(_token, other._token);
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(null, obj)) return false;
return obj is SyntaxToken token && Equals(token); return obj is SyntaxToken token && Equals(token);

View File

@ -22,7 +22,7 @@ namespace Parser
return Equals(_parent, other._parent) && Equals(_trivia, other._trivia); return Equals(_parent, other._parent) && Equals(_trivia, other._trivia);
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(null, obj)) return false;
return obj is SyntaxTrivia trivia && Equals(trivia); return obj is SyntaxTrivia trivia && Equals(trivia);

View File

@ -1,3 +1,4 @@
#nullable enable
namespace Parser namespace Parser
{ {
public partial class SyntaxVisitor public partial class SyntaxVisitor
@ -251,5 +252,10 @@ namespace Parser
{ {
DefaultVisit(node); DefaultVisit(node);
} }
public virtual void VisitEndKeyword(EndKeywordSyntaxNode node)
{
DefaultVisit(node);
}
} }
}; };

View File

@ -2,7 +2,7 @@
{ {
public abstract partial class SyntaxVisitor public abstract partial class SyntaxVisitor
{ {
public virtual void Visit(SyntaxNode node) public virtual void Visit(SyntaxNode? node)
{ {
node?.Accept(this); node?.Accept(this);
} }

View File

@ -6,7 +6,7 @@
private Position _position; private Position _position;
public Position Position => _position; public Position Position => _position;
public TextWindow(string text, string fileName = null) public TextWindow(string text, string? fileName = null)
{ {
Text = text; Text = text;
_position = new Position _position = new Position

View File

@ -2,7 +2,7 @@
{ {
public class TextWindowWithNull : TextWindow public class TextWindowWithNull : TextWindow
{ {
public TextWindowWithNull(string text, string fileName = null) : base(text, fileName) public TextWindowWithNull(string text, string? fileName = null) : base(text, fileName)
{ {
} }

View File

@ -271,5 +271,7 @@
// ToggleSomething // ToggleSomething
// end // end
EventsList, EventsList,
EndKeyword,
Root
} }
} }

View File

@ -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>

View File

@ -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" />

View File

@ -15,7 +15,7 @@ namespace SyntaxGenerator
private static readonly List<(string visitorMethodName, string className)> Visitors = new List<(string, string)>(); private static readonly List<(string visitorMethodName, string className)> Visitors = new List<(string, string)>();
private static string _outputPath; private static readonly string _outputPath;
static GenerateSyntax() static GenerateSyntax()
{ {
@ -62,12 +62,14 @@ namespace SyntaxGenerator
private static string GenerateInternalFieldDeclaration(FieldDescription field) private static string GenerateInternalFieldDeclaration(FieldDescription field)
{ {
return $" internal readonly {field.FieldType} _{field.FieldName};\n"; return $" internal readonly {FullFieldType(field)} _{field.FieldName};\n";
} }
private static string GeneratePrivateFieldDeclaration(FieldDescription field) private static string GeneratePrivateFieldDeclaration(FieldDescription field)
{ {
return $" private SyntaxNode _{field.FieldName};\n"; //var typeDeclaration = field.FieldIsNullable ? "SyntaxNode?" : "SyntaxNode";
var typeDeclaration = "SyntaxNode?";
return $" private {typeDeclaration} _{field.FieldName};\n";
} }
private static string GenerateFieldAssignmentInsideConstructor(FieldDescription field) private static string GenerateFieldAssignmentInsideConstructor(FieldDescription field)
@ -76,20 +78,41 @@ namespace SyntaxGenerator
var fieldAssignment = $" _{field.FieldName} = {field.FieldName};\n"; var fieldAssignment = $" _{field.FieldName} = {field.FieldName};\n";
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(
",", ",",
node.Fields.Select(field => $"\n {field.FieldType} {field.FieldName}")); node.Fields.Select(field => $"\n {FullFieldType(field)} {field.FieldName}"));
var header = var header =
$" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName})\n"; $" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName})";
var slotsAssignment = $"\n Slots = {node.Fields.Length};\n"; var slotsAssignment = $" Slots = {node.Fields.Length};";
var assignments = string.Join( var assignments = string.Join(
"", "",
node.Fields.Select(GenerateFieldAssignmentInsideConstructor)); node.Fields.Select(GenerateFieldAssignmentInsideConstructor));
return header + " {\n" + slotsAssignment + 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)
@ -100,9 +123,21 @@ 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";
var cases = string.Join( var cases = string.Join(
"", "",
node.Fields.Select((f, i) => $" case {i}: return _{f.FieldName};\n")); node.Fields.Select((f, i) => $" case {i}: return _{f.FieldName};\n"));
@ -117,10 +152,16 @@ namespace SyntaxGenerator
private static string GenerateGetSlot(SyntaxNodeDescription node, List<(FieldDescription field, int index)> pairs) private static string GenerateGetSlot(SyntaxNodeDescription node, List<(FieldDescription field, int index)> pairs)
{ {
var header = $" internal override SyntaxNode GetNode(int i)\n"; var header = $" internal override SyntaxNode? GetNode(int i)\n";
string GetFieldNameWithPossibleBang(FieldDescription field)
{
return field.FieldIsNullable ? field.FieldName : field.FieldName + "!";
}
var cases = string.Join( var cases = string.Join(
"", "",
pairs.Select(pair => $" case {pair.index}: return GetRed(ref _{pair.field.FieldName}, {pair.index});\n")); pairs.Select(pair => $" case {pair.index}: return GetRed(ref _{GetFieldNameWithPossibleBang(pair.field)}, {pair.index});\n"));
var defaultCase = " default: return null;\n"; var defaultCase = " default: return null;\n";
return header return header
+ " {\n switch (i)\n {\n" + " {\n switch (i)\n {\n"
@ -148,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";
} }
@ -185,12 +228,17 @@ namespace SyntaxGenerator
{ {
type = "SyntaxNodeOrTokenList"; type = "SyntaxNodeOrTokenList";
} }
var header = $" public {type} {Capitalize(field.FieldName)}\n {{\n get\n {{\n";
var typeName = type + (field.FieldIsNullable ? "?" : "");
var header = $" public {typeName} {Capitalize(field.FieldName)}\n {{\n get\n {{\n";
var defaultReturnStatement = field.FieldIsNullable ? $"return default({type});" : $"throw new System.Exception(\"{field.FieldName} cannot be null\");";
var fieldNameWithPossibleBang = field.FieldIsNullable ? field.FieldName : field.FieldName + "!";
var text = var text =
$" var red = this.GetRed(ref this._{field.FieldName}, {index});\n" $" var red = this.GetRed(ref this._{fieldNameWithPossibleBang}, {index});\n"
+ $" if (red != null)\n" + $" if (red != null)\n"
+ $" return ({type})red;\n\n" + $" return ({type})red;\n\n"
+ $" return default({type});\n"; + $" {defaultReturnStatement}\n";
return header + text + " }\n }\n"; return header + text + " }\n }\n";
} }
@ -257,7 +305,7 @@ namespace SyntaxGenerator
private static string GenerateInternalSyntaxNodeFile(SyntaxDescription syntax) private static string GenerateInternalSyntaxNodeFile(SyntaxDescription syntax)
{ {
var header = $"namespace {InternalNamespace}\n"; var header = $"#nullable enable\nnamespace {InternalNamespace}\n";
var classes = string.Join( var classes = string.Join(
"\n", "\n",
syntax.Nodes.Select(GenerateInternalClass) syntax.Nodes.Select(GenerateInternalClass)
@ -267,7 +315,7 @@ namespace SyntaxGenerator
private static string GenerateSyntaxNodeFile(SyntaxDescription syntax) private static string GenerateSyntaxNodeFile(SyntaxDescription syntax)
{ {
var header = $"namespace {OuterNamespace}\n"; var header = $"#nullable enable\nnamespace {OuterNamespace}\n";
var classes = string.Join( var classes = string.Join(
"\n", "\n",
syntax.Nodes.Select(GenerateClass) syntax.Nodes.Select(GenerateClass)
@ -287,13 +335,18 @@ namespace SyntaxGenerator
} }
} }
private static string FullFieldType(FieldDescription field)
{
return field.FieldIsNullable ? field.FieldType + "?" : field.FieldType;
}
private static string GenerateFactoryMethod(SyntaxNodeDescription node) private static string GenerateFactoryMethod(SyntaxNodeDescription node)
{ {
var methodName = FactoryMethodNameFromClassName(node.ClassName); var methodName = FactoryMethodNameFromClassName(node.ClassName);
var header = $" public {node.ClassName} {methodName}"; var header = $" public {node.ClassName} {methodName}";
var arguments = string.Join( var arguments = string.Join(
", ", ", ",
node.Fields.Select(field => $"\n {field.FieldType} {field.FieldName}")); node.Fields.Select(field => $"\n {FullFieldType(field)} {field.FieldName}"));
var constructorParameters = string.Join( var constructorParameters = string.Join(
", ", ", ",
node.Fields.Select(field => $"\n {field.FieldName}")); node.Fields.Select(field => $"\n {field.FieldName}"));
@ -305,7 +358,7 @@ namespace SyntaxGenerator
private static string GenerateSyntaxFactoryFile(SyntaxDescription syntax) private static string GenerateSyntaxFactoryFile(SyntaxDescription syntax)
{ {
var header = $"namespace {InternalNamespace}\n{{\n internal partial class SyntaxFactory\n"; var header = $"#nullable enable\nnamespace {InternalNamespace}\n{{\n internal partial class SyntaxFactory\n";
var methods = string.Join( var methods = string.Join(
"\n", "\n",
syntax.Nodes.Select(GenerateFactoryMethod) syntax.Nodes.Select(GenerateFactoryMethod)
@ -322,7 +375,7 @@ namespace SyntaxGenerator
private static string GenerateSyntaxVisitorFile(SyntaxDescription syntax) private static string GenerateSyntaxVisitorFile(SyntaxDescription syntax)
{ {
var header = $"namespace {OuterNamespace}\n{{\n public partial class SyntaxVisitor\n"; var header = $"#nullable enable\nnamespace {OuterNamespace}\n{{\n public partial class SyntaxVisitor\n";
var methods = string.Join( var methods = string.Join(
"\n", "\n",
Visitors.Select(GenerateVisitor)); Visitors.Select(GenerateVisitor));
@ -335,8 +388,7 @@ namespace SyntaxGenerator
var serializer = new XmlSerializer(typeof(SyntaxDescription)); var serializer = new XmlSerializer(typeof(SyntaxDescription));
using (var stream = new FileStream("input.xml", FileMode.Open)) using (var stream = new FileStream("input.xml", FileMode.Open))
{ {
var syntax = serializer.Deserialize(stream) as SyntaxDescription; if (!(serializer.Deserialize(stream) is SyntaxDescription syntax))
if (syntax == null)
{ {
Console.WriteLine("Couldn't deserialize syntax."); Console.WriteLine("Couldn't deserialize syntax.");
return; return;

View File

@ -34,5 +34,7 @@ namespace SyntaxGenerator
public string FieldType { get; set; } public string FieldType { get; set; }
[XmlAttribute("Name")] [XmlAttribute("Name")]
public string FieldName { get; set; } public string FieldName { get; set; }
[XmlAttribute("Nullable")]
public bool FieldIsNullable { get; set; }
} }
} }

View File

@ -6,12 +6,12 @@
</Class> </Class>
<Class Name="FunctionDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="FunctionDeclaration"> <Class Name="FunctionDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="FunctionDeclaration">
<Field Type="SyntaxToken" Name="functionKeyword" /> <Field Type="SyntaxToken" Name="functionKeyword" />
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" /> <Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" Nullable="true" />
<Field Type="SyntaxToken" Name="name" /> <Field Type="SyntaxToken" Name="name" />
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" /> <Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
<Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" /> <Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" />
<Field Type="SyntaxList" Name="body" /> <Field Type="SyntaxList" Name="body" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="EndKeywordSyntaxNode" Name="endKeyword" Nullable="true"/>
</Class> </Class>
<Class Name="FunctionOutputDescriptionSyntaxNode" BaseClass="SyntaxNode" Kind="FunctionOutputDescription"> <Class Name="FunctionOutputDescriptionSyntaxNode" BaseClass="SyntaxNode" Kind="FunctionOutputDescription">
<Field Type="SyntaxList" Name="outputList" /> <Field Type="SyntaxList" Name="outputList" />
@ -58,7 +58,7 @@
<Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="optionalCommas" /> <Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="optionalCommas" />
<Field Type="SyntaxList" Name="body" /> <Field Type="SyntaxList" Name="body" />
<Field Type="SyntaxList&lt;ElseifClause&gt;" Name="elseifClauses" /> <Field Type="SyntaxList&lt;ElseifClause&gt;" Name="elseifClauses" />
<Field Type="ElseClause" Name="elseClause" /> <Field Type="ElseClause" Name="elseClause" Nullable="true" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
<Class Name="ForStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ForStatement"> <Class Name="ForStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ForStatement">
@ -80,7 +80,7 @@
<Class Name="TryCatchStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="TryCatchStatement"> <Class Name="TryCatchStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="TryCatchStatement">
<Field Type="SyntaxToken" Name="tryKeyword" /> <Field Type="SyntaxToken" Name="tryKeyword" />
<Field Type="SyntaxList" Name="tryBody" /> <Field Type="SyntaxList" Name="tryBody" />
<Field Type="CatchClauseSyntaxNode" Name="catchClause" /> <Field Type="CatchClauseSyntaxNode" Name="catchClause" Nullable="true" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
<Class Name="ExpressionStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ExpressionStatement"> <Class Name="ExpressionStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ExpressionStatement">
@ -183,7 +183,7 @@
</Class> </Class>
<Class Name="AttributeSyntaxNode" BaseClass="SyntaxNode" Kind="Attribute"> <Class Name="AttributeSyntaxNode" BaseClass="SyntaxNode" Kind="Attribute">
<Field Type="IdentifierNameSyntaxNode" Name="name" /> <Field Type="IdentifierNameSyntaxNode" Name="name" />
<Field Type="AttributeAssignmentSyntaxNode" Name="assignment" /> <Field Type="AttributeAssignmentSyntaxNode" Name="assignment" Nullable="true" />
</Class> </Class>
<Class Name="AttributeListSyntaxNode" BaseClass="SyntaxNode" Kind="AttributeList"> <Class Name="AttributeListSyntaxNode" BaseClass="SyntaxNode" Kind="AttributeList">
<Field Type="SyntaxToken" Name="openingBracket" /> <Field Type="SyntaxToken" Name="openingBracket" />
@ -192,27 +192,27 @@
</Class> </Class>
<Class Name="MethodDefinitionSyntaxNode" BaseClass="MethodDeclarationSyntaxNode" Kind="MethodDefinition"> <Class Name="MethodDefinitionSyntaxNode" BaseClass="MethodDeclarationSyntaxNode" Kind="MethodDefinition">
<Field Type="SyntaxToken" Name="functionKeyword" /> <Field Type="SyntaxToken" Name="functionKeyword" />
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" /> <Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" Nullable="true" />
<Field Type="CompoundNameSyntaxNode" Name="name" /> <Field Type="CompoundNameSyntaxNode" Name="name" />
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" /> <Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
<Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" /> <Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" />
<Field Type="SyntaxList" Name="body" /> <Field Type="SyntaxList" Name="body" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="EndKeywordSyntaxNode" Name="endKeyword" Nullable="true" />
</Class> </Class>
<Class Name="AbstractMethodDeclarationSyntaxNode" BaseClass="MethodDeclarationSyntaxNode" Kind="AbstractMethodDeclaration"> <Class Name="AbstractMethodDeclarationSyntaxNode" BaseClass="MethodDeclarationSyntaxNode" Kind="AbstractMethodDeclaration">
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" /> <Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" Nullable="true" />
<Field Type="CompoundNameSyntaxNode" Name="name" /> <Field Type="CompoundNameSyntaxNode" Name="name" />
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" /> <Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
</Class> </Class>
<Class Name="MethodsListSyntaxNode" BaseClass="SyntaxNode" Kind="MethodsList"> <Class Name="MethodsListSyntaxNode" BaseClass="SyntaxNode" Kind="MethodsList">
<Field Type="SyntaxToken" Name="methodsKeyword" /> <Field Type="SyntaxToken" Name="methodsKeyword" />
<Field Type="AttributeListSyntaxNode" Name="attributes" /> <Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
<Field Type="SyntaxList" Name="methods" /> <Field Type="SyntaxList" Name="methods" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
<Class Name="PropertiesListSyntaxNode" BaseClass="SyntaxNode" Kind="PropertiesList"> <Class Name="PropertiesListSyntaxNode" BaseClass="SyntaxNode" Kind="PropertiesList">
<Field Type="SyntaxToken" Name="propertiesKeyword" /> <Field Type="SyntaxToken" Name="propertiesKeyword" />
<Field Type="AttributeListSyntaxNode" Name="attributes" /> <Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
<Field Type="SyntaxList" Name="properties" /> <Field Type="SyntaxList" Name="properties" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
@ -222,9 +222,9 @@
</Class> </Class>
<Class Name="ClassDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ClassDeclaration"> <Class Name="ClassDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ClassDeclaration">
<Field Type="SyntaxToken" Name="classdefKeyword" /> <Field Type="SyntaxToken" Name="classdefKeyword" />
<Field Type="AttributeListSyntaxNode" Name="attributes" /> <Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
<Field Type="IdentifierNameSyntaxNode" Name="className" /> <Field Type="IdentifierNameSyntaxNode" Name="className" />
<Field Type="BaseClassListSyntaxNode" Name="baseClassList" /> <Field Type="BaseClassListSyntaxNode" Name="baseClassList" Nullable="true" />
<Field Type="SyntaxList" Name="nodes" /> <Field Type="SyntaxList" Name="nodes" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
@ -235,19 +235,22 @@
</Class> </Class>
<Class Name="EnumerationItemSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationItem"> <Class Name="EnumerationItemSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationItem">
<Field Type="IdentifierNameSyntaxNode" Name="name" /> <Field Type="IdentifierNameSyntaxNode" Name="name" />
<Field Type="EnumerationItemValueSyntaxNode" Name="values" /> <Field Type="EnumerationItemValueSyntaxNode" Name="values" Nullable="true"/>
<Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" /> <Field Type="SyntaxList&lt;SyntaxToken&gt;" Name="commas" />
</Class> </Class>
<Class Name="EnumerationListSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationList"> <Class Name="EnumerationListSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationList">
<Field Type="SyntaxToken" Name="enumerationKeyword" /> <Field Type="SyntaxToken" Name="enumerationKeyword" />
<Field Type="AttributeListSyntaxNode" Name="attributes" /> <Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true"/>
<Field Type="SyntaxList&lt;EnumerationItemSyntaxNode&gt;" Name="items" /> <Field Type="SyntaxList&lt;EnumerationItemSyntaxNode&gt;" Name="items" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
<Class Name="EventsListSyntaxNode" BaseClass="SyntaxNode" Kind="EventsList"> <Class Name="EventsListSyntaxNode" BaseClass="SyntaxNode" Kind="EventsList">
<Field Type="SyntaxToken" Name="eventsKeyword" /> <Field Type="SyntaxToken" Name="eventsKeyword" />
<Field Type="AttributeListSyntaxNode" Name="attributes" /> <Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
<Field Type="SyntaxList" Name="events" /> <Field Type="SyntaxList" Name="events" />
<Field Type="SyntaxToken" Name="endKeyword" /> <Field Type="SyntaxToken" Name="endKeyword" />
</Class> </Class>
<Class Name="EndKeywordSyntaxNode" BaseClass="SyntaxNode" Kind="EndKeyword">
<Field Type="SyntaxToken" Name="endKeyword" />
</Class>
</Syntax> </Syntax>