Merge pull request #1 from mahalex/nullable-reference-types
Nullable reference types
This commit is contained in:
commit
9f84f64a58
@ -196,6 +196,11 @@ namespace ProjectConsole
|
||||
Visit(node.InputDescription);
|
||||
Visit(node.Commas);
|
||||
Visit(node.Body);
|
||||
Visit(node.EndKeyword);
|
||||
}
|
||||
|
||||
public override void VisitEndKeyword(EndKeywordSyntaxNode node)
|
||||
{
|
||||
OutputKeyword(node.EndKeyword);
|
||||
}
|
||||
|
||||
@ -207,7 +212,7 @@ namespace ProjectConsole
|
||||
Visit(node.InputDescription);
|
||||
Visit(node.Commas);
|
||||
Visit(node.Body);
|
||||
OutputKeyword(node.EndKeyword);
|
||||
Visit(node.EndKeyword);
|
||||
}
|
||||
|
||||
public override void VisitIfStatement(IfStatementSyntaxNode node)
|
||||
|
47
Parser.Tests/DiagnosticExtensions.cs
Normal file
47
Parser.Tests/DiagnosticExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[MemberData(nameof(SingleTokensData))]
|
||||
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
public void MLexerGreen_Parses_Token(TokenKind kind, string text)
|
||||
{
|
||||
var tokens = ParseText(text);
|
||||
@ -24,7 +26,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[MemberData(nameof(PairTokensData))]
|
||||
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
public void MLexerGreen_Parses_PairOfTokens(TokenKind kind1, string text1, TokenKind kind2, string text2)
|
||||
{
|
||||
var text = text1 + text2;
|
||||
@ -35,7 +39,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[MemberData(nameof(PairTokensWithSeparatorData))]
|
||||
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
public void MLexerGreen_Parses_PairOfTokensWithSeparator(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)
|
||||
{
|
||||
var text = text1 + separatorText + text2;
|
||||
@ -78,17 +84,17 @@ namespace Parser.Tests
|
||||
|
||||
public static IEnumerable<(TokenKind kind, string text)> GetTokens()
|
||||
{
|
||||
var fixedTokens = Enum.GetValues(typeof(TokenKind))
|
||||
.Cast<TokenKind>()
|
||||
.Select(k => (kind: k, text: SyntaxFacts.GetText(k)))
|
||||
.Where(t => !(t.text is null))
|
||||
.Where(t => !(SyntaxFacts.IsUnaryTokenKind(t.kind)
|
||||
|| SyntaxFacts.IsOpeningToken(t.kind)
|
||||
|| SyntaxFacts.IsClosingToken(t.kind)
|
||||
|| t.kind == TokenKind.ApostropheToken));
|
||||
var fixedTokens =
|
||||
from TokenKind kind in Enum.GetValues(typeof(TokenKind))
|
||||
let text = SyntaxFacts.GetText(kind)
|
||||
where !(text is null)
|
||||
where !(SyntaxFacts.IsUnaryTokenKind(kind)
|
||||
|| SyntaxFacts.IsOpeningToken(kind)
|
||||
|| SyntaxFacts.IsClosingToken(kind)
|
||||
|| kind == TokenKind.ApostropheToken)
|
||||
select (kind, text);
|
||||
|
||||
|
||||
var dynamicTokens = new[]
|
||||
var dynamicTokens = new[]
|
||||
{
|
||||
(TokenKind.IdentifierToken, "a"),
|
||||
(TokenKind.IdentifierToken, "abc"),
|
||||
@ -105,33 +111,21 @@ namespace Parser.Tests
|
||||
|
||||
public static IEnumerable<(TokenKind kind1, string text1, TokenKind kind2, string text2)> GetPairsOfTokens()
|
||||
{
|
||||
foreach (var token1 in GetTokens())
|
||||
{
|
||||
foreach (var token2 in GetTokens())
|
||||
{
|
||||
if (!RequiresSeparator(token1.kind, token2.kind))
|
||||
{
|
||||
yield return (token1.kind, token1.text, token2.kind, token2.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
from token1 in GetTokens()
|
||||
from token2 in GetTokens()
|
||||
where !RequiresSeparator(token1.kind, token2.kind)
|
||||
select (token1.kind, token1.text, token2.kind, token2.text);
|
||||
}
|
||||
|
||||
public static IEnumerable<(TokenKind kind1, string text1, string separatorText, TokenKind kind2, string text2)> GetPairsOfTokensWithSeparators()
|
||||
{
|
||||
foreach (var token1 in GetTokens())
|
||||
{
|
||||
foreach (var token2 in GetTokens())
|
||||
{
|
||||
if (RequiresSeparator(token1.kind, token2.kind))
|
||||
{
|
||||
foreach (var separatorText in GetSeparators())
|
||||
{
|
||||
yield return (token1.kind, token1.text, separatorText, token2.kind, token2.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
from token1 in GetTokens()
|
||||
from token2 in GetTokens()
|
||||
where RequiresSeparator(token1.kind, token2.kind)
|
||||
from separatorText in GetSeparators()
|
||||
select (token1.kind, token1.text, separatorText, token2.kind, token2.text);
|
||||
}
|
||||
|
||||
private static bool RequiresSeparator(TokenKind kind1, TokenKind kind2)
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Parser.Tests
|
||||
{
|
||||
using static DiagnosticExtensions;
|
||||
|
||||
public class MParserShould
|
||||
{
|
||||
private static MParser GetSut(string text)
|
||||
@ -19,6 +21,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||
}
|
||||
|
||||
@ -30,6 +37,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var statement = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||
if (statement is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement).Expression);
|
||||
}
|
||||
|
||||
@ -41,6 +53,11 @@ namespace Parser.Tests
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
Assert.IsType<AssignmentExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)assignment).Expression);
|
||||
}
|
||||
|
||||
@ -50,7 +67,8 @@ namespace Parser.Tests
|
||||
{
|
||||
var sut = GetSut(text);
|
||||
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]
|
||||
@ -60,8 +78,8 @@ namespace Parser.Tests
|
||||
var sut = GetSut(text);
|
||||
var actual = sut.Parse();
|
||||
var statement = actual.Root.StatementList[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||
var expression = statement.Expression as BinaryOperationExpressionSyntaxNode;
|
||||
var lhs = expression.Lhs;
|
||||
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||
var lhs = expression!.Lhs;
|
||||
var operation = expression.Operation;
|
||||
var rhs = expression.Rhs;
|
||||
Assert.Equal(0, lhs.Position);
|
||||
|
@ -2,11 +2,16 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||
|
@ -44,7 +44,9 @@ namespace Parser.Tests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
#pragma warning disable xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
[MemberData(nameof(FilesData))]
|
||||
#pragma warning restore xUnit1019 // MemberData must reference a member providing a valid data type
|
||||
public void TestFile(string fileName)
|
||||
{
|
||||
var text = File.ReadAllText(fileName);
|
||||
|
@ -68,7 +68,7 @@ namespace Parser
|
||||
internal SyntaxNodeOrToken ThisInternal(int index)
|
||||
{
|
||||
var currentSlotIndex = 0;
|
||||
GreenNode currentSlot = null;
|
||||
GreenNode? currentSlot = null;
|
||||
while (true)
|
||||
{
|
||||
currentSlot = _node._green.GetSlot(currentSlotIndex);
|
||||
@ -84,13 +84,17 @@ namespace Parser
|
||||
if (currentSlot.IsList)
|
||||
{
|
||||
var listSlot = _node.GetNode(currentSlotIndex);
|
||||
if (listSlot is null)
|
||||
{
|
||||
throw new Exception($"Unexpected null in list slot.");
|
||||
}
|
||||
var red = listSlot.GetNode(index);
|
||||
if (red != null)
|
||||
if (!(red is null))
|
||||
{
|
||||
return red;
|
||||
}
|
||||
// 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
|
||||
{
|
||||
@ -100,7 +104,7 @@ namespace Parser
|
||||
return red;
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ namespace Parser.Internal
|
||||
{
|
||||
public class Diagnostic
|
||||
{
|
||||
public TextSpan Span { get; }
|
||||
public TextSpan? Span { get; }
|
||||
public string Message { get; }
|
||||
|
||||
public Diagnostic(TextSpan span, string message)
|
||||
@ -12,5 +12,10 @@ namespace Parser.Internal
|
||||
Span = span;
|
||||
Message = message ?? throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
public Diagnostic(string message)
|
||||
{
|
||||
Message = message ?? throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,12 @@ namespace Parser.Internal
|
||||
_diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
private void Report(string message)
|
||||
{
|
||||
var diagnostic = new Diagnostic(message);
|
||||
_diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
internal void ReportUnexpectedEndOfFile(TextSpan span)
|
||||
{
|
||||
Report(span, "Unexpected end of file.");
|
||||
@ -46,9 +52,9 @@ namespace Parser.Internal
|
||||
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()
|
||||
|
@ -10,7 +10,10 @@ namespace Parser.Internal
|
||||
{
|
||||
public TokenKind Kind { get; }
|
||||
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)
|
||||
{
|
||||
@ -23,13 +26,28 @@ namespace Parser.Internal
|
||||
_fullWidth = fullWidth;
|
||||
}
|
||||
|
||||
public GreenNode(TokenKind kind, TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
Kind = kind;
|
||||
HasDiagnostics = true;
|
||||
diagnosticsTable[this] = diagnostics;
|
||||
}
|
||||
|
||||
public GreenNode(TokenKind kind, int fullWidth, TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
Kind = kind;
|
||||
_fullWidth = fullWidth;
|
||||
HasDiagnostics = true;
|
||||
diagnosticsTable[this] = diagnostics;
|
||||
}
|
||||
|
||||
internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position);
|
||||
|
||||
protected int _fullWidth;
|
||||
|
||||
public int FullWidth => _fullWidth;
|
||||
|
||||
protected void AdjustWidth(GreenNode node)
|
||||
protected void AdjustWidth(GreenNode? node)
|
||||
{
|
||||
if (!(node is null))
|
||||
{
|
||||
@ -56,11 +74,6 @@ namespace Parser.Internal
|
||||
|
||||
internal bool IsMissing => _isMissing;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString();
|
||||
}
|
||||
|
||||
private void WriteTo(TextWriter writer, bool leading, bool trailing)
|
||||
{
|
||||
var stack = new Stack<(GreenNode node, bool leading, bool trailing)>();
|
||||
@ -109,12 +122,12 @@ namespace Parser.Internal
|
||||
return -1;
|
||||
}
|
||||
|
||||
private GreenNode GetFirstTerminal()
|
||||
private GreenNode? GetFirstTerminal()
|
||||
{
|
||||
var current = this;
|
||||
while (true)
|
||||
{
|
||||
GreenNode next = null;
|
||||
GreenNode? next = null;
|
||||
if (current.Slots == 0)
|
||||
{
|
||||
return current;
|
||||
@ -141,12 +154,12 @@ namespace Parser.Internal
|
||||
}
|
||||
}
|
||||
|
||||
private GreenNode GetLastTerminal()
|
||||
private GreenNode? GetLastTerminal()
|
||||
{
|
||||
var current = this;
|
||||
while (true)
|
||||
{
|
||||
GreenNode next = null;
|
||||
GreenNode? next = null;
|
||||
if (current.Slots == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
14
Parser/Internal/GreenNodeExtensions.cs
Normal file
14
Parser/Internal/GreenNodeExtensions.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Parser.Internal
|
||||
{
|
||||
internal static class GreenNodeExtensions
|
||||
{
|
||||
public static TNode WithDiagnostics<TNode>(this TNode node, params TokenDiagnostic[] diagnostics)
|
||||
where TNode : GreenNode
|
||||
{
|
||||
return (TNode)node.SetDiagnostics(diagnostics.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -9,9 +9,9 @@ namespace Parser.Internal
|
||||
{
|
||||
private class TokenInfo
|
||||
{
|
||||
public TokenKind Kind { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string StringValue { get; set; }
|
||||
public TokenKind Kind { get; set; } = TokenKind.None;
|
||||
public string Text { get; set; } = "";
|
||||
public string StringValue { get; set; } = "";
|
||||
public double DoubleValue { get; set; }
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ namespace Parser.Internal
|
||||
public MLexerGreen(ITextWindow window)
|
||||
{
|
||||
Window = window;
|
||||
LastToken = SyntaxToken.NoneToken;
|
||||
TokenStack = new Stack<TokenKind>();
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,20 @@ namespace Parser.Internal
|
||||
return token;
|
||||
}
|
||||
|
||||
private SyntaxToken CreateMissingToken(TokenKind kind)
|
||||
{
|
||||
return TokenFactory
|
||||
.CreateMissing(kind, null, null)
|
||||
.WithDiagnostics(TokenDiagnostic.MissingToken(kind));
|
||||
}
|
||||
|
||||
private SyntaxToken EatToken(TokenKind kind)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
if (token.Kind != kind)
|
||||
{
|
||||
Diagnostics.ReportUnexpectedToken(token.Span, kind, token.Kind);
|
||||
return TokenFactory.CreateMissing(kind, null, null);
|
||||
Diagnostics.ReportUnexpectedToken(kind, token.Kind);
|
||||
return CreateMissingToken(kind);
|
||||
}
|
||||
_index++;
|
||||
return token;
|
||||
@ -55,13 +62,13 @@ namespace Parser.Internal
|
||||
var token = CurrentToken;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -69,7 +76,7 @@ namespace Parser.Internal
|
||||
return token;
|
||||
}
|
||||
|
||||
private SyntaxToken PossiblyEatIdentifier(string s)
|
||||
private SyntaxToken? PossiblyEatIdentifier(string s)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
if (token.Kind == TokenKind.IdentifierToken && token.Text == s)
|
||||
@ -94,7 +101,7 @@ namespace Parser.Internal
|
||||
new List<SyntaxTrivia>());
|
||||
}
|
||||
|
||||
private SyntaxList ParseFunctionOutputList()
|
||||
private SyntaxList? ParseFunctionOutputList()
|
||||
{
|
||||
var outputs = new SyntaxListBuilder();
|
||||
var firstToken = true;
|
||||
@ -112,7 +119,7 @@ namespace Parser.Internal
|
||||
return outputs.ToList();
|
||||
}
|
||||
|
||||
private FunctionOutputDescriptionSyntaxNode ParseFunctionOutputDescription()
|
||||
private FunctionOutputDescriptionSyntaxNode? ParseFunctionOutputDescription()
|
||||
{
|
||||
SyntaxToken assignmentSign;
|
||||
var builder = new SyntaxListBuilder();
|
||||
@ -180,7 +187,7 @@ namespace Parser.Internal
|
||||
return builder.ToList();
|
||||
}
|
||||
|
||||
private FunctionInputDescriptionSyntaxNode ParseFunctionInputDescription()
|
||||
private FunctionInputDescriptionSyntaxNode? ParseFunctionInputDescription()
|
||||
{
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
@ -206,7 +213,8 @@ namespace Parser.Internal
|
||||
var inputDescription = ParseFunctionInputDescription();
|
||||
var commas = ParseOptionalCommas();
|
||||
var body = ParseStatementList();
|
||||
var endKeyword = EatPossiblyMissingIdentifier("end");
|
||||
var endKeyword = ParseEndKeyword();
|
||||
//var endKeyword =
|
||||
return Factory.FunctionDeclarationSyntax(
|
||||
functionKeyword,
|
||||
outputDescription,
|
||||
@ -217,6 +225,12 @@ namespace Parser.Internal
|
||||
endKeyword);
|
||||
}
|
||||
|
||||
private EndKeywordSyntaxNode? ParseEndKeyword()
|
||||
{
|
||||
var keyword = EatPossiblyMissingIdentifier("end");
|
||||
return keyword is null ? null : Factory.EndKeywordSyntax(keyword);
|
||||
}
|
||||
|
||||
internal struct ParseOptions
|
||||
{
|
||||
public bool ParsingArrayElements { get; set; }
|
||||
@ -224,12 +238,12 @@ namespace Parser.Internal
|
||||
public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false };
|
||||
}
|
||||
|
||||
private ExpressionSyntaxNode ParseExpression()
|
||||
private ExpressionSyntaxNode? ParseExpression()
|
||||
{
|
||||
return ParseExpression(ParseOptions.Default);
|
||||
}
|
||||
|
||||
private ExpressionSyntaxNode ParseExpression(ParseOptions options)
|
||||
private ExpressionSyntaxNode? ParseExpression(ParseOptions options)
|
||||
{
|
||||
return ParseSubExpression(options, SyntaxFacts.Precedence.Expression);
|
||||
}
|
||||
@ -286,10 +300,10 @@ namespace Parser.Internal
|
||||
return builder.ToList();
|
||||
}
|
||||
|
||||
private ExpressionSyntaxNode ParseTerm(ParseOptions options)
|
||||
private ExpressionSyntaxNode? ParseTerm(ParseOptions options)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
ExpressionSyntaxNode expression = null;
|
||||
ExpressionSyntaxNode? expression = null;
|
||||
switch (token.Kind)
|
||||
{
|
||||
case TokenKind.NumberLiteralToken:
|
||||
@ -410,6 +424,11 @@ namespace Parser.Internal
|
||||
|
||||
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}.");
|
||||
}
|
||||
|
||||
@ -420,6 +439,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var atToken = EatToken();
|
||||
var baseClassNameWithArguments = ParseExpression();
|
||||
if (baseClassNameWithArguments is null)
|
||||
{
|
||||
throw new Exception($"Base class name cannot be empty.");
|
||||
}
|
||||
return Factory.BaseClassInvokationSyntax(methodName, atToken, baseClassNameWithArguments);
|
||||
}
|
||||
if (expression is MemberAccessSyntaxNode memberAccess
|
||||
@ -427,6 +450,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var atToken = EatToken();
|
||||
var baseClassNameWithArguments = ParseExpression();
|
||||
if (baseClassNameWithArguments is null)
|
||||
{
|
||||
throw new Exception($"Base class name cannot be empty.");
|
||||
}
|
||||
return Factory.BaseClassInvokationSyntax(memberAccess, atToken, baseClassNameWithArguments);
|
||||
}
|
||||
throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}.");
|
||||
@ -442,6 +469,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var openingBracket = EatToken();
|
||||
var indirectMember = ParseExpression();
|
||||
if (indirectMember is null)
|
||||
{
|
||||
throw new Exception("Indirect member invokation cannot be empty.");
|
||||
}
|
||||
var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
|
||||
return Factory.IndirectMemberAccessSyntax(
|
||||
openingBracket,
|
||||
@ -466,7 +497,12 @@ namespace Parser.Internal
|
||||
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();
|
||||
@ -476,6 +512,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var openParen = EatToken(TokenKind.OpenParenthesisToken);
|
||||
var expression = ParseExpression();
|
||||
if (expression is null)
|
||||
{
|
||||
throw new Exception("Parenthesized expression cannot be empty.");
|
||||
}
|
||||
var closeParen = EatToken(TokenKind.CloseParenthesisToken);
|
||||
return Factory.ParenthesizedExpressionSyntax(
|
||||
openParen,
|
||||
@ -514,17 +554,25 @@ namespace Parser.Internal
|
||||
else if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
var inputs = ParseFunctionInputDescription();
|
||||
if (inputs is null)
|
||||
{
|
||||
throw new Exception($"Lambda expression inputs cannot be empty.");
|
||||
}
|
||||
var body = ParseExpression();
|
||||
if (body is null)
|
||||
{
|
||||
throw new Exception($"Lambda expression body cannot be empty.");
|
||||
}
|
||||
return Factory.LambdaSyntax(atSign, inputs, body);
|
||||
}
|
||||
throw new ParsingException($"Unexpected token {CurrentToken} while parsing function handle at {CurrentPosition}.");
|
||||
}
|
||||
|
||||
private ExpressionSyntaxNode ParseSubExpression(
|
||||
private ExpressionSyntaxNode? ParseSubExpression(
|
||||
ParseOptions options,
|
||||
SyntaxFacts.Precedence precedence)
|
||||
{
|
||||
ExpressionSyntaxNode lhs;
|
||||
ExpressionSyntaxNode? lhs;
|
||||
if (SyntaxFacts.IsUnaryOperator(CurrentToken.Kind))
|
||||
{
|
||||
var operation = EatToken();
|
||||
@ -551,6 +599,10 @@ namespace Parser.Internal
|
||||
else
|
||||
{
|
||||
lhs = ParseTerm(options);
|
||||
if (lhs is null)
|
||||
{
|
||||
throw new Exception("Left-hand side in subexpression cannot be empty.");
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
@ -579,9 +631,10 @@ namespace Parser.Internal
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs = null;
|
||||
throw new Exception("Right-hand side in subexpression cannot be empty.");
|
||||
}
|
||||
}
|
||||
|
||||
if (token.Kind == TokenKind.EqualsToken)
|
||||
{
|
||||
lhs = Factory.AssignmentExpressionSyntax(lhs, token, rhs);
|
||||
@ -627,6 +680,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var caseKeyword = EatIdentifier("case");
|
||||
var caseId = ParseExpression();
|
||||
if (caseId is null)
|
||||
{
|
||||
throw new Exception("Case label cannot be empty.");
|
||||
}
|
||||
var commas = ParseOptionalCommas();
|
||||
var statementList = ParseStatementList();
|
||||
return Factory.SwitchCaseSyntax(caseKeyword, caseId, commas, statementList);
|
||||
@ -636,6 +693,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var switchKeyword = EatIdentifier("switch");
|
||||
var expression = ParseExpression();
|
||||
if (expression is null)
|
||||
{
|
||||
throw new Exception("Match expression in switch statement cannot be empty.");
|
||||
}
|
||||
var commas = ParseOptionalCommas();
|
||||
var builder = new SyntaxListBuilder<SwitchCaseSyntaxNode>();
|
||||
while (IsIdentifier(CurrentToken, "case"))
|
||||
@ -655,6 +716,11 @@ namespace Parser.Internal
|
||||
{
|
||||
var whileKeyword = EatIdentifier("while");
|
||||
var condition = ParseExpression();
|
||||
if (condition is null)
|
||||
{
|
||||
throw new Exception("Condition in while statement cannot be empty.");
|
||||
}
|
||||
|
||||
var commas = ParseOptionalCommas();
|
||||
var body = ParseStatementList();
|
||||
var endKeyword = EatIdentifier("end");
|
||||
@ -670,6 +736,10 @@ namespace Parser.Internal
|
||||
{
|
||||
var elseifKeyword = EatIdentifier("elseif");
|
||||
var condition = ParseExpression();
|
||||
if (condition is null)
|
||||
{
|
||||
throw new Exception("Condition in elseif clause cannot be empty.");
|
||||
}
|
||||
var commas = ParseOptionalCommas();
|
||||
var body = ParseStatementList();
|
||||
return Factory.ElseifClause(elseifKeyword, condition, commas, body);
|
||||
@ -686,10 +756,14 @@ namespace Parser.Internal
|
||||
{
|
||||
var ifKeyword = EatIdentifier();
|
||||
var condition = ParseExpression();
|
||||
if (condition is null)
|
||||
{
|
||||
throw new Exception("Condition in if statement cannot be empty.");
|
||||
}
|
||||
var commas = ParseOptionalSemicolonsOrCommas();
|
||||
var body = ParseStatementList();
|
||||
var elseifClauses = new SyntaxListBuilder<ElseifClause>();
|
||||
ElseClause elseClause = null;
|
||||
ElseClause? elseClause = null;
|
||||
while (true)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
@ -740,7 +814,7 @@ namespace Parser.Internal
|
||||
endKeyword);
|
||||
}
|
||||
|
||||
private CatchClauseSyntaxNode ParseCatchClause()
|
||||
private CatchClauseSyntaxNode? ParseCatchClause()
|
||||
{
|
||||
if (IsIdentifier(CurrentToken, "catch"))
|
||||
{
|
||||
@ -766,15 +840,24 @@ namespace Parser.Internal
|
||||
private ExpressionStatementSyntaxNode ParseExpressionStatement()
|
||||
{
|
||||
var expression = ParseExpression();
|
||||
if (expression is null)
|
||||
{
|
||||
throw new Exception("Expression statement cannot be empty.");
|
||||
}
|
||||
|
||||
return Factory.ExpressionStatementSyntax(expression);
|
||||
}
|
||||
|
||||
private AttributeAssignmentSyntaxNode ParseAttributeAssignment()
|
||||
private AttributeAssignmentSyntaxNode? ParseAttributeAssignment()
|
||||
{
|
||||
if (CurrentToken.Kind == TokenKind.EqualsToken)
|
||||
{
|
||||
var assignmentSign = EatToken();
|
||||
var value = ParseExpression();
|
||||
if (value is null)
|
||||
{
|
||||
throw new Exception("Right-hand side in attribute assignment cannot be empty.");
|
||||
}
|
||||
return Factory.AttributeAssignmentSyntax(assignmentSign, value);
|
||||
}
|
||||
|
||||
@ -845,7 +928,7 @@ namespace Parser.Internal
|
||||
var inputDescription = ParseFunctionInputDescription();
|
||||
var commas = ParseOptionalCommas();
|
||||
var body = ParseStatementList();
|
||||
var endKeyword = PossiblyEatIdentifier("end");
|
||||
var endKeyword = ParseEndKeyword();
|
||||
return Factory.MethodDefinitionSyntax(
|
||||
functionKeyword,
|
||||
outputDescription,
|
||||
@ -859,7 +942,7 @@ namespace Parser.Internal
|
||||
private MethodsListSyntaxNode ParseMethods()
|
||||
{
|
||||
var methodsKeyword = EatToken();
|
||||
AttributeListSyntaxNode attributes = null;
|
||||
AttributeListSyntaxNode? attributes = null;
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
attributes = ParseAttributesList();
|
||||
@ -876,7 +959,7 @@ namespace Parser.Internal
|
||||
return Factory.MethodsListSyntax(methodsKeyword, attributes, builder.ToList(), endKeyword);
|
||||
}
|
||||
|
||||
private GreenNode ParsePropertyDeclaration()
|
||||
private GreenNode? ParsePropertyDeclaration()
|
||||
{
|
||||
if (CurrentToken.Kind == TokenKind.CommaToken)
|
||||
{
|
||||
@ -885,7 +968,7 @@ namespace Parser.Internal
|
||||
return ParseStatement();
|
||||
}
|
||||
|
||||
private SyntaxNode ParseEventDeclaration()
|
||||
private SyntaxNode? ParseEventDeclaration()
|
||||
{
|
||||
return ParseStatement();
|
||||
}
|
||||
@ -893,7 +976,7 @@ namespace Parser.Internal
|
||||
private PropertiesListSyntaxNode ParseProperties()
|
||||
{
|
||||
var propertiesKeyword = EatToken();
|
||||
AttributeListSyntaxNode attributes = null;
|
||||
AttributeListSyntaxNode? attributes = null;
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
attributes = ParseAttributesList();
|
||||
@ -902,14 +985,19 @@ namespace Parser.Internal
|
||||
var builder = new SyntaxListBuilder();
|
||||
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();
|
||||
return Factory.PropertiesListSyntax(propertiesKeyword, attributes, builder.ToList(), endKeyword);
|
||||
}
|
||||
|
||||
private EnumerationItemValueSyntaxNode ParseEnumerationValue()
|
||||
private EnumerationItemValueSyntaxNode? ParseEnumerationValue()
|
||||
{
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
@ -920,7 +1008,12 @@ namespace Parser.Internal
|
||||
while (CurrentToken.Kind == TokenKind.CommaToken)
|
||||
{
|
||||
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);
|
||||
return Factory.EnumerationItemValueSyntax(openingBracket, builder.ToList(), closingBracket);
|
||||
@ -940,7 +1033,7 @@ namespace Parser.Internal
|
||||
{
|
||||
var enumerationKeyword = EatToken();
|
||||
var builder = new SyntaxListBuilder<EnumerationItemSyntaxNode>();
|
||||
AttributeListSyntaxNode attributes = null;
|
||||
AttributeListSyntaxNode? attributes = null;
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
attributes = ParseAttributesList();
|
||||
@ -962,7 +1055,7 @@ namespace Parser.Internal
|
||||
private SyntaxNode ParseEvents()
|
||||
{
|
||||
var eventsKeyword = EatToken();
|
||||
AttributeListSyntaxNode attributes = null;
|
||||
AttributeListSyntaxNode? attributes = null;
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
attributes = ParseAttributesList();
|
||||
@ -971,7 +1064,12 @@ namespace Parser.Internal
|
||||
var builder = new SyntaxListBuilder();
|
||||
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();
|
||||
@ -1001,13 +1099,13 @@ namespace Parser.Internal
|
||||
private StatementSyntaxNode ParseClassDeclaration()
|
||||
{
|
||||
var classdefKeyword = EatToken();
|
||||
AttributeListSyntaxNode attributes = null;
|
||||
AttributeListSyntaxNode? attributes = null;
|
||||
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
|
||||
{
|
||||
attributes = ParseAttributesList();
|
||||
}
|
||||
var className = Factory.IdentifierNameSyntax(EatToken(TokenKind.IdentifierToken));
|
||||
BaseClassListSyntaxNode baseClassList = null;
|
||||
BaseClassListSyntaxNode? baseClassList = null;
|
||||
if (CurrentToken.Kind == TokenKind.LessToken)
|
||||
{
|
||||
baseClassList = ParseBaseClassList();
|
||||
@ -1052,7 +1150,7 @@ namespace Parser.Internal
|
||||
endKeyword);
|
||||
}
|
||||
|
||||
private StatementSyntaxNode ParseStatement()
|
||||
private StatementSyntaxNode? ParseStatement()
|
||||
{
|
||||
if (CurrentToken.Kind == TokenKind.IdentifierToken)
|
||||
{
|
||||
@ -1120,5 +1218,11 @@ namespace Parser.Internal
|
||||
var endOfFileToken = EatToken();
|
||||
return Factory.FileSyntax(statementList, endOfFileToken);
|
||||
}
|
||||
|
||||
public RootSyntaxNode ParseRoot()
|
||||
{
|
||||
var file = ParseFile();
|
||||
return Factory.RootSyntax(file);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#nullable enable
|
||||
namespace Parser.Internal
|
||||
{
|
||||
internal partial class SyntaxFactory
|
||||
@ -13,12 +14,12 @@ namespace Parser.Internal
|
||||
|
||||
public FunctionDeclarationSyntaxNode FunctionDeclarationSyntax(
|
||||
SyntaxToken functionKeyword,
|
||||
FunctionOutputDescriptionSyntaxNode outputDescription,
|
||||
FunctionOutputDescriptionSyntaxNode? outputDescription,
|
||||
SyntaxToken name,
|
||||
FunctionInputDescriptionSyntaxNode inputDescription,
|
||||
FunctionInputDescriptionSyntaxNode? inputDescription,
|
||||
SyntaxList<SyntaxToken> commas,
|
||||
SyntaxList body,
|
||||
SyntaxToken endKeyword)
|
||||
EndKeywordSyntaxNode? endKeyword)
|
||||
{
|
||||
return new FunctionDeclarationSyntaxNode(
|
||||
functionKeyword,
|
||||
@ -121,7 +122,7 @@ namespace Parser.Internal
|
||||
SyntaxList<SyntaxToken> optionalCommas,
|
||||
SyntaxList body,
|
||||
SyntaxList<ElseifClause> elseifClauses,
|
||||
ElseClause elseClause,
|
||||
ElseClause? elseClause,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
return new IfStatementSyntaxNode(
|
||||
@ -172,7 +173,7 @@ namespace Parser.Internal
|
||||
public TryCatchStatementSyntaxNode TryCatchStatementSyntax(
|
||||
SyntaxToken tryKeyword,
|
||||
SyntaxList tryBody,
|
||||
CatchClauseSyntaxNode catchClause,
|
||||
CatchClauseSyntaxNode? catchClause,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
return new TryCatchStatementSyntaxNode(
|
||||
@ -404,7 +405,7 @@ namespace Parser.Internal
|
||||
|
||||
public AttributeSyntaxNode AttributeSyntax(
|
||||
IdentifierNameSyntaxNode name,
|
||||
AttributeAssignmentSyntaxNode assignment)
|
||||
AttributeAssignmentSyntaxNode? assignment)
|
||||
{
|
||||
return new AttributeSyntaxNode(
|
||||
name,
|
||||
@ -424,12 +425,12 @@ namespace Parser.Internal
|
||||
|
||||
public MethodDefinitionSyntaxNode MethodDefinitionSyntax(
|
||||
SyntaxToken functionKeyword,
|
||||
FunctionOutputDescriptionSyntaxNode outputDescription,
|
||||
FunctionOutputDescriptionSyntaxNode? outputDescription,
|
||||
CompoundNameSyntaxNode name,
|
||||
FunctionInputDescriptionSyntaxNode inputDescription,
|
||||
FunctionInputDescriptionSyntaxNode? inputDescription,
|
||||
SyntaxList<SyntaxToken> commas,
|
||||
SyntaxList body,
|
||||
SyntaxToken endKeyword)
|
||||
EndKeywordSyntaxNode? endKeyword)
|
||||
{
|
||||
return new MethodDefinitionSyntaxNode(
|
||||
functionKeyword,
|
||||
@ -442,9 +443,9 @@ namespace Parser.Internal
|
||||
}
|
||||
|
||||
public AbstractMethodDeclarationSyntaxNode AbstractMethodDeclarationSyntax(
|
||||
FunctionOutputDescriptionSyntaxNode outputDescription,
|
||||
FunctionOutputDescriptionSyntaxNode? outputDescription,
|
||||
CompoundNameSyntaxNode name,
|
||||
FunctionInputDescriptionSyntaxNode inputDescription)
|
||||
FunctionInputDescriptionSyntaxNode? inputDescription)
|
||||
{
|
||||
return new AbstractMethodDeclarationSyntaxNode(
|
||||
outputDescription,
|
||||
@ -454,7 +455,7 @@ namespace Parser.Internal
|
||||
|
||||
public MethodsListSyntaxNode MethodsListSyntax(
|
||||
SyntaxToken methodsKeyword,
|
||||
AttributeListSyntaxNode attributes,
|
||||
AttributeListSyntaxNode? attributes,
|
||||
SyntaxList methods,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
@ -467,7 +468,7 @@ namespace Parser.Internal
|
||||
|
||||
public PropertiesListSyntaxNode PropertiesListSyntax(
|
||||
SyntaxToken propertiesKeyword,
|
||||
AttributeListSyntaxNode attributes,
|
||||
AttributeListSyntaxNode? attributes,
|
||||
SyntaxList properties,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
@ -489,9 +490,9 @@ namespace Parser.Internal
|
||||
|
||||
public ClassDeclarationSyntaxNode ClassDeclarationSyntax(
|
||||
SyntaxToken classdefKeyword,
|
||||
AttributeListSyntaxNode attributes,
|
||||
AttributeListSyntaxNode? attributes,
|
||||
IdentifierNameSyntaxNode className,
|
||||
BaseClassListSyntaxNode baseClassList,
|
||||
BaseClassListSyntaxNode? baseClassList,
|
||||
SyntaxList nodes,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
@ -517,7 +518,7 @@ namespace Parser.Internal
|
||||
|
||||
public EnumerationItemSyntaxNode EnumerationItemSyntax(
|
||||
IdentifierNameSyntaxNode name,
|
||||
EnumerationItemValueSyntaxNode values,
|
||||
EnumerationItemValueSyntaxNode? values,
|
||||
SyntaxList<SyntaxToken> commas)
|
||||
{
|
||||
return new EnumerationItemSyntaxNode(
|
||||
@ -528,7 +529,7 @@ namespace Parser.Internal
|
||||
|
||||
public EnumerationListSyntaxNode EnumerationListSyntax(
|
||||
SyntaxToken enumerationKeyword,
|
||||
AttributeListSyntaxNode attributes,
|
||||
AttributeListSyntaxNode? attributes,
|
||||
SyntaxList<EnumerationItemSyntaxNode> items,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
@ -541,7 +542,7 @@ namespace Parser.Internal
|
||||
|
||||
public EventsListSyntaxNode EventsListSyntax(
|
||||
SyntaxToken eventsKeyword,
|
||||
AttributeListSyntaxNode attributes,
|
||||
AttributeListSyntaxNode? attributes,
|
||||
SyntaxList events,
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
@ -551,5 +552,12 @@ namespace Parser.Internal
|
||||
events,
|
||||
endKeyword);
|
||||
}
|
||||
|
||||
public EndKeywordSyntaxNode EndKeywordSyntax(
|
||||
SyntaxToken endKeyword)
|
||||
{
|
||||
return new EndKeywordSyntaxNode(
|
||||
endKeyword);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,5 +2,9 @@
|
||||
{
|
||||
internal partial class SyntaxFactory
|
||||
{
|
||||
public RootSyntaxNode RootSyntax(FileSyntaxNode file)
|
||||
{
|
||||
return new RootSyntaxNode(file);
|
||||
}
|
||||
}
|
||||
}
|
@ -155,7 +155,7 @@ namespace Parser.Internal
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] StringFromKind =
|
||||
private static readonly string?[] StringFromKind =
|
||||
{
|
||||
null, // None = 0,
|
||||
null, // BadToken = 1,
|
||||
@ -210,7 +210,7 @@ namespace Parser.Internal
|
||||
"?", // UnaryQuestionMark = 60,
|
||||
};
|
||||
|
||||
public static string GetText(TokenKind kind)
|
||||
public static string? GetText(TokenKind kind)
|
||||
{
|
||||
if ((int) kind < (int) TokenKind.File)
|
||||
{
|
||||
|
@ -5,7 +5,7 @@ namespace Parser.Internal
|
||||
{
|
||||
internal class SyntaxList : SyntaxNode
|
||||
{
|
||||
private readonly GreenNode[] _elements;
|
||||
internal readonly GreenNode[] _elements;
|
||||
|
||||
protected SyntaxList(GreenNode[] elements) : base(TokenKind.List)
|
||||
{
|
||||
@ -17,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];
|
||||
}
|
||||
|
||||
public override GreenNode? GetSlot(int i)
|
||||
{
|
||||
return GetListSlot(i);
|
||||
}
|
||||
|
||||
public static SyntaxList List(GreenNode[] elements)
|
||||
{
|
||||
return new SyntaxList(elements);
|
||||
}
|
||||
|
||||
public static SyntaxList EmptyList { get; } = new SyntaxList(new GreenNode[] { });
|
||||
|
||||
public override bool IsList => true;
|
||||
|
||||
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
||||
{
|
||||
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxList(_elements, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
@ -20,14 +20,14 @@ namespace Parser.Internal
|
||||
{
|
||||
for (var i = 0; i < list.Slots; i++)
|
||||
{
|
||||
var element = list.GetSlot(i);
|
||||
var element = list.GetListSlot(i);
|
||||
_list.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
public SyntaxList ToList()
|
||||
{
|
||||
return _list.Count == 0 ? null : SyntaxList.List(_list.ToArray());
|
||||
return _list.Count == 0 ? SyntaxList.EmptyList : SyntaxList.List(_list.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ namespace Parser.Internal
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace Parser.Internal
|
||||
using System.Linq;
|
||||
|
||||
namespace Parser.Internal
|
||||
{
|
||||
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)
|
||||
@ -24,11 +36,18 @@
|
||||
return new SyntaxList<T>(elements);
|
||||
}
|
||||
|
||||
public static SyntaxList<T> Empty => new SyntaxList<T>(new T[] { });
|
||||
|
||||
public override bool IsList => true;
|
||||
|
||||
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
||||
{
|
||||
return new Parser.SyntaxNodeOrTokenList(parent, this, position);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxList<T>(_list._elements.Select(x => (T)x).ToArray(), diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,11 @@ namespace Parser.Internal
|
||||
{
|
||||
}
|
||||
|
||||
protected SyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics)
|
||||
: base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<SyntaxToken> DescendantTokens => CalculateChildTokens();
|
||||
|
||||
private IEnumerable<SyntaxToken> CalculateChildTokens()
|
||||
@ -57,6 +62,10 @@ namespace Parser.Internal
|
||||
protected StatementSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected StatementSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class ExpressionSyntaxNode : SyntaxNode
|
||||
@ -64,6 +73,10 @@ namespace Parser.Internal
|
||||
protected ExpressionSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected ExpressionSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode
|
||||
@ -71,6 +84,10 @@ namespace Parser.Internal
|
||||
protected FunctionHandleSyntaxNode(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected FunctionHandleSyntaxNode(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode
|
||||
@ -78,5 +95,47 @@ namespace Parser.Internal
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace Parser.Internal
|
||||
{
|
||||
internal abstract class SyntaxToken : GreenNode
|
||||
{
|
||||
public TextSpan Span { get; }
|
||||
internal static IReadOnlyList<SyntaxTrivia> s_EmptySyntaxTriviaList = new List<SyntaxTrivia>();
|
||||
|
||||
internal class SyntaxTokenWithTrivia : SyntaxToken
|
||||
{
|
||||
@ -36,6 +36,31 @@ namespace Parser.Internal
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public SyntaxTokenWithTrivia(
|
||||
TokenKind kind,
|
||||
string text,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
LeadingTriviaCore = leadingTrivia;
|
||||
TrailingTriviaCore = trailingTrivia;
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public SyntaxTokenWithTrivia(
|
||||
TokenKind kind,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
_text = base.Text;
|
||||
LeadingTriviaCore = leadingTrivia;
|
||||
TrailingTriviaCore = trailingTrivia;
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||
{
|
||||
if (leading)
|
||||
@ -55,6 +80,11 @@ namespace Parser.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxTokenWithTrivia(Kind, _text, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||
}
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
||||
@ -75,10 +105,27 @@ namespace Parser.Internal
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
}
|
||||
|
||||
public SyntaxTokenWithValue(
|
||||
TokenKind kind,
|
||||
string text,
|
||||
T value,
|
||||
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
_value = value;
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
}
|
||||
|
||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||
{
|
||||
writer.Write(_text);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxTokenWithValue<T>(Kind, _text, _value, diagnostics);
|
||||
}
|
||||
|
||||
public T Value => _value;
|
||||
}
|
||||
|
||||
@ -96,6 +143,19 @@ namespace Parser.Internal
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public SyntaxTokenWithValueAndTrivia(
|
||||
TokenKind kind,
|
||||
string text,
|
||||
T value,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||
TokenDiagnostic[] diagnostics) : base(kind, text, value, diagnostics)
|
||||
{
|
||||
LeadingTriviaCore = leadingTrivia;
|
||||
TrailingTriviaCore = trailingTrivia;
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
||||
@ -118,6 +178,11 @@ namespace Parser.Internal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxTokenWithValueAndTrivia<T>(Kind, _text, Value, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyntaxIdentifier : SyntaxToken
|
||||
@ -129,9 +194,21 @@ namespace Parser.Internal
|
||||
writer.Write(_text);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxIdentifier(_text, diagnostics);
|
||||
}
|
||||
|
||||
public SyntaxIdentifier(
|
||||
string text
|
||||
) : base(TokenKind.IdentifierToken)
|
||||
string text) : base(TokenKind.IdentifierToken)
|
||||
{
|
||||
_text = text;
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
}
|
||||
|
||||
public SyntaxIdentifier(
|
||||
string text,
|
||||
TokenDiagnostic[] diagnostics) : base(TokenKind.IdentifierToken, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
_fullWidth = text?.Length ?? 0;
|
||||
@ -157,6 +234,17 @@ namespace Parser.Internal
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public SyntaxIdentifierWithTrivia(
|
||||
string text,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||
TokenDiagnostic[] diagnostics) : base(text, diagnostics)
|
||||
{
|
||||
_leadingTrivia = leadingTrivia;
|
||||
_trailingTrivia = trailingTrivia;
|
||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
||||
}
|
||||
|
||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||
{
|
||||
if (leading)
|
||||
@ -178,6 +266,11 @@ namespace Parser.Internal
|
||||
|
||||
public override bool IsToken => true;
|
||||
public override bool IsNode => false;
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxIdentifierWithTrivia(Text, _leadingTrivia, _trailingTrivia, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissingTokenWithTrivia : SyntaxTokenWithTrivia
|
||||
@ -191,19 +284,39 @@ namespace Parser.Internal
|
||||
_isMissing = true;
|
||||
}
|
||||
|
||||
public MissingTokenWithTrivia(
|
||||
TokenKind kind,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
||||
TokenDiagnostic[] diagnostics) : base(kind, leadingTrivia, trailingTrivia, diagnostics)
|
||||
{
|
||||
_isMissing = true;
|
||||
}
|
||||
|
||||
public override string Text => "";
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new MissingTokenWithTrivia(Kind, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
protected SyntaxToken(TokenKind kind) : base(kind)
|
||||
{
|
||||
}
|
||||
|
||||
protected SyntaxToken(TokenKind kind, TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||
{
|
||||
}
|
||||
|
||||
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
||||
|
||||
public virtual int Width => Text.Length;
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>();
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>();
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => s_EmptySyntaxTriviaList;
|
||||
|
||||
public override GreenNode GetSlot(int i)
|
||||
public override GreenNode? GetSlot(int i)
|
||||
{
|
||||
throw new System.InvalidOperationException();
|
||||
}
|
||||
|
@ -14,10 +14,15 @@ namespace Parser.Internal
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public SyntaxTrivia(TokenKind kind, string text, TokenDiagnostic[] diagnostics) : base(kind, text.Length, diagnostics)
|
||||
{
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public override string Text => _text;
|
||||
public int Width => _text.Length;
|
||||
|
||||
public override GreenNode GetSlot(int i)
|
||||
public override GreenNode? GetSlot(int i)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
@ -35,6 +40,11 @@ namespace Parser.Internal
|
||||
writer.Write(_text);
|
||||
}
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new SyntaxTrivia(Kind, _text, diagnostics);
|
||||
}
|
||||
|
||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>();
|
||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>();
|
||||
}
|
||||
|
24
Parser/Internal/TokenDiagnostic.cs
Normal file
24
Parser/Internal/TokenDiagnostic.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace Parser.Internal
|
||||
{
|
||||
public class TokenDiagnostic
|
||||
{
|
||||
protected TokenDiagnostic()
|
||||
{
|
||||
}
|
||||
|
||||
public static TokenDiagnostic MissingToken(TokenKind kind)
|
||||
{
|
||||
return new MissingTokenDiagnostic(kind);
|
||||
}
|
||||
}
|
||||
|
||||
public class MissingTokenDiagnostic : TokenDiagnostic
|
||||
{
|
||||
internal MissingTokenDiagnostic(TokenKind kind)
|
||||
{
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public TokenKind Kind { get; }
|
||||
}
|
||||
}
|
@ -51,10 +51,10 @@ namespace Parser.Internal
|
||||
|
||||
public static SyntaxToken CreateMissing(
|
||||
TokenKind kind,
|
||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
||||
IReadOnlyList<SyntaxTrivia>? leadingTrivia,
|
||||
IReadOnlyList<SyntaxTrivia>? trailingTrivia)
|
||||
{
|
||||
return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia, trailingTrivia);
|
||||
return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList, trailingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList);
|
||||
}
|
||||
}
|
||||
}
|
@ -20,23 +20,24 @@ namespace Parser
|
||||
var lexerDiagnostics = lexer.Diagnostics;
|
||||
var tokens = lexer.ParseAll();
|
||||
var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory());
|
||||
var green = parser.ParseFile();
|
||||
var green = parser.ParseRoot();
|
||||
var parserDiagnostics = parser.Diagnostics;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public FileSyntaxNode Root { get; }
|
||||
public RootSyntaxNode NullRoot { get; }
|
||||
public FileSyntaxNode Root => NullRoot.File;
|
||||
public DiagnosticsBag Diagnostics { get; }
|
||||
}
|
||||
|
||||
|
13
Parser/MissingTokenSyntaxDiagnostic.cs
Normal file
13
Parser/MissingTokenSyntaxDiagnostic.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
public struct Position
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
public int Line { get; set; }
|
||||
public int Column { get; set; }
|
||||
public int Offset { get; set; }
|
||||
|
23
Parser/SyntaxDiagnostic.cs
Normal file
23
Parser/SyntaxDiagnostic.cs
Normal 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
@ -15,6 +15,13 @@ namespace Parser
|
||||
Position = position;
|
||||
}
|
||||
|
||||
private protected SyntaxNode(Internal.GreenNode green, int position)
|
||||
{
|
||||
_parent = this;
|
||||
_green = green;
|
||||
Position = position;
|
||||
}
|
||||
|
||||
public TokenKind Kind => _green.Kind;
|
||||
|
||||
public SyntaxNode Parent => _parent;
|
||||
@ -43,9 +50,9 @@ namespace Parser
|
||||
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)
|
||||
{
|
||||
@ -89,6 +96,35 @@ namespace Parser
|
||||
}
|
||||
|
||||
public abstract void Accept(SyntaxVisitor visitor);
|
||||
|
||||
public SyntaxDiagnostic[] GetDiagnostics()
|
||||
{
|
||||
return GetDiagnosticsRecursive(_green, Position).ToArray();
|
||||
}
|
||||
|
||||
private static IEnumerable<SyntaxDiagnostic> GetDiagnosticsRecursive(Internal.GreenNode node, int position)
|
||||
{
|
||||
if (node.HasDiagnostics)
|
||||
{
|
||||
foreach (var diagnostic in node.GetDiagnostics())
|
||||
{
|
||||
yield return SyntaxDiagnostic.From(diagnostic, position);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < node.Slots; i++)
|
||||
{
|
||||
var maybeChild = node.GetSlot(i);
|
||||
if (maybeChild is Internal.GreenNode child) {
|
||||
foreach (var diagnostic in GetDiagnosticsRecursive(child, position))
|
||||
{
|
||||
yield return diagnostic;
|
||||
}
|
||||
|
||||
position += child.FullWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
public struct SyntaxNodeOrToken
|
||||
{
|
||||
private readonly Internal.GreenNode _token;
|
||||
private readonly Internal.GreenNode? _token;
|
||||
private readonly SyntaxNode _nodeOrParent;
|
||||
private readonly bool _isToken;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
public int Position { get; }
|
||||
|
||||
public SyntaxNode AsNode()
|
||||
public SyntaxNode? AsNode()
|
||||
{
|
||||
if (_isToken)
|
||||
{
|
||||
@ -43,7 +43,7 @@
|
||||
{
|
||||
return default(SyntaxToken);
|
||||
}
|
||||
return new SyntaxToken(_nodeOrParent, _token, Position);
|
||||
return new SyntaxToken(_nodeOrParent, _token!, Position);
|
||||
}
|
||||
|
||||
public static implicit operator SyntaxNodeOrToken(SyntaxToken token)
|
||||
|
@ -24,7 +24,7 @@ namespace Parser
|
||||
}
|
||||
else
|
||||
{
|
||||
return green.CreateRed(this, this.GetChildPosition(index));
|
||||
return green!.CreateRed(this, this.GetChildPosition(index));
|
||||
}
|
||||
}
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@ -81,7 +81,7 @@ namespace Parser
|
||||
|
||||
public int Count => _green.Slots;
|
||||
|
||||
internal override SyntaxNode GetNode(int index)
|
||||
internal override SyntaxNode? GetNode(int index)
|
||||
{
|
||||
if (index < _green.Slots)
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace Parser
|
||||
|
||||
public TokenKind Kind => _token.Kind;
|
||||
|
||||
public override string ToString()
|
||||
public override string? ToString()
|
||||
{
|
||||
return _token.ToString();
|
||||
}
|
||||
@ -34,7 +34,7 @@ namespace Parser
|
||||
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;
|
||||
return obj is SyntaxToken token && Equals(token);
|
||||
|
@ -22,7 +22,7 @@ namespace Parser
|
||||
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;
|
||||
return obj is SyntaxTrivia trivia && Equals(trivia);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#nullable enable
|
||||
namespace Parser
|
||||
{
|
||||
public partial class SyntaxVisitor
|
||||
@ -251,5 +252,10 @@ namespace Parser
|
||||
{
|
||||
DefaultVisit(node);
|
||||
}
|
||||
|
||||
public virtual void VisitEndKeyword(EndKeywordSyntaxNode node)
|
||||
{
|
||||
DefaultVisit(node);
|
||||
}
|
||||
}
|
||||
};
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
public abstract partial class SyntaxVisitor
|
||||
{
|
||||
public virtual void Visit(SyntaxNode node)
|
||||
public virtual void Visit(SyntaxNode? node)
|
||||
{
|
||||
node?.Accept(this);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
private Position _position;
|
||||
public Position Position => _position;
|
||||
|
||||
public TextWindow(string text, string fileName = null)
|
||||
public TextWindow(string text, string? fileName = null)
|
||||
{
|
||||
Text = text;
|
||||
_position = new Position
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
public class TextWindowWithNull : TextWindow
|
||||
{
|
||||
public TextWindowWithNull(string text, string fileName = null) : base(text, fileName)
|
||||
public TextWindowWithNull(string text, string? fileName = null) : base(text, fileName)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -271,5 +271,7 @@
|
||||
// ToggleSomething
|
||||
// end
|
||||
EventsList,
|
||||
EndKeyword,
|
||||
Root
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||
|
@ -15,7 +15,7 @@ namespace SyntaxGenerator
|
||||
|
||||
private static readonly List<(string visitorMethodName, string className)> Visitors = new List<(string, string)>();
|
||||
|
||||
private static string _outputPath;
|
||||
private static readonly string _outputPath;
|
||||
|
||||
static GenerateSyntax()
|
||||
{
|
||||
@ -62,12 +62,14 @@ namespace SyntaxGenerator
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -77,19 +79,40 @@ namespace SyntaxGenerator
|
||||
return widthAdjustment + fieldAssignment;
|
||||
}
|
||||
|
||||
private static string GenerateInternalConstructor(SyntaxNodeDescription node)
|
||||
private static string GenerateInternalConstructorSimple(SyntaxNodeDescription node)
|
||||
{
|
||||
var arguments = string.Join(
|
||||
",",
|
||||
node.Fields.Select(field => $"\n {field.FieldType} {field.FieldName}"));
|
||||
node.Fields.Select(field => $"\n {FullFieldType(field)} {field.FieldName}"));
|
||||
|
||||
var header =
|
||||
$" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName})\n";
|
||||
var slotsAssignment = $"\n Slots = {node.Fields.Length};\n";
|
||||
$" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName})";
|
||||
var slotsAssignment = $" Slots = {node.Fields.Length};";
|
||||
var assignments = string.Join(
|
||||
"",
|
||||
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)
|
||||
@ -100,9 +123,21 @@ namespace SyntaxGenerator
|
||||
return header + " {\n }\n";
|
||||
}
|
||||
|
||||
private static string GenerateInternalSetDiagnostics(SyntaxNodeDescription node)
|
||||
{
|
||||
var header = $" public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)";
|
||||
var arguments = string.Join(
|
||||
", ",
|
||||
node.Fields
|
||||
.Select(field => "_" + field.FieldName)
|
||||
.Concat(new[] { "diagnostics" }));
|
||||
var text = $" return new {node.ClassName}({arguments});";
|
||||
return header + "\n {\n" + text + "\n }\n";
|
||||
}
|
||||
|
||||
private static string GenerateInternalGetSlot(SyntaxNodeDescription node)
|
||||
{
|
||||
var header = $" public override GreenNode GetSlot(int i)\n";
|
||||
var header = $" public override GreenNode? GetSlot(int i)\n";
|
||||
var cases = string.Join(
|
||||
"",
|
||||
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)
|
||||
{
|
||||
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(
|
||||
"",
|
||||
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";
|
||||
return header
|
||||
+ " {\n switch (i)\n {\n"
|
||||
@ -148,15 +189,17 @@ namespace SyntaxGenerator
|
||||
var fields = string.Join(
|
||||
"",
|
||||
node.Fields.Select(GenerateInternalFieldDeclaration));
|
||||
var constructor = GenerateInternalConstructor(node);
|
||||
var constructor = GenerateInternalConstructors(node);
|
||||
var getSlot = GenerateInternalGetSlot(node);
|
||||
var createRed = GenerateCreateRed(node);
|
||||
var setDiagnostics = GenerateInternalSetDiagnostics(node);
|
||||
return
|
||||
header
|
||||
+ "\n {\n"
|
||||
+ fields + "\n"
|
||||
+ constructor + "\n"
|
||||
+ createRed + "\n"
|
||||
+ setDiagnostics + "\n"
|
||||
+ getSlot + " }\n";
|
||||
}
|
||||
|
||||
@ -185,12 +228,17 @@ namespace SyntaxGenerator
|
||||
{
|
||||
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 red = this.GetRed(ref this._{field.FieldName}, {index});\n"
|
||||
$" var red = this.GetRed(ref this._{fieldNameWithPossibleBang}, {index});\n"
|
||||
+ $" if (red != null)\n"
|
||||
+ $" return ({type})red;\n\n"
|
||||
+ $" return default({type});\n";
|
||||
+ $" {defaultReturnStatement}\n";
|
||||
return header + text + " }\n }\n";
|
||||
}
|
||||
|
||||
@ -257,7 +305,7 @@ namespace SyntaxGenerator
|
||||
|
||||
private static string GenerateInternalSyntaxNodeFile(SyntaxDescription syntax)
|
||||
{
|
||||
var header = $"namespace {InternalNamespace}\n";
|
||||
var header = $"#nullable enable\nnamespace {InternalNamespace}\n";
|
||||
var classes = string.Join(
|
||||
"\n",
|
||||
syntax.Nodes.Select(GenerateInternalClass)
|
||||
@ -267,7 +315,7 @@ namespace SyntaxGenerator
|
||||
|
||||
private static string GenerateSyntaxNodeFile(SyntaxDescription syntax)
|
||||
{
|
||||
var header = $"namespace {OuterNamespace}\n";
|
||||
var header = $"#nullable enable\nnamespace {OuterNamespace}\n";
|
||||
var classes = string.Join(
|
||||
"\n",
|
||||
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)
|
||||
{
|
||||
var methodName = FactoryMethodNameFromClassName(node.ClassName);
|
||||
var header = $" public {node.ClassName} {methodName}";
|
||||
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(
|
||||
", ",
|
||||
node.Fields.Select(field => $"\n {field.FieldName}"));
|
||||
@ -305,7 +358,7 @@ namespace SyntaxGenerator
|
||||
|
||||
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(
|
||||
"\n",
|
||||
syntax.Nodes.Select(GenerateFactoryMethod)
|
||||
@ -322,7 +375,7 @@ namespace SyntaxGenerator
|
||||
|
||||
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(
|
||||
"\n",
|
||||
Visitors.Select(GenerateVisitor));
|
||||
@ -335,8 +388,7 @@ namespace SyntaxGenerator
|
||||
var serializer = new XmlSerializer(typeof(SyntaxDescription));
|
||||
using (var stream = new FileStream("input.xml", FileMode.Open))
|
||||
{
|
||||
var syntax = serializer.Deserialize(stream) as SyntaxDescription;
|
||||
if (syntax == null)
|
||||
if (!(serializer.Deserialize(stream) is SyntaxDescription syntax))
|
||||
{
|
||||
Console.WriteLine("Couldn't deserialize syntax.");
|
||||
return;
|
||||
|
@ -34,5 +34,7 @@ namespace SyntaxGenerator
|
||||
public string FieldType { get; set; }
|
||||
[XmlAttribute("Name")]
|
||||
public string FieldName { get; set; }
|
||||
[XmlAttribute("Nullable")]
|
||||
public bool FieldIsNullable { get; set; }
|
||||
}
|
||||
}
|
@ -6,12 +6,12 @@
|
||||
</Class>
|
||||
<Class Name="FunctionDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="FunctionDeclaration">
|
||||
<Field Type="SyntaxToken" Name="functionKeyword" />
|
||||
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" />
|
||||
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" Nullable="true" />
|
||||
<Field Type="SyntaxToken" Name="name" />
|
||||
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" />
|
||||
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
|
||||
<Field Type="SyntaxList<SyntaxToken>" Name="commas" />
|
||||
<Field Type="SyntaxList" Name="body" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
<Field Type="EndKeywordSyntaxNode" Name="endKeyword" Nullable="true"/>
|
||||
</Class>
|
||||
<Class Name="FunctionOutputDescriptionSyntaxNode" BaseClass="SyntaxNode" Kind="FunctionOutputDescription">
|
||||
<Field Type="SyntaxList" Name="outputList" />
|
||||
@ -58,7 +58,7 @@
|
||||
<Field Type="SyntaxList<SyntaxToken>" Name="optionalCommas" />
|
||||
<Field Type="SyntaxList" Name="body" />
|
||||
<Field Type="SyntaxList<ElseifClause>" Name="elseifClauses" />
|
||||
<Field Type="ElseClause" Name="elseClause" />
|
||||
<Field Type="ElseClause" Name="elseClause" Nullable="true" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
<Class Name="ForStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ForStatement">
|
||||
@ -80,7 +80,7 @@
|
||||
<Class Name="TryCatchStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="TryCatchStatement">
|
||||
<Field Type="SyntaxToken" Name="tryKeyword" />
|
||||
<Field Type="SyntaxList" Name="tryBody" />
|
||||
<Field Type="CatchClauseSyntaxNode" Name="catchClause" />
|
||||
<Field Type="CatchClauseSyntaxNode" Name="catchClause" Nullable="true" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
<Class Name="ExpressionStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ExpressionStatement">
|
||||
@ -183,7 +183,7 @@
|
||||
</Class>
|
||||
<Class Name="AttributeSyntaxNode" BaseClass="SyntaxNode" Kind="Attribute">
|
||||
<Field Type="IdentifierNameSyntaxNode" Name="name" />
|
||||
<Field Type="AttributeAssignmentSyntaxNode" Name="assignment" />
|
||||
<Field Type="AttributeAssignmentSyntaxNode" Name="assignment" Nullable="true" />
|
||||
</Class>
|
||||
<Class Name="AttributeListSyntaxNode" BaseClass="SyntaxNode" Kind="AttributeList">
|
||||
<Field Type="SyntaxToken" Name="openingBracket" />
|
||||
@ -192,27 +192,27 @@
|
||||
</Class>
|
||||
<Class Name="MethodDefinitionSyntaxNode" BaseClass="MethodDeclarationSyntaxNode" Kind="MethodDefinition">
|
||||
<Field Type="SyntaxToken" Name="functionKeyword" />
|
||||
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" />
|
||||
<Field Type="FunctionOutputDescriptionSyntaxNode" Name="outputDescription" Nullable="true" />
|
||||
<Field Type="CompoundNameSyntaxNode" Name="name" />
|
||||
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" />
|
||||
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
|
||||
<Field Type="SyntaxList<SyntaxToken>" Name="commas" />
|
||||
<Field Type="SyntaxList" Name="body" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
<Field Type="EndKeywordSyntaxNode" Name="endKeyword" Nullable="true" />
|
||||
</Class>
|
||||
<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="FunctionInputDescriptionSyntaxNode" Name="inputDescription" />
|
||||
<Field Type="FunctionInputDescriptionSyntaxNode" Name="inputDescription" Nullable="true"/>
|
||||
</Class>
|
||||
<Class Name="MethodsListSyntaxNode" BaseClass="SyntaxNode" Kind="MethodsList">
|
||||
<Field Type="SyntaxToken" Name="methodsKeyword" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
|
||||
<Field Type="SyntaxList" Name="methods" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
<Class Name="PropertiesListSyntaxNode" BaseClass="SyntaxNode" Kind="PropertiesList">
|
||||
<Field Type="SyntaxToken" Name="propertiesKeyword" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
|
||||
<Field Type="SyntaxList" Name="properties" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
@ -222,9 +222,9 @@
|
||||
</Class>
|
||||
<Class Name="ClassDeclarationSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ClassDeclaration">
|
||||
<Field Type="SyntaxToken" Name="classdefKeyword" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
|
||||
<Field Type="IdentifierNameSyntaxNode" Name="className" />
|
||||
<Field Type="BaseClassListSyntaxNode" Name="baseClassList" />
|
||||
<Field Type="BaseClassListSyntaxNode" Name="baseClassList" Nullable="true" />
|
||||
<Field Type="SyntaxList" Name="nodes" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
@ -235,19 +235,22 @@
|
||||
</Class>
|
||||
<Class Name="EnumerationItemSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationItem">
|
||||
<Field Type="IdentifierNameSyntaxNode" Name="name" />
|
||||
<Field Type="EnumerationItemValueSyntaxNode" Name="values" />
|
||||
<Field Type="EnumerationItemValueSyntaxNode" Name="values" Nullable="true"/>
|
||||
<Field Type="SyntaxList<SyntaxToken>" Name="commas" />
|
||||
</Class>
|
||||
<Class Name="EnumerationListSyntaxNode" BaseClass="SyntaxNode" Kind="EnumerationList">
|
||||
<Field Type="SyntaxToken" Name="enumerationKeyword" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true"/>
|
||||
<Field Type="SyntaxList<EnumerationItemSyntaxNode>" Name="items" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
<Class Name="EventsListSyntaxNode" BaseClass="SyntaxNode" Kind="EventsList">
|
||||
<Field Type="SyntaxToken" Name="eventsKeyword" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" />
|
||||
<Field Type="AttributeListSyntaxNode" Name="attributes" Nullable="true" />
|
||||
<Field Type="SyntaxList" Name="events" />
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
<Class Name="EndKeywordSyntaxNode" BaseClass="SyntaxNode" Kind="EndKeyword">
|
||||
<Field Type="SyntaxToken" Name="endKeyword" />
|
||||
</Class>
|
||||
</Syntax>
|
||||
|
Loading…
x
Reference in New Issue
Block a user