From fb4cb901f21899764d31ce1a94b1b54190b11c4c Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Fri, 5 Oct 2018 19:14:43 +0200 Subject: [PATCH] Merge parser & lexer --- ConsoleDemo/ConsoleDemo.csproj | 10 + ConsoleDemo/DumbWalker.cs | 189 ++ ConsoleDemo/PrettyPrinter.cs | 504 ++++ {ProjectConsole => ConsoleDemo}/Program.cs | 164 +- ConsoleDemo/UsageGathering.cs | 151 + Lexer.Tests/Lexer.Tests.csproj | 14 - Lexer.Tests/MLexerShould.cs | 276 -- Lexer/IPosition.cs | 6 - Lexer/Lexer.csproj | 5 - Lexer/PositionInsideFile.cs | 14 - Lexer/PureToken.cs | 20 - Lexer/PureTokenFactory.cs | 111 - Lexer/Token.cs | 32 - Lexer/TokenKind.cs | 56 - Lexer/Trivia.cs | 14 - Lexer/TriviaType.cs | 10 - Parser.Tests/MParserShould.cs | 488 +-- Parser.Tests/Parser.Tests.csproj | 7 +- .../TextWindowShould.cs | 2 +- .../TextWindowWithNullShould.cs | 2 +- Parser/ChildNodesAndTokensList.cs | 145 + {Lexer => Parser}/ILexer.cs | 4 +- {Lexer => Parser}/ITextWindow.cs | 4 +- Parser/Internal/GreenNode.cs | 217 ++ .../Internal/MLexerGreen.cs | 574 ++-- Parser/Internal/MParserGreen.cs | 1117 +++++++ Parser/Internal/SyntaxFactory.Generated.cs | 555 ++++ Parser/Internal/SyntaxFactory.cs | 6 + Parser/Internal/SyntaxFacts.cs | 276 ++ Parser/Internal/SyntaxList.cs | 32 + Parser/Internal/SyntaxListBuilder.cs | 33 + Parser/Internal/SyntaxListBuilder`1.cs | 25 + Parser/Internal/SyntaxList`1.cs | 32 + Parser/Internal/SyntaxNode.Generated.cs | 1652 +++++++++++ Parser/Internal/SyntaxNode.cs | 82 + Parser/Internal/SyntaxToken.cs | 215 ++ Parser/Internal/SyntaxTrivia.cs | 41 + Parser/Internal/TokenFactory.cs | 60 + Parser/MParser.cs | 938 +----- Parser/Parser.csproj | 4 +- {Lexer => Parser}/ParsingException.cs | 2 +- Parser/Position.cs | 14 + Parser/SyntaxFactory.cs | 592 ---- Parser/SyntaxNode.Generated.cs | 2631 +++++++++++++++++ Parser/SyntaxNode.cs | 774 +---- Parser/SyntaxNodeOrToken.cs | 55 + Parser/SyntaxNodeOrTokenList.cs | 103 + Parser/SyntaxToken.cs | 80 + Parser/SyntaxTrivia.cs | 57 + Parser/SyntaxVisitor.Generated.cs | 255 ++ Parser/SyntaxVisitor.cs | 19 + Parser/SyntaxWalker.cs | 24 + {Lexer => Parser}/TextWindow.cs | 10 +- {Lexer => Parser}/TextWindowWithNull.cs | 2 +- Parser/TokenKind.cs | 115 + Semantics/ClassContext.cs | 32 + Semantics/Context.cs | 141 + Semantics/FunctionContext.cs | 12 + Semantics/GetClass.cs | 82 + Semantics/MClass.cs | 21 + Semantics/MMethod.cs | 15 + Semantics/MethodAssignments.cs | 30 + Semantics/PackageContext.cs | 33 + .../Semantics.csproj | 3 +- Semantics/Variable.cs | 7 + Semantics/VariableAssignments.cs | 30 + Solution.sln | 26 +- SyntaxGenerator/GenerateSyntax.cs | 360 +++ SyntaxGenerator/SyntaxGenerator.csproj | 11 + SyntaxGenerator/SyntaxNodeDescription.cs | 38 + SyntaxGenerator/input.xml | 253 ++ 71 files changed, 10265 insertions(+), 3649 deletions(-) create mode 100644 ConsoleDemo/ConsoleDemo.csproj create mode 100644 ConsoleDemo/DumbWalker.cs create mode 100644 ConsoleDemo/PrettyPrinter.cs rename {ProjectConsole => ConsoleDemo}/Program.cs (51%) create mode 100644 ConsoleDemo/UsageGathering.cs delete mode 100644 Lexer.Tests/Lexer.Tests.csproj delete mode 100644 Lexer.Tests/MLexerShould.cs delete mode 100644 Lexer/IPosition.cs delete mode 100644 Lexer/Lexer.csproj delete mode 100644 Lexer/PositionInsideFile.cs delete mode 100644 Lexer/PureToken.cs delete mode 100644 Lexer/PureTokenFactory.cs delete mode 100644 Lexer/Token.cs delete mode 100644 Lexer/TokenKind.cs delete mode 100644 Lexer/Trivia.cs delete mode 100644 Lexer/TriviaType.cs rename {Lexer.Tests => Parser.Tests}/TextWindowShould.cs (97%) rename {Lexer.Tests => Parser.Tests}/TextWindowWithNullShould.cs (96%) create mode 100644 Parser/ChildNodesAndTokensList.cs rename {Lexer => Parser}/ILexer.cs (62%) rename {Lexer => Parser}/ITextWindow.cs (84%) create mode 100644 Parser/Internal/GreenNode.cs rename Lexer/MLexer.cs => Parser/Internal/MLexerGreen.cs (57%) create mode 100644 Parser/Internal/MParserGreen.cs create mode 100644 Parser/Internal/SyntaxFactory.Generated.cs create mode 100644 Parser/Internal/SyntaxFactory.cs create mode 100644 Parser/Internal/SyntaxFacts.cs create mode 100644 Parser/Internal/SyntaxList.cs create mode 100644 Parser/Internal/SyntaxListBuilder.cs create mode 100644 Parser/Internal/SyntaxListBuilder`1.cs create mode 100644 Parser/Internal/SyntaxList`1.cs create mode 100644 Parser/Internal/SyntaxNode.Generated.cs create mode 100644 Parser/Internal/SyntaxNode.cs create mode 100644 Parser/Internal/SyntaxToken.cs create mode 100644 Parser/Internal/SyntaxTrivia.cs create mode 100644 Parser/Internal/TokenFactory.cs rename {Lexer => Parser}/ParsingException.cs (89%) create mode 100644 Parser/Position.cs delete mode 100644 Parser/SyntaxFactory.cs create mode 100644 Parser/SyntaxNode.Generated.cs create mode 100644 Parser/SyntaxNodeOrToken.cs create mode 100644 Parser/SyntaxNodeOrTokenList.cs create mode 100644 Parser/SyntaxToken.cs create mode 100644 Parser/SyntaxTrivia.cs create mode 100644 Parser/SyntaxVisitor.Generated.cs create mode 100644 Parser/SyntaxVisitor.cs create mode 100644 Parser/SyntaxWalker.cs rename {Lexer => Parser}/TextWindow.cs (90%) rename {Lexer => Parser}/TextWindowWithNull.cs (95%) create mode 100644 Parser/TokenKind.cs create mode 100644 Semantics/ClassContext.cs create mode 100644 Semantics/Context.cs create mode 100644 Semantics/FunctionContext.cs create mode 100644 Semantics/GetClass.cs create mode 100644 Semantics/MClass.cs create mode 100644 Semantics/MMethod.cs create mode 100644 Semantics/MethodAssignments.cs create mode 100644 Semantics/PackageContext.cs rename ProjectConsole/ProjectConsole.csproj => Semantics/Semantics.csproj (66%) create mode 100644 Semantics/Variable.cs create mode 100644 Semantics/VariableAssignments.cs create mode 100644 SyntaxGenerator/GenerateSyntax.cs create mode 100644 SyntaxGenerator/SyntaxGenerator.csproj create mode 100644 SyntaxGenerator/SyntaxNodeDescription.cs create mode 100644 SyntaxGenerator/input.xml diff --git a/ConsoleDemo/ConsoleDemo.csproj b/ConsoleDemo/ConsoleDemo.csproj new file mode 100644 index 0000000..8e56b75 --- /dev/null +++ b/ConsoleDemo/ConsoleDemo.csproj @@ -0,0 +1,10 @@ + + + Exe + netcoreapp2.1 + + + + + + \ No newline at end of file diff --git a/ConsoleDemo/DumbWalker.cs b/ConsoleDemo/DumbWalker.cs new file mode 100644 index 0000000..909db41 --- /dev/null +++ b/ConsoleDemo/DumbWalker.cs @@ -0,0 +1,189 @@ +using System; +using System.Linq; +using Parser; +using Semantics; + +namespace ConsoleDemo +{ + public class DumbWalker : SyntaxWalker + { + private bool _insideMethod; + private bool _insideFunction; + private VariableAssignments _variableAssignments; + private MethodAssignments _methodAssignments; + private Context _context; + + public DumbWalker(Context context) + { + _context = context; + } + + private void Assign(SyntaxNode lhs, SyntaxNode rhs) + { + switch (lhs.Kind) + { + case TokenKind.IdentifierName: + var name = ((IdentifierNameSyntaxNode) lhs).Name.Text; + Console.WriteLine($"Adding variable assignment for {name}"); + _variableAssignments.Add(name, new Variable()); + break; + default: + break; + } + } + + public override void VisitAssignmentExpression(AssignmentExpressionSyntaxNode node) + { + if (_insideMethod || _insideFunction) + { + Console.Write($"Assignment: {node.Lhs} <- {node.Rhs}..."); + if (IsDefined(node.Rhs)) + { + Console.WriteLine("Ok."); + Assign(node.Lhs, node.Rhs); + } + else + { + Console.WriteLine("Right-hand side is not defined!"); + } + } + } + + private bool IsDefinedToken(SyntaxToken token) + { + switch (token.Kind) + { + case TokenKind.Comma: + return true; + default: + break; + } + + return false; + } + + private bool IsDefinedFunctionName(SyntaxNode node) + { + switch (node.Kind) + { + case TokenKind.IdentifierName: + var name = (IdentifierNameSyntaxNode) node; + if (_context.FindFunction(name.Name.Text)) + { + return true; + } + + if (_methodAssignments.Find(name.Text) != null) + { + return true; + } + break; + default: + break; + } + + return false; + } + + private bool IsDefined(SyntaxNode node) + { + Variable assignment; + switch (node.Kind) + { + case TokenKind.IdentifierName: + assignment = _variableAssignments.Find(node.Text); + if (assignment != null || node.Text == "end") + { + return true; + } + + break; + case TokenKind.FunctionCall: + var functionCall = (FunctionCallExpressionSyntaxNode)node; + return + (IsDefined(functionCall.FunctionName) && IsDefined(functionCall.Nodes)) || + (IsDefinedFunctionName(functionCall.FunctionName) && IsDefined(functionCall.Nodes)); + case TokenKind.CellArrayElementAccess: + var cellArrayElementAccess = (CellArrayElementAccessExpressionSyntaxNode) node; + return IsDefined(cellArrayElementAccess.Expression) && IsDefined(cellArrayElementAccess.Nodes); + case TokenKind.List: + var list = (SyntaxNodeOrTokenList) node; + return list.All(x => x.IsNode ? IsDefined(x.AsNode()) : IsDefinedToken(x.AsToken())); + case TokenKind.NumberLiteralExpression: + return true; + case TokenKind.StringLiteralExpression: + return true; + case TokenKind.BinaryOperation: + var binaryOperation = (BinaryOperationExpressionSyntaxNode) node; + return IsDefined(binaryOperation.Lhs) && IsDefined(binaryOperation.Rhs); + case TokenKind.UnaryPrefixOperationExpression: + var unaryOperation = (UnaryPrefixOperationExpressionSyntaxNode) node; + return IsDefined(unaryOperation.Operand); + case TokenKind.ArrayLiteralExpression: + var arrayLiteral = (ArrayLiteralExpressionSyntaxNode) node; + return arrayLiteral.Nodes == null || IsDefined(arrayLiteral.Nodes); + default: + break; + } + return false; + } + + public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node) + { + _insideFunction = true; + _variableAssignments = new VariableAssignments(); + var parameterList = node.InputDescription.ParameterList; + foreach (var parameter in parameterList) + { + if (parameter.IsNode) + { + var parameterAsNode = parameter.AsNode(); + Console.WriteLine($"Parameter node: {parameterAsNode}"); + if (parameterAsNode.Kind == TokenKind.IdentifierName) + { + Console.WriteLine($"Adding variable assignment for {parameterAsNode.Text}"); + _variableAssignments.Add(parameterAsNode.Text, new Variable()); + } + else + { + Console.WriteLine($"Don't know how to add assignment for {parameterAsNode.Text}"); + } + } + else + { + Console.WriteLine($"Parameter token: {parameter.AsToken()}"); + } + } + base.VisitFunctionDeclaration(node); + _variableAssignments = null; + _insideFunction = false; + } + + public override void VisitMethodDefinition(MethodDefinitionSyntaxNode node) + { + _insideMethod = true; + base.VisitMethodDefinition(node); + _insideMethod = false; + } + + public override void VisitFile(FileSyntaxNode node) + { + _methodAssignments = new MethodAssignments(); + foreach (var nodeOrToken in node.StatementList) + { + if (nodeOrToken.IsToken) + { + continue; + } + + var n = nodeOrToken.AsNode(); + if (n.Kind == TokenKind.FunctionDeclaration) + { + var functionDeclaration = (FunctionDeclarationSyntaxNode) n; + _methodAssignments.Add(functionDeclaration.Name.Text, new Variable()); + } + } + base.VisitFile(node); + } + } +} diff --git a/ConsoleDemo/PrettyPrinter.cs b/ConsoleDemo/PrettyPrinter.cs new file mode 100644 index 0000000..143aa82 --- /dev/null +++ b/ConsoleDemo/PrettyPrinter.cs @@ -0,0 +1,504 @@ +using System; +using Parser; +using Parser.Internal; + +namespace ProjectConsole +{ + public class PrettyPrinter : SyntaxVisitor + { + public override void VisitFile(FileSyntaxNode node) + { + Visit(node.StatementList); + OutputKeyword(node.EndOfFile); + } + + private void PrintToken(SyntaxToken token, ConsoleColor color, bool useBold = false) + { + if (token == default(SyntaxToken)) + { + return; + } + Console.ForegroundColor = ConsoleColor.DarkGray; + foreach (var t in token.LeadingTrivia) + { + Console.Write(t); + } + + Console.ForegroundColor = color; + if (useBold) + { + BoldOn(); + } + Console.Write(token.Text); + if (useBold) + { + BoldOff(); + } + + Console.ForegroundColor = ConsoleColor.DarkGray; + foreach (var t in token.TrailingTrivia) + { + Console.Write(t); + } + } + + private static void UnderlineOn() + { + Console.Write("\x1b[4m"); + } + + private static void UnderlineOff() + { + Console.Write("\x1b[0m"); + } + + private static void BoldOn() + { + Console.Write("\x1b[1m"); + } + + private static void BoldOff() + { + Console.Write("\x1b[0m"); + } + + private void OutputKeyword(SyntaxToken token) + { + PrintToken(token, ConsoleColor.Green, useBold: true); + } + + private void OutputControlKeyword(SyntaxToken token) + { + PrintToken(token, ConsoleColor.Yellow, useBold: true); + } + + private void OutputPunctuation(SyntaxToken token) + { + PrintToken(token, ConsoleColor.DarkBlue); + } + + private void OutputOperator(SyntaxToken token) + { + PrintToken(token, ConsoleColor.Cyan); + } + + private void OutputIdentifier(SyntaxToken token) + { + PrintToken(token, ConsoleColor.White, useBold: true); + } + + private void OutputUnquotedStringLiteral(SyntaxToken token) + { + PrintToken(token, ConsoleColor.Blue); + } + + private void OutputStringLiteral(SyntaxToken token) + { + PrintToken(token, ConsoleColor.Magenta); + } + + private void OutputNumberLiteral(SyntaxToken token) + { + PrintToken(token, ConsoleColor.DarkGreen); + } + + private void OutputBracket(SyntaxToken token) + { + PrintToken(token, ConsoleColor.DarkYellow); + } + + public override void VisitBaseClassList(BaseClassListSyntaxNode node) + { + OutputPunctuation(node.LessSign); + Visit(node.BaseClasses); + } + + public override void VisitClassDeclaration(ClassDeclarationSyntaxNode node) + { + OutputKeyword(node.ClassdefKeyword); + Visit(node.Attributes); + BoldOn(); + Visit(node.ClassName); + BoldOff(); + Visit(node.BaseClassList); + Visit(node.Nodes); + OutputKeyword(node.EndKeyword); + } + + public override void DefaultVisit(SyntaxNode node) + { + Console.ForegroundColor = ConsoleColor.Gray; + foreach (var t in node.LeadingTrivia) + { + Console.Write(t); + } + + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write(node.Text); + + Console.ForegroundColor = ConsoleColor.DarkGray; + foreach (var t in node.TrailingTrivia) + { + Console.Write(t); + } + } + + public override void VisitList(SyntaxNodeOrTokenList list) + { + foreach (var nodeOrToken in list) + { + if (nodeOrToken.IsToken) + { + var token = nodeOrToken.AsToken(); + if (token.Kind == TokenKind.Identifier) + { + OutputIdentifier(token); + } + else if (SyntaxFacts.IsBracket(token.Kind)) + { + OutputBracket(token); + } + else + { + OutputPunctuation(token); + } + } + else + { + Visit(nodeOrToken.AsNode()); + } + } + } + + public override void VisitMethodsList(MethodsListSyntaxNode node) + { + OutputKeyword(node.MethodsKeyword); + Visit(node.Attributes); + Visit(node.Methods); + OutputKeyword(node.EndKeyword); + } + + public override void VisitPropertiesList(PropertiesListSyntaxNode node) + { + OutputKeyword(node.PropertiesKeyword); + Visit(node.Attributes); + Visit(node.Properties); + OutputKeyword(node.EndKeyword); + } + + public override void VisitMethodDefinition(MethodDefinitionSyntaxNode node) + { + OutputKeyword(node.FunctionKeyword); + Visit(node.OutputDescription); + BoldOn(); + Visit(node.Name); + BoldOff(); + Visit(node.InputDescription); + Visit(node.Commas); + Visit(node.Body); + OutputKeyword(node.EndKeyword); + } + + public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node) + { + OutputKeyword(node.FunctionKeyword); + Visit(node.OutputDescription); + OutputIdentifier(node.Name); + Visit(node.InputDescription); + Visit(node.Commas); + Visit(node.Body); + OutputKeyword(node.EndKeyword); + } + + public override void VisitIfStatement(IfStatementSyntaxNode node) + { + OutputControlKeyword(node.IfKeyword); + Visit(node.Condition); + Visit(node.OptionalCommas); + Visit(node.Body); + Visit(node.ElseifClauses); + Visit(node.ElseClause); + OutputControlKeyword(node.EndKeyword); + } + + public override void VisitElseClause(ElseClause node) + { + OutputControlKeyword(node.ElseKeyword); + Visit(node.Body); + } + + public override void VisitElseifClause(ElseifClause node) + { + OutputControlKeyword(node.ElseifKeyword); + Visit(node.Condition); + Visit(node.Body); + } + + public override void VisitAbstractMethodDeclaration(AbstractMethodDeclarationSyntaxNode node) + { + Visit(node.OutputDescription); + BoldOn(); + Visit(node.Name); + BoldOff(); + Visit(node.InputDescription); + } + + public override void VisitAssignmentExpression(AssignmentExpressionSyntaxNode node) + { + Visit(node.Lhs); + OutputOperator(node.AssignmentSign); + Visit(node.Rhs); + } + + public override void VisitExpressionStatement(ExpressionStatementSyntaxNode node) + { + Visit(node.Expression); + } + + public override void VisitArrayLiteralExpression(ArrayLiteralExpressionSyntaxNode node) + { + OutputBracket(node.OpeningSquareBracket); + Visit(node.Nodes); + OutputBracket(node.ClosingSquareBracket); + } + + public override void VisitCellArrayLiteralExpression(CellArrayLiteralExpressionSyntaxNode node) + { + OutputBracket(node.OpeningBrace); + Visit(node.Nodes); + OutputBracket(node.ClosingBrace); + } + + public override void VisitIdentifierName(IdentifierNameSyntaxNode node) + { + OutputIdentifier(node.Name); + } + + public override void VisitForStatement(ForStatementSyntaxNode node) + { + OutputControlKeyword(node.ForKeyword); + Visit(node.Assignment); + Visit(node.OptionalCommas); + Visit(node.Body); + OutputControlKeyword(node.EndKeyword); + } + + public override void VisitSwitchStatement(SwitchStatementSyntaxNode node) + { + OutputControlKeyword(node.SwitchKeyword); + Visit(node.SwitchExpression); + Visit(node.OptionalCommas); + Visit(node.Cases); + OutputControlKeyword(node.EndKeyword); + } + + public override void VisitWhileStatement(WhileStatementSyntaxNode node) + { + OutputControlKeyword(node.WhileKeyword); + Visit(node.Condition); + Visit(node.OptionalCommas); + Visit(node.Body); + OutputControlKeyword(node.EndKeyword); + } + + public override void VisitUnquotedStringLiteral(UnquotedStringLiteralSyntaxNode node) + { + OutputUnquotedStringLiteral(node.StringToken); + } + + public override void VisitStringLiteral(StringLiteralSyntaxNode node) + { + OutputStringLiteral(node.StringToken); + } + + public override void VisitBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node) + { + Visit(node.Lhs); + OutputOperator(node.Operation); + Visit(node.Rhs); + } + + public override void VisitFunctionCallExpression(FunctionCallExpressionSyntaxNode node) + { + Visit(node.FunctionName); + OutputBracket(node.OpeningBracket); + Visit(node.Nodes); + OutputBracket(node.ClosingBracket); + } + + public override void VisitSwitchCase(SwitchCaseSyntaxNode node) + { + OutputControlKeyword(node.CaseKeyword); + Visit(node.CaseIdentifier); + Visit(node.OptionalCommas); + Visit(node.Body); + } + + public override void VisitCatchClause(CatchClauseSyntaxNode node) + { + OutputControlKeyword(node.CatchKeyword); + Visit(node.CatchBody); + } + + public override void VisitTryCatchStatement(TryCatchStatementSyntaxNode node) + { + OutputControlKeyword(node.TryKeyword); + Visit(node.TryBody); + Visit(node.CatchClause); + OutputControlKeyword(node.EndKeyword); + } + + public override void VisitCommandExpression(CommandExpressionSyntaxNode node) + { + Visit(node.CommandName); + Visit(node.Arguments); + } + + public override void VisitNumberLiteral(NumberLiteralSyntaxNode node) + { + OutputNumberLiteral(node.Number); + } + + public override void VisitUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node) + { + OutputOperator(node.Operation); + Visit(node.Operand); + } + + public override void VisitUnaryPostixOperationExpression(UnaryPostixOperationExpressionSyntaxNode node) + { + Visit(node.Operand); + OutputOperator(node.Operation); + } + + public override void VisitBaseClassInvokation(BaseClassInvokationSyntaxNode node) + { + Visit(node.MethodName); + OutputOperator(node.AtSign); + Visit(node.BaseClassNameAndArguments); + } + + public override void VisitAttributeAssignment(AttributeAssignmentSyntaxNode node) + { + OutputOperator(node.AssignmentSign); + Visit(node.Value); + } + + public override void VisitAttribute(AttributeSyntaxNode node) + { + Visit(node.Name); + Visit(node.Assignment); + } + + public override void VisitAttributeList(AttributeListSyntaxNode node) + { + OutputBracket(node.OpeningBracket); + Visit(node.Nodes); + OutputBracket(node.ClosingBracket); + } + + public override void VisitCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node) + { + Visit(node.Expression); + OutputBracket(node.OpeningBrace); + Visit(node.Nodes); + OutputBracket(node.ClosingBrace); + } + + public override void VisitCompoundName(CompoundNameSyntaxNode node) + { + Visit(node.Nodes); + } + + public override void VisitDoubleQuotedStringLiteral(DoubleQuotedStringLiteralSyntaxNode node) + { + OutputStringLiteral(node.StringToken); + } + + public override void VisitEmptyExpression(EmptyExpressionSyntaxNode node) + { + } + + public override void VisitEmptyStatement(EmptyStatementSyntaxNode node) + { + OutputPunctuation(node.Semicolon); + } + + public override void VisitEnumerationList(EnumerationListSyntaxNode node) + { + OutputKeyword(node.EnumerationKeyword); + Visit(node.Attributes); + Visit(node.Items); + OutputKeyword(node.EndKeyword); + } + + public override void VisitEventsList(EventsListSyntaxNode node) + { + OutputKeyword(node.EventsKeyword); + Visit(node.Attributes); + Visit(node.Events); + OutputKeyword(node.EndKeyword); + } + + public override void VisitEnumerationItemValue(EnumerationItemValueSyntaxNode node) + { + OutputPunctuation(node.OpeningBracket); + Visit(node.Values); + OutputPunctuation(node.ClosingBracket); + } + + public override void VisitEnumerationItem(EnumerationItemSyntaxNode node) + { + Visit(node.Name); + Visit(node.Values); + Visit(node.Commas); + } + + public override void VisitFunctionInputDescription(FunctionInputDescriptionSyntaxNode node) + { + OutputBracket(node.OpeningBracket); + Visit(node.ParameterList); + OutputBracket(node.ClosingBracket); + } + + public override void VisitFunctionOutputDescription(FunctionOutputDescriptionSyntaxNode node) + { + Visit(node.OutputList); + OutputOperator(node.AssignmentSign); + } + + public override void VisitIndirectMemberAccess(IndirectMemberAccessSyntaxNode node) + { + OutputBracket(node.OpeningBracket); + Visit(node.Expression); + OutputBracket(node.ClosingBracket); + } + + public override void VisitLambda(LambdaSyntaxNode node) + { + OutputOperator(node.AtSign); + Visit(node.Input); + Visit(node.Body); + } + + public override void VisitNamedFunctionHandle(NamedFunctionHandleSyntaxNode node) + { + OutputOperator(node.AtSign); + Visit(node.FunctionName); + } + + public override void VisitMemberAccess(MemberAccessSyntaxNode node) + { + Visit(node.LeftOperand); + OutputOperator(node.Dot); + Visit(node.RightOperand); + } + + public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntaxNode node) + { + OutputBracket(node.OpeningBracket); + Visit(node.Expression); + OutputBracket(node.ClosingBracket); + } + } +} \ No newline at end of file diff --git a/ProjectConsole/Program.cs b/ConsoleDemo/Program.cs similarity index 51% rename from ProjectConsole/Program.cs rename to ConsoleDemo/Program.cs index 459416f..424bd46 100644 --- a/ProjectConsole/Program.cs +++ b/ConsoleDemo/Program.cs @@ -2,19 +2,19 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; -using Lexer; using Parser; +using ProjectConsole; +using Semantics; -namespace ProjectConsole +namespace ConsoleDemo { class Program { private static readonly string BaseDirectory; private const string BaseDirectoryMacOs = @"/Applications/MATLAB_R2017b.app/toolbox/matlab/"; - private const string BaseDirectoryWindows = @"C:\Program Files\MATLAB\R2018a\toolbox\matlab\"; + private const string BaseDirectoryWindows = @"D:\Program Files\MATLAB\R2018a\toolbox\matlab\"; - private static HashSet skipFiles = new HashSet + private static readonly HashSet SkipFiles = new HashSet { @"codetools\private\template.m", // this is a template, so it contains '$' characters. @"plottools\+matlab\+graphics\+internal\+propertyinspector\+views\CategoricalHistogramPropertyView.m", // this one contains a 0xA0 character (probably it's 'non-breakable space' in Win-1252). @@ -26,32 +26,31 @@ namespace ProjectConsole @"plottools/+matlab/+graphics/+internal/+propertyinspector/+views/PrimitiveHistogramPropertyView.m", // same }; - static void ProcessFile(string fileName) + private static MParser CreateParser(ITextWindow window) + { + return new MParser(window); + } + + private static void ProcessFile(string fileName) { var text = File.ReadAllText(fileName); - Console.WriteLine($"Parsing {fileName}..."); + //Console.Write($"Parsing {fileName}..."); var window = new TextWindowWithNull(text, fileName); - ILexer lexer = new MLexer(window, new PureTokenFactory(window)); - var tokens = lexer.ParseAll(); - //AfterFunction(tokens); - //FirstToken(tokens); - var parser = new MParser(tokens); + var parser = CreateParser(window); var tree = parser.Parse(); - var back = string.Join("", tokens.Select(token => token.FullText)); - if (text != back) + //Console.WriteLine("Done."); + var actual = tree.FullText; + if (actual != text) { throw new ApplicationException(); } + //var printer = new PrettyPrinter(); + //printer.Visit(tree); + //Console.ReadKey(); } - private static readonly int[] firstTokenCount; - private static readonly int[] afterFunctionCount; - static Program() { - var maxKind = ((int[]) typeof(TokenKind).GetEnumValues()).Max(); - firstTokenCount = new int[maxKind + 1]; - afterFunctionCount = new int[maxKind + 1]; switch (Environment.OSVersion.Platform) { case PlatformID.MacOSX: @@ -64,57 +63,14 @@ namespace ProjectConsole } } - static void AfterFunction(List tokens) - { - for (var i = 0; i < tokens.Count; i++) - { - if (tokens[i].PureToken.Kind == TokenKind.Identifier && - tokens[i].PureToken.LiteralText == "function") - { - var nextKind = tokens[i + 1].PureToken.Kind; - afterFunctionCount[(int) nextKind]++; - if (nextKind != TokenKind.Identifier && nextKind != TokenKind.OpeningSquareBracket) - { - Console.WriteLine("===EXAMPLE==="); - Console.WriteLine($"{tokens[i]}{tokens[i+1]}"); - } - } - } - } - - static void FirstToken(List tokens) - { - var firstKind = tokens[0].PureToken.Kind; - firstTokenCount[(int) firstKind]++; - } - - static void AfterFunctionFinish() - { - for (var i = 0; i < afterFunctionCount.Length; i++) - { - Console.WriteLine($"{(TokenKind)i}: {afterFunctionCount[i]}."); - } - } - - static void FirstTokenFinish() - { - for (var i = 0; i < firstTokenCount.Length; i++) - { - if (firstTokenCount[i] != 0) - { - Console.WriteLine($"{(TokenKind) i}: {firstTokenCount[i]}."); - } - } - } - - static int ProcessDirectory(string directory) + private static int ProcessDirectory(string directory) { var counter = 0; var files = Directory.GetFiles(directory, "*.m"); foreach (var file in files) { var relativePath = Path.GetRelativePath(BaseDirectory, file); - if (skipFiles.Contains(relativePath)) + if (SkipFiles.Contains(relativePath)) { continue; } @@ -130,8 +86,8 @@ namespace ProjectConsole return counter; } - - static void Main(string[] args) + + private static void ParserDemo() { Console.WriteLine("Hello World!"); var sw = new Stopwatch(); @@ -141,6 +97,80 @@ namespace ProjectConsole Console.WriteLine($"{processed} files parsed. Elapsed: {sw.Elapsed}."); //AfterFunctionFinish(); //FirstTokenFinish(); + Console.ReadKey(); + } + + private static FileSyntaxNode GetTree(string fileName) + { + var text = File.ReadAllText(fileName); + var window = new TextWindowWithNull(text, fileName); + var parser = CreateParser(window); + var tree = parser.Parse(); + return tree; + } + + public static void SemanticsDemo() + { + var fileName = Path.Combine( + BaseDirectory, + "datatypes", + "@table", + "table.m"); + var tree = GetTree(fileName); + var childNodesAndTokens = tree.GetChildNodesAndTokens(); + var node = childNodesAndTokens[0].AsNode(); + var classChildNodesAndTokens = node.GetChildNodesAndTokens(); + var c = GetClass.FromTree(tree, fileName); + Console.WriteLine(c.Name); + foreach (var m in c.Methods) + { + Console.WriteLine($"* Method {m.Name}"); + if (m.Description != "") + { + Console.WriteLine($"* Description: {m.Description}"); + } + } + } + + public static void ContextDemo() + { + var context = new Context(); + context.ScanPath(BaseDirectory); + } + + public static void DumbPrinterDemo() + { + var context = new Context(); + context.ScanPath(BaseDirectory); + var fileName = Path.Combine( + BaseDirectory, + "specgraph", + "heatmap.m"); + var tree = GetTree(fileName); + var printer = new DumbWalker(context); + printer.Visit(tree); + } + + public static void UsageDemo() + { + var context = new Context(); + context.ScanPath(BaseDirectory); + var fileName = Path.Combine( + BaseDirectory, + "specgraph", + "heatmap.m"); + var tree = GetTree(fileName); + var printer = new UsageGathering(context); + printer.Visit(tree); + } + + public static void Main(string[] args) + { + //ParserDemo(); + //SemanticsDemo(); + //ContextDemo(); + //DumbPrinterDemo(); + UsageDemo(); Console.ReadKey(); } } diff --git a/ConsoleDemo/UsageGathering.cs b/ConsoleDemo/UsageGathering.cs new file mode 100644 index 0000000..9ad4de3 --- /dev/null +++ b/ConsoleDemo/UsageGathering.cs @@ -0,0 +1,151 @@ +using System; +using Parser; +using Semantics; + +namespace ConsoleDemo +{ + public class UsageGathering : SyntaxWalker + { + private MethodAssignments _methodAssignments; + private VariableAssignments _variableAssignments; + private bool _insideFunction; + private bool _insideMethod; + + private Context _context; + + public UsageGathering(Context context) + { + _context = context; + } + + public override void VisitFunctionCallExpression(FunctionCallExpressionSyntaxNode node) + { + if (!(_insideFunction || _insideMethod)) + { + return; + } + var name = node.FunctionName.Text; + if (_variableAssignments.Find(name) != null) + { + return; + } + Console.Write($"Function call: {name}..."); + if (_context.FindFunction(name) || _methodAssignments.Find(name) != null) + { + Console.WriteLine("found."); + } + else + { + Console.WriteLine("NOT FOUND."); + } + base.VisitFunctionCallExpression(node); + } + + private void Assign(SyntaxNode lhs, SyntaxNode rhs) + { + switch (lhs.Kind) + { + case TokenKind.IdentifierName: + var name = ((IdentifierNameSyntaxNode)lhs).Name.Text; + Console.WriteLine($"Adding variable assignment for {name}"); + _variableAssignments.Add(name, new Variable()); + break; + default: + break; + } + } + + public override void VisitAssignmentExpression(AssignmentExpressionSyntaxNode node) + { + if (!(_insideFunction || _insideMethod)) + { + return; + } + Assign(node.Lhs, node.Rhs); + base.VisitAssignmentExpression(node); + } + + public override void VisitFile(FileSyntaxNode node) + { + _methodAssignments = new MethodAssignments(); + foreach (var nodeOrToken in node.StatementList) + { + if (nodeOrToken.IsToken) + { + continue; + } + + var n = nodeOrToken.AsNode(); + if (n.Kind == TokenKind.FunctionDeclaration) + { + var functionDeclaration = (FunctionDeclarationSyntaxNode)n; + _methodAssignments.Add(functionDeclaration.Name.Text, new Variable()); + } + } + base.VisitFile(node); + } + + public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node) + { + _insideFunction = true; + _variableAssignments = new VariableAssignments(); + var parameterList = node.InputDescription.ParameterList; + foreach (var parameter in parameterList) + { + if (parameter.IsNode) + { + var parameterAsNode = parameter.AsNode(); + Console.WriteLine($"Parameter node: {parameterAsNode}"); + if (parameterAsNode.Kind == TokenKind.IdentifierName) + { + Console.WriteLine($"Adding variable assignment for {parameterAsNode.Text}"); + _variableAssignments.Add(parameterAsNode.Text, new Variable()); + } + else + { + Console.WriteLine($"Don't know how to add assignment for {parameterAsNode.Text}"); + } + } + else + { + Console.WriteLine($"Parameter token: {parameter.AsToken()}"); + } + } + base.VisitFunctionDeclaration(node); + _variableAssignments = null; + _insideFunction = false; + } + + public override void VisitMethodDefinition(MethodDefinitionSyntaxNode node) + { + _insideMethod = true; + _variableAssignments = new VariableAssignments(); + var parameterList = node.InputDescription.ParameterList; + foreach (var parameter in parameterList) + { + if (parameter.IsNode) + { + var parameterAsNode = parameter.AsNode(); + Console.WriteLine($"Parameter node: {parameterAsNode}"); + if (parameterAsNode.Kind == TokenKind.IdentifierName) + { + Console.WriteLine($"Adding variable assignment for {parameterAsNode.Text}"); + _variableAssignments.Add(parameterAsNode.Text, new Variable()); + } + else + { + Console.WriteLine($"Don't know how to add assignment for {parameterAsNode.Text}"); + } + } + else + { + Console.WriteLine($"Parameter token: {parameter.AsToken()}"); + } + } + base.VisitMethodDefinition(node); + _variableAssignments = null; + _insideMethod = false; + } + + } +} diff --git a/Lexer.Tests/Lexer.Tests.csproj b/Lexer.Tests/Lexer.Tests.csproj deleted file mode 100644 index d5204a5..0000000 --- a/Lexer.Tests/Lexer.Tests.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - netcoreapp2.0 - false - - - - - - - - - - \ No newline at end of file diff --git a/Lexer.Tests/MLexerShould.cs b/Lexer.Tests/MLexerShould.cs deleted file mode 100644 index 06c8985..0000000 --- a/Lexer.Tests/MLexerShould.cs +++ /dev/null @@ -1,276 +0,0 @@ -using System.Linq; -using NUnit.Framework; - -namespace Lexer.Tests -{ - public class MLexerShould - { - private static MLexer CreateLexer(string text) - { - var window = new TextWindowWithNull(text); - return new MLexer(window, new PureTokenFactory(window)); - } - - [Test] - public void ParseSequenceOfIdentifiers() - { - var sut = CreateLexer("undefined is not\n a function"); - var tokens = sut.ParseAll(); - Assert.AreEqual(6, tokens.Count); - CollectionAssert.AreEqual( - new[] {"undefined", "is", "not", "a", "function"}, - tokens.Take(5).Select(token => token.PureToken.LiteralText)); - CollectionAssert.AreEqual( - new[] { TokenKind.Identifier, TokenKind.UnquotedStringLiteral, TokenKind.UnquotedStringLiteral, - TokenKind.Identifier, TokenKind.UnquotedStringLiteral }, - tokens.Take(5).Select(token => token.Kind)); - } - - [Test] - public void ParseIdentifierAndBrackets() - { - var sut = CreateLexer("undefined()"); - var tokens = sut.ParseAll(); - Assert.AreEqual(4, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.Identifier, - TokenKind.OpeningBracket, - TokenKind.ClosingBracket, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseTransposeSignAfterClosingSquareBracket() - { - var sut = CreateLexer("[undefined]'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(5, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.OpeningSquareBracket, - TokenKind.Identifier, - TokenKind.ClosingSquareBracket, - TokenKind.Transpose, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseTransposeSignAfterClosingBrace() - { - var sut = CreateLexer("{undefined}'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(5, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.OpeningBrace, - TokenKind.Identifier, - TokenKind.ClosingBrace, - TokenKind.Transpose, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseTransposeSignAfterClosingBracket() - { - var sut = CreateLexer("undefined()'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(5, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.Identifier, - TokenKind.OpeningBracket, - TokenKind.ClosingBracket, - TokenKind.Transpose, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseTransposeSignAfterIdentifier() - { - var sut = CreateLexer("undefined'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(3, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.Identifier, - TokenKind.Transpose, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseTransposeSignAfterDot() - { - var sut = CreateLexer("undefined.'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(3, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.Identifier, - TokenKind.DotTranspose, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseDotPowerAfterNumber() - { - var sut = CreateLexer("26.^[1]"); - var tokens = sut.ParseAll(); - Assert.AreEqual(6, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.NumberLiteral, - TokenKind.DotPower, - TokenKind.OpeningSquareBracket, - TokenKind.NumberLiteral, - TokenKind.ClosingSquareBracket, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseDotInNumberBeforeSemicolon() - { - var sut = CreateLexer("42.;"); - var tokens = sut.ParseAll(); - Assert.AreEqual(3, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.NumberLiteral, - TokenKind.Semicolon, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseEAfterDotInANumber() - { - var sut = CreateLexer("42.e-5"); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - CollectionAssert.AreEqual( - new[] - { - TokenKind.NumberLiteral, - TokenKind.EndOfFile - }, - tokens.Select(token => token.PureToken.Kind)); - } - - [Test] - public void ParseEmptyLine() - { - var sut = CreateLexer("\n\nfunction shmunction\n\n\n"); - var tokens = sut.ParseAll(); - Assert.AreEqual(3, tokens.Count); - } - - [Test] - public void ParseCommentsAfterDotDotDot() - { - var sut = CreateLexer("something ... #$@#%*^!@#\n"); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - } - - [TestCase("something ... #$@#%*^!@#\n")] - [TestCase("undefined is not a function")] - [TestCase("\n\nfunction shmunction\n\n\n")] - public void ReconstructTest(string s) - { - var sut = CreateLexer(s); - var tokens = sut.ParseAll(); - var actual = string.Join("", tokens.Select(token => token.FullText)); - Assert.AreEqual(s, actual); - } - - [Test] - public void ParseStringLiteral() - { - var sut = CreateLexer("'just a string'"); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - Assert.AreEqual(TokenKind.StringLiteral, tokens[0].Kind); - Assert.AreEqual("just a string", tokens[0].PureToken.Value); - } - - [Test] - public void ParseStringLiteralWithEscapedQuotes() - { - var sut = CreateLexer("'just a ''string'''"); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - Assert.AreEqual(TokenKind.StringLiteral, tokens[0].Kind); - Assert.AreEqual("just a 'string'", tokens[0].PureToken.Value); - } - - [Test] - public void ParseDoubleQuotedStringLiteralWithEscapedQuotes() - { - var sut = CreateLexer("\"just a \"\"string\"\"\""); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - Assert.AreEqual(TokenKind.DoubleQuotedStringLiteral, tokens[0].Kind); - Assert.AreEqual("just a \"string\"", tokens[0].PureToken.Value); - } - - [Test] - public void ParseNumberStartingWithDot() - { - var sut = CreateLexer(".42"); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - Assert.AreEqual(TokenKind.NumberLiteral, tokens[0].Kind); - } - - [TestCase("%{\nabc\n%}", true)] - [TestCase("%{ a\nabc\n%}", false)] - [TestCase("if %{\nabc\n%}", false)] - public void ParseMultilineComments(string text, bool isMultiline) - { - var sut = CreateLexer(text); - var tokens = sut.ParseAll(); - if (isMultiline) - { - Assert.AreEqual(1, tokens.Count); - } - else - { - Assert.Less(1, tokens.Count); - } - } - - [TestCase(".42i")] - [TestCase("42i")] - [TestCase("42e-1i")] - public void ParseComplexNumbers(string text) - { - var sut = CreateLexer(text); - var tokens = sut.ParseAll(); - Assert.AreEqual(2, tokens.Count); - Assert.AreEqual(TokenKind.NumberLiteral, tokens[0].Kind); - } - } -} \ No newline at end of file diff --git a/Lexer/IPosition.cs b/Lexer/IPosition.cs deleted file mode 100644 index c4a08cf..0000000 --- a/Lexer/IPosition.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Lexer -{ - public interface IPosition - { - } -} \ No newline at end of file diff --git a/Lexer/Lexer.csproj b/Lexer/Lexer.csproj deleted file mode 100644 index 18344e7..0000000 --- a/Lexer/Lexer.csproj +++ /dev/null @@ -1,5 +0,0 @@ - - - netcoreapp2.0 - - \ No newline at end of file diff --git a/Lexer/PositionInsideFile.cs b/Lexer/PositionInsideFile.cs deleted file mode 100644 index c80d2b3..0000000 --- a/Lexer/PositionInsideFile.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Lexer -{ - public struct PositionInsideFile : IPosition - { - public string File { get; set; } - public int Line { get; set; } - public int Column { get; set; } - - public override string ToString() - { - return $"line {Line}, column {Column}" + (File != null ? $" of {File}" : ""); - } - } -} \ No newline at end of file diff --git a/Lexer/PureToken.cs b/Lexer/PureToken.cs deleted file mode 100644 index ecc0fa5..0000000 --- a/Lexer/PureToken.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Lexer -{ - public struct PureToken - { - public TokenKind Kind { get; } - public string LiteralText { get; } - public object Value { get; } - public IPosition Position { get; } - - public PureToken(TokenKind kind, string literalText, object value, IPosition position) - { - Kind = kind; - LiteralText = literalText; - Value = value; - Position = position; - } - - public override string ToString() => LiteralText; - } -} \ No newline at end of file diff --git a/Lexer/PureTokenFactory.cs b/Lexer/PureTokenFactory.cs deleted file mode 100644 index 4fc0757..0000000 --- a/Lexer/PureTokenFactory.cs +++ /dev/null @@ -1,111 +0,0 @@ -namespace Lexer -{ - public class PureTokenFactory - { - private ITextWindow Window { get; } - - public PureTokenFactory(ITextWindow window) - { - Window = window; - } - - private static readonly string[] PureTokenOfKind = - { - null, // None = 0, - null, // EndOfFile = 1, - null, // Identifier = 2, - null, // NumberLiteral = 3, - null, // StringLiteral = 4, - null, // DoubleQuotedStringLiteral = 5, - null, // UnquotedStringLiteral = 6 - null, null, null, null, null, null, null, null, null, null, null, null, null, - "=", // Assignment = 20, - "==", // Equality = 21, - "~=", // Inequality = 22, - "&&", // LogicalAnd = 23, - "||", // LogicalOr = 24, - "&", // BitwiseAnd = 25, - "|", // BitwiseOr = 26, - "<", // Less = 27, - "<=", // LessOrEqual = 28, - ">", // Greater = 29, - ">=", // GreaterOrEqual = 30, - "~", // Not = 31, - "+", // Plus = 32, - "-", // Minus = 33, - "*", // Multiply = 34, - "/", // Divide = 35, - "^", // Power = 36, - "\\", // Backslash = 37, - "'", // Transpose = 38, - ".*", // DotMultiply = 39, - "./", // DotDivide = 40, - ".^", // DotPower = 41, - ".\\", // DotBackslash = 42, - ".'", // DotTranspose = 43, - "@", // At = 44, - ":", // Colon = 45, - "?", // QuestionMark = 46, - ",", // Comma = 47, - ";", // Semicolon = 48, - "{", // OpeningBrace = 49, - "}", // ClosingBrace = 50, - "[", // OpeningSquareBracket = 51, - "]", // ClosingSquareBracket = 52, - "(", // OpeningBracket = 53, - ")", // ClosingBracket = 54, - ".", // Dot = 55, - "...", // DotDotDot = 56, - - "+", // UnaryPlus = 57, - "-", // UnaryMinus = 58, - "~", // UnaryNot = 59, - "?", // UnaryQuestionMark = 60, - }; - - public PureToken CreatePunctuation(TokenKind kind) - { - return new PureToken(kind, PureTokenOfKind[(int)kind], null, Window.Position); - } - - public PureToken CreateIdentifier(string s) - { - return new PureToken(TokenKind.Identifier, s, null, Window.Position); - } - - public PureToken CreateNumberLiteral(string s) - { - return new PureToken(TokenKind.NumberLiteral, s, null, Window.Position); // TODO: actually parse number (here or in the lexer?) - } - - private string EscapeStringLiteral(string s) - { - return s.Replace("'", "''"); - } - - public PureToken CreateStringLiteral(string s) - { - return new PureToken(TokenKind.StringLiteral, "'" + EscapeStringLiteral(s) + "'", s, Window.Position); - } - - private string EscapeDoubleQuotedStringLiteral(string s) - { - return s.Replace("\"", "\"\""); - } - - public PureToken CreateDoubleQuotedStringLiteral(string s) - { - return new PureToken(TokenKind.DoubleQuotedStringLiteral, "\"" + EscapeDoubleQuotedStringLiteral(s) + "\"", s, Window.Position); - } - - public PureToken CreateUnquotedStringLiteral(string s) - { - return new PureToken(TokenKind.UnquotedStringLiteral, s, s, Window.Position); - } - - public PureToken CreateEndOfFileToken() - { - return new PureToken(TokenKind.EndOfFile, "", null, Window.Position); - } - } -} \ No newline at end of file diff --git a/Lexer/Token.cs b/Lexer/Token.cs deleted file mode 100644 index a9b7a09..0000000 --- a/Lexer/Token.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Lexer -{ - public class Token - { - public List LeadingTrivia { get; } - public List TrailingTrivia { get; } - public PureToken PureToken { get; } - public string FullText { get; } - public TokenKind Kind => PureToken.Kind; - - public Token(PureToken pureToken, List leadingTrivia, List trailingTrivia) - { - PureToken = pureToken; - LeadingTrivia = leadingTrivia; - TrailingTrivia = trailingTrivia; - FullText = BuildFullText(); - } - - private string BuildFullText() - { - var leading = LeadingTrivia.Select(t => t.LiteralText); - var token = PureToken.LiteralText; - var trailing = TrailingTrivia.Select(t => t.LiteralText); - return string.Join("", leading.Concat(new[] {token}).Concat(trailing)); - } - - public override string ToString() => FullText; - } -} \ No newline at end of file diff --git a/Lexer/TokenKind.cs b/Lexer/TokenKind.cs deleted file mode 100644 index b842016..0000000 --- a/Lexer/TokenKind.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Lexer -{ - public enum TokenKind - { - None = 0, - EndOfFile = 1, - Identifier = 2, - NumberLiteral = 3, - StringLiteral = 4, - DoubleQuotedStringLiteral = 5, - UnquotedStringLiteral = 6, - - Assignment = 20, - Equality = 21, - Inequality = 22, - LogicalAnd = 23, - LogicalOr = 24, - BitwiseAnd = 25, - BitwiseOr = 26, - Less = 27, - LessOrEqual = 28, - Greater = 29, - GreaterOrEqual = 30, - Not = 31, - Plus = 32, - Minus = 33, - Multiply = 34, - Divide = 35, - Power = 36, - Backslash = 37, - Transpose = 38, - DotMultiply = 39, - DotDivide = 40, - DotPower = 41, - DotBackslash = 42, - DotTranspose = 43, - At = 44, - Colon = 45, - QuestionMark = 46, - Comma = 47, - Semicolon = 48, - OpeningBrace = 49, - ClosingBrace = 50, - OpeningSquareBracket = 51, - ClosingSquareBracket = 52, - OpeningBracket = 53, - ClosingBracket = 54, - Dot = 55, - DotDotDot = 56, - // unary tokens are not recognized during lexing; they are contextually recognized while parsing. - UnaryPlus = 57, - UnaryMinus = 58, - UnaryNot = 59, - UnaryQuestionMark = 60, - } -} \ No newline at end of file diff --git a/Lexer/Trivia.cs b/Lexer/Trivia.cs deleted file mode 100644 index 4e70158..0000000 --- a/Lexer/Trivia.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Lexer -{ - public class Trivia - { - public TriviaType Type { get; } - public string LiteralText { get; } - - public Trivia(TriviaType type, string literalText) - { - Type = type; - LiteralText = literalText; - } - } -} \ No newline at end of file diff --git a/Lexer/TriviaType.cs b/Lexer/TriviaType.cs deleted file mode 100644 index c7eb255..0000000 --- a/Lexer/TriviaType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Lexer -{ - public enum TriviaType - { - Whitespace, - NewLine, - Comment, - MultiLineComment - } -} \ No newline at end of file diff --git a/Parser.Tests/MParserShould.cs b/Parser.Tests/MParserShould.cs index bec08e8..d351218 100644 --- a/Parser.Tests/MParserShould.cs +++ b/Parser.Tests/MParserShould.cs @@ -1,495 +1,25 @@ -using System.Collections.Generic; -using System.Linq; -using Lexer; - -using NUnit.Framework; +using NUnit.Framework; namespace Parser.Tests { public class MParserShould { - private static MParser CreateParser(string text) + private static MParser GetSut(string text) { var window = new TextWindowWithNull(text); - var lexer = new MLexer(window, new PureTokenFactory(window)); - var tokens = lexer.ParseAll(); - var parser = new MParser(tokens); + var parser = new MParser(window); return parser; } - + [Test] public void ParseAssignmentExpression() { var text = "a = b"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseSimpleStatement() - { - var text = "a = b"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseFunctionCallExpression() - { - var text = "func(a, 2, 'abc', d)"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = actual as FunctionCallExpressionNode; - Assert.AreEqual(4, f?.Parameters.Parameters.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseArrayLiteralExpression() - { - var text = "[a, 2, 'text']"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = actual as ArrayLiteralExpressionNode; - Assert.AreEqual(3, a?.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseLeftAssociativeSamePrecedence() - { - var text = "2 + 3 + 4"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (BinaryOperationExpressionNode)actual; - Assert.IsInstanceOf(e.Lhs); - Assert.IsInstanceOf(e.Rhs); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseLeftAssociativeRaisingPrecedence() - { - var text = "2 + 3 * 4"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (BinaryOperationExpressionNode) actual; - Assert.AreEqual(TokenKind.Plus, e.Operation.Token.Kind); - Assert.IsInstanceOf(e.Lhs); - Assert.IsInstanceOf(e.Rhs); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseLeftAssociativeLoweringPrecedence() - { - var text = "2 * 3 + 4"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (BinaryOperationExpressionNode) actual; - Assert.AreEqual(TokenKind.Plus, e.Operation.Token.Kind); - Assert.IsInstanceOf(e.Lhs); - Assert.IsInstanceOf(e.Rhs); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseUnaryOperators() - { - var text = "-42"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (UnaryPrefixOperationExpressionNode) actual; - Assert.AreEqual(TokenKind.Minus, e.Operation.Token.Kind); - Assert.IsInstanceOf(e.Operand); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseMemberAccess() - { - var text = "a.b.c"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var m = (MemberAccessNode) actual; - Assert.IsInstanceOf(m.LeftOperand); - Assert.IsInstanceOf(m.RightOperand); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseWhileStatement() - { - var text = "while a < b c = d end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseWhileStatementWithComma() - { - var text = "while a < b, c = d end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseIfStatement() - { - var text = "if 2 < 3 a = b end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseIfElseStatement() - { - var text = "if 2 < 3 a = b else c = d end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseParenthesizedExpression() - { - var text = "2 * (3 + 4)"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (BinaryOperationExpressionNode) actual; - Assert.IsInstanceOf(e.Lhs); - Assert.IsInstanceOf(e.Rhs); - var p = (ParenthesizedExpressionNode) e.Rhs; - Assert.IsInstanceOf(p.Expression); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseForStatement() - { - var text = "for i = 1:5 a = i end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseEmptyArray() - { - var text = "[]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(0, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseCellArrayLiteral() - { - var text = "{ 1 2, 3 }"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (CellArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseIndirectMemberAccess() - { - var text = "abc.(def)"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (MemberAccessNode) actual; - Assert.IsInstanceOf(a.LeftOperand); - Assert.IsInstanceOf(a.RightOperand); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseMemberAccessAfterElementAccess() - { - var text = "a(1).b"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var m = (MemberAccessNode) actual; - Assert.IsInstanceOf(m.LeftOperand); - Assert.IsInstanceOf(m.RightOperand); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseFunctionDeclarationWithoutInputs() - { - var text = "function a = b a = 1"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - var f = (FunctionDeclarationNode) actual; - Assert.AreEqual(f.InputDescription, null); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseCellArrayWithCellArrayLiteralInside() - { - var text = "{1 2 a {3}}"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (CellArrayLiteralExpressionNode) actual; - Assert.AreEqual(4, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseCellArrayWithCellArrayAccessInside() - { - var text = "{1 2 a{3}}"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (CellArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseCellArrayWithElementInBracketsInside() - { - var text = "{1 2 a (3)}"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (CellArrayLiteralExpressionNode) actual; - Assert.AreEqual(4, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseCellArrayWithFunctionCallInside() - { - var text = "{1 2 a(3)}"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (CellArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseArrayWithCellArrayLiteralInside() - { - var text = "[1 2 a {3}]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(4, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseArrayWithCellArrayAccessInside() - { - var text = "[1 2 a{3}]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseArrayWithElementInBracketsInside() - { - var text = "[1 2 a (3)]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(4, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseArrayWithFunctionCallInside() - { - var text = "[1 2 a(3)]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var a = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, a.Elements.Elements.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseFunctionHandle() - { - var text = "@sqrt"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = (NamedFunctionHandleNode) actual; - Assert.AreEqual(1, f.FunctionName.Names.Count); - Assert.AreEqual("sqrt", f.FunctionName.Names[0].Token.PureToken.LiteralText); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseFunctionHandleWithCompoundName() - { - var text = "@a.b.c"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = (NamedFunctionHandleNode) actual; - Assert.AreEqual(3, f.FunctionName.Names.Count); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseLambda() - { - var text = "@(x, y) x + y"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = (LambdaNode) actual; - Assert.AreEqual(2, f.Input.Parameters.Parameters.Count); - Assert.IsInstanceOf(f.Body); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseTildeAsResultReplacement() - { - var text = "[a, ~, b]"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = (ArrayLiteralExpressionNode) actual; - Assert.AreEqual(3, f.Elements.Elements.Count); - Assert.IsInstanceOf(f.Elements.Elements[1]); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseTildeAsFunctionInputReplacement() - { - var text = "function a(b, ~, c) end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - var f = (FunctionDeclarationNode) actual; - Assert.AreEqual(3, f.InputDescription.Parameters.Parameters.Count); - CollectionAssert.AreEqual(new[] { "b", "~", "c" }, f.InputDescription.Parameters.Parameters.Select(p => (p as TokenNode).Token.PureToken.LiteralText)); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseDotTranspose() - { - var text = "a.'"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (UnaryPostfixOperationExpressionNode) actual; - Assert.AreEqual(TokenKind.DotTranspose, e.Operation.Token.Kind); - Assert.AreEqual("a", (e.Operand as IdentifierNameNode)?.Token.PureToken.LiteralText); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseDoubleQuotedStringLiteral() - { - var text = "\"some string\""; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var s = (DoubleQuotedStringLiteralNode) actual; - Assert.AreEqual("some string", s.Token.PureToken.Value); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseTryCatchStatement() - { - var text = "try a = b catch c = d end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseElseif() - { - var text = @"if a == 1 - f() - elseif a == 2 - g() - elseif a == 3 - h() - end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseBaseClassInvokation() - { - var text = "a@b.c.d(e, f)"; - var sut = CreateParser(text); - var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var e = (BaseClassInvokationNode) actual; - Assert.AreEqual("a", e.MethodName.Token.PureToken.LiteralText); - Assert.IsInstanceOf(e.BaseClassNameAndArguments); - Assert.AreEqual(text, actual.FullText); - } - - [Test] - public void ParseFunctionWithEmptyOutputsList() - { - var text = "function [] = a(b) end"; - var sut = CreateParser(text); - var actual = sut.ParseStatement(); - Assert.IsInstanceOf(actual); - var f = (FunctionDeclarationNode) actual; - Assert.AreEqual(0, f.OutputDescription.Outputs.Count); - Assert.AreEqual(text, actual.FullText); - + var sut = GetSut(text); + var actual = sut.Parse(); + var assignment = actual.StatementList[0].AsNode(); + Assert.IsInstanceOf(assignment); + Assert.IsInstanceOf(((ExpressionStatementSyntaxNode)assignment).Expression); } } } \ No newline at end of file diff --git a/Parser.Tests/Parser.Tests.csproj b/Parser.Tests/Parser.Tests.csproj index fe0e1b6..bf1772c 100644 --- a/Parser.Tests/Parser.Tests.csproj +++ b/Parser.Tests/Parser.Tests.csproj @@ -1,6 +1,6 @@  - netcoreapp2.0 + netcoreapp2.1 false @@ -9,9 +9,6 @@ - - {B20EDC10-E6E6-4430-8527-B95206DEF941} - Parser - + \ No newline at end of file diff --git a/Lexer.Tests/TextWindowShould.cs b/Parser.Tests/TextWindowShould.cs similarity index 97% rename from Lexer.Tests/TextWindowShould.cs rename to Parser.Tests/TextWindowShould.cs index 27c3a50..82f1b97 100644 --- a/Lexer.Tests/TextWindowShould.cs +++ b/Parser.Tests/TextWindowShould.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Lexer.Tests +namespace Parser.Tests { [TestFixture] public class TestWindowShould diff --git a/Lexer.Tests/TextWindowWithNullShould.cs b/Parser.Tests/TextWindowWithNullShould.cs similarity index 96% rename from Lexer.Tests/TextWindowWithNullShould.cs rename to Parser.Tests/TextWindowWithNullShould.cs index 17dbafe..20c4b46 100644 --- a/Lexer.Tests/TextWindowWithNullShould.cs +++ b/Parser.Tests/TextWindowWithNullShould.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Lexer.Tests +namespace Parser.Tests { [TestFixture] public class TestWindowWithNullShould diff --git a/Parser/ChildNodesAndTokensList.cs b/Parser/ChildNodesAndTokensList.cs new file mode 100644 index 0000000..f0501d1 --- /dev/null +++ b/Parser/ChildNodesAndTokensList.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Parser.Internal; + +namespace Parser +{ + public class ChildNodesAndTokensList : IReadOnlyList + { + private readonly SyntaxNode _node; + private readonly int _count; + + internal ChildNodesAndTokensList(SyntaxNode node) + { + _node = node; + _count = CountChildNodes(node._green); + } + + private int CountChildNodes(GreenNode green) + { + var counter = 0; + for (var i = 0; i < green.Slots; i++) + { + var child = green.GetSlot(i); + if (child == null) + { + continue; + } + + if (child.IsList) + { + counter += child.Slots; + } + else + { + counter++; + } + } + + return counter; + } + + public IEnumerator GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int Count => _count; + + public SyntaxNodeOrToken this[int index] + { + get + { + if (index < 0 || index >= Count) + { + throw new IndexOutOfRangeException(); + } + return ThisInternal(index); + + } + } + + internal SyntaxNodeOrToken ThisInternal(int index) + { + var currentSlotIndex = 0; + GreenNode currentSlot = null; + while (true) + { + currentSlot = _node._green.GetSlot(currentSlotIndex); + if (currentSlot == null) + { + currentSlotIndex++; + continue; + } + + var nodesInCurrentSlot = currentSlot.IsList ? currentSlot.Slots : 1; + if (index < nodesInCurrentSlot) + { + if (currentSlot.IsList) + { + var listSlot = _node.GetNode(currentSlotIndex); + var red = listSlot.GetNode(index); + if (red != null) + { + return red; + } + // this is a token + return new SyntaxToken(listSlot, listSlot._green.GetSlot(index)); + } + else + { + var red = _node.GetNode(currentSlotIndex); + if (red != null) + { + return red; + } + // this is a token + return new SyntaxToken(_node, _node._green.GetSlot(currentSlotIndex)); + } + } + + index -= nodesInCurrentSlot; + currentSlotIndex++; + } + } + + private struct Enumerator : IEnumerator + { + private int _index; + private readonly ChildNodesAndTokensList _list; + private readonly int _count; + + internal Enumerator(ChildNodesAndTokensList list) + { + _index = -1; + _list = list; + _count = _list.Count; + } + + public bool MoveNext() + { + _index++; + return _index < _count; + } + + public void Reset() + { + throw new NotImplementedException(); + } + + public SyntaxNodeOrToken Current => _list[_index]; + + object IEnumerator.Current => Current; + + public void Dispose() + { + } + } + } +} \ No newline at end of file diff --git a/Lexer/ILexer.cs b/Parser/ILexer.cs similarity index 62% rename from Lexer/ILexer.cs rename to Parser/ILexer.cs index 1df7603..89689d6 100644 --- a/Lexer/ILexer.cs +++ b/Parser/ILexer.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -namespace Lexer +namespace Parser { - public interface ILexer where T : class + public interface ILexer { T NextToken(); List ParseAll(); diff --git a/Lexer/ITextWindow.cs b/Parser/ITextWindow.cs similarity index 84% rename from Lexer/ITextWindow.cs rename to Parser/ITextWindow.cs index aa43a66..40ae147 100644 --- a/Lexer/ITextWindow.cs +++ b/Parser/ITextWindow.cs @@ -1,4 +1,4 @@ -namespace Lexer +namespace Parser { public interface ITextWindow { @@ -10,6 +10,6 @@ char GetAndConsumeChar(); string GetAndConsumeChars(int n); int CharactersLeft(); - IPosition Position { get; } + Position Position { get; } } } \ No newline at end of file diff --git a/Parser/Internal/GreenNode.cs b/Parser/Internal/GreenNode.cs new file mode 100644 index 0000000..23607b9 --- /dev/null +++ b/Parser/Internal/GreenNode.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Parser.Internal +{ + internal abstract class GreenNode + { + public TokenKind Kind { get; } + public int Slots { get; } + public abstract GreenNode GetSlot(int i); + + public GreenNode(TokenKind kind) + { + Kind = kind; + } + + public GreenNode(TokenKind kind, int slots) + { + Kind =kind; + Slots = slots; + } + + internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent); + + public virtual string Text + { + get + { + var sb = new StringBuilder(); + + using (var writer = new System.IO.StringWriter(sb, CultureInfo.InvariantCulture)) + { + WriteTo(writer, leading: false, trailing: false); + } + + return sb.ToString(); + } + } + + protected bool _isMissing = false; + + 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)>(); + stack.Push((this, leading, trailing)); + WriteStackTo(writer, stack); + } + + public virtual bool IsToken => false; + public virtual bool IsTrivia => false; + public virtual bool IsNode => true; + public virtual bool IsList => false; + + public virtual void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + throw new NotImplementedException(); + } + + public virtual void WriteTriviaTo(TextWriter writer) + { + throw new NotImplementedException(); + } + + private int GetFirstNonNullChildIndex() + { + for (var i = 0; i < Slots; i++) + { + if (GetSlot(i) != null) + { + return i; + } + } + + return Slots; + } + + private int GetLastNonNullChildIndex() + { + for (var i = Slots - 1; i >= 0; i--) + { + if (GetSlot(i) != null) + { + return i; + } + } + + return -1; + } + + private GreenNode GetFirstTerminal() + { + var current = this; + while (true) + { + GreenNode next = null; + if (current.Slots == 0) + { + return current; + } + + for (var i = 0; i < current.Slots; i++) + { + var child = current.GetSlot(i); + if (child == null) + { + continue; + } + + next = child; + break; + } + + if (next == null) + { + return null; + } + + current = next; + } + } + + private GreenNode GetLastTerminal() + { + var current = this; + while (true) + { + GreenNode next = null; + if (current.Slots == 0) + { + return current; + } + + for (var i = current.Slots - 1; i >= 0; i--) + { + var child = current.GetSlot(i); + if (child == null) + { + continue; + } + + next = child; + break; + } + + if (next == null) + { + return null; + } + + current = next; + } + } + + public virtual IReadOnlyList LeadingTrivia => GetFirstTerminal()?.LeadingTriviaCore ?? new List(); + public virtual IReadOnlyList TrailingTrivia => GetLastTerminal()?.TrailingTriviaCore ?? new List(); + + public abstract IReadOnlyList LeadingTriviaCore { get; } + public abstract IReadOnlyList TrailingTriviaCore { get; } + + public virtual string FullText + { + get + { + var sb = new StringBuilder(); + + using (var writer = new System.IO.StringWriter(sb, CultureInfo.InvariantCulture)) + { + WriteTo(writer, leading: true, trailing: true); + } + + return sb.ToString(); + + } + } + + private void WriteStackTo(TextWriter writer, Stack<(GreenNode node, bool leading, bool trailing)> stack) + { + while (stack.Count > 0) + { + var currentTriple = stack.Pop(); + if (currentTriple.node.IsToken) + { + currentTriple.node.WriteTokenTo(writer, currentTriple.leading, currentTriple.trailing); + } else if (currentTriple.node.IsTrivia) + { + currentTriple.node.WriteTriviaTo(writer); + } + else + { + var firstIndex = currentTriple.node.GetFirstNonNullChildIndex(); + var lastIndex = currentTriple.node.GetLastNonNullChildIndex(); + for (var i = lastIndex; i >= firstIndex; i--) + { + var child = currentTriple.node.GetSlot(i); + if (child != null) + { + stack.Push(( + child, + currentTriple.leading || i != firstIndex, + currentTriple.trailing || i != lastIndex)); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Lexer/MLexer.cs b/Parser/Internal/MLexerGreen.cs similarity index 57% rename from Lexer/MLexer.cs rename to Parser/Internal/MLexerGreen.cs index d9ae32a..ddbf0ff 100644 --- a/Lexer/MLexer.cs +++ b/Parser/Internal/MLexerGreen.cs @@ -1,46 +1,46 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text; -namespace Lexer +namespace Parser.Internal { - public class MLexer : ILexer + internal class MLexerGreen : ILexer<(SyntaxToken, Position)> { + private class TokenInfo + { + public TokenKind Kind { get; set; } + public string Text { get; set; } + public string StringValue { get; set; } + public double DoubleValue { get; set; } + } + private ITextWindow Window { get; } - private Token LastToken { get; set; } + private SyntaxToken LastToken { get; set; } private int TokensSinceNewLine { get; set; } - private PureTokenFactory PureTokenFactory { get; } private Stack TokenStack { get; } - public MLexer(ITextWindow window, PureTokenFactory pureTokenFactory) + public MLexerGreen(ITextWindow window) { Window = window; - PureTokenFactory = pureTokenFactory; TokenStack = new Stack(); } - private static bool IsEolOrEof(char c) - { - return c == '\n' || c == '\r' || c == '\0'; - } - - private Trivia LexComment() + private SyntaxTrivia LexComment() { if (TokensSinceNewLine == 0 && Window.PeekChar(1) == '{') { return LexMultilineComment(); } var n = 1; - while (!IsEolOrEof(Window.PeekChar(n))) + while (!SyntaxFacts.IsEolOrEof(Window.PeekChar(n))) { n++; } - return new Trivia(TriviaType.Comment, Window.GetAndConsumeChars(n)); + return TokenFactory.CreateTrivia(TokenKind.Comment, Window.GetAndConsumeChars(n)); } - private Trivia LexMultilineComment() + private SyntaxTrivia LexMultilineComment() { var n = 2; var metPercentSign = false; @@ -50,7 +50,7 @@ namespace Lexer var c = Window.PeekChar(n); if (c == '\0') { - throw new ParsingException($"Unexpected end of file while parsing multi-line comment."); + throw new ParsingException("Unexpected end of file while parsing multi-line comment."); } if (c == '\n') @@ -58,58 +58,62 @@ namespace Lexer atFirstLine = false; } - if (atFirstLine && !IsWhitespace(c)) // this is a one-line comment + if (atFirstLine && !SyntaxFacts.IsWhitespace(c)) // this is a one-line comment { - while (!IsEolOrEof(Window.PeekChar(n))) + while (!SyntaxFacts.IsEolOrEof(Window.PeekChar(n))) { n++; } - return new Trivia(TriviaType.Comment, Window.GetAndConsumeChars(n)); + return TokenFactory.CreateTrivia(TokenKind.Comment, Window.GetAndConsumeChars(n)); } if (metPercentSign && c == '}') { - return new Trivia(TriviaType.MultiLineComment, Window.GetAndConsumeChars(n+1)); + return TokenFactory.CreateTrivia(TokenKind.Comment, Window.GetAndConsumeChars(n+1)); } - if (c == '%') - { - metPercentSign = true; - } - else - { - metPercentSign = false; - } + metPercentSign = c == '%'; n++; } } - private List LexCommentAfterDotDotDot() + private List LexCommentAfterDotDotDot() { var n = 0; - while (!IsEolOrEof(Window.PeekChar(n))) + while (!SyntaxFacts.IsEolOrEof(Window.PeekChar(n))) { n++; } - var comment = new Trivia(TriviaType.Comment, Window.GetAndConsumeChars(n)); - var result = new List { comment }; + var comment = TokenFactory.CreateTrivia(TokenKind.Comment, Window.GetAndConsumeChars(n)); + var result = new List { comment }; var character = Window.PeekChar(); if (character == '\n' || character == '\r') { Window.ConsumeChar(); - result.Add(new Trivia(TriviaType.Whitespace, character.ToString())); + result.Add(TokenFactory.CreateTrivia(TokenKind.Whitespace, character.ToString())); } return result; } - private List LexTrivia(bool isTrailing) + private List LexTrivia(bool isTrailing) { - var triviaList = new List(); - var whiteSpaceCache = new StringBuilder(); + var triviaList = new List(); + var whitespaceCache = new StringBuilder(); + + void FlushWhitespaceCache() + { + if (whitespaceCache.Length > 0) + { + triviaList.Add(TokenFactory.CreateTrivia(TokenKind.Whitespace, whitespaceCache.ToString())); + } + + whitespaceCache.Clear(); + } + while (true) { var character = Window.PeekChar(); @@ -118,18 +122,13 @@ namespace Lexer case ' ': case '\t': Window.ConsumeChar(); - whiteSpaceCache.Append(character); + whitespaceCache.Append(character); break; case '\r': case '\n': - if (whiteSpaceCache.Length > 0) - { - triviaList.Add(new Trivia(TriviaType.Whitespace, whiteSpaceCache.ToString())); - } - - whiteSpaceCache.Clear(); + FlushWhitespaceCache(); Window.ConsumeChar(); - triviaList.Add(new Trivia(TriviaType.NewLine, character.ToString())); + triviaList.Add(TokenFactory.CreateTrivia(TokenKind.Newline, character.ToString())); if (isTrailing) { return triviaList; @@ -137,39 +136,23 @@ namespace Lexer break; case '%': - if (whiteSpaceCache.Length > 0) - { - triviaList.Add(new Trivia(TriviaType.Whitespace, whiteSpaceCache.ToString())); - } - - whiteSpaceCache.Clear(); + FlushWhitespaceCache(); triviaList.Add(LexComment()); break; case '.': if (Window.PeekChar(1) == '.' && Window.PeekChar(2) == '.') { - if (whiteSpaceCache.Length > 0) - { - triviaList.Add(new Trivia(TriviaType.Whitespace, whiteSpaceCache.ToString())); - } - - whiteSpaceCache.Clear(); + FlushWhitespaceCache(); triviaList.AddRange(LexCommentAfterDotDotDot()); } else { - if (whiteSpaceCache.Length > 0) - { - triviaList.Add(new Trivia(TriviaType.Whitespace, whiteSpaceCache.ToString())); - } + FlushWhitespaceCache(); return triviaList; } break; default: - if (whiteSpaceCache.Length > 0) - { - triviaList.Add(new Trivia(TriviaType.Whitespace, whiteSpaceCache.ToString())); - } + FlushWhitespaceCache(); return triviaList; } } @@ -180,7 +163,8 @@ namespace Lexer return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_'); } - private PureToken ContinueParsingIdentifier() + + private bool ContinueLexingIdentifier(ref TokenInfo tokenInfo) { var n = 1; while (IsLetterOrDigitOrUnderscore(Window.PeekChar(n))) @@ -189,7 +173,28 @@ namespace Lexer } var identifier = Window.GetAndConsumeChars(n); - return PureTokenFactory.CreateIdentifier(identifier); + tokenInfo.Kind = TokenKind.Identifier; + tokenInfo.Text = identifier; + return true; + } + + private bool ContinueParsingUnquotedStringLiteral(ref TokenInfo tokenInfo) + { + var n = 0; + while (true) + { + var c = Window.PeekChar(n); + if (c == ' ' || c == '\n' || c == '\0') + { + var literal = Window.GetAndConsumeChars(n); + tokenInfo.Kind = TokenKind.UnquotedStringLiteral; + tokenInfo.Text = literal; + tokenInfo.StringValue = literal; + return true; + } + + n++; + } } private enum NumberParsingState @@ -203,22 +208,7 @@ namespace Lexer DigitsAfterE } - private static bool IsDigit(char c) - { - return c >= '0' && c <= '9'; - } - - private static bool IsDigitOrDot(char c) - { - return c == '.' || (c >= '0' && c <= '9'); - } - - private static bool IsWhitespace(char c) - { - return c == ' ' || c == '\t' || c == '\n'; - } - - private PureToken? ContinueParsingNumber() + private bool ContinueLexingNumber(ref TokenInfo tokenInfo) { var state = NumberParsingState.Start; var n = 0; @@ -231,7 +221,7 @@ namespace Lexer switch (state) { case NumberParsingState.Start: - if (IsDigitOrDot(c)) + if (SyntaxFacts.IsDigitOrDot(c)) { state = NumberParsingState.DigitsBeforeDot; } @@ -241,7 +231,7 @@ namespace Lexer } break; case NumberParsingState.DigitsBeforeDot: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { } else if (c == '.') @@ -258,7 +248,7 @@ namespace Lexer } break; case NumberParsingState.AfterDot: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { state = NumberParsingState.DigitsAfterDot; } @@ -266,7 +256,7 @@ namespace Lexer { state = NumberParsingState.AfterE; } - else if (IsWhitespace(c) || c == ';' || c == ']' || c == ')' || c == '}') + else if (SyntaxFacts.IsWhitespace(c) || c == ';' || c == ']' || c == ')' || c == '}') { success = true; } @@ -282,7 +272,7 @@ namespace Lexer break; case NumberParsingState.DigitsAfterDot: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { } else if (c == 'e' || c == 'E') @@ -296,7 +286,7 @@ namespace Lexer break; case NumberParsingState.AfterE: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { state = NumberParsingState.DigitsAfterE; } @@ -311,7 +301,7 @@ namespace Lexer break; case NumberParsingState.SignAfterE: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { state = NumberParsingState.DigitsAfterE; } @@ -322,7 +312,7 @@ namespace Lexer break; case NumberParsingState.DigitsAfterE: - if (IsDigit(c)) + if (SyntaxFacts.IsDigit(c)) { } else @@ -364,27 +354,36 @@ namespace Lexer n++; } var s = Window.GetAndConsumeChars(n); - return PureTokenFactory.CreateNumberLiteral(s); + + tokenInfo.Kind = TokenKind.NumberLiteral; + tokenInfo.Text = s; + return true; } - return null; + return false; } - private PureToken ContinueParsingStringLiteral() + private bool ContinueLexingGeneralStringLiteral(ref TokenInfo tokenInfo, char quote) { Window.ConsumeChar(); - var pieces = new List(); + var textBuilder = new StringBuilder(); + textBuilder.Append(quote); + var valueBuilder = new StringBuilder(); var n = 0; - while (true) { - if (Window.PeekChar(n) == '\'') + while (true) + { + if (Window.PeekChar(n) == quote) { - if (Window.PeekChar(n + 1) == '\'') + if (Window.PeekChar(n + 1) == quote) { var piece = Window.GetAndConsumeChars(n); - pieces.Add(piece); + textBuilder.Append(piece); + valueBuilder.Append(piece); Window.ConsumeChar(); Window.ConsumeChar(); - pieces.Add("'"); + textBuilder.Append(quote); + textBuilder.Append(quote); + valueBuilder.Append(quote); n = -1; } else @@ -392,7 +391,7 @@ namespace Lexer break; } } - if (IsEolOrEof(Window.PeekChar(n))) + if (SyntaxFacts.IsEolOrEof(Window.PeekChar(n))) { throw new ParsingException("Unfinished string literal."); } @@ -400,101 +399,56 @@ namespace Lexer } var lastPiece = Window.GetAndConsumeChars(n); - pieces.Add(lastPiece); - var total = string.Join("", pieces); + textBuilder.Append(lastPiece); + valueBuilder.Append(lastPiece); Window.ConsumeChar(); - return PureTokenFactory.CreateStringLiteral(total); + textBuilder.Append(quote); + tokenInfo.Text = textBuilder.ToString(); + tokenInfo.StringValue = valueBuilder.ToString(); + return true; } - private PureToken ContinueParsingDoubleQuotedStringLiteral() + private bool ContinueLexingStringLiteral(ref TokenInfo tokenInfo) { - Window.ConsumeChar(); - var n = 0; - var pieces = new List(); - while (true) - { - if (Window.PeekChar(n) == '"') - { - if (Window.PeekChar(n + 1) == '"') - { - var piece = Window.GetAndConsumeChars(n); - pieces.Add(piece); - Window.ConsumeChar(); - Window.ConsumeChar(); - pieces.Add("\""); - n = -1; - } - else - { - break; - } - } - if (IsEolOrEof(Window.PeekChar(n))) - { - throw new ParsingException("Unfinished double-quoted string literal."); - } - - n++; - } - - var lastPiece = Window.GetAndConsumeChars(n); - pieces.Add(lastPiece); - var total = string.Join("", pieces); - Window.ConsumeChar(); - return PureTokenFactory.CreateDoubleQuotedStringLiteral(total); + ContinueLexingGeneralStringLiteral(ref tokenInfo, '\''); + tokenInfo.Kind = TokenKind.StringLiteral; + return true; } - private PureToken ContinueParsingUnquotedStringLiteral() + private bool ContinueLexingDoubleQuotedStringLiteral(ref TokenInfo tokenInfo) { - var n = 0; - while (true) - { - var c = Window.PeekChar(n); - if (c == ' ' || c == '\n' || c == '\0') - { - var literal = Window.GetAndConsumeChars(n); - return PureTokenFactory.CreateUnquotedStringLiteral(literal); - } - - n++; - } + ContinueLexingGeneralStringLiteral(ref tokenInfo, '"'); + tokenInfo.Kind = TokenKind.StringLiteral; + return true; } - private static readonly HashSet Keywords; - - static MLexer() - { - Keywords = new HashSet - { - "for", "if", "function", "while", "case", "try", "catch", "end", - "switch", "classdef", "elseif", "persistent", "else" - }; - } - - private PureToken LexTokenWithoutTrivia(List leadingTrivia) + private bool LexTokenWithoutTrivia(List leadingTrivia, ref TokenInfo tokenInfo) { var character = Window.PeekChar(); if (character == '\0') { - return PureTokenFactory.CreateEndOfFileToken(); + tokenInfo.Kind = TokenKind.EndOfFile; + tokenInfo.Text = ""; + return true; } - + if (TokensSinceNewLine == 1 && !TokenStack.Any() && LastToken.Kind == TokenKind.Identifier && LastToken.TrailingTrivia.Any() && character != '=' && character != '(' - && !Keywords.Contains(LastToken.PureToken.LiteralText)) + && !SyntaxFacts.Keywords.Contains(LastToken.Text)) { - return ContinueParsingUnquotedStringLiteral(); + return ContinueParsingUnquotedStringLiteral(ref tokenInfo); } if (LastToken?.Kind == TokenKind.UnquotedStringLiteral && !TokenStack.Any() && TokensSinceNewLine > 0) { - return ContinueParsingUnquotedStringLiteral(); + return ContinueParsingUnquotedStringLiteral(ref tokenInfo); } + switch (character) { case 'a': @@ -549,7 +503,7 @@ namespace Lexer case 'X': case 'Y': case 'Z': - return ContinueParsingIdentifier(); + return ContinueLexingIdentifier(ref tokenInfo); case '0': case '1': case '2': @@ -560,31 +514,35 @@ namespace Lexer case '7': case '8': case '9': - var possiblyNumberToken = ContinueParsingNumber(); - if (possiblyNumberToken == null) + var parsedNumber = ContinueLexingNumber(ref tokenInfo); + if (!parsedNumber) { throw new ParsingException($"Unexpected character \"{Window.PeekChar()}\" while parsing a number"); } - - return (PureToken)possiblyNumberToken; + return true; case '=': Window.ConsumeChar(); if (Window.PeekChar() == '=') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Equality); + tokenInfo.Kind = TokenKind.Equality; + } + else + { + tokenInfo.Kind = TokenKind.Assignment; } - return PureTokenFactory.CreatePunctuation(TokenKind.Assignment); + return true; case '.': - if (IsDigit(Window.PeekChar(1))) + if (SyntaxFacts.IsDigit(Window.PeekChar(1))) { - var possiblyNumberToken2 = ContinueParsingNumber(); - if (possiblyNumberToken2 == null) + var possiblyNumberToken2 = ContinueLexingNumber(ref tokenInfo); + if (!possiblyNumberToken2) { throw new ParsingException($"Unexpected character \"{Window.PeekChar()}\" while parsing a number"); } - return (PureToken)possiblyNumberToken2; + + return true; } Window.ConsumeChar(); var c = Window.PeekChar(); @@ -592,113 +550,164 @@ namespace Lexer { case '*': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.DotMultiply); + tokenInfo.Kind = TokenKind.DotMultiply; + break; case '/': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.DotDivide); + tokenInfo.Kind = TokenKind.DotDivide; + break; case '^': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.DotPower); + tokenInfo.Kind = TokenKind.DotPower; + break; case '\\': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.DotBackslash); + tokenInfo.Kind = TokenKind.DotBackslash; + break; case '\'': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.DotTranspose); + tokenInfo.Kind = TokenKind.DotTranspose; + break; default: - return PureTokenFactory.CreatePunctuation(TokenKind.Dot); + tokenInfo.Kind = TokenKind.Dot; + break; } + + return true; case '(': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.OpeningBracket); + tokenInfo.Kind = TokenKind.OpeningBracket; + return true; case ')': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.ClosingBracket); + tokenInfo.Kind = TokenKind.ClosingBracket; + return true; case '[': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.OpeningSquareBracket); + tokenInfo.Kind = TokenKind.OpeningSquareBracket; + return true; case ']': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.ClosingSquareBracket); + tokenInfo.Kind = TokenKind.ClosingSquareBracket; + return true; case '{': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.OpeningBrace); + tokenInfo.Kind = TokenKind.OpeningBrace; + return true; case '}': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.ClosingBrace); + tokenInfo.Kind = TokenKind.ClosingBrace; + return true; case ',': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Comma); + tokenInfo.Kind = TokenKind.Comma; + return true; case ';': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Semicolon); + tokenInfo.Kind = TokenKind.Semicolon; + return true; case '&': Window.ConsumeChar(); if (Window.PeekChar() == '&') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.LogicalAnd); + tokenInfo.Kind = TokenKind.LogicalAnd; } - return PureTokenFactory.CreatePunctuation(TokenKind.BitwiseAnd); + else + { + tokenInfo.Kind = TokenKind.BitwiseAnd; + } + + return true; case '|': Window.ConsumeChar(); if (Window.PeekChar() == '|') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.LogicalOr); + tokenInfo.Kind = TokenKind.LogicalOr; } - return PureTokenFactory.CreatePunctuation(TokenKind.BitwiseOr); + else + { + tokenInfo.Kind = TokenKind.BitwiseOr; + + } + + return true; case '<': Window.ConsumeChar(); if (Window.PeekChar() == '=') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.LessOrEqual); + tokenInfo.Kind = TokenKind.LessOrEqual; } - return PureTokenFactory.CreatePunctuation(TokenKind.Less); + else + { + tokenInfo.Kind = TokenKind.Less; + } + + return true; case '>': Window.ConsumeChar(); if (Window.PeekChar() == '=') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.GreaterOrEqual); + tokenInfo.Kind = TokenKind.GreaterOrEqual; } - return PureTokenFactory.CreatePunctuation(TokenKind.Greater); + else + { + tokenInfo.Kind = TokenKind.Greater; + } + + return true; case '~': Window.ConsumeChar(); if (Window.PeekChar() == '=') { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Inequality); + tokenInfo.Kind = TokenKind.Inequality; } - return PureTokenFactory.CreatePunctuation(TokenKind.Not); + else + { + tokenInfo.Kind = TokenKind.Not; + } + + return true; case '+': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Plus); + tokenInfo.Kind = TokenKind.Plus; + return true; case '-': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Minus); + tokenInfo.Kind = TokenKind.Minus; + return true; case '*': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Multiply); + tokenInfo.Kind = TokenKind.Multiply; + return true; case '/': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Divide); + tokenInfo.Kind = TokenKind.Divide; + return true; case '\\': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Backslash); + tokenInfo.Kind = TokenKind.Backslash; + return true; case '^': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Power); + tokenInfo.Kind = TokenKind.Power; + return true; case '@': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.At); + tokenInfo.Kind = TokenKind.At; + return true; case ':': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Colon); + tokenInfo.Kind = TokenKind.Colon; + return true; case '?': Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.QuestionMark); + tokenInfo.Kind = TokenKind.QuestionMark; + return true; case '\'': if (LastToken != null && (LastToken.Kind == TokenKind.ClosingBrace @@ -709,14 +718,16 @@ namespace Lexer if (LastToken.TrailingTrivia.Count == 0 && leadingTrivia.Count == 0) { Window.ConsumeChar(); - return PureTokenFactory.CreatePunctuation(TokenKind.Transpose); + tokenInfo.Kind = TokenKind.Transpose; + return true; } } - return ContinueParsingStringLiteral(); + return ContinueLexingStringLiteral(ref tokenInfo); case '"': - return ContinueParsingDoubleQuotedStringLiteral(); + return ContinueLexingDoubleQuotedStringLiteral(ref tokenInfo); case '\0': - return PureTokenFactory.CreateEndOfFileToken(); + tokenInfo.Kind = TokenKind.EndOfFile; + return true; default: throw new ParsingException( $"Unknown symbol \"{character}\" at {Window.Position}." @@ -724,53 +735,14 @@ namespace Lexer } } - private bool IsOpeningToken(TokenKind tokenKind) - { - switch (tokenKind) - { - case TokenKind.OpeningBrace: - case TokenKind.OpeningBracket: - case TokenKind.OpeningSquareBracket: - return true; - default: - return false; - } - } - - private bool IsClosingToken(TokenKind tokenKind) - { - switch (tokenKind) - { - case TokenKind.ClosingBrace: - case TokenKind.ClosingBracket: - case TokenKind.ClosingSquareBracket: - return true; - default: - return false; - } - } - - private TokenKind? OpeningFromClosing(TokenKind tokenKind) - { - switch (tokenKind) - { - case TokenKind.ClosingBrace: - return TokenKind.OpeningBrace; - case TokenKind.ClosingBracket: - return TokenKind.OpeningBracket; - case TokenKind.ClosingSquareBracket: - return TokenKind.OpeningSquareBracket; - default: - return null; - } - } - - public Token NextToken() + public (SyntaxToken, Position) NextToken() { var leadingTrivia = LexTrivia(false); - var token = LexTokenWithoutTrivia(leadingTrivia); + var position = Window.Position; + var tokenInfo = new TokenInfo(); + LexTokenWithoutTrivia(leadingTrivia, ref tokenInfo); var trailingTrivia = LexTrivia(true); - if (trailingTrivia.Where(t => t.Type == TriviaType.NewLine).Any()) + if (trailingTrivia.Any(t => t.Kind == TokenKind.Newline)) { TokensSinceNewLine = 0; } @@ -778,58 +750,104 @@ namespace Lexer { TokensSinceNewLine++; } - - if (IsOpeningToken(token.Kind)) + + if (SyntaxFacts.IsOpeningToken(tokenInfo.Kind)) { - TokenStack.Push(token.Kind); + TokenStack.Push(tokenInfo.Kind); } - if (IsClosingToken(token.Kind)) + if (SyntaxFacts.IsClosingToken(tokenInfo.Kind)) { - if (TokenStack.TryPeek(out var t)) + if (TokenStack.Count > 0) { - if (t == OpeningFromClosing(token.Kind)) + var t = TokenStack.Peek(); + if (t == SyntaxFacts.OpeningFromClosing(tokenInfo.Kind)) { TokenStack.Pop(); } else { - throw new ParsingException($"Unmatched \"{token.LiteralText}\" at {token.Position}."); + throw new ParsingException($"Unmatched \"{tokenInfo.Text}\" at {Window.Position}."); } } else { - throw new ParsingException($"Unmatched \"{token.LiteralText}\" at {token.Position}."); + throw new ParsingException($"Unmatched \"{tokenInfo.Text}\" at {Window.Position}."); } } - if (token.Kind == TokenKind.EndOfFile + if (tokenInfo.Kind == TokenKind.EndOfFile && TokenStack.Any()) { throw new ParsingException($"Unmatched \"{TokenStack.Pop()}\" by the end of file."); } - var result = new Token(token, leadingTrivia, trailingTrivia); + var result = Create( + tokenInfo, + leadingTrivia, + trailingTrivia); LastToken = result; - return result; + return (result, position); } - public List ParseAll() + private SyntaxToken Create( + TokenInfo tokenInfo, + List leadingTrivia, + List trailingTrivia) { - var result = new List(); + switch (tokenInfo.Kind) + { + case TokenKind.Identifier: + return TokenFactory.CreateIdentifier( + tokenInfo.Text, + leadingTrivia, + trailingTrivia); + case TokenKind.UnquotedStringLiteral: + return TokenFactory.CreateUnquotedStringLiteral( + tokenInfo.Text, + tokenInfo.StringValue, + leadingTrivia, + trailingTrivia); + case TokenKind.NumberLiteral: + return TokenFactory.CreateTokenWithValueAndTrivia( + tokenInfo.Kind, + tokenInfo.Text, + tokenInfo.DoubleValue, + leadingTrivia, + trailingTrivia); + case TokenKind.StringLiteral: + return TokenFactory.CreateTokenWithValueAndTrivia( + tokenInfo.Kind, + tokenInfo.Text, + tokenInfo.StringValue, + leadingTrivia, + trailingTrivia); + default: + return TokenFactory.CreateTokenWithTrivia( + tokenInfo.Kind, + leadingTrivia, + trailingTrivia); + } + } + + public List<(SyntaxToken, Position)> ParseAll() + { + var result = new List<(SyntaxToken, Position)>(); while (true) { - var token = NextToken(); + var pair = NextToken(); + var (token, _) = pair; if (token == null) { throw new ParsingException($"Unexpected character: '{Window.PeekChar()}' at {Window.Position}."); } - result.Add(token); - if (token.PureToken.Kind == TokenKind.EndOfFile) + result.Add(pair); + if (token.Kind == TokenKind.EndOfFile) { return result; } } + } } } \ No newline at end of file diff --git a/Parser/Internal/MParserGreen.cs b/Parser/Internal/MParserGreen.cs new file mode 100644 index 0000000..129eae5 --- /dev/null +++ b/Parser/Internal/MParserGreen.cs @@ -0,0 +1,1117 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Parser.Internal +{ + internal class MParserGreen + { + private List<(SyntaxToken token, Position position)> Pairs { get; } + private int _index; + private SyntaxToken CurrentToken => Pairs[_index].token; + private Position CurrentPosition => Pairs[_index].position; + private SyntaxToken PeekToken(int n) => Pairs[_index + n].token; + private SyntaxFactory Factory { get; } + + public MParserGreen(List<(SyntaxToken, Position)> pairs, SyntaxFactory factory) + { + Pairs = pairs; + Factory = factory; + } + + private SyntaxToken EatToken() + { + var token = CurrentToken; + _index++; + return token; + } + + private SyntaxToken EatToken(TokenKind kind) + { + var token = CurrentToken; + if (token.Kind != kind) + { + throw new ParsingException($"Unexpected token \"{token.Text}\" instead of {kind} at {CurrentPosition}."); + } + _index++; + return token; + } + + private SyntaxToken EatIdentifier() + { + var token = CurrentToken; + if (token.Kind != TokenKind.Identifier) + { + throw new ParsingException($"Unexpected token \"{token}\" instead of identifier at {CurrentPosition}."); + } + _index++; + return token; + } + + private bool IsIdentifier(SyntaxToken token, string s) + { + return token.Kind == TokenKind.Identifier && token.Text == s; + } + + private SyntaxToken EatIdentifier(string s) + { + var token = CurrentToken; + if (token.Kind != TokenKind.Identifier) + { + throw new ParsingException($"Unexpected token \"{token}\" instead of identifier \"{s}\" at {CurrentPosition}."); + } + + if (token.Text != s) + { + throw new ParsingException($"Unexpected identifier \"{token.Text}\" instead of \"{s}\" at {CurrentPosition}."); + } + + _index++; + return token; + } + + private SyntaxToken PossiblyEatIdentifier(string s) + { + var token = CurrentToken; + if (token.Kind == TokenKind.Identifier && token.Text == s) + { + return EatToken(); + } + + return null; + } + + private SyntaxToken EatPossiblyMissingIdentifier(string s) + { + var token = CurrentToken; + if (token.Kind == TokenKind.Identifier && token.Text == s) + { + return EatToken(); + } + + return TokenFactory.CreateMissing( + TokenKind.Identifier, + new List(), + new List()); + } + + private SyntaxList ParseFunctionOutputList() + { + var outputs = new SyntaxListBuilder(); + var firstToken = true; + while (CurrentToken.Kind != TokenKind.ClosingSquareBracket) + { + if (!firstToken && CurrentToken.Kind == TokenKind.Comma) + { + outputs.Add(EatToken()); + } + + firstToken = false; + outputs.Add(Factory.IdentifierNameSyntax(EatToken(TokenKind.Identifier))); + } + + return outputs.ToList(); + } + + private FunctionOutputDescriptionSyntaxNode ParseFunctionOutputDescription() + { + SyntaxToken assignmentSign; + var builder = new SyntaxListBuilder(); + + if (CurrentToken.Kind == TokenKind.Identifier) + { + if (PeekToken(1).Kind == TokenKind.Assignment) + { + builder.Add(Factory.IdentifierNameSyntax(EatToken())); + assignmentSign = EatToken(TokenKind.Assignment); + } + else + { + return null; + } + } + else if (CurrentToken.Kind == TokenKind.OpeningSquareBracket) + { + builder.Add(EatToken()); + var outputs = ParseFunctionOutputList(); + if (outputs != null) + { + builder.AddRange(outputs); + } + + builder.Add(EatToken(TokenKind.ClosingSquareBracket)); + assignmentSign = EatToken(TokenKind.Assignment); + } + else + { + throw new ParsingException($"Unexpected token {CurrentToken} during parsing function output descritpion at {CurrentPosition}."); + } + + return Factory.FunctionOutputDescriptionSyntax(builder.ToList(), assignmentSign); + } + + private SyntaxList ParseParameterList() + { + var builder = new SyntaxListBuilder(); + var firstToken = true; + while (CurrentToken.Kind != TokenKind.ClosingBracket) + { + if (!firstToken) + { + builder.Add(EatToken(TokenKind.Comma)); + } + else + { + firstToken = false; + } + + if (CurrentToken.Kind == TokenKind.Not) + { + var notToken = EatToken(); + builder.Add(notToken); + } + else + { + var identifierToken = EatToken(TokenKind.Identifier); + builder.Add(Factory.IdentifierNameSyntax(identifierToken)); + } + } + + return builder.ToList(); + } + + private FunctionInputDescriptionSyntaxNode ParseFunctionInputDescription() + { + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + var openingBracket = EatToken(TokenKind.OpeningBracket); + var parameterList = ParseParameterList(); + var closingBracket = EatToken(TokenKind.ClosingBracket); + return Factory.FunctionInputDescriptionSyntax( + openingBracket, + parameterList, + closingBracket); + } + else + { + return null; + } + } + + private FunctionDeclarationSyntaxNode ParseFunctionDeclaration() + { + var functionKeyword = EatIdentifier("function"); + var outputDescription = ParseFunctionOutputDescription(); + var name = EatToken(TokenKind.Identifier); + var inputDescription = ParseFunctionInputDescription(); + var commas = ParseOptionalCommas(); + var body = ParseStatementList(); + var endKeyword = EatPossiblyMissingIdentifier("end"); + return Factory.FunctionDeclarationSyntax( + functionKeyword, + outputDescription, + name, + inputDescription, + commas, + body, + endKeyword); + } + + internal struct ParseOptions + { + public bool ParsingArrayElements { get; set; } + + public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false }; + } + + private ExpressionSyntaxNode ParseExpression() + { + return ParseExpression(ParseOptions.Default); + } + + private ExpressionSyntaxNode ParseExpression(ParseOptions options) + { + return ParseSubExpression(options, SyntaxFacts.Precedence.Expression); + } + + private ArrayLiteralExpressionSyntaxNode ParseArrayLiteral() + { + var openingSquareBracket = EatToken(TokenKind.OpeningSquareBracket); + var elements = ParseArrayElementList(TokenKind.ClosingSquareBracket); + var closingSquareBracket = EatToken(TokenKind.ClosingSquareBracket); + return Factory.ArrayLiteralExpressionSyntax( + openingSquareBracket, + elements, + closingSquareBracket); + } + + private CellArrayLiteralExpressionSyntaxNode ParseCellArrayLiteral() + { + var openingBrace = EatToken(TokenKind.OpeningBrace); + var elements = ParseArrayElementList(TokenKind.ClosingBrace); + var closingBrace = EatToken(TokenKind.ClosingBrace); + return Factory.CellArrayLiteralExpressionSyntax( + openingBrace, + elements, + closingBrace); + } + + + private SyntaxList ParseArrayElementList(TokenKind closing) + { + var builder = new SyntaxListBuilder(); + var firstToken = true; + while (CurrentToken.Kind != closing) + { + if (!firstToken) + { + if (CurrentToken.Kind == TokenKind.Comma + || CurrentToken.Kind == TokenKind.Semicolon) + { + builder.Add(EatToken()); + } + } + else + { + firstToken = false; + } + + var expression = ParseExpression(new ParseOptions { ParsingArrayElements = true }); + if (expression != null) + { + builder.Add(expression); + } + } + + return builder.ToList(); + } + + private ExpressionSyntaxNode ParseTerm(ParseOptions options) + { + var token = CurrentToken; + ExpressionSyntaxNode expression = null; + switch (token.Kind) + { + case TokenKind.Identifier: + expression = Factory.IdentifierNameSyntax(EatToken()); + break; + case TokenKind.NumberLiteral: + expression = Factory.NumberLiteralSyntax(EatToken()); + break; + case TokenKind.StringLiteral: + expression = Factory.StringLiteralSyntax(EatToken()); + break; + case TokenKind.DoubleQuotedStringLiteral: + expression = Factory.DoubleQuotedStringLiteralSyntax(EatToken()); + break; + case TokenKind.OpeningSquareBracket: + expression = ParseArrayLiteral(); + break; + case TokenKind.OpeningBrace: + expression = ParseCellArrayLiteral(); + break; + case TokenKind.Colon: + expression = Factory.EmptyExpressionSyntax(); + break; + case TokenKind.OpeningBracket: + expression = ParseParenthesizedExpression(); + break; + } + + if (expression == null) + { + return null; + } + return ParsePostfix(options, expression); + } + + private ExpressionSyntaxNode ParsePostfix(ParseOptions options, ExpressionSyntaxNode expression) + { + while (true) + { + var token = CurrentToken; + switch (token.Kind) + { + case TokenKind.OpeningBrace: // cell array element access + if (options.ParsingArrayElements && expression.TrailingTrivia.Any()) + { + return expression; + } + var openingBrace = EatToken(); + var indices = ParseArrayElementList(TokenKind.ClosingBrace); + var closingBrace = EatToken(TokenKind.ClosingBrace); + expression = Factory.CellArrayElementAccessExpressionSyntax( + expression, + openingBrace, + indices, + closingBrace + ); + break; + case TokenKind.OpeningBracket: // function call + if (options.ParsingArrayElements && expression.TrailingTrivia.Any()) + { + return expression; + } + var openingBracket = EatToken(); + var parameters = ParseFunctionCallParameterList(); + var closingBracket = EatToken(TokenKind.ClosingBracket); + expression = Factory.FunctionCallExpressionSyntax( + expression, + openingBracket, + parameters, + closingBracket); + break; + case TokenKind.Dot: // member access + if (expression is IdentifierNameSyntaxNode + || expression is MemberAccessSyntaxNode + || expression is FunctionCallExpressionSyntaxNode + || expression is CellArrayElementAccessExpressionSyntaxNode) + { + var dot = EatToken(); + var member = ParseMemberAccess(); + expression = Factory.MemberAccessSyntax(expression, dot, member); + } + else + { + throw new ParsingException( + $"Unexpected token {token} at {CurrentPosition}."); + } + + break; + case TokenKind.Transpose: + case TokenKind.DotTranspose: + var operation = EatToken(); + expression = Factory.UnaryPostixOperationExpressionSyntax(expression, operation); + break; + case TokenKind.UnquotedStringLiteral: + return ParseCommandExpression(expression); + case TokenKind.At: + if (expression.TrailingTrivia.Any()) + { + return expression; + } + return ParseBaseClassInvokation(expression); + default: + return expression; + } + } + } + + private CommandExpressionSyntaxNode ParseCommandExpression(ExpressionSyntaxNode expression) + { + if (expression is IdentifierNameSyntaxNode idNameNode) + { + var builder = new SyntaxListBuilder(); + while (CurrentToken.Kind == TokenKind.UnquotedStringLiteral) + { + builder.Add(Factory.UnquotedStringLiteralSyntax(EatToken())); + } + + return Factory.CommandExpressionSyntax(idNameNode, builder.ToList()); + } + throw new ParsingException($"Unexpected token \"{CurrentToken}\" while parsing expression \"{expression.FullText}\" at {CurrentPosition}."); + } + + private BaseClassInvokationSyntaxNode ParseBaseClassInvokation(ExpressionSyntaxNode expression) + { + if (expression is IdentifierNameSyntaxNode methodName + && !expression.TrailingTrivia.Any()) + { + var atToken = EatToken(); + var baseClassNameWithArguments = ParseExpression(); + return Factory.BaseClassInvokationSyntax(methodName, atToken, baseClassNameWithArguments); + } + if (expression is MemberAccessSyntaxNode memberAccess + && !expression.TrailingTrivia.Any()) + { + var atToken = EatToken(); + var baseClassNameWithArguments = ParseExpression(); + return Factory.BaseClassInvokationSyntax(memberAccess, atToken, baseClassNameWithArguments); + } + throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}."); + } + + private ExpressionSyntaxNode ParseMemberAccess() + { + if (CurrentToken.Kind == TokenKind.Identifier) + { + return Factory.IdentifierNameSyntax(EatToken()); + } + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + var openingBracket = EatToken(); + var indirectMember = ParseExpression(); + var closingBracket = EatToken(TokenKind.ClosingBracket); + return Factory.IndirectMemberAccessSyntax( + openingBracket, + indirectMember, + closingBracket); + } + throw new ParsingException($"Unexpected token {CurrentToken} at {CurrentPosition}."); + } + + private SyntaxList ParseFunctionCallParameterList() + { + var builder = new SyntaxListBuilder(); + var firstToken = true; + while (CurrentToken.Kind != TokenKind.ClosingBracket) + { + if (!firstToken) + { + builder.Add(EatToken(TokenKind.Comma)); + } + else + { + firstToken = false; + } + + builder.Add(ParseExpression()); + } + + return builder.ToList(); + } + + private ParenthesizedExpressionSyntaxNode ParseParenthesizedExpression() + { + var openParen = EatToken(TokenKind.OpeningBracket); + var expression = ParseExpression(); + var closeParen = EatToken(TokenKind.ClosingBracket); + return Factory.ParenthesizedExpressionSyntax( + openParen, + expression, + closeParen); + } + + private CompoundNameSyntaxNode ParseCompoundName() + { + var lastToken = EatToken(TokenKind.Identifier); + var firstName = lastToken; + var builder = new SyntaxListBuilder(); + builder.Add(firstName); + while (CurrentToken.Kind == TokenKind.Dot + && !lastToken.TrailingTrivia.Any()) + { + var dot = EatToken(); + builder.Add(dot); + lastToken = EatToken(TokenKind.Identifier); + builder.Add(lastToken); + } + + return Factory.CompoundNameSyntax(builder.ToList()); + } + + private FunctionHandleSyntaxNode ParseFunctionHandle() + { + var atSign = EatToken(); + if (CurrentToken.Kind == TokenKind.Identifier) + { + var compoundName = ParseCompoundName(); + return Factory.NamedFunctionHandleSyntax( + atSign, + compoundName); + } + else if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + var inputs = ParseFunctionInputDescription(); + var body = ParseExpression(); + return Factory.LambdaSyntax(atSign, inputs, body); + } + throw new ParsingException($"Unexpected token {CurrentToken} while parsing function handle at {CurrentPosition}."); + } + + private ExpressionSyntaxNode ParseSubExpression( + ParseOptions options, + SyntaxFacts.Precedence precedence) + { + ExpressionSyntaxNode lhs; + if (SyntaxFacts.IsUnaryOperator(CurrentToken.Kind)) + { + var operation = EatToken(); + var unaryTokenKind = SyntaxFacts.ConvertToUnaryTokenKind(operation.Kind); + var newPrecedence = SyntaxFacts.GetPrecedence(unaryTokenKind); + var operand = ParseSubExpression(options, newPrecedence); + if (operand == null) + { + if (options.ParsingArrayElements && operation.Kind == TokenKind.Not) + { + operand = Factory.EmptyExpressionSyntax(); + } + else + { + throw new ParsingException($"Unexpected token {CurrentToken} at {CurrentPosition}."); + } + } + lhs = Factory.UnaryPrefixOperationExpressionSyntax(operation, operand); + } + else if (CurrentToken.Kind == TokenKind.At) + { + return ParseFunctionHandle(); + } + else + { + lhs = ParseTerm(options); + } + + while (true) + { + var token = CurrentToken; + if (SyntaxFacts.IsBinaryOperator(token.Kind)) + { + var newPrecedence = SyntaxFacts.GetPrecedence(token.Kind); + if (newPrecedence < precedence) + { + break; + } + + if (newPrecedence == precedence && SyntaxFacts.IsLeftAssociative(token.Kind)) + { + break; + } + + EatToken(); + var rhs = ParseSubExpression(options, newPrecedence); + if (rhs == null && token.Kind == TokenKind.Colon) // for parsing things like a{:} + { + rhs = Factory.EmptyExpressionSyntax(); + } + if (token.Kind == TokenKind.Assignment) + { + lhs = Factory.AssignmentExpressionSyntax(lhs, token, rhs); + } + else + { + lhs = Factory.BinaryOperationExpressionSyntax(lhs, token, rhs); + } + } + else + { + break; + } + } + + return lhs; + } + + private SyntaxList ParseOptionalCommas() + { + var builder = new SyntaxListBuilder(); + while (CurrentToken.Kind == TokenKind.Comma) + { + builder.Add(EatToken()); + } + + return builder.ToList(); + } + + private SyntaxList ParseOptionalSemicolonsOrCommas() + { + var builder = new SyntaxListBuilder(); + while (CurrentToken.Kind == TokenKind.Comma + || CurrentToken.Kind == TokenKind.Semicolon) + { + builder.Add(EatToken()); + } + + return builder.ToList(); + } + + private SwitchCaseSyntaxNode ParseSwitchCase() + { + var caseKeyword = EatIdentifier("case"); + var caseId = ParseExpression(); + var commas = ParseOptionalCommas(); + var statementList = ParseStatementList(); + return Factory.SwitchCaseSyntax(caseKeyword, caseId, commas, statementList); + } + + private SwitchStatementSyntaxNode ParseSwitchStatement() + { + var switchKeyword = EatIdentifier("switch"); + var expression = ParseExpression(); + var commas = ParseOptionalCommas(); + var builder = new SyntaxListBuilder(); + while (IsIdentifier(CurrentToken, "case")) + { + builder.Add(ParseSwitchCase()); + } + var endKeyword = EatIdentifier("end"); + return Factory.SwitchStatementSyntax( + switchKeyword, + expression, + commas, + builder.ToList(), + endKeyword); + } + + private WhileStatementSyntaxNode ParseWhileStatement() + { + var whileKeyword = EatIdentifier("while"); + var condition = ParseExpression(); + var commas = ParseOptionalCommas(); + var body = ParseStatementList(); + var endKeyword = EatIdentifier("end"); + return Factory.WhileStatementSyntax( + whileKeyword, + condition, + commas, + body, + endKeyword); + } + + private ElseifClause ParseElseifClause() + { + var elseifKeyword = EatIdentifier("elseif"); + var condition = ParseExpression(); + var commas = ParseOptionalCommas(); + var body = ParseStatementList(); + return Factory.ElseifClause(elseifKeyword, condition, commas, body); + } + + private ElseClause ParseElseClause() + { + var elseKeyword = EatIdentifier("else"); + var body = ParseStatementList(); + return Factory.ElseClause(elseKeyword, body); + } + + private IfStatementSyntaxNode ParseIfStatement() + { + var ifKeyword = EatIdentifier(); + var condition = ParseExpression(); + var commas = ParseOptionalSemicolonsOrCommas(); + var body = ParseStatementList(); + var elseifClauses = new SyntaxListBuilder(); + ElseClause elseClause = null; + while (true) + { + var token = CurrentToken; + if (IsIdentifier(token, "elseif")) + { + var elseifClause = ParseElseifClause(); + elseifClauses.Add(elseifClause); + continue; + } else if (IsIdentifier(token, "else")) + { + elseClause = ParseElseClause(); + break; + } else if (IsIdentifier(token, "end")) + { + break; + } + throw new ParsingException($"Unexpected token \"{token}\" while parsing \"if\" statement at {CurrentPosition}."); + } + var endKeyword = EatIdentifier("end"); + return Factory.IfStatementSyntax( + ifKeyword, + condition, + commas, + body, + elseifClauses.ToList(), + elseClause, + endKeyword); + } + + private ForStatementSyntaxNode ParseForStatement() + { + var forKeyword = EatIdentifier("for"); + var expression = ParseExpression(); + if (!(expression is AssignmentExpressionSyntaxNode)) + { + throw new ParsingException($"Unexpected expression \"{expression}\" while parsing FOR statement at {CurrentPosition}."); + } + + var forAssignment = (AssignmentExpressionSyntaxNode) expression; + var commas = ParseOptionalSemicolonsOrCommas(); + var body = ParseStatementList(); + var endKeyword = EatIdentifier("end"); + return Factory.ForStatementSyntax( + forKeyword, + forAssignment, + commas, + body, + endKeyword); + } + + private CatchClauseSyntaxNode ParseCatchClause() + { + if (IsIdentifier(CurrentToken, "catch")) + { + var catchKeyword = EatIdentifier(); + var catchBody = ParseStatementList(); + return Factory.CatchClauseSyntax( + catchKeyword, + catchBody); + } + + return null; + } + + private TryCatchStatementSyntaxNode ParseTryCatchStatement() + { + var tryKeyword = EatIdentifier("try"); + var tryBody = ParseStatementList(); + var catchClause = ParseCatchClause(); + var endKeyword = EatIdentifier("end"); + return Factory.TryCatchStatementSyntax(tryKeyword, tryBody, catchClause, endKeyword); + } + + private ExpressionStatementSyntaxNode ParseExpressionStatement() + { + var expression = ParseExpression(); + return Factory.ExpressionStatementSyntax(expression); + } + + private AttributeAssignmentSyntaxNode ParseAttributeAssignment() + { + if (CurrentToken.Kind == TokenKind.Assignment) + { + var assignmentSign = EatToken(); + var value = ParseExpression(); + return Factory.AttributeAssignmentSyntax(assignmentSign, value); + } + + return null; + } + + private AttributeSyntaxNode ParseAttribute() + { + var name = Factory.IdentifierNameSyntax(EatToken(TokenKind.Identifier)); + var assignment = ParseAttributeAssignment(); + return Factory.AttributeSyntax(name, assignment); + } + + private AttributeListSyntaxNode ParseAttributesList() + { + var openingBracket = EatToken(); + var first = true; + var builder = new SyntaxListBuilder(); + while (CurrentToken.Kind != TokenKind.ClosingBracket) + { + if (!first) + { + var comma = EatToken(TokenKind.Comma); + builder.Add(comma); + } + + first = false; + builder.Add(ParseAttribute()); + } + + var closingBracket = EatToken(); + return Factory.AttributeListSyntax(openingBracket, builder.ToList(), closingBracket); + } + + private AbstractMethodDeclarationSyntaxNode ParseAbstractMethodDeclaration() + { + var outputDescription = ParseFunctionOutputDescription(); + var name = ParseCompoundName(); + var inputDescription = ParseFunctionInputDescription(); + return Factory.AbstractMethodDeclarationSyntax(outputDescription, name, inputDescription); + } + + private StatementSyntaxNode ParseMethodDeclaration() + { + if (IsIdentifier(CurrentToken, "function")) + { + return ParseMethodDefinition(); + } + + if (CurrentToken.Kind == TokenKind.OpeningSquareBracket + || CurrentToken.Kind == TokenKind.Identifier) + { + return ParseAbstractMethodDeclaration(); + } + + if (CurrentToken.Kind == TokenKind.Semicolon) + { + return Factory.EmptyStatementSyntax(EatToken()); + } + throw new ParsingException($"Unexpected token {CurrentToken} while parsing method declaration at {CurrentPosition}."); + } + + private MethodDefinitionSyntaxNode ParseMethodDefinition() + { + var functionKeyword = EatIdentifier("function"); + var outputDescription = ParseFunctionOutputDescription(); + var name = ParseCompoundName(); + var inputDescription = ParseFunctionInputDescription(); + var commas = ParseOptionalCommas(); + var body = ParseStatementList(); + var endKeyword = PossiblyEatIdentifier("end"); + return Factory.MethodDefinitionSyntax( + functionKeyword, + outputDescription, + name, + inputDescription, + commas, + body, + endKeyword); + } + + private MethodsListSyntaxNode ParseMethods() + { + var methodsKeyword = EatToken(); + AttributeListSyntaxNode attributes = null; + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + attributes = ParseAttributesList(); + } + + var builder = new SyntaxListBuilder(); + while (!IsIdentifier(CurrentToken, "end")) + { + var method = ParseMethodDeclaration(); + builder.Add(method); + } + + var endKeyword = EatToken(); + return Factory.MethodsListSyntax(methodsKeyword, attributes, builder.ToList(), endKeyword); + } + + private GreenNode ParsePropertyDeclaration() + { + if (CurrentToken.Kind == TokenKind.Comma) + { + return EatToken(); + } + return ParseStatement(); + } + + private SyntaxNode ParseEventDeclaration() + { + return ParseStatement(); + } + + private PropertiesListSyntaxNode ParseProperties() + { + var propertiesKeyword = EatToken(); + AttributeListSyntaxNode attributes = null; + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + attributes = ParseAttributesList(); + } + + var builder = new SyntaxListBuilder(); + while (!IsIdentifier(CurrentToken, "end")) + { + builder.Add(ParsePropertyDeclaration()); + } + + var endKeyword = EatToken(); + return Factory.PropertiesListSyntax(propertiesKeyword, attributes, builder.ToList(), endKeyword); + } + + private EnumerationItemValueSyntaxNode ParseEnumerationValue() + { + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + var builder = new SyntaxListBuilder(); + var openingBracket = EatToken(TokenKind.OpeningBracket); + var expression = ParseExpression() ?? Factory.EmptyExpressionSyntax(); + builder.Add(expression); + while (CurrentToken.Kind == TokenKind.Comma) + { + builder.Add(EatToken()); + builder.Add(ParseExpression()); + } + var closingBracket = EatToken(TokenKind.ClosingBracket); + return Factory.EnumerationItemValueSyntax(openingBracket, builder.ToList(), closingBracket); + } + return null; + } + + private EnumerationItemSyntaxNode ParseEnumerationItem() + { + var name = Factory.IdentifierNameSyntax(EatToken()); + var values = ParseEnumerationValue(); + var commas = ParseOptionalCommas(); + return Factory.EnumerationItemSyntax(name, values, commas); + } + + private EnumerationListSyntaxNode ParseEnumeration() + { + var enumerationKeyword = EatToken(); + var builder = new SyntaxListBuilder(); + AttributeListSyntaxNode attributes = null; + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + attributes = ParseAttributesList(); + } + while (!IsIdentifier(CurrentToken, "end")) + { + var item = ParseEnumerationItem(); + builder.Add(item); + } + + var endkeyword = EatToken(); + return Factory.EnumerationListSyntax( + enumerationKeyword, + attributes, + builder.ToList(), + endkeyword); + } + + private SyntaxNode ParseEvents() + { + var eventsKeyword = EatToken(); + AttributeListSyntaxNode attributes = null; + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + attributes = ParseAttributesList(); + } + + var builder = new SyntaxListBuilder(); + while (!IsIdentifier(CurrentToken, "end")) + { + builder.Add(ParseEventDeclaration()); + } + + var endKeyword = EatToken(); + return Factory.EventsListSyntax(eventsKeyword, attributes, builder.ToList(), endKeyword); + } + + private SyntaxList ParseBaseClassNames() + { + var builder = new SyntaxListBuilder(); + builder.Add(ParseCompoundName()); + while (CurrentToken.Kind == TokenKind.BitwiseAnd) + { + builder.Add(EatToken()); + builder.Add(ParseCompoundName()); + } + + return builder.ToList(); + } + + private BaseClassListSyntaxNode ParseBaseClassList() + { + var lessSign = EatToken(); + var baseClassNames = ParseBaseClassNames(); + return Factory.BaseClassListSyntax(lessSign, baseClassNames); + } + + private StatementSyntaxNode ParseClassDeclaration() + { + var classdefKeyword = EatToken(); + AttributeListSyntaxNode attributes = null; + if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + attributes = ParseAttributesList(); + } + var className = Factory.IdentifierNameSyntax(EatToken(TokenKind.Identifier)); + BaseClassListSyntaxNode baseClassList = null; + if (CurrentToken.Kind == TokenKind.Less) + { + baseClassList = ParseBaseClassList(); + } + + var builder = new SyntaxListBuilder(); + while (!IsIdentifier(CurrentToken, "end")) + { + if (IsIdentifier(CurrentToken, "methods")) + { + var methods = ParseMethods(); + builder.Add(methods); + } + else if (IsIdentifier(CurrentToken, "properties")) + { + var properties = ParseProperties(); + builder.Add(properties); + } + else if (IsIdentifier(CurrentToken, "events")) + { + var events = ParseEvents(); + builder.Add(events); + } + else if (IsIdentifier(CurrentToken, "enumeration")) + { + var enumeration = ParseEnumeration(); + builder.Add(enumeration); + } + else + { + throw new ParsingException($"Unknown token \"{CurrentToken}\" while parsing class definition at {CurrentPosition}."); + } + } + + var endKeyword = EatToken(); + return Factory.ClassDeclarationSyntax( + classdefKeyword, + attributes, + className, + baseClassList, + builder.ToList(), + endKeyword); + } + + private StatementSyntaxNode ParseStatement() + { + if (CurrentToken.Kind == TokenKind.Identifier) + { + switch (CurrentToken.Text) + { + case "function": + return ParseFunctionDeclaration(); + case "classdef": + return ParseClassDeclaration(); + case "switch": + return ParseSwitchStatement(); + case "while": + return ParseWhileStatement(); + case "if": + return ParseIfStatement(); + case "for": + return ParseForStatement(); + case "try": + return ParseTryCatchStatement(); + case "case": + case "catch": + case "else": + case "elseif": + case "end": + return null; + default: + return ParseExpressionStatement(); + } + } + + if (CurrentToken.Kind == TokenKind.OpeningSquareBracket) + { + return ParseExpressionStatement(); + } + + if (CurrentToken.Kind == TokenKind.Semicolon) + { + return Factory.EmptyStatementSyntax(EatToken()); + } + throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}."); + } + + private SyntaxList ParseStatementList() + { + var builder = new SyntaxListBuilder(); + while (CurrentToken.Kind != TokenKind.EndOfFile) + { + var node = ParseStatement(); + if (node == null) + { + break; + } + builder.Add(node); + while (CurrentToken.Kind == TokenKind.Comma + || CurrentToken.Kind == TokenKind.Semicolon) + { + builder.Add(EatToken()); + } + } + + return builder.ToList(); + } + + public FileSyntaxNode ParseFile() + { + var statementList = ParseStatementList(); + var endOfFileToken = EatToken(); + return Factory.FileSyntax(statementList, endOfFileToken); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxFactory.Generated.cs b/Parser/Internal/SyntaxFactory.Generated.cs new file mode 100644 index 0000000..b6f42c2 --- /dev/null +++ b/Parser/Internal/SyntaxFactory.Generated.cs @@ -0,0 +1,555 @@ +namespace Parser.Internal +{ + internal partial class SyntaxFactory + { + public FileSyntaxNode FileSyntax( + SyntaxList statementList, + SyntaxToken endOfFile) + { + return new FileSyntaxNode( + statementList, + endOfFile); + } + + public FunctionDeclarationSyntaxNode FunctionDeclarationSyntax( + SyntaxToken functionKeyword, + FunctionOutputDescriptionSyntaxNode outputDescription, + SyntaxToken name, + FunctionInputDescriptionSyntaxNode inputDescription, + SyntaxList commas, + SyntaxList body, + SyntaxToken endKeyword) + { + return new FunctionDeclarationSyntaxNode( + functionKeyword, + outputDescription, + name, + inputDescription, + commas, + body, + endKeyword); + } + + public FunctionOutputDescriptionSyntaxNode FunctionOutputDescriptionSyntax( + SyntaxList outputList, + SyntaxToken assignmentSign) + { + return new FunctionOutputDescriptionSyntaxNode( + outputList, + assignmentSign); + } + + public FunctionInputDescriptionSyntaxNode FunctionInputDescriptionSyntax( + SyntaxToken openingBracket, + SyntaxList parameterList, + SyntaxToken closingBracket) + { + return new FunctionInputDescriptionSyntaxNode( + openingBracket, + parameterList, + closingBracket); + } + + public SwitchStatementSyntaxNode SwitchStatementSyntax( + SyntaxToken switchKeyword, + ExpressionSyntaxNode switchExpression, + SyntaxList optionalCommas, + SyntaxList cases, + SyntaxToken endKeyword) + { + return new SwitchStatementSyntaxNode( + switchKeyword, + switchExpression, + optionalCommas, + cases, + endKeyword); + } + + public SwitchCaseSyntaxNode SwitchCaseSyntax( + SyntaxToken caseKeyword, + ExpressionSyntaxNode caseIdentifier, + SyntaxList optionalCommas, + SyntaxList body) + { + return new SwitchCaseSyntaxNode( + caseKeyword, + caseIdentifier, + optionalCommas, + body); + } + + public WhileStatementSyntaxNode WhileStatementSyntax( + SyntaxToken whileKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxToken endKeyword) + { + return new WhileStatementSyntaxNode( + whileKeyword, + condition, + optionalCommas, + body, + endKeyword); + } + + public ElseifClause ElseifClause( + SyntaxToken elseifKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body) + { + return new ElseifClause( + elseifKeyword, + condition, + optionalCommas, + body); + } + + public ElseClause ElseClause( + SyntaxToken elseKeyword, + SyntaxList body) + { + return new ElseClause( + elseKeyword, + body); + } + + public IfStatementSyntaxNode IfStatementSyntax( + SyntaxToken ifKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxList elseifClauses, + ElseClause elseClause, + SyntaxToken endKeyword) + { + return new IfStatementSyntaxNode( + ifKeyword, + condition, + optionalCommas, + body, + elseifClauses, + elseClause, + endKeyword); + } + + public ForStatementSyntaxNode ForStatementSyntax( + SyntaxToken forKeyword, + AssignmentExpressionSyntaxNode assignment, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxToken endKeyword) + { + return new ForStatementSyntaxNode( + forKeyword, + assignment, + optionalCommas, + body, + endKeyword); + } + + public AssignmentExpressionSyntaxNode AssignmentExpressionSyntax( + ExpressionSyntaxNode lhs, + SyntaxToken assignmentSign, + ExpressionSyntaxNode rhs) + { + return new AssignmentExpressionSyntaxNode( + lhs, + assignmentSign, + rhs); + } + + public CatchClauseSyntaxNode CatchClauseSyntax( + SyntaxToken catchKeyword, + SyntaxList catchBody) + { + return new CatchClauseSyntaxNode( + catchKeyword, + catchBody); + } + + public TryCatchStatementSyntaxNode TryCatchStatementSyntax( + SyntaxToken tryKeyword, + SyntaxList tryBody, + CatchClauseSyntaxNode catchClause, + SyntaxToken endKeyword) + { + return new TryCatchStatementSyntaxNode( + tryKeyword, + tryBody, + catchClause, + endKeyword); + } + + public ExpressionStatementSyntaxNode ExpressionStatementSyntax( + ExpressionSyntaxNode expression) + { + return new ExpressionStatementSyntaxNode( + expression); + } + + public EmptyStatementSyntaxNode EmptyStatementSyntax( + SyntaxToken semicolon) + { + return new EmptyStatementSyntaxNode( + semicolon); + } + + public EmptyExpressionSyntaxNode EmptyExpressionSyntax() + { + return new EmptyExpressionSyntaxNode(); + } + + public UnaryPrefixOperationExpressionSyntaxNode UnaryPrefixOperationExpressionSyntax( + SyntaxToken operation, + ExpressionSyntaxNode operand) + { + return new UnaryPrefixOperationExpressionSyntaxNode( + operation, + operand); + } + + public CompoundNameSyntaxNode CompoundNameSyntax( + SyntaxList nodes) + { + return new CompoundNameSyntaxNode( + nodes); + } + + public NamedFunctionHandleSyntaxNode NamedFunctionHandleSyntax( + SyntaxToken atSign, + CompoundNameSyntaxNode functionName) + { + return new NamedFunctionHandleSyntaxNode( + atSign, + functionName); + } + + public LambdaSyntaxNode LambdaSyntax( + SyntaxToken atSign, + FunctionInputDescriptionSyntaxNode input, + ExpressionSyntaxNode body) + { + return new LambdaSyntaxNode( + atSign, + input, + body); + } + + public BinaryOperationExpressionSyntaxNode BinaryOperationExpressionSyntax( + ExpressionSyntaxNode lhs, + SyntaxToken operation, + ExpressionSyntaxNode rhs) + { + return new BinaryOperationExpressionSyntaxNode( + lhs, + operation, + rhs); + } + + public IdentifierNameSyntaxNode IdentifierNameSyntax( + SyntaxToken name) + { + return new IdentifierNameSyntaxNode( + name); + } + + public NumberLiteralSyntaxNode NumberLiteralSyntax( + SyntaxToken number) + { + return new NumberLiteralSyntaxNode( + number); + } + + public StringLiteralSyntaxNode StringLiteralSyntax( + SyntaxToken stringToken) + { + return new StringLiteralSyntaxNode( + stringToken); + } + + public DoubleQuotedStringLiteralSyntaxNode DoubleQuotedStringLiteralSyntax( + SyntaxToken stringToken) + { + return new DoubleQuotedStringLiteralSyntaxNode( + stringToken); + } + + public UnquotedStringLiteralSyntaxNode UnquotedStringLiteralSyntax( + SyntaxToken stringToken) + { + return new UnquotedStringLiteralSyntaxNode( + stringToken); + } + + public ArrayLiteralExpressionSyntaxNode ArrayLiteralExpressionSyntax( + SyntaxToken openingSquareBracket, + SyntaxList nodes, + SyntaxToken closingSquareBracket) + { + return new ArrayLiteralExpressionSyntaxNode( + openingSquareBracket, + nodes, + closingSquareBracket); + } + + public CellArrayLiteralExpressionSyntaxNode CellArrayLiteralExpressionSyntax( + SyntaxToken openingBrace, + SyntaxList nodes, + SyntaxToken closingBrace) + { + return new CellArrayLiteralExpressionSyntaxNode( + openingBrace, + nodes, + closingBrace); + } + + public ParenthesizedExpressionSyntaxNode ParenthesizedExpressionSyntax( + SyntaxToken openingBracket, + ExpressionSyntaxNode expression, + SyntaxToken closingBracket) + { + return new ParenthesizedExpressionSyntaxNode( + openingBracket, + expression, + closingBracket); + } + + public CellArrayElementAccessExpressionSyntaxNode CellArrayElementAccessExpressionSyntax( + ExpressionSyntaxNode expression, + SyntaxToken openingBrace, + SyntaxList nodes, + SyntaxToken closingBrace) + { + return new CellArrayElementAccessExpressionSyntaxNode( + expression, + openingBrace, + nodes, + closingBrace); + } + + public FunctionCallExpressionSyntaxNode FunctionCallExpressionSyntax( + ExpressionSyntaxNode functionName, + SyntaxToken openingBracket, + SyntaxList nodes, + SyntaxToken closingBracket) + { + return new FunctionCallExpressionSyntaxNode( + functionName, + openingBracket, + nodes, + closingBracket); + } + + public MemberAccessSyntaxNode MemberAccessSyntax( + SyntaxNode leftOperand, + SyntaxToken dot, + SyntaxNode rightOperand) + { + return new MemberAccessSyntaxNode( + leftOperand, + dot, + rightOperand); + } + + public UnaryPostixOperationExpressionSyntaxNode UnaryPostixOperationExpressionSyntax( + ExpressionSyntaxNode operand, + SyntaxToken operation) + { + return new UnaryPostixOperationExpressionSyntaxNode( + operand, + operation); + } + + public IndirectMemberAccessSyntaxNode IndirectMemberAccessSyntax( + SyntaxToken openingBracket, + ExpressionSyntaxNode expression, + SyntaxToken closingBracket) + { + return new IndirectMemberAccessSyntaxNode( + openingBracket, + expression, + closingBracket); + } + + public CommandExpressionSyntaxNode CommandExpressionSyntax( + IdentifierNameSyntaxNode commandName, + SyntaxList arguments) + { + return new CommandExpressionSyntaxNode( + commandName, + arguments); + } + + public BaseClassInvokationSyntaxNode BaseClassInvokationSyntax( + ExpressionSyntaxNode methodName, + SyntaxToken atSign, + ExpressionSyntaxNode baseClassNameAndArguments) + { + return new BaseClassInvokationSyntaxNode( + methodName, + atSign, + baseClassNameAndArguments); + } + + public AttributeAssignmentSyntaxNode AttributeAssignmentSyntax( + SyntaxToken assignmentSign, + ExpressionSyntaxNode value) + { + return new AttributeAssignmentSyntaxNode( + assignmentSign, + value); + } + + public AttributeSyntaxNode AttributeSyntax( + IdentifierNameSyntaxNode name, + AttributeAssignmentSyntaxNode assignment) + { + return new AttributeSyntaxNode( + name, + assignment); + } + + public AttributeListSyntaxNode AttributeListSyntax( + SyntaxToken openingBracket, + SyntaxList nodes, + SyntaxToken closingBracket) + { + return new AttributeListSyntaxNode( + openingBracket, + nodes, + closingBracket); + } + + public MethodDefinitionSyntaxNode MethodDefinitionSyntax( + SyntaxToken functionKeyword, + FunctionOutputDescriptionSyntaxNode outputDescription, + CompoundNameSyntaxNode name, + FunctionInputDescriptionSyntaxNode inputDescription, + SyntaxList commas, + SyntaxList body, + SyntaxToken endKeyword) + { + return new MethodDefinitionSyntaxNode( + functionKeyword, + outputDescription, + name, + inputDescription, + commas, + body, + endKeyword); + } + + public AbstractMethodDeclarationSyntaxNode AbstractMethodDeclarationSyntax( + FunctionOutputDescriptionSyntaxNode outputDescription, + CompoundNameSyntaxNode name, + FunctionInputDescriptionSyntaxNode inputDescription) + { + return new AbstractMethodDeclarationSyntaxNode( + outputDescription, + name, + inputDescription); + } + + public MethodsListSyntaxNode MethodsListSyntax( + SyntaxToken methodsKeyword, + AttributeListSyntaxNode attributes, + SyntaxList methods, + SyntaxToken endKeyword) + { + return new MethodsListSyntaxNode( + methodsKeyword, + attributes, + methods, + endKeyword); + } + + public PropertiesListSyntaxNode PropertiesListSyntax( + SyntaxToken propertiesKeyword, + AttributeListSyntaxNode attributes, + SyntaxList properties, + SyntaxToken endKeyword) + { + return new PropertiesListSyntaxNode( + propertiesKeyword, + attributes, + properties, + endKeyword); + } + + public BaseClassListSyntaxNode BaseClassListSyntax( + SyntaxToken lessSign, + SyntaxList baseClasses) + { + return new BaseClassListSyntaxNode( + lessSign, + baseClasses); + } + + public ClassDeclarationSyntaxNode ClassDeclarationSyntax( + SyntaxToken classdefKeyword, + AttributeListSyntaxNode attributes, + IdentifierNameSyntaxNode className, + BaseClassListSyntaxNode baseClassList, + SyntaxList nodes, + SyntaxToken endKeyword) + { + return new ClassDeclarationSyntaxNode( + classdefKeyword, + attributes, + className, + baseClassList, + nodes, + endKeyword); + } + + public EnumerationItemValueSyntaxNode EnumerationItemValueSyntax( + SyntaxToken openingBracket, + SyntaxList values, + SyntaxToken closingBracket) + { + return new EnumerationItemValueSyntaxNode( + openingBracket, + values, + closingBracket); + } + + public EnumerationItemSyntaxNode EnumerationItemSyntax( + IdentifierNameSyntaxNode name, + EnumerationItemValueSyntaxNode values, + SyntaxList commas) + { + return new EnumerationItemSyntaxNode( + name, + values, + commas); + } + + public EnumerationListSyntaxNode EnumerationListSyntax( + SyntaxToken enumerationKeyword, + AttributeListSyntaxNode attributes, + SyntaxList items, + SyntaxToken endKeyword) + { + return new EnumerationListSyntaxNode( + enumerationKeyword, + attributes, + items, + endKeyword); + } + + public EventsListSyntaxNode EventsListSyntax( + SyntaxToken eventsKeyword, + AttributeListSyntaxNode attributes, + SyntaxList events, + SyntaxToken endKeyword) + { + return new EventsListSyntaxNode( + eventsKeyword, + attributes, + events, + endKeyword); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxFactory.cs b/Parser/Internal/SyntaxFactory.cs new file mode 100644 index 0000000..83a9d8b --- /dev/null +++ b/Parser/Internal/SyntaxFactory.cs @@ -0,0 +1,6 @@ +namespace Parser.Internal +{ + internal partial class SyntaxFactory + { + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxFacts.cs b/Parser/Internal/SyntaxFacts.cs new file mode 100644 index 0000000..0971672 --- /dev/null +++ b/Parser/Internal/SyntaxFacts.cs @@ -0,0 +1,276 @@ +using System; +using System.Collections.Generic; + +namespace Parser.Internal +{ + public static class SyntaxFacts + { + public static readonly HashSet Keywords; + + static SyntaxFacts() + { + Keywords = new HashSet + { + "for", "if", "function", "while", "case", "try", "catch", "end", + "switch", "classdef", "elseif", "persistent", "else" + }; + } + + public enum Precedence + { + // see https://mathworks.com/help/matlab/matlab_prog/operator-precedence.html + Expression = 0, + Assignment, + LogicalOr, + LogicalAnd, + BitwiseOr, + BitwiseAnd, + Relational, + Colon, + Additive, + Multiplicative, + Unary, + WeirdPower, + Power + } + + public static Precedence GetPrecedence(TokenKind kind) + { + switch (kind) + { + case TokenKind.Assignment: + return Precedence.Assignment; + case TokenKind.LogicalOr: + return Precedence.LogicalOr; + case TokenKind.LogicalAnd: + return Precedence.LogicalAnd; + case TokenKind.BitwiseOr: + return Precedence.BitwiseOr; + case TokenKind.BitwiseAnd: + return Precedence.BitwiseAnd; + case TokenKind.Less: + case TokenKind.LessOrEqual: + case TokenKind.Greater: + case TokenKind.GreaterOrEqual: + case TokenKind.Equality: + case TokenKind.Inequality: + return Precedence.Relational; + case TokenKind.Colon: + return Precedence.Colon; + case TokenKind.Plus: + case TokenKind.Minus: + return Precedence.Additive; + case TokenKind.Multiply: + case TokenKind.DotMultiply: + case TokenKind.Divide: + case TokenKind.DotDivide: + case TokenKind.Backslash: + case TokenKind.DotBackslash: + return Precedence.Multiplicative; + case TokenKind.Not: + return Precedence.Unary; + case TokenKind.Power: + case TokenKind.DotPower: + case TokenKind.Transpose: + case TokenKind.DotTranspose: + return Precedence.Power; + default: + return Precedence.Expression; + } + } + + public static bool IsDigit(char c) + { + return c >= '0' && c <= '9'; + } + + public static bool IsDigitOrDot(char c) + { + return c == '.' || (c >= '0' && c <= '9'); + } + + public static bool IsEolOrEof(char c) + { + return c == '\n' || c == '\r' || c == '\0'; + } + + public static bool IsWhitespace(char c) + { + return c == ' ' || c == '\t' || c == '\n'; + } + + public static bool IsOpeningToken(TokenKind tokenKind) + { + switch (tokenKind) + { + case TokenKind.OpeningBrace: + case TokenKind.OpeningBracket: + case TokenKind.OpeningSquareBracket: + return true; + default: + return false; + } + } + + public static bool IsClosingToken(TokenKind tokenKind) + { + switch (tokenKind) + { + case TokenKind.ClosingBrace: + case TokenKind.ClosingBracket: + case TokenKind.ClosingSquareBracket: + return true; + default: + return false; + } + } + + public static bool IsBracket(TokenKind tokenKind) + { + return IsOpeningToken(tokenKind) || IsClosingToken(tokenKind); + } + + public static TokenKind? OpeningFromClosing(TokenKind tokenKind) + { + switch (tokenKind) + { + case TokenKind.ClosingBrace: + return TokenKind.OpeningBrace; + case TokenKind.ClosingBracket: + return TokenKind.OpeningBracket; + case TokenKind.ClosingSquareBracket: + return TokenKind.OpeningSquareBracket; + default: + return null; + } + } + + private static readonly string[] StringFromKind = + { + null, // None = 0, + "", // EndOfFile = 1, + null, // Identifier = 2, + null, // NumberLiteral = 3, + null, // StringLiteral = 4, + null, // DoubleQuotedStringLiteral = 5, + null, // UnquotedStringLiteral = 6 + null, null, null, null, null, null, null, null, null, null, null, null, null, + "=", // Assignment = 20, + "==", // Equality = 21, + "~=", // Inequality = 22, + "&&", // LogicalAnd = 23, + "||", // LogicalOr = 24, + "&", // BitwiseAnd = 25, + "|", // BitwiseOr = 26, + "<", // Less = 27, + "<=", // LessOrEqual = 28, + ">", // Greater = 29, + ">=", // GreaterOrEqual = 30, + "~", // Not = 31, + "+", // Plus = 32, + "-", // Minus = 33, + "*", // Multiply = 34, + "/", // Divide = 35, + "^", // Power = 36, + "\\", // Backslash = 37, + "'", // Transpose = 38, + ".*", // DotMultiply = 39, + "./", // DotDivide = 40, + ".^", // DotPower = 41, + ".\\", // DotBackslash = 42, + ".'", // DotTranspose = 43, + "@", // At = 44, + ":", // Colon = 45, + "?", // QuestionMark = 46, + ",", // Comma = 47, + ";", // Semicolon = 48, + "{", // OpeningBrace = 49, + "}", // ClosingBrace = 50, + "[", // OpeningSquareBracket = 51, + "]", // ClosingSquareBracket = 52, + "(", // OpeningBracket = 53, + ")", // ClosingBracket = 54, + ".", // Dot = 55, + "...", // DotDotDot = 56, + + "+", // UnaryPlus = 57, + "-", // UnaryMinus = 58, + "~", // UnaryNot = 59, + "?", // UnaryQuestionMark = 60, + }; + + public static string GetText(TokenKind kind) + { + return StringFromKind[(int) kind]; + } + + public static bool IsUnaryOperator(TokenKind kind) + { + switch (kind) + { + case TokenKind.Plus: + case TokenKind.Minus: + case TokenKind.Not: + case TokenKind.QuestionMark: + return true; + default: + return false; + } + } + + public static bool IsBinaryOperator(TokenKind kind) + { + switch (kind) + { + case TokenKind.Assignment: + case TokenKind.LogicalOr: + case TokenKind.LogicalAnd: + case TokenKind.BitwiseOr: + case TokenKind.BitwiseAnd: + case TokenKind.Less: + case TokenKind.LessOrEqual: + case TokenKind.Greater: + case TokenKind.GreaterOrEqual: + case TokenKind.Equality: + case TokenKind.Inequality: + case TokenKind.Colon: + case TokenKind.Plus: + case TokenKind.Minus: + case TokenKind.Multiply: + case TokenKind.DotMultiply: + case TokenKind.Divide: + case TokenKind.DotDivide: + case TokenKind.Backslash: + case TokenKind.DotBackslash: + case TokenKind.Not: + case TokenKind.Power: + case TokenKind.DotPower: + return true; + default: + return false; + } + } + + public static bool IsLeftAssociative(TokenKind kind) + { + return true; // TODO: really? + } + + public static TokenKind ConvertToUnaryTokenKind(TokenKind kind) + { + switch (kind) + { + case TokenKind.Plus: + return TokenKind.UnaryPlus; + case TokenKind.Minus: + return TokenKind.UnaryMinus; + case TokenKind.Not: + return TokenKind.UnaryNot; + case TokenKind.QuestionMark: + return TokenKind.UnaryQuestionMark; + default: + throw new ArgumentException(nameof(kind)); + } + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxList.cs b/Parser/Internal/SyntaxList.cs new file mode 100644 index 0000000..25977e8 --- /dev/null +++ b/Parser/Internal/SyntaxList.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace Parser.Internal +{ + internal class SyntaxList : SyntaxNode + { + private readonly GreenNode[] _elements; + + protected SyntaxList(GreenNode[] elements) : base(TokenKind.List, elements.Length) + { + _elements = elements; + } + + public override GreenNode GetSlot(int i) + { + return _elements[i]; + } + + public static SyntaxList List(GreenNode[] elements) + { + return new SyntaxList(elements); + } + + public override bool IsList => true; + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.SyntaxNodeOrTokenList(parent, this); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxListBuilder.cs b/Parser/Internal/SyntaxListBuilder.cs new file mode 100644 index 0000000..15567ce --- /dev/null +++ b/Parser/Internal/SyntaxListBuilder.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Parser.Internal +{ + internal class SyntaxListBuilder + { + private readonly List _list; + + public SyntaxListBuilder() + { + _list = new List(); + } + + public void Add(GreenNode node) + { + _list.Add(node); + } + + public void AddRange(SyntaxList list) + { + for (var i = 0; i < list.Slots; i++) + { + var element = list.GetSlot(i); + _list.Add(element); + } + } + + public SyntaxList ToList() + { + return _list.Count == 0 ? null : SyntaxList.List(_list.ToArray()); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxListBuilder`1.cs b/Parser/Internal/SyntaxListBuilder`1.cs new file mode 100644 index 0000000..6f7edb8 --- /dev/null +++ b/Parser/Internal/SyntaxListBuilder`1.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Parser.Internal +{ + internal class SyntaxListBuilder where T : GreenNode + { + private readonly List _list; + + public SyntaxListBuilder() + { + _list = new List(); + } + + public void Add(T node) + { + _list.Add(node); + } + + public SyntaxList ToList() + { + return _list.Count == 0 ? null : SyntaxList.List(_list.ToArray()); + } + + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxList`1.cs b/Parser/Internal/SyntaxList`1.cs new file mode 100644 index 0000000..eda616c --- /dev/null +++ b/Parser/Internal/SyntaxList`1.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace Parser.Internal +{ + internal class SyntaxList : SyntaxNode where T : GreenNode + { + private readonly SyntaxList _list; + + protected SyntaxList(T[] list) : base(TokenKind.List, list.Length) + { + _list = SyntaxList.List(list); + } + + public override GreenNode GetSlot(int i) + { + return (T)_list.GetSlot(i); + } + + public static SyntaxList List(T[] elements) + { + return new SyntaxList(elements); + } + + public override bool IsList => true; + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.SyntaxNodeOrTokenList(parent, this); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxNode.Generated.cs b/Parser/Internal/SyntaxNode.Generated.cs new file mode 100644 index 0000000..980c310 --- /dev/null +++ b/Parser/Internal/SyntaxNode.Generated.cs @@ -0,0 +1,1652 @@ +namespace Parser.Internal +{ + internal class FileSyntaxNode : SyntaxNode + { + internal readonly SyntaxList _statementList; + internal readonly SyntaxToken _endOfFile; + + internal FileSyntaxNode( + SyntaxList statementList, + SyntaxToken endOfFile) : base(TokenKind.File, 2) + { + _statementList = statementList; + _endOfFile = endOfFile; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.FileSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _statementList; + case 1: return _endOfFile; + default: return null; + } + } + } + + internal class FunctionDeclarationSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _functionKeyword; + internal readonly FunctionOutputDescriptionSyntaxNode _outputDescription; + internal readonly SyntaxToken _name; + internal readonly FunctionInputDescriptionSyntaxNode _inputDescription; + internal readonly SyntaxList _commas; + internal readonly SyntaxList _body; + internal readonly SyntaxToken _endKeyword; + + internal FunctionDeclarationSyntaxNode( + SyntaxToken functionKeyword, + FunctionOutputDescriptionSyntaxNode outputDescription, + SyntaxToken name, + FunctionInputDescriptionSyntaxNode inputDescription, + SyntaxList commas, + SyntaxList body, + SyntaxToken endKeyword) : base(TokenKind.FunctionDeclaration, 7) + { + _functionKeyword = functionKeyword; + _outputDescription = outputDescription; + _name = name; + _inputDescription = inputDescription; + _commas = commas; + _body = body; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.FunctionDeclarationSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _functionKeyword; + case 1: return _outputDescription; + case 2: return _name; + case 3: return _inputDescription; + case 4: return _commas; + case 5: return _body; + case 6: return _endKeyword; + default: return null; + } + } + } + + internal class FunctionOutputDescriptionSyntaxNode : SyntaxNode + { + internal readonly SyntaxList _outputList; + internal readonly SyntaxToken _assignmentSign; + + internal FunctionOutputDescriptionSyntaxNode( + SyntaxList outputList, + SyntaxToken assignmentSign) : base(TokenKind.FunctionOutputDescription, 2) + { + _outputList = outputList; + _assignmentSign = assignmentSign; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.FunctionOutputDescriptionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _outputList; + case 1: return _assignmentSign; + default: return null; + } + } + } + + internal class FunctionInputDescriptionSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _openingBracket; + internal readonly SyntaxList _parameterList; + internal readonly SyntaxToken _closingBracket; + + internal FunctionInputDescriptionSyntaxNode( + SyntaxToken openingBracket, + SyntaxList parameterList, + SyntaxToken closingBracket) : base(TokenKind.FunctionInputDescription, 3) + { + _openingBracket = openingBracket; + _parameterList = parameterList; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.FunctionInputDescriptionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBracket; + case 1: return _parameterList; + case 2: return _closingBracket; + default: return null; + } + } + } + + internal class SwitchStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _switchKeyword; + internal readonly ExpressionSyntaxNode _switchExpression; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _cases; + internal readonly SyntaxToken _endKeyword; + + internal SwitchStatementSyntaxNode( + SyntaxToken switchKeyword, + ExpressionSyntaxNode switchExpression, + SyntaxList optionalCommas, + SyntaxList cases, + SyntaxToken endKeyword) : base(TokenKind.SwitchStatement, 5) + { + _switchKeyword = switchKeyword; + _switchExpression = switchExpression; + _optionalCommas = optionalCommas; + _cases = cases; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.SwitchStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _switchKeyword; + case 1: return _switchExpression; + case 2: return _optionalCommas; + case 3: return _cases; + case 4: return _endKeyword; + default: return null; + } + } + } + + internal class SwitchCaseSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _caseKeyword; + internal readonly ExpressionSyntaxNode _caseIdentifier; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _body; + + internal SwitchCaseSyntaxNode( + SyntaxToken caseKeyword, + ExpressionSyntaxNode caseIdentifier, + SyntaxList optionalCommas, + SyntaxList body) : base(TokenKind.SwitchCase, 4) + { + _caseKeyword = caseKeyword; + _caseIdentifier = caseIdentifier; + _optionalCommas = optionalCommas; + _body = body; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.SwitchCaseSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _caseKeyword; + case 1: return _caseIdentifier; + case 2: return _optionalCommas; + case 3: return _body; + default: return null; + } + } + } + + internal class WhileStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _whileKeyword; + internal readonly ExpressionSyntaxNode _condition; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _body; + internal readonly SyntaxToken _endKeyword; + + internal WhileStatementSyntaxNode( + SyntaxToken whileKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxToken endKeyword) : base(TokenKind.WhileStatement, 5) + { + _whileKeyword = whileKeyword; + _condition = condition; + _optionalCommas = optionalCommas; + _body = body; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.WhileStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _whileKeyword; + case 1: return _condition; + case 2: return _optionalCommas; + case 3: return _body; + case 4: return _endKeyword; + default: return null; + } + } + } + + internal class ElseifClause : SyntaxNode + { + internal readonly SyntaxToken _elseifKeyword; + internal readonly ExpressionSyntaxNode _condition; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _body; + + internal ElseifClause( + SyntaxToken elseifKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body) : base(TokenKind.ElseifClause, 4) + { + _elseifKeyword = elseifKeyword; + _condition = condition; + _optionalCommas = optionalCommas; + _body = body; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ElseifClause(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _elseifKeyword; + case 1: return _condition; + case 2: return _optionalCommas; + case 3: return _body; + default: return null; + } + } + } + + internal class ElseClause : SyntaxNode + { + internal readonly SyntaxToken _elseKeyword; + internal readonly SyntaxList _body; + + internal ElseClause( + SyntaxToken elseKeyword, + SyntaxList body) : base(TokenKind.ElseClause, 2) + { + _elseKeyword = elseKeyword; + _body = body; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ElseClause(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _elseKeyword; + case 1: return _body; + default: return null; + } + } + } + + internal class IfStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _ifKeyword; + internal readonly ExpressionSyntaxNode _condition; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _body; + internal readonly SyntaxList _elseifClauses; + internal readonly ElseClause _elseClause; + internal readonly SyntaxToken _endKeyword; + + internal IfStatementSyntaxNode( + SyntaxToken ifKeyword, + ExpressionSyntaxNode condition, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxList elseifClauses, + ElseClause elseClause, + SyntaxToken endKeyword) : base(TokenKind.IfStatement, 7) + { + _ifKeyword = ifKeyword; + _condition = condition; + _optionalCommas = optionalCommas; + _body = body; + _elseifClauses = elseifClauses; + _elseClause = elseClause; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.IfStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _ifKeyword; + case 1: return _condition; + case 2: return _optionalCommas; + case 3: return _body; + case 4: return _elseifClauses; + case 5: return _elseClause; + case 6: return _endKeyword; + default: return null; + } + } + } + + internal class ForStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _forKeyword; + internal readonly AssignmentExpressionSyntaxNode _assignment; + internal readonly SyntaxList _optionalCommas; + internal readonly SyntaxList _body; + internal readonly SyntaxToken _endKeyword; + + internal ForStatementSyntaxNode( + SyntaxToken forKeyword, + AssignmentExpressionSyntaxNode assignment, + SyntaxList optionalCommas, + SyntaxList body, + SyntaxToken endKeyword) : base(TokenKind.ForStatement, 5) + { + _forKeyword = forKeyword; + _assignment = assignment; + _optionalCommas = optionalCommas; + _body = body; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ForStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _forKeyword; + case 1: return _assignment; + case 2: return _optionalCommas; + case 3: return _body; + case 4: return _endKeyword; + default: return null; + } + } + } + + internal class AssignmentExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _lhs; + internal readonly SyntaxToken _assignmentSign; + internal readonly ExpressionSyntaxNode _rhs; + + internal AssignmentExpressionSyntaxNode( + ExpressionSyntaxNode lhs, + SyntaxToken assignmentSign, + ExpressionSyntaxNode rhs) : base(TokenKind.AssignmentExpression, 3) + { + _lhs = lhs; + _assignmentSign = assignmentSign; + _rhs = rhs; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.AssignmentExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _lhs; + case 1: return _assignmentSign; + case 2: return _rhs; + default: return null; + } + } + } + + internal class CatchClauseSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _catchKeyword; + internal readonly SyntaxList _catchBody; + + internal CatchClauseSyntaxNode( + SyntaxToken catchKeyword, + SyntaxList catchBody) : base(TokenKind.CatchClause, 2) + { + _catchKeyword = catchKeyword; + _catchBody = catchBody; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.CatchClauseSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _catchKeyword; + case 1: return _catchBody; + default: return null; + } + } + } + + internal class TryCatchStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _tryKeyword; + internal readonly SyntaxList _tryBody; + internal readonly CatchClauseSyntaxNode _catchClause; + internal readonly SyntaxToken _endKeyword; + + internal TryCatchStatementSyntaxNode( + SyntaxToken tryKeyword, + SyntaxList tryBody, + CatchClauseSyntaxNode catchClause, + SyntaxToken endKeyword) : base(TokenKind.TryCatchStatement, 4) + { + _tryKeyword = tryKeyword; + _tryBody = tryBody; + _catchClause = catchClause; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.TryCatchStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _tryKeyword; + case 1: return _tryBody; + case 2: return _catchClause; + case 3: return _endKeyword; + default: return null; + } + } + } + + internal class ExpressionStatementSyntaxNode : StatementSyntaxNode + { + internal readonly ExpressionSyntaxNode _expression; + + internal ExpressionStatementSyntaxNode( + ExpressionSyntaxNode expression) : base(TokenKind.ExpressionStatement, 1) + { + _expression = expression; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ExpressionStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _expression; + default: return null; + } + } + } + + internal class EmptyStatementSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _semicolon; + + internal EmptyStatementSyntaxNode( + SyntaxToken semicolon) : base(TokenKind.EmptyStatement, 1) + { + _semicolon = semicolon; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EmptyStatementSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _semicolon; + default: return null; + } + } + } + + internal class EmptyExpressionSyntaxNode : ExpressionSyntaxNode + { + + internal EmptyExpressionSyntaxNode() : base(TokenKind.EmptyExpression, 0) + { + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EmptyExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + default: return null; + } + } + } + + internal class UnaryPrefixOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _operation; + internal readonly ExpressionSyntaxNode _operand; + + internal UnaryPrefixOperationExpressionSyntaxNode( + SyntaxToken operation, + ExpressionSyntaxNode operand) : base(TokenKind.UnaryPrefixOperationExpression, 2) + { + _operation = operation; + _operand = operand; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.UnaryPrefixOperationExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _operation; + case 1: return _operand; + default: return null; + } + } + } + + internal class CompoundNameSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxList _nodes; + + internal CompoundNameSyntaxNode( + SyntaxList nodes) : base(TokenKind.CompoundName, 1) + { + _nodes = nodes; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.CompoundNameSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _nodes; + default: return null; + } + } + } + + internal class NamedFunctionHandleSyntaxNode : FunctionHandleSyntaxNode + { + internal readonly SyntaxToken _atSign; + internal readonly CompoundNameSyntaxNode _functionName; + + internal NamedFunctionHandleSyntaxNode( + SyntaxToken atSign, + CompoundNameSyntaxNode functionName) : base(TokenKind.NamedFunctionHandle, 2) + { + _atSign = atSign; + _functionName = functionName; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.NamedFunctionHandleSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _atSign; + case 1: return _functionName; + default: return null; + } + } + } + + internal class LambdaSyntaxNode : FunctionHandleSyntaxNode + { + internal readonly SyntaxToken _atSign; + internal readonly FunctionInputDescriptionSyntaxNode _input; + internal readonly ExpressionSyntaxNode _body; + + internal LambdaSyntaxNode( + SyntaxToken atSign, + FunctionInputDescriptionSyntaxNode input, + ExpressionSyntaxNode body) : base(TokenKind.Lambda, 3) + { + _atSign = atSign; + _input = input; + _body = body; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.LambdaSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _atSign; + case 1: return _input; + case 2: return _body; + default: return null; + } + } + } + + internal class BinaryOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _lhs; + internal readonly SyntaxToken _operation; + internal readonly ExpressionSyntaxNode _rhs; + + internal BinaryOperationExpressionSyntaxNode( + ExpressionSyntaxNode lhs, + SyntaxToken operation, + ExpressionSyntaxNode rhs) : base(TokenKind.BinaryOperation, 3) + { + _lhs = lhs; + _operation = operation; + _rhs = rhs; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.BinaryOperationExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _lhs; + case 1: return _operation; + case 2: return _rhs; + default: return null; + } + } + } + + internal class IdentifierNameSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _name; + + internal IdentifierNameSyntaxNode( + SyntaxToken name) : base(TokenKind.IdentifierName, 1) + { + _name = name; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.IdentifierNameSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _name; + default: return null; + } + } + } + + internal class NumberLiteralSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _number; + + internal NumberLiteralSyntaxNode( + SyntaxToken number) : base(TokenKind.NumberLiteralExpression, 1) + { + _number = number; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.NumberLiteralSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _number; + default: return null; + } + } + } + + internal class StringLiteralSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _stringToken; + + internal StringLiteralSyntaxNode( + SyntaxToken stringToken) : base(TokenKind.StringLiteralExpression, 1) + { + _stringToken = stringToken; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.StringLiteralSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _stringToken; + default: return null; + } + } + } + + internal class DoubleQuotedStringLiteralSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _stringToken; + + internal DoubleQuotedStringLiteralSyntaxNode( + SyntaxToken stringToken) : base(TokenKind.DoubleQuotedStringLiteralExpression, 1) + { + _stringToken = stringToken; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.DoubleQuotedStringLiteralSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _stringToken; + default: return null; + } + } + } + + internal class UnquotedStringLiteralSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _stringToken; + + internal UnquotedStringLiteralSyntaxNode( + SyntaxToken stringToken) : base(TokenKind.UnquotedStringLiteralExpression, 1) + { + _stringToken = stringToken; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.UnquotedStringLiteralSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _stringToken; + default: return null; + } + } + } + + internal class ArrayLiteralExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _openingSquareBracket; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _closingSquareBracket; + + internal ArrayLiteralExpressionSyntaxNode( + SyntaxToken openingSquareBracket, + SyntaxList nodes, + SyntaxToken closingSquareBracket) : base(TokenKind.ArrayLiteralExpression, 3) + { + _openingSquareBracket = openingSquareBracket; + _nodes = nodes; + _closingSquareBracket = closingSquareBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ArrayLiteralExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingSquareBracket; + case 1: return _nodes; + case 2: return _closingSquareBracket; + default: return null; + } + } + } + + internal class CellArrayLiteralExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _openingBrace; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _closingBrace; + + internal CellArrayLiteralExpressionSyntaxNode( + SyntaxToken openingBrace, + SyntaxList nodes, + SyntaxToken closingBrace) : base(TokenKind.CellArrayLiteralExpression, 3) + { + _openingBrace = openingBrace; + _nodes = nodes; + _closingBrace = closingBrace; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.CellArrayLiteralExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBrace; + case 1: return _nodes; + case 2: return _closingBrace; + default: return null; + } + } + } + + internal class ParenthesizedExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _openingBracket; + internal readonly ExpressionSyntaxNode _expression; + internal readonly SyntaxToken _closingBracket; + + internal ParenthesizedExpressionSyntaxNode( + SyntaxToken openingBracket, + ExpressionSyntaxNode expression, + SyntaxToken closingBracket) : base(TokenKind.ParenthesizedExpression, 3) + { + _openingBracket = openingBracket; + _expression = expression; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ParenthesizedExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBracket; + case 1: return _expression; + case 2: return _closingBracket; + default: return null; + } + } + } + + internal class CellArrayElementAccessExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _expression; + internal readonly SyntaxToken _openingBrace; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _closingBrace; + + internal CellArrayElementAccessExpressionSyntaxNode( + ExpressionSyntaxNode expression, + SyntaxToken openingBrace, + SyntaxList nodes, + SyntaxToken closingBrace) : base(TokenKind.CellArrayElementAccess, 4) + { + _expression = expression; + _openingBrace = openingBrace; + _nodes = nodes; + _closingBrace = closingBrace; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.CellArrayElementAccessExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _expression; + case 1: return _openingBrace; + case 2: return _nodes; + case 3: return _closingBrace; + default: return null; + } + } + } + + internal class FunctionCallExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _functionName; + internal readonly SyntaxToken _openingBracket; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _closingBracket; + + internal FunctionCallExpressionSyntaxNode( + ExpressionSyntaxNode functionName, + SyntaxToken openingBracket, + SyntaxList nodes, + SyntaxToken closingBracket) : base(TokenKind.FunctionCall, 4) + { + _functionName = functionName; + _openingBracket = openingBracket; + _nodes = nodes; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.FunctionCallExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _functionName; + case 1: return _openingBracket; + case 2: return _nodes; + case 3: return _closingBracket; + default: return null; + } + } + } + + internal class MemberAccessSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxNode _leftOperand; + internal readonly SyntaxToken _dot; + internal readonly SyntaxNode _rightOperand; + + internal MemberAccessSyntaxNode( + SyntaxNode leftOperand, + SyntaxToken dot, + SyntaxNode rightOperand) : base(TokenKind.MemberAccess, 3) + { + _leftOperand = leftOperand; + _dot = dot; + _rightOperand = rightOperand; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.MemberAccessSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _leftOperand; + case 1: return _dot; + case 2: return _rightOperand; + default: return null; + } + } + } + + internal class UnaryPostixOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _operand; + internal readonly SyntaxToken _operation; + + internal UnaryPostixOperationExpressionSyntaxNode( + ExpressionSyntaxNode operand, + SyntaxToken operation) : base(TokenKind.UnaryPostfixOperationExpression, 2) + { + _operand = operand; + _operation = operation; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.UnaryPostixOperationExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _operand; + case 1: return _operation; + default: return null; + } + } + } + + internal class IndirectMemberAccessSyntaxNode : ExpressionSyntaxNode + { + internal readonly SyntaxToken _openingBracket; + internal readonly ExpressionSyntaxNode _expression; + internal readonly SyntaxToken _closingBracket; + + internal IndirectMemberAccessSyntaxNode( + SyntaxToken openingBracket, + ExpressionSyntaxNode expression, + SyntaxToken closingBracket) : base(TokenKind.IndirectMemberAccess, 3) + { + _openingBracket = openingBracket; + _expression = expression; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.IndirectMemberAccessSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBracket; + case 1: return _expression; + case 2: return _closingBracket; + default: return null; + } + } + } + + internal class CommandExpressionSyntaxNode : ExpressionSyntaxNode + { + internal readonly IdentifierNameSyntaxNode _commandName; + internal readonly SyntaxList _arguments; + + internal CommandExpressionSyntaxNode( + IdentifierNameSyntaxNode commandName, + SyntaxList arguments) : base(TokenKind.Command, 2) + { + _commandName = commandName; + _arguments = arguments; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.CommandExpressionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _commandName; + case 1: return _arguments; + default: return null; + } + } + } + + internal class BaseClassInvokationSyntaxNode : ExpressionSyntaxNode + { + internal readonly ExpressionSyntaxNode _methodName; + internal readonly SyntaxToken _atSign; + internal readonly ExpressionSyntaxNode _baseClassNameAndArguments; + + internal BaseClassInvokationSyntaxNode( + ExpressionSyntaxNode methodName, + SyntaxToken atSign, + ExpressionSyntaxNode baseClassNameAndArguments) : base(TokenKind.ClassInvokation, 3) + { + _methodName = methodName; + _atSign = atSign; + _baseClassNameAndArguments = baseClassNameAndArguments; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.BaseClassInvokationSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _methodName; + case 1: return _atSign; + case 2: return _baseClassNameAndArguments; + default: return null; + } + } + } + + internal class AttributeAssignmentSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _assignmentSign; + internal readonly ExpressionSyntaxNode _value; + + internal AttributeAssignmentSyntaxNode( + SyntaxToken assignmentSign, + ExpressionSyntaxNode value) : base(TokenKind.AttributeAssignment, 2) + { + _assignmentSign = assignmentSign; + _value = value; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.AttributeAssignmentSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _assignmentSign; + case 1: return _value; + default: return null; + } + } + } + + internal class AttributeSyntaxNode : SyntaxNode + { + internal readonly IdentifierNameSyntaxNode _name; + internal readonly AttributeAssignmentSyntaxNode _assignment; + + internal AttributeSyntaxNode( + IdentifierNameSyntaxNode name, + AttributeAssignmentSyntaxNode assignment) : base(TokenKind.Attribute, 2) + { + _name = name; + _assignment = assignment; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.AttributeSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _name; + case 1: return _assignment; + default: return null; + } + } + } + + internal class AttributeListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _openingBracket; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _closingBracket; + + internal AttributeListSyntaxNode( + SyntaxToken openingBracket, + SyntaxList nodes, + SyntaxToken closingBracket) : base(TokenKind.AttributeList, 3) + { + _openingBracket = openingBracket; + _nodes = nodes; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.AttributeListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBracket; + case 1: return _nodes; + case 2: return _closingBracket; + default: return null; + } + } + } + + internal class MethodDefinitionSyntaxNode : MethodDeclarationSyntaxNode + { + internal readonly SyntaxToken _functionKeyword; + internal readonly FunctionOutputDescriptionSyntaxNode _outputDescription; + internal readonly CompoundNameSyntaxNode _name; + internal readonly FunctionInputDescriptionSyntaxNode _inputDescription; + internal readonly SyntaxList _commas; + internal readonly SyntaxList _body; + internal readonly SyntaxToken _endKeyword; + + internal MethodDefinitionSyntaxNode( + SyntaxToken functionKeyword, + FunctionOutputDescriptionSyntaxNode outputDescription, + CompoundNameSyntaxNode name, + FunctionInputDescriptionSyntaxNode inputDescription, + SyntaxList commas, + SyntaxList body, + SyntaxToken endKeyword) : base(TokenKind.MethodDefinition, 7) + { + _functionKeyword = functionKeyword; + _outputDescription = outputDescription; + _name = name; + _inputDescription = inputDescription; + _commas = commas; + _body = body; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.MethodDefinitionSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _functionKeyword; + case 1: return _outputDescription; + case 2: return _name; + case 3: return _inputDescription; + case 4: return _commas; + case 5: return _body; + case 6: return _endKeyword; + default: return null; + } + } + } + + internal class AbstractMethodDeclarationSyntaxNode : MethodDeclarationSyntaxNode + { + internal readonly FunctionOutputDescriptionSyntaxNode _outputDescription; + internal readonly CompoundNameSyntaxNode _name; + internal readonly FunctionInputDescriptionSyntaxNode _inputDescription; + + internal AbstractMethodDeclarationSyntaxNode( + FunctionOutputDescriptionSyntaxNode outputDescription, + CompoundNameSyntaxNode name, + FunctionInputDescriptionSyntaxNode inputDescription) : base(TokenKind.AbstractMethodDeclaration, 3) + { + _outputDescription = outputDescription; + _name = name; + _inputDescription = inputDescription; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.AbstractMethodDeclarationSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _outputDescription; + case 1: return _name; + case 2: return _inputDescription; + default: return null; + } + } + } + + internal class MethodsListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _methodsKeyword; + internal readonly AttributeListSyntaxNode _attributes; + internal readonly SyntaxList _methods; + internal readonly SyntaxToken _endKeyword; + + internal MethodsListSyntaxNode( + SyntaxToken methodsKeyword, + AttributeListSyntaxNode attributes, + SyntaxList methods, + SyntaxToken endKeyword) : base(TokenKind.MethodsList, 4) + { + _methodsKeyword = methodsKeyword; + _attributes = attributes; + _methods = methods; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.MethodsListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _methodsKeyword; + case 1: return _attributes; + case 2: return _methods; + case 3: return _endKeyword; + default: return null; + } + } + } + + internal class PropertiesListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _propertiesKeyword; + internal readonly AttributeListSyntaxNode _attributes; + internal readonly SyntaxList _properties; + internal readonly SyntaxToken _endKeyword; + + internal PropertiesListSyntaxNode( + SyntaxToken propertiesKeyword, + AttributeListSyntaxNode attributes, + SyntaxList properties, + SyntaxToken endKeyword) : base(TokenKind.PropertiesList, 4) + { + _propertiesKeyword = propertiesKeyword; + _attributes = attributes; + _properties = properties; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.PropertiesListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _propertiesKeyword; + case 1: return _attributes; + case 2: return _properties; + case 3: return _endKeyword; + default: return null; + } + } + } + + internal class BaseClassListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _lessSign; + internal readonly SyntaxList _baseClasses; + + internal BaseClassListSyntaxNode( + SyntaxToken lessSign, + SyntaxList baseClasses) : base(TokenKind.BaseClassList, 2) + { + _lessSign = lessSign; + _baseClasses = baseClasses; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.BaseClassListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _lessSign; + case 1: return _baseClasses; + default: return null; + } + } + } + + internal class ClassDeclarationSyntaxNode : StatementSyntaxNode + { + internal readonly SyntaxToken _classdefKeyword; + internal readonly AttributeListSyntaxNode _attributes; + internal readonly IdentifierNameSyntaxNode _className; + internal readonly BaseClassListSyntaxNode _baseClassList; + internal readonly SyntaxList _nodes; + internal readonly SyntaxToken _endKeyword; + + internal ClassDeclarationSyntaxNode( + SyntaxToken classdefKeyword, + AttributeListSyntaxNode attributes, + IdentifierNameSyntaxNode className, + BaseClassListSyntaxNode baseClassList, + SyntaxList nodes, + SyntaxToken endKeyword) : base(TokenKind.ClassDeclaration, 6) + { + _classdefKeyword = classdefKeyword; + _attributes = attributes; + _className = className; + _baseClassList = baseClassList; + _nodes = nodes; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.ClassDeclarationSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _classdefKeyword; + case 1: return _attributes; + case 2: return _className; + case 3: return _baseClassList; + case 4: return _nodes; + case 5: return _endKeyword; + default: return null; + } + } + } + + internal class EnumerationItemValueSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _openingBracket; + internal readonly SyntaxList _values; + internal readonly SyntaxToken _closingBracket; + + internal EnumerationItemValueSyntaxNode( + SyntaxToken openingBracket, + SyntaxList values, + SyntaxToken closingBracket) : base(TokenKind.EnumerationItemValue, 3) + { + _openingBracket = openingBracket; + _values = values; + _closingBracket = closingBracket; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EnumerationItemValueSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _openingBracket; + case 1: return _values; + case 2: return _closingBracket; + default: return null; + } + } + } + + internal class EnumerationItemSyntaxNode : SyntaxNode + { + internal readonly IdentifierNameSyntaxNode _name; + internal readonly EnumerationItemValueSyntaxNode _values; + internal readonly SyntaxList _commas; + + internal EnumerationItemSyntaxNode( + IdentifierNameSyntaxNode name, + EnumerationItemValueSyntaxNode values, + SyntaxList commas) : base(TokenKind.EnumerationItem, 3) + { + _name = name; + _values = values; + _commas = commas; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EnumerationItemSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _name; + case 1: return _values; + case 2: return _commas; + default: return null; + } + } + } + + internal class EnumerationListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _enumerationKeyword; + internal readonly AttributeListSyntaxNode _attributes; + internal readonly SyntaxList _items; + internal readonly SyntaxToken _endKeyword; + + internal EnumerationListSyntaxNode( + SyntaxToken enumerationKeyword, + AttributeListSyntaxNode attributes, + SyntaxList items, + SyntaxToken endKeyword) : base(TokenKind.EnumerationList, 4) + { + _enumerationKeyword = enumerationKeyword; + _attributes = attributes; + _items = items; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EnumerationListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _enumerationKeyword; + case 1: return _attributes; + case 2: return _items; + case 3: return _endKeyword; + default: return null; + } + } + } + + internal class EventsListSyntaxNode : SyntaxNode + { + internal readonly SyntaxToken _eventsKeyword; + internal readonly AttributeListSyntaxNode _attributes; + internal readonly SyntaxList _events; + internal readonly SyntaxToken _endKeyword; + + internal EventsListSyntaxNode( + SyntaxToken eventsKeyword, + AttributeListSyntaxNode attributes, + SyntaxList events, + SyntaxToken endKeyword) : base(TokenKind.EventsList, 4) + { + _eventsKeyword = eventsKeyword; + _attributes = attributes; + _events = events; + _endKeyword = endKeyword; + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + return new Parser.EventsListSyntaxNode(parent, this); + } + + public override GreenNode GetSlot(int i) + { + switch (i) + { + case 0: return _eventsKeyword; + case 1: return _attributes; + case 2: return _events; + case 3: return _endKeyword; + default: return null; + } + } + } +} diff --git a/Parser/Internal/SyntaxNode.cs b/Parser/Internal/SyntaxNode.cs new file mode 100644 index 0000000..23608e0 --- /dev/null +++ b/Parser/Internal/SyntaxNode.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Parser.Internal +{ + internal abstract class SyntaxNode : GreenNode + { + protected SyntaxNode(TokenKind kind, int slots) : base(kind, slots) + { + } + + public IEnumerable DescendantTokens => CalculateChildTokens(); + + private IEnumerable CalculateChildTokens() + { + for (var i = 0; i < Slots; i++) + { + var slot = GetSlot(i); + switch (slot) + { + case null: + continue; + case SyntaxToken token: + yield return token; + break; + case SyntaxNode node: + foreach (var t in node.DescendantTokens) + { + yield return t; + } + + break; + } + } + } + + protected virtual string CollectFullText() + { + var builder = new StringBuilder(); + foreach (var token in DescendantTokens) + { + builder.Append(token.FullText); + } + + return builder.ToString(); + } + + public override string FullText => CollectFullText(); + + public override IReadOnlyList LeadingTriviaCore => throw new NotImplementedException(); + public override IReadOnlyList TrailingTriviaCore => throw new NotImplementedException(); + } + + internal abstract class StatementSyntaxNode : SyntaxNode + { + protected StatementSyntaxNode(TokenKind kind, int slots) : base(kind, slots + 1) + { + } + } + + internal abstract class ExpressionSyntaxNode : SyntaxNode + { + protected ExpressionSyntaxNode(TokenKind kind, int slots) : base(kind, slots) + { + } + } + + internal abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode + { + protected FunctionHandleSyntaxNode(TokenKind kind, int slots) : base(kind, slots) + { + } + } + + internal abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode + { + protected MethodDeclarationSyntaxNode(TokenKind kind, int slots) : base(kind, slots) + { + } + } +} diff --git a/Parser/Internal/SyntaxToken.cs b/Parser/Internal/SyntaxToken.cs new file mode 100644 index 0000000..b82a020 --- /dev/null +++ b/Parser/Internal/SyntaxToken.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Parser.Internal +{ + internal abstract class SyntaxToken : GreenNode + { + internal class SyntaxTokenWithTrivia : SyntaxToken + { + private readonly string _text; + + public SyntaxTokenWithTrivia( + TokenKind kind, + string text, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) : base(kind) + { + _text = text; + LeadingTriviaCore = leadingTrivia; + TrailingTriviaCore = trailingTrivia; + } + + public SyntaxTokenWithTrivia( + TokenKind kind, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) : base(kind) + { + _text = base.Text; + LeadingTriviaCore = leadingTrivia; + TrailingTriviaCore = trailingTrivia; + } + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + if (leading) + { + foreach (var trivia in LeadingTrivia) + { + writer.Write(trivia.Text); + } + } + base.WriteTokenTo(writer, leading, trailing); + if (trailing) + { + foreach (var trivia in TrailingTrivia) + { + writer.Write(trivia.Text); + } + } + } + + public override IReadOnlyList LeadingTriviaCore { get; } + + public override IReadOnlyList TrailingTriviaCore { get; } + } + + internal class SyntaxTokenWithValue : SyntaxToken + { + protected readonly string _text; + private readonly T _value; + + public SyntaxTokenWithValue( + TokenKind kind, + string text, + T value) : base(kind) + { + _text = text; + _value = value; + } + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + writer.Write(_text); + } + public T Value => _value; + } + + internal class SyntaxTokenWithValueAndTrivia : SyntaxTokenWithValue + { + public SyntaxTokenWithValueAndTrivia( + TokenKind kind, + string text, + T value, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) : base(kind, text, value) + { + LeadingTriviaCore = leadingTrivia; + TrailingTriviaCore = trailingTrivia; + } + + public override IReadOnlyList LeadingTriviaCore { get; } + + public override IReadOnlyList TrailingTriviaCore { get; } + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + if (leading) + { + foreach (var trivia in LeadingTrivia) + { + writer.Write(trivia.Text); + } + } + base.WriteTokenTo(writer, leading, trailing); + if (trailing) + { + foreach (var trivia in TrailingTrivia) + { + writer.Write(trivia.Text); + } + } + } + } + + internal class SyntaxIdentifier : SyntaxToken + { + private readonly string _text; + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + writer.Write(_text); + } + + public SyntaxIdentifier( + string text + ) : base(TokenKind.Identifier) + { + _text = text; + } + } + + internal class SyntaxIdentifierWithTrivia : SyntaxIdentifier + { + private readonly IReadOnlyList _leadingTrivia; + private readonly IReadOnlyList _trailingTrivia; + + public override IReadOnlyList LeadingTriviaCore => _leadingTrivia; + public override IReadOnlyList TrailingTriviaCore => _trailingTrivia; + + public SyntaxIdentifierWithTrivia( + string text, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia + ) : base(text) + { + _leadingTrivia = leadingTrivia; + _trailingTrivia = trailingTrivia; + } + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + if (leading) + { + foreach (var trivia in LeadingTrivia) + { + writer.Write(trivia.Text); + } + } + base.WriteTokenTo(writer, leading, trailing); + if (trailing) + { + foreach (var trivia in TrailingTrivia) + { + writer.Write(trivia.Text); + } + } + } + + public override bool IsToken => true; + public override bool IsNode => false; + } + + internal class MissingTokenWithTrivia : SyntaxTokenWithTrivia + { + public MissingTokenWithTrivia( + TokenKind kind, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia + ) : base(kind, leadingTrivia, trailingTrivia) + { + _isMissing = true; + } + + public override string Text => ""; + } + + protected SyntaxToken(TokenKind kind) : base(kind, 0) + { + } + + public virtual int Width => Text.Length; + + public override IReadOnlyList LeadingTriviaCore => new List(); + public override IReadOnlyList TrailingTriviaCore => new List(); + + public override GreenNode GetSlot(int i) + { + throw new System.InvalidOperationException(); + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + throw new InvalidOperationException(); + } + + public override bool IsToken => true; + public override bool IsNode => false; + + public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing) + { + writer.Write(SyntaxFacts.GetText(Kind)); + } + } +} \ No newline at end of file diff --git a/Parser/Internal/SyntaxTrivia.cs b/Parser/Internal/SyntaxTrivia.cs new file mode 100644 index 0000000..e0a82bb --- /dev/null +++ b/Parser/Internal/SyntaxTrivia.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; + +namespace Parser.Internal +{ + internal class SyntaxTrivia : GreenNode + { + private readonly string _text; + + public SyntaxTrivia(TokenKind kind, string text) : base(kind, 0) + { + _text = text; + } + + public override string Text => _text; + public int Width => _text.Length; + + public override GreenNode GetSlot(int i) + { + throw new System.NotImplementedException(); + } + + internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent) + { + throw new InvalidOperationException(); + } + + public override bool IsTrivia => true; + public override bool IsNode => false; + + public override void WriteTriviaTo(TextWriter writer) + { + writer.Write(_text); + } + + public override IReadOnlyList LeadingTriviaCore => new List(); + public override IReadOnlyList TrailingTriviaCore => new List(); + } +} \ No newline at end of file diff --git a/Parser/Internal/TokenFactory.cs b/Parser/Internal/TokenFactory.cs new file mode 100644 index 0000000..9ff1d70 --- /dev/null +++ b/Parser/Internal/TokenFactory.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace Parser.Internal +{ + internal static class TokenFactory + { + public static SyntaxTrivia CreateTrivia(TokenKind kind, string text) + { + return new SyntaxTrivia(kind, text); + } + + public static SyntaxToken CreateTokenWithTrivia( + TokenKind kind, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) + { + return new SyntaxToken.SyntaxTokenWithTrivia(kind, leadingTrivia, trailingTrivia); + } + + public static SyntaxToken CreateIdentifier( + string text, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) + { + return new SyntaxToken.SyntaxIdentifierWithTrivia(text, leadingTrivia, trailingTrivia); + } + + public static SyntaxToken CreateTokenWithValueAndTrivia( + TokenKind kind, + string text, + T value, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) + { + return new SyntaxToken.SyntaxTokenWithValueAndTrivia(kind, text, value, leadingTrivia, trailingTrivia); + } + + public static SyntaxToken CreateUnquotedStringLiteral( + string text, + string value, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) + { + return new SyntaxToken.SyntaxTokenWithValueAndTrivia( + TokenKind.UnquotedStringLiteral, + text, + value, + leadingTrivia, + trailingTrivia); + } + + public static SyntaxToken CreateMissing( + TokenKind kind, + IReadOnlyList leadingTrivia, + IReadOnlyList trailingTrivia) + { + return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia, trailingTrivia); + } + } +} \ No newline at end of file diff --git a/Parser/MParser.cs b/Parser/MParser.cs index 205d4a5..67d4ece 100644 --- a/Parser/MParser.cs +++ b/Parser/MParser.cs @@ -1,939 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Lexer; - -namespace Parser +namespace Parser { public class MParser { - public enum Precedence - { - // see https://mathworks.com/help/matlab/matlab_prog/operator-precedence.html - Expression = 0, - Assignment, - LogicalOr, - LogicalAnd, - BitwiseOr, - BitwiseAnd, - Relational, - Colon, - Additive, - Multiplicative, - Unary, - WeirdPower, - Power - } - - private static Precedence GetPrecedence(TokenKind kind) - { - switch (kind) - { - case TokenKind.Assignment: - return Precedence.Assignment; - case TokenKind.LogicalOr: - return Precedence.LogicalOr; - case TokenKind.LogicalAnd: - return Precedence.LogicalAnd; - case TokenKind.BitwiseOr: - return Precedence.BitwiseOr; - case TokenKind.BitwiseAnd: - return Precedence.BitwiseAnd; - case TokenKind.Less: - case TokenKind.LessOrEqual: - case TokenKind.Greater: - case TokenKind.GreaterOrEqual: - case TokenKind.Equality: - case TokenKind.Inequality: - return Precedence.Relational; - case TokenKind.Colon: - return Precedence.Colon; - case TokenKind.Plus: - case TokenKind.Minus: - return Precedence.Additive; - case TokenKind.Multiply: - case TokenKind.DotMultiply: - case TokenKind.Divide: - case TokenKind.DotDivide: - case TokenKind.Backslash: - case TokenKind.DotBackslash: - return Precedence.Multiplicative; - case TokenKind.Not: - return Precedence.Unary; - case TokenKind.Power: - case TokenKind.DotPower: - case TokenKind.Transpose: - case TokenKind.DotTranspose: - return Precedence.Power; - default: - return Precedence.Expression; - } - } + private readonly ITextWindow _window; - private List Tokens { get; } - private int _index; - private Token CurrentToken => Tokens[_index]; - private Token PeekToken(int n) => Tokens[_index + n]; - private SyntaxFactory Factory { get; } - - public MParser(List tokens) + public MParser(ITextWindow window) { - Tokens = tokens; - _index = 0; - Factory = new SyntaxFactory(); + _window = window; } - private Token EatToken() + public FileSyntaxNode Parse() { - var token = Tokens[_index]; - //Console.WriteLine($"{token} at {token.PureToken.Position}"); - _index++; - return token; - } - - private Token EatToken(TokenKind kind) - { - var token = Tokens[_index]; - //Console.WriteLine($"{token} at {token.PureToken.Position}"); - if (token.Kind != kind) - { - throw new ParsingException($"Unexpected token \"{token.PureToken}\" instead of {kind} at {token.PureToken.Position}."); - } - _index++; - return token; - } - - private Token EatIdentifier(string s) - { - var token = Tokens[_index]; - //Console.WriteLine($"{token} at {token.PureToken.Position}"); - if (token.PureToken.Kind != TokenKind.Identifier) - { - throw new ParsingException($"Unexpected token \"{token.PureToken}\" instead of identifier \"{s}\" at {token.PureToken.Position}."); - } - - if (token.PureToken.LiteralText != s) - { - throw new ParsingException($"Unexpected identifier \"{token.PureToken.LiteralText}\" instead of \"{s}\" at {token.PureToken.Position}."); - } - _index++; - return token; - } - - private void EatAll() - { - _index = Tokens.Count - 1; - } - - private List ParseFunctionOutputList() - { - var outputs = new List(); - while (CurrentToken.Kind != TokenKind.ClosingSquareBracket) - { - if (outputs.Count > 0 && CurrentToken.Kind == TokenKind.Comma) - { - outputs.Add(EatToken()); - } - outputs.Add(EatToken(TokenKind.Identifier)); - } - - return outputs.Select(token => new TokenNode(token) as SyntaxNode).ToList(); - } - - private FunctionOutputDescriptionNode ParseFunctionOutputDescription() - { - if (CurrentToken.Kind == TokenKind.Identifier) - { - if (PeekToken(1).Kind == TokenKind.Assignment) - { - var identifier = EatToken(); - var assignmentSign = EatToken(TokenKind.Assignment); - return Factory.FunctionOutputDescription( - new List { Factory.Token(identifier) }, - Factory.Token(assignmentSign) - ); - } - - return null; - } else if (CurrentToken.Kind == TokenKind.OpeningSquareBracket) - { - var leftBracket = EatToken(); - var outputs = ParseFunctionOutputList(); - var rightBracket = EatToken(TokenKind.ClosingSquareBracket); - var nodes = new List {Factory.Token(leftBracket)}; - nodes.AddRange(outputs); - nodes.Add(Factory.Token(rightBracket)); - var assignmentSign = EatToken(TokenKind.Assignment); - return Factory.FunctionOutputDescription(nodes, Factory.Token(assignmentSign)); - } - throw new ParsingException($"Unexpected token {CurrentToken.PureToken} during parsing function output descritpion at {CurrentToken.PureToken.Position}."); - } - - private ParameterListNode ParseParameterList() - { - var identifierTokens = new List(); - - while (CurrentToken.Kind != TokenKind.ClosingBracket) - { - if (identifierTokens.Count > 0) - { - identifierTokens.Add(EatToken(TokenKind.Comma)); - } - - if (CurrentToken.Kind == TokenKind.Not) - { - var notToken = EatToken(); - identifierTokens.Add(notToken); - } - else - { - identifierTokens.Add(EatToken(TokenKind.Identifier)); - } - } - - return Factory.ParameterList(identifierTokens.Select(token => Factory.Token(token) as SyntaxNode).ToList()); - } - - private FunctionInputDescriptionNode ParseFunctionInputDescription() - { - if (CurrentToken.Kind == TokenKind.OpeningBracket) - { - var openingBracket = EatToken(TokenKind.OpeningBracket); - var parameterList = ParseParameterList(); - var closingBracket = EatToken(TokenKind.ClosingBracket); - return Factory.FunctionInputDescription( - new TokenNode(openingBracket), - parameterList, - new TokenNode(closingBracket)); - } - else - { - return null; - } - } - - private TokenNode PossibleSemicolonOrComma() - { - if (CurrentToken.Kind == TokenKind.Semicolon - || CurrentToken.Kind == TokenKind.Comma) - { - return Factory.Token(EatToken()); - } - - return null; - } - - private FunctionDeclarationNode ParseFunctionDeclaration() - { - var functionKeyword = EatIdentifier("function"); - var outputDescription = ParseFunctionOutputDescription(); - var name = EatToken(TokenKind.Identifier); - var inputDescription = ParseFunctionInputDescription(); - var body = ParseStatements(); - TokenNode end = null; - if (CurrentToken.Kind == TokenKind.Identifier - && CurrentToken.PureToken.LiteralText == "end") - { - end = Factory.Token(EatIdentifier("end")); - } - - var semicolonOrComma = PossibleSemicolonOrComma(); - return Factory.FunctionDeclaration( - Factory.Token(functionKeyword), - outputDescription, - Factory.Token(name), - inputDescription, - body, - end, - semicolonOrComma); - } - - private StatementNode ParseClassDeclaration() - { - var node = new TokenNode(CurrentToken); - EatAll(); - return null; - } - - private FunctionCallParameterListNode ParseFunctionCallParameterList() - { - var nodes = new List(); - while (CurrentToken.Kind != TokenKind.ClosingBracket) - { - if (nodes.Count > 0) - { - nodes.Add(Factory.Token(EatToken(TokenKind.Comma))); - } - - nodes.Add(ParseExpression()); - } - - return Factory.FunctionCallParameterList(nodes); - } - - private ExpressionNode ParseMember() - { - if (CurrentToken.Kind == TokenKind.Identifier) - { - return Factory.IdentifierName(EatToken()); - } else if (CurrentToken.Kind == TokenKind.OpeningBracket) - { - var openingBracket = EatToken(); - var indirectMember = ParseExpression(); - var closingBracket = EatToken(TokenKind.ClosingBracket); - return Factory.IndirectMemberAccess( - Factory.Token(openingBracket), - indirectMember, - Factory.Token(closingBracket)); - } - throw new ParsingException($"Unexpected token {CurrentToken.PureToken} at {CurrentToken.PureToken.Position}."); - } - - private ExpressionNode ParsePostfix(ParseOptions options, ExpressionNode expression) - { - while (true) - { - var token = CurrentToken; - switch(token.Kind) { - case TokenKind.OpeningBrace: // cell array element access - if (options.ParsingArrayElements && expression.TrailingTrivia.Any()) - { - return expression; - } - var openingBrace = EatToken(); - var indices = ParseArrayElementList(TokenKind.ClosingBrace); - var closingBrace = EatToken(TokenKind.ClosingBrace); - expression = Factory.CellArrayElementAccessExpression( - expression, - Factory.Token(openingBrace), - indices, - Factory.Token(closingBrace) - ); - break; - case TokenKind.OpeningBracket: // function call - if (options.ParsingArrayElements && expression.TrailingTrivia.Any()) - { - return expression; - } - var openingBracket = EatToken(); - var parameters = ParseFunctionCallParameterList(); - var closingBracket = EatToken(TokenKind.ClosingBracket); - expression = Factory.FunctionCallExpression( - expression, - Factory.Token(openingBracket), - parameters, - Factory.Token(closingBracket)); - break; - case TokenKind.Dot: // member access - if (expression is IdentifierNameNode - || expression is MemberAccessNode - || expression is FunctionCallExpressionNode - || expression is CellArrayElementAccessExpressionNode) - { - var dot = EatToken(); - var member = ParseMember(); - expression = Factory.MemberAccess(expression, Factory.Token(dot), member); - } - else - { - throw new ParsingException( - $"Unexpected token {token.PureToken} at {token.PureToken.Position}."); - } - - break; - case TokenKind.Transpose: - case TokenKind.DotTranspose: - var operation = Factory.Token(EatToken()); - expression = Factory.UnaryPostfixOperationExpression(expression, operation); - break; - case TokenKind.UnquotedStringLiteral: - if (expression is IdentifierNameNode idNameNode) - { - var arguments = new List(); - while (CurrentToken.Kind == TokenKind.UnquotedStringLiteral) - { - arguments.Add(Factory.UnquotedStringLiteral(EatToken())); - } - - return Factory.CommandExpression(idNameNode, arguments); - } - else - { - throw new ParsingException($"Unexpected token \"{CurrentToken.PureToken.LiteralText}\" while parsing expression \"{expression.FullText}\" at {CurrentToken.PureToken.Position}."); - } - case TokenKind.At: - if (expression is IdentifierNameNode idNameNode2 - && !expression.TrailingTrivia.Any()) - { - var atToken = Factory.Token(EatToken()); - var baseClassNameWithArguments = ParseExpression(); - return Factory.BaseClassInvokation(idNameNode2, atToken, baseClassNameWithArguments); - } - else - { - throw new ParsingException($"Unexpected token \"{CurrentToken.PureToken.LiteralText}\" at {CurrentToken.PureToken.Position}."); - } - default: - return expression; - } - } - } - - private ArrayElementListNode ParseArrayElementList(TokenKind closing) - { - var nodes = new List {}; - - while (CurrentToken.Kind != closing) - { - if (nodes.Count > 0) - { - if (CurrentToken.Kind == TokenKind.Comma - || CurrentToken.Kind == TokenKind.Semicolon) - { - nodes.Add(Factory.Token(EatToken())); - } - } - - var expression = ParseExpression(new ParseOptions {ParsingArrayElements = true}); - if (expression != null) - { - nodes.Add(expression); - } - } - - return Factory.ArrayElementList(nodes); - } - - private ArrayLiteralExpressionNode ParseArrayLiteral() - { - var openingSquareBracket = EatToken(TokenKind.OpeningSquareBracket); - var elements = ParseArrayElementList(TokenKind.ClosingSquareBracket); - var closingSquareBracket = EatToken(TokenKind.ClosingSquareBracket); - return Factory.ArrayLiteralExpression( - Factory.Token(openingSquareBracket), - elements, - Factory.Token(closingSquareBracket)); - } - - private CellArrayLiteralExpressionNode ParseCellArrayLiteral() - { - var openingBrace = EatToken(TokenKind.OpeningBrace); - var elements = ParseArrayElementList(TokenKind.ClosingBrace); - var closingBrace = EatToken(TokenKind.ClosingBrace); - return Factory.CellArrayLiteralExpression( - Factory.Token(openingBrace), - elements, - Factory.Token(closingBrace)); - } - - private ParenthesizedExpressionNode ParseParenthesizedExpression() - { - var openParen = Factory.Token(EatToken(TokenKind.OpeningBracket)); - var expression = ParseExpression(); - var closeParen = Factory.Token(EatToken(TokenKind.ClosingBracket)); - return Factory.ParenthesizedExpression( - openParen, - expression, - closeParen); - } - - private ExpressionNode ParseTerm(ParseOptions options) - { - var token = CurrentToken; - ExpressionNode expression = null; - if (token.Kind == TokenKind.Identifier) - { - var term = EatToken(); - expression = Factory.IdentifierName(term); - } - else if (token.Kind == TokenKind.NumberLiteral) - { - var number = EatToken(); - expression = Factory.NumberLiteral(number); - } - else if (token.Kind == TokenKind.StringLiteral) - { - var str = EatToken(); - expression = Factory.StringLiteral(str); - } - else if (token.Kind == TokenKind.DoubleQuotedStringLiteral) - { - var str = EatToken(); - expression = Factory.DoubleQuotedStringLiteral(str); - } - else if (token.Kind == TokenKind.OpeningSquareBracket) // array literal expression - { - expression = ParseArrayLiteral(); - } - else if (token.Kind == TokenKind.OpeningBrace) // cell array literal expression - { - expression = ParseCellArrayLiteral(); - } - else if (token.Kind == TokenKind.Colon) // for parsing things like a{:} - { - expression = Factory.EmptyExpression(); - } - else if (token.Kind == TokenKind.OpeningBracket) - { - expression = ParseParenthesizedExpression(); - } - - if (expression == null) - { - return null; - } - return ParsePostfix(options, expression); - } - - internal struct ParseOptions - { - public bool ParsingArrayElements { get; set; } - - public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false }; - } - - public ExpressionNode ParseExpression() - { - return ParseExpression(ParseOptions.Default); - } - - private ExpressionNode ParseExpression(ParseOptions options) - { - return ParseSubExpression(options, Precedence.Expression); - } - - private bool IsUnaryOperator(TokenKind kind) - { - switch (kind) - { - case TokenKind.Plus: - case TokenKind.Minus: - case TokenKind.Not: - case TokenKind.QuestionMark: - return true; - default: - return false; - } - } - - private bool IsBinaryOperator(TokenKind kind) - { - switch (kind) - { - case TokenKind.Assignment: - case TokenKind.LogicalOr: - case TokenKind.LogicalAnd: - case TokenKind.BitwiseOr: - case TokenKind.BitwiseAnd: - case TokenKind.Less: - case TokenKind.LessOrEqual: - case TokenKind.Greater: - case TokenKind.GreaterOrEqual: - case TokenKind.Equality: - case TokenKind.Inequality: - case TokenKind.Colon: - case TokenKind.Plus: - case TokenKind.Minus: - case TokenKind.Multiply: - case TokenKind.DotMultiply: - case TokenKind.Divide: - case TokenKind.DotDivide: - case TokenKind.Backslash: - case TokenKind.DotBackslash: - case TokenKind.Not: - case TokenKind.Power: - case TokenKind.DotPower: - return true; - default: - return false; - } - } - - private bool IsLeftAssociative(TokenKind kind) - { - return true; // TODO: really? - } - - private TokenKind ConvertToUnaryTokenKind(TokenKind kind) - { - switch (kind) - { - case TokenKind.Plus: - return TokenKind.UnaryPlus; - case TokenKind.Minus: - return TokenKind.UnaryMinus; - case TokenKind.Not: - return TokenKind.UnaryNot; - case TokenKind.QuestionMark: - return TokenKind.UnaryQuestionMark; - default: - throw new ArgumentException(nameof(kind)); - } - } - - private CompoundNameNode ParseCompoundName() - { - var lastToken = EatToken(TokenKind.Identifier); - var firstName = Factory.IdentifierName(lastToken); - var nodes = new List {firstName}; - while (CurrentToken.Kind == TokenKind.Dot - && !lastToken.TrailingTrivia.Any()) - { - var dot = Factory.Token(EatToken()); - nodes.Add(dot); - lastToken = EatToken(TokenKind.Identifier); - nodes.Add(Factory.IdentifierName(lastToken)); - } - - return Factory.CompoundName(nodes); - } - - private FunctionHandleNode ParseFunctionHandle() - { - var atSign = EatToken(); - if (CurrentToken.Kind == TokenKind.Identifier) - { - var compoundName = ParseCompoundName(); - return Factory.NamedFunctionHandle( - Factory.Token(atSign), - compoundName); - } else if (CurrentToken.Kind == TokenKind.OpeningBracket) - { - var inputs = ParseFunctionInputDescription(); - var body = ParseExpression(); - return Factory.Lambda(Factory.Token(atSign), inputs, body); - } - throw new ParsingException($"Unexpected token {CurrentToken.PureToken} while parsing function handle at {CurrentToken.PureToken.Position}."); - } - - private ExpressionNode ParseSubExpression(ParseOptions options, Precedence precedence) - { - ExpressionNode lhs = null; - if (IsUnaryOperator(CurrentToken.Kind)) - { - var operation = EatToken(); - var unaryTokenKind = ConvertToUnaryTokenKind(operation.Kind); - var newPrecedence = GetPrecedence(unaryTokenKind); - var operand = ParseSubExpression(options, newPrecedence); - if (operand == null) - { - if (options.ParsingArrayElements && operation.Kind == TokenKind.Not) - { - operand = Factory.EmptyExpression(); - } - else - { - throw new ParsingException($"Unexpected token {CurrentToken.Kind} at {operation.PureToken.Position}."); - } - } - lhs = Factory.UnaryPrefixOperationExpression(Factory.Token(operation), operand); - } - else if (CurrentToken.Kind == TokenKind.At) - { - return ParseFunctionHandle(); - } - else - { - lhs = ParseTerm(options); - } - while (true) - { - var token = CurrentToken; - if (IsBinaryOperator(token.Kind)) - { - var newPrecedence = GetPrecedence(token.Kind); - if (newPrecedence < precedence) - { - break; - } - - if (newPrecedence == precedence && IsLeftAssociative(token.Kind)) - { - break; - } - - EatToken(); - var rhs = ParseSubExpression(options, newPrecedence); - if (rhs == null && token.Kind == TokenKind.Colon) // for parsing things like a{:} - { - rhs = Factory.EmptyExpression(); - } - if (token.Kind == TokenKind.Assignment) - { - lhs = Factory.AssignmentExpression(lhs, Factory.Token(token), rhs); - } - else - { - lhs = Factory.BinaryOperationExpression(lhs, Factory.Token(token), rhs); - } - } - else - { - break; - } - } - - return lhs; - } - - private List ParseOptionalCommas() - { - var commas = new List(); - while (CurrentToken.Kind == TokenKind.Comma) - { - commas.Add(Factory.Token(EatToken())); - } - - return commas; - } - - private List ParseOptionalSemicolonsOrCommas() - { - var commas = new List(); - while (CurrentToken.Kind == TokenKind.Comma - || CurrentToken.Kind == TokenKind.Semicolon) - { - commas.Add(Factory.Token(EatToken())); - } - - return commas; - } - - private SwitchCaseNode ParseSwitchCase() - { - var caseKeyword = EatIdentifier("case"); - var caseId = ParseExpression(); - var commas = ParseOptionalCommas(); - var statementList = ParseStatements(); - return Factory.SwitchCase(Factory.Token(caseKeyword), caseId, statementList, commas); - } - - private SwitchStatementNode ParseSwitchStatement() - { - var switchKeyword = EatIdentifier("switch"); - var expression = ParseExpression(); - var commas = ParseOptionalCommas(); - var casesList = new List(); - while (CurrentToken.Kind == TokenKind.Identifier - && CurrentToken.PureToken.LiteralText == "case") - { - casesList.Add(ParseSwitchCase()); - } - - var endKeyword = EatIdentifier("end"); - return Factory.SwitchStatement( - Factory.Token(switchKeyword), - expression, - casesList, - Factory.Token(endKeyword), - commas); - } - - public ExpressionStatementNode ParseExpressionStatement() - { - var statement = ParseExpression(); - var possibleSemicolonOrComma = PossibleSemicolonOrComma(); - return Factory.ExpressionStatement(statement, possibleSemicolonOrComma); - } - - public WhileStatementNode ParseWhileStatement() - { - var whileKeyword = EatToken(); - var condition = ParseExpression(); - var commas = ParseOptionalCommas(); - var body = ParseStatements(); - var endKeyword = EatIdentifier("end"); - var semicolonOrComma = PossibleSemicolonOrComma(); - return Factory.WhileStatement( - Factory.Token(whileKeyword), - condition, - commas, - body, - Factory.Token(endKeyword), - semicolonOrComma); - } - - public StatementNode ParseStatement() - { - var statement = ParseStatementCore(); - return statement; - } - - public IfStatementNode ParseIfStatement() - { - var ifKeyword = Factory.Token(EatToken()); - var condition = ParseExpression(); - var commas = ParseOptionalSemicolonsOrCommas(); - var body = ParseStatements(); - TokenNode elseKeyword = null; - StatementListNode elseBody = null; - if (CurrentToken.Kind == TokenKind.Identifier - && CurrentToken.PureToken.LiteralText == "else") - { - elseKeyword = Factory.Token(EatToken()); - elseBody = ParseStatements(); - } - if (CurrentToken.Kind == TokenKind.Identifier - && CurrentToken.PureToken.LiteralText == "elseif") - { - elseKeyword = null; - var ifStatement = ParseIfStatement(); - elseBody = Factory.StatementList(new List { ifStatement }); - return Factory.IfStatement( - ifKeyword, - condition, - commas, - body, - null, - elseBody, - null, - null); - } - - var endKeyword = Factory.Token(EatIdentifier("end")); - var possibleSemicolonOrComma = PossibleSemicolonOrComma(); - return Factory.IfStatement( - ifKeyword, - condition, - commas, - body, - elseKeyword, - elseBody, - endKeyword, - possibleSemicolonOrComma); - } - - public ForStatementNode ParseForStatement() - { - var forKeyword = Factory.Token(EatIdentifier("for")); - var expression = ParseExpression(); - if (!(expression is AssignmentExpressionNode)) - { - throw new ParsingException($"Unexpected expression \"{expression.FullText}\" while parsing FOR statement at {CurrentToken.PureToken.Position}."); - } - - var forAssignment = (AssignmentExpressionNode) expression; - var commas = ParseOptionalSemicolonsOrCommas(); - - var body = ParseStatements(); - var endKeyword = Factory.Token(EatIdentifier("end")); - return Factory.ForStatement(forKeyword, forAssignment, body, endKeyword, commas); - } - - public TryCatchStatementNode ParseTryCatchStatement() - { - var tryKeyword = Factory.Token(EatIdentifier("try")); - var tryBody = ParseStatements(); - if (CurrentToken.PureToken.LiteralText == "catch") - { - var catchKeyword = Factory.Token(EatIdentifier("catch")); - var catchBody = ParseStatements(); - var endKeyword = Factory.Token(EatIdentifier("end")); - return Factory.TryCatchStatement(tryKeyword, tryBody, catchKeyword, catchBody, endKeyword); - } - else if (CurrentToken.PureToken.LiteralText == "end") - { - var endKeyword = Factory.Token(EatIdentifier("end")); - return Factory.TryCatchStatement(tryKeyword, tryBody, endKeyword); - } - else - { - throw new ParsingException($"Unexpected token {CurrentToken.PureToken} while parsing try/catch statement at {CurrentToken.PureToken.Position}."); - } - } - - public StatementNode ParseStatementCore() - { - if (CurrentToken.Kind == TokenKind.Identifier) - { - if (CurrentToken.PureToken.LiteralText == "function") - { - return ParseFunctionDeclaration(); - } - else if (CurrentToken.PureToken.LiteralText == "classdef") - { - return ParseClassDeclaration(); - } - else if (CurrentToken.PureToken.LiteralText == "switch") - { - return ParseSwitchStatement(); - } - else if (CurrentToken.PureToken.LiteralText == "while") - { - return ParseWhileStatement(); - } - else if (CurrentToken.PureToken.LiteralText == "if") - { - return ParseIfStatement(); - } - else if (CurrentToken.PureToken.LiteralText == "case") - { - return null; - } - else if (CurrentToken.PureToken.LiteralText == "else") - { - return null; - } - else if (CurrentToken.PureToken.LiteralText == "elseif") - { - return null; - } - else if (CurrentToken.PureToken.LiteralText == "end") - { - return null; - } - else if (CurrentToken.PureToken.LiteralText == "for") - { - return ParseForStatement(); - } - else if (CurrentToken.PureToken.LiteralText == "try") - { - return ParseTryCatchStatement(); - } - else if (CurrentToken.PureToken.LiteralText == "catch") - { - return null; - } - - return ParseExpressionStatement(); - } - - if (CurrentToken.Kind == TokenKind.OpeningSquareBracket) - { - return ParseExpressionStatement(); - } - - if (CurrentToken.Kind == TokenKind.Semicolon) - { - return Factory.ExpressionStatement(Factory.EmptyExpression(), Factory.Token(EatToken())); - } - throw new ParsingException($"Unexpected token: \"{CurrentToken.PureToken}\" at {CurrentToken.PureToken.Position}"); - } - - private StatementListNode ParseStatements() - { - var statements = new List(); - while (CurrentToken.PureToken.Kind != TokenKind.EndOfFile) - { - var node = ParseStatement(); - if (node == null) - { - break; - } - statements.Add(node); - } - - return Factory.StatementList(statements); - } - - private StatementListNode ParseFile() - { - return ParseStatements(); - } - - public StatementListNode Parse() - { - return ParseFile(); + var lexer = new Internal.MLexerGreen(_window); + var tokens = lexer.ParseAll(); + var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory()); + var green = parser.ParseFile(); + return new FileSyntaxNode(null, green); } } } \ No newline at end of file diff --git a/Parser/Parser.csproj b/Parser/Parser.csproj index 4d7af63..2e5ff7c 100644 --- a/Parser/Parser.csproj +++ b/Parser/Parser.csproj @@ -1,8 +1,8 @@  - netcoreapp2.0 + netstandard2.0 - + \ No newline at end of file diff --git a/Lexer/ParsingException.cs b/Parser/ParsingException.cs similarity index 89% rename from Lexer/ParsingException.cs rename to Parser/ParsingException.cs index 14a6277..d3f60b0 100644 --- a/Lexer/ParsingException.cs +++ b/Parser/ParsingException.cs @@ -1,6 +1,6 @@ using System; -namespace Lexer +namespace Parser { public class ParsingException : Exception { diff --git a/Parser/Position.cs b/Parser/Position.cs new file mode 100644 index 0000000..95ff528 --- /dev/null +++ b/Parser/Position.cs @@ -0,0 +1,14 @@ +namespace Parser +{ + public struct Position + { + public string FileName { get; set; } + public int Line { get; set; } + public int Column { get; set; } + + public override string ToString() + { + return $"line {Line}, column {Column} of {FileName}."; + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxFactory.cs b/Parser/SyntaxFactory.cs deleted file mode 100644 index 298ac5c..0000000 --- a/Parser/SyntaxFactory.cs +++ /dev/null @@ -1,592 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Lexer; - -namespace Parser -{ - public class SyntaxFactory - { - private static List RemoveNulls(List children) - { - return children.Where(x => x != null).ToList(); - } - - public FunctionDeclarationNode FunctionDeclaration( - TokenNode functionKeyword, - FunctionOutputDescriptionNode outputDescription, - TokenNode name, - FunctionInputDescriptionNode inputDescription, - StatementListNode body, - TokenNode end, - TokenNode semicolonOrComma = null) - { - var children = new List - { - functionKeyword, - outputDescription, - name, - inputDescription, - body, - end, - semicolonOrComma - }; - return new FunctionDeclarationNode( - RemoveNulls(children), - functionKeyword, - outputDescription, - name, - inputDescription, - body, - end, - semicolonOrComma); - } - - public FunctionOutputDescriptionNode FunctionOutputDescription( - List nodes, - TokenNode equalitySign) - { - var children = new List(nodes); - children.Add(equalitySign); - return new FunctionOutputDescriptionNode( - children, - children - .Where(node => node is TokenNode tokenNode && tokenNode.Token.Kind == TokenKind.Identifier) - .Select(node => (TokenNode)node) - .ToList(), - equalitySign - ); - } - - public ParameterListNode ParameterList(List nodes) - { - return new ParameterListNode( - nodes, - nodes - .Where( - node => node is TokenNode tokenNode && tokenNode.Token.Kind != TokenKind.Comma - ) - .ToList()); - } - - public StatementListNode StatementList(List nodes) - { - return new StatementListNode(nodes); - } - - public FunctionInputDescriptionNode FunctionInputDescription( - TokenNode openingBracket, - ParameterListNode parameterList, - TokenNode closingBracket) - { - var children = new List - { - openingBracket, - parameterList, - closingBracket - }; - return new FunctionInputDescriptionNode(children, openingBracket, parameterList, closingBracket); - } - - public TokenNode Token(Token token) - { - return new TokenNode(token); - } - - public SwitchStatementNode SwitchStatement( - TokenNode switchKeyword, - ExpressionNode switchExpression, - List cases, - TokenNode endKeyword, - List optionalCommasAfterExpression, - TokenNode semicolonOrComma = null) - { - var children = new List { switchKeyword, switchExpression }; - children.AddRange(optionalCommasAfterExpression); - children.AddRange(cases); - children.Add(endKeyword); - children.Add(semicolonOrComma); - - return new SwitchStatementNode( - RemoveNulls(children), - switchKeyword, - switchExpression, - cases, - endKeyword, - semicolonOrComma, - optionalCommasAfterExpression); - } - - public SwitchCaseNode SwitchCase( - TokenNode caseKeyword, - ExpressionNode caseIdentifier, - StatementListNode statementList, - List optionalCommasAfterIdentifier) - { - var children = new List - { - caseKeyword, - caseIdentifier - }; - children.AddRange(optionalCommasAfterIdentifier); - children.Add(statementList); - return new SwitchCaseNode( - RemoveNulls(children), - caseKeyword, - caseIdentifier, - statementList, - optionalCommasAfterIdentifier); - } - - public AssignmentExpressionNode AssignmentExpression( - ExpressionNode lhs, - TokenNode assignmentSign, - ExpressionNode rhs) - { - var children = new List - { - lhs, - assignmentSign, - rhs - }; - return new AssignmentExpressionNode(children, lhs, assignmentSign, rhs); - } - - public UnaryPrefixOperationExpressionNode UnaryPrefixOperationExpression( - TokenNode operation, - ExpressionNode operand) - { - var children = new List - { - operation, - operand - }; - return new UnaryPrefixOperationExpressionNode(children, operation, operand); - } - - public UnaryPostfixOperationExpressionNode UnaryPostfixOperationExpression( - ExpressionNode operand, - TokenNode operation) - { - var children = new List - { - operand, - operation - }; - return new UnaryPostfixOperationExpressionNode(children, operand, operation); - } - - public BinaryOperationExpressionNode BinaryOperationExpression( - ExpressionNode lhs, - TokenNode operation, - ExpressionNode rhs) - { - var children = new List - { - lhs, - operation, - rhs - }; - return new BinaryOperationExpressionNode(children, lhs, operation, rhs); - } - - public IdentifierNameNode IdentifierName( - Token identifier) - { - return new IdentifierNameNode(identifier); - } - - public NumberLiteralNode NumberLiteral( - Token numberLiteral) - { - return new NumberLiteralNode(numberLiteral); - } - - public StringLiteralNode StringLiteral( - Token stringLiteral) - { - return new StringLiteralNode(stringLiteral); - } - - public DoubleQuotedStringLiteralNode DoubleQuotedStringLiteral( - Token stringLiteral) - { - return new DoubleQuotedStringLiteralNode(stringLiteral); - } - - public UnquotedStringLiteralNode UnquotedStringLiteral( - Token stringLiteral) - { - return new UnquotedStringLiteralNode(stringLiteral); - } - - public ExpressionStatementNode ExpressionStatement(ExpressionNode expression, TokenNode semicolonOrComma) - { - var children = new List {expression, semicolonOrComma}; - return new ExpressionStatementNode( - RemoveNulls(children), - expression, - semicolonOrComma); - } - - public CellArrayElementAccessExpressionNode CellArrayElementAccessExpression( - ExpressionNode cellArray, - TokenNode openingBrace, - ArrayElementListNode indices, - TokenNode closingBrace) - { - var children = new List {cellArray, openingBrace, indices, closingBrace}; - return new CellArrayElementAccessExpressionNode( - children, - cellArray, - openingBrace, - indices, - closingBrace); - } - - public FunctionCallExpressionNode FunctionCallExpression( - ExpressionNode functionName, - TokenNode openingBracket, - FunctionCallParameterListNode parameters, - TokenNode closingBracket) - { - var children = new List - { - functionName, - openingBracket, - parameters, - closingBracket - }; - return new FunctionCallExpressionNode( - children, - functionName, - openingBracket, - parameters, - closingBracket); - } - - public FunctionCallParameterListNode FunctionCallParameterList(List nodes) - { - return new FunctionCallParameterListNode( - nodes, - nodes - .OfType() - .ToList()); - } - - public ArrayElementListNode ArrayElementList(List nodes) - { - return new ArrayElementListNode( - nodes, - nodes - .OfType() - .ToList()); - } - - public CompoundNameNode CompoundName(List nodes) - { - return new CompoundNameNode( - nodes, - nodes - .OfType() - .ToList()); - } - - public ArrayLiteralExpressionNode ArrayLiteralExpression( - TokenNode openingSquareBracket, - ArrayElementListNode elements, - TokenNode closingSquareBracket) - { - var children = new List - { - openingSquareBracket, - elements, - closingSquareBracket - }; - return new ArrayLiteralExpressionNode( - children, - openingSquareBracket, - elements, - closingSquareBracket); - } - - public CellArrayLiteralExpressionNode CellArrayLiteralExpression( - TokenNode openingBrace, - ArrayElementListNode elements, - TokenNode closingBrace) - { - var children = new List - { - openingBrace, - elements, - closingBrace - }; - return new CellArrayLiteralExpressionNode( - children, - openingBrace, - elements, - closingBrace); - } - - public EmptyExpressionNode EmptyExpression() - { - return new EmptyExpressionNode(); - } - - public MemberAccessNode MemberAccess( - SyntaxNode leftOperand, - TokenNode dot, - SyntaxNode rightOperand) - { - var children = new List - { - leftOperand, - dot, - rightOperand - }; - return new MemberAccessNode( - children, - leftOperand, - dot, - rightOperand); - } - - public WhileStatementNode WhileStatement( - TokenNode whileKeyword, - ExpressionNode condition, - List optionalCommasAfterCondition, - StatementListNode body, - TokenNode end, - TokenNode semicolonOrComma) - { - var children = new List - { - whileKeyword, - condition, - }; - children.AddRange(optionalCommasAfterCondition); - children.Add(body); - children.Add(end); - children.Add(semicolonOrComma); - return new WhileStatementNode( - RemoveNulls(children), - whileKeyword, - condition, - optionalCommasAfterCondition, - body, - end, - semicolonOrComma); - } - - public StatementNode AppendSemicolonOrComma(StatementNode statement, TokenNode semicolonOrComma) - { - statement.SemicolonOrComma = semicolonOrComma; - statement.Children.Add(semicolonOrComma); - statement.Children[statement.Children.Count - 1].Parent = statement; - return statement; - } - - public IfStatementNode IfStatement( - TokenNode ifKeyword, - ExpressionNode condition, - List optionalCommasAfterCondition, - StatementListNode body, - TokenNode elseKeyword, - StatementListNode elseBody, - TokenNode endKeyword, - TokenNode possibleSemicolonOrComma) - { - var children = new List - { - ifKeyword, - condition - }; - children.AddRange(optionalCommasAfterCondition); - children.Add(body); - children.Add(elseKeyword); - children.Add(elseBody); - children.Add(endKeyword); - children.Add(possibleSemicolonOrComma); - - return new IfStatementNode( - RemoveNulls(children), - ifKeyword, - condition, - optionalCommasAfterCondition, - body, - elseKeyword, - elseBody, - endKeyword, - possibleSemicolonOrComma); - } - - public ParenthesizedExpressionNode ParenthesizedExpression( - TokenNode openParen, - ExpressionNode expression, - TokenNode closeParen) - { - var children = new List - { - openParen, - expression, - closeParen - }; - return new ParenthesizedExpressionNode( - children, - openParen, - expression, - closeParen); - } - - public ForStatementNode ForStatement( - TokenNode forKeyword, - AssignmentExpressionNode forAssignment, - StatementListNode body, - TokenNode endKeyword, - List optionalCommasAfterAssignment) - { - var children = new List - { - forKeyword, - forAssignment, - }; - children.AddRange(optionalCommasAfterAssignment); - children.Add(body); - children.Add(endKeyword); - return new ForStatementNode( - RemoveNulls(children), - forKeyword, - forAssignment, - body, - endKeyword, - optionalCommasAfterAssignment); - } - - public IndirectMemberAccessNode IndirectMemberAccess( - TokenNode openingBracket, - ExpressionNode indirectMemberName, - TokenNode closingBracket) - { - var children = new List - { - openingBracket, - indirectMemberName, - closingBracket - }; - return new IndirectMemberAccessNode( - children, - openingBracket, - indirectMemberName, - closingBracket); - } - - public NamedFunctionHandleNode NamedFunctionHandle( - TokenNode atSign, - CompoundNameNode functionName) - { - var children = new List - { - atSign, - functionName - }; - return new NamedFunctionHandleNode( - children, - atSign, - functionName); - } - - public LambdaNode Lambda( - TokenNode atSign, - FunctionInputDescriptionNode input, - ExpressionNode body) - { - var children = new List - { - atSign, - input, - body - }; - return new LambdaNode( - children, - atSign, - input, - body); - } - - public TryCatchStatementNode TryCatchStatement( - TokenNode tryKeyword, - StatementListNode tryBody, - TokenNode catchKeyword, - StatementListNode catchBody, - TokenNode endKeyword) - { - var children = new List - { - tryKeyword, - tryBody, - catchKeyword, - catchBody, - endKeyword - }; - return new TryCatchStatementNode( - children, - tryKeyword, - tryBody, - catchKeyword, - catchBody, - endKeyword); - } - - public TryCatchStatementNode TryCatchStatement( - TokenNode tryKeyword, - StatementListNode tryBody, - TokenNode endKeyword) - { - var children = new List - { - tryKeyword, - tryBody, - endKeyword - }; - return new TryCatchStatementNode( - children, - tryKeyword, - tryBody, - null, - null, - endKeyword); - } - - public CommandExpressionNode CommandExpression( - IdentifierNameNode identifierName, - List arguments) - { - var children = new List - { - identifierName - }; - children.AddRange(arguments); - return new CommandExpressionNode( - children, - identifierName, - arguments); - } - - public BaseClassInvokationNode BaseClassInvokation( - IdentifierNameNode methodName, - TokenNode atToken, - ExpressionNode baseClassNameAndArguments) - { - var children = new List - { - methodName, - atToken, - baseClassNameAndArguments - }; - return new BaseClassInvokationNode( - children, - methodName, - atToken, - baseClassNameAndArguments); - } - } -} \ No newline at end of file diff --git a/Parser/SyntaxNode.Generated.cs b/Parser/SyntaxNode.Generated.cs new file mode 100644 index 0000000..22ef17d --- /dev/null +++ b/Parser/SyntaxNode.Generated.cs @@ -0,0 +1,2631 @@ +namespace Parser +{ + public class FileSyntaxNode : SyntaxNode + { + private SyntaxNode _statementList; + + internal FileSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken EndOfFile + { + get { return new SyntaxToken(this, ((Parser.Internal.FileSyntaxNode)_green)._endOfFile); } + } + + public SyntaxNodeOrTokenList StatementList + { + get + { + var red = this.GetRed(ref this._statementList, 0); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _statementList, 0); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitFile(this); + } + + } + + public class FunctionDeclarationSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _outputDescription; + private SyntaxNode _inputDescription; + private SyntaxNode _commas; + private SyntaxNode _body; + + internal FunctionDeclarationSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken FunctionKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionDeclarationSyntaxNode)_green)._functionKeyword); } + } + + public SyntaxToken Name + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionDeclarationSyntaxNode)_green)._name); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionDeclarationSyntaxNode)_green)._endKeyword); } + } + + public FunctionOutputDescriptionSyntaxNode OutputDescription + { + get + { + var red = this.GetRed(ref this._outputDescription, 1); + if (red != null) + return (FunctionOutputDescriptionSyntaxNode)red; + + return default(FunctionOutputDescriptionSyntaxNode); + } + } + + public FunctionInputDescriptionSyntaxNode InputDescription + { + get + { + var red = this.GetRed(ref this._inputDescription, 3); + if (red != null) + return (FunctionInputDescriptionSyntaxNode)red; + + return default(FunctionInputDescriptionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Commas + { + get + { + var red = this.GetRed(ref this._commas, 4); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 5); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _outputDescription, 1); + case 3: return GetRed(ref _inputDescription, 3); + case 4: return GetRed(ref _commas, 4); + case 5: return GetRed(ref _body, 5); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitFunctionDeclaration(this); + } + + } + + public class FunctionOutputDescriptionSyntaxNode : SyntaxNode + { + private SyntaxNode _outputList; + + internal FunctionOutputDescriptionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AssignmentSign + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionOutputDescriptionSyntaxNode)_green)._assignmentSign); } + } + + public SyntaxNodeOrTokenList OutputList + { + get + { + var red = this.GetRed(ref this._outputList, 0); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _outputList, 0); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitFunctionOutputDescription(this); + } + + } + + public class FunctionInputDescriptionSyntaxNode : SyntaxNode + { + private SyntaxNode _parameterList; + + internal FunctionInputDescriptionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionInputDescriptionSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionInputDescriptionSyntaxNode)_green)._closingBracket); } + } + + public SyntaxNodeOrTokenList ParameterList + { + get + { + var red = this.GetRed(ref this._parameterList, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _parameterList, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitFunctionInputDescription(this); + } + + } + + public class SwitchStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _switchExpression; + private SyntaxNode _optionalCommas; + private SyntaxNode _cases; + + internal SwitchStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken SwitchKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.SwitchStatementSyntaxNode)_green)._switchKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.SwitchStatementSyntaxNode)_green)._endKeyword); } + } + + public ExpressionSyntaxNode SwitchExpression + { + get + { + var red = this.GetRed(ref this._switchExpression, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Cases + { + get + { + var red = this.GetRed(ref this._cases, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _switchExpression, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _cases, 3); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitSwitchStatement(this); + } + + } + + public class SwitchCaseSyntaxNode : SyntaxNode + { + private SyntaxNode _caseIdentifier; + private SyntaxNode _optionalCommas; + private SyntaxNode _body; + + internal SwitchCaseSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken CaseKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.SwitchCaseSyntaxNode)_green)._caseKeyword); } + } + + public ExpressionSyntaxNode CaseIdentifier + { + get + { + var red = this.GetRed(ref this._caseIdentifier, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _caseIdentifier, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _body, 3); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitSwitchCase(this); + } + + } + + public class WhileStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _condition; + private SyntaxNode _optionalCommas; + private SyntaxNode _body; + + internal WhileStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken WhileKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.WhileStatementSyntaxNode)_green)._whileKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.WhileStatementSyntaxNode)_green)._endKeyword); } + } + + public ExpressionSyntaxNode Condition + { + get + { + var red = this.GetRed(ref this._condition, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _condition, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _body, 3); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitWhileStatement(this); + } + + } + + public class ElseifClause : SyntaxNode + { + private SyntaxNode _condition; + private SyntaxNode _optionalCommas; + private SyntaxNode _body; + + internal ElseifClause(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken ElseifKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ElseifClause)_green)._elseifKeyword); } + } + + public ExpressionSyntaxNode Condition + { + get + { + var red = this.GetRed(ref this._condition, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _condition, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _body, 3); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitElseifClause(this); + } + + } + + public class ElseClause : SyntaxNode + { + private SyntaxNode _body; + + internal ElseClause(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken ElseKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ElseClause)_green)._elseKeyword); } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _body, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitElseClause(this); + } + + } + + public class IfStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _condition; + private SyntaxNode _optionalCommas; + private SyntaxNode _body; + private SyntaxNode _elseifClauses; + private SyntaxNode _elseClause; + + internal IfStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken IfKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.IfStatementSyntaxNode)_green)._ifKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.IfStatementSyntaxNode)_green)._endKeyword); } + } + + public ExpressionSyntaxNode Condition + { + get + { + var red = this.GetRed(ref this._condition, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList ElseifClauses + { + get + { + var red = this.GetRed(ref this._elseifClauses, 4); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public ElseClause ElseClause + { + get + { + var red = this.GetRed(ref this._elseClause, 5); + if (red != null) + return (ElseClause)red; + + return default(ElseClause); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _condition, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _body, 3); + case 4: return GetRed(ref _elseifClauses, 4); + case 5: return GetRed(ref _elseClause, 5); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitIfStatement(this); + } + + } + + public class ForStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _assignment; + private SyntaxNode _optionalCommas; + private SyntaxNode _body; + + internal ForStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken ForKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ForStatementSyntaxNode)_green)._forKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ForStatementSyntaxNode)_green)._endKeyword); } + } + + public AssignmentExpressionSyntaxNode Assignment + { + get + { + var red = this.GetRed(ref this._assignment, 1); + if (red != null) + return (AssignmentExpressionSyntaxNode)red; + + return default(AssignmentExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList OptionalCommas + { + get + { + var red = this.GetRed(ref this._optionalCommas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 3); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _assignment, 1); + case 2: return GetRed(ref _optionalCommas, 2); + case 3: return GetRed(ref _body, 3); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitForStatement(this); + } + + } + + public class AssignmentExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _lhs; + private SyntaxNode _rhs; + + internal AssignmentExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AssignmentSign + { + get { return new SyntaxToken(this, ((Parser.Internal.AssignmentExpressionSyntaxNode)_green)._assignmentSign); } + } + + public ExpressionSyntaxNode Lhs + { + get + { + var red = this.GetRed(ref this._lhs, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public ExpressionSyntaxNode Rhs + { + get + { + var red = this.GetRed(ref this._rhs, 2); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _lhs, 0); + case 2: return GetRed(ref _rhs, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitAssignmentExpression(this); + } + + } + + public class CatchClauseSyntaxNode : SyntaxNode + { + private SyntaxNode _catchBody; + + internal CatchClauseSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken CatchKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.CatchClauseSyntaxNode)_green)._catchKeyword); } + } + + public SyntaxNodeOrTokenList CatchBody + { + get + { + var red = this.GetRed(ref this._catchBody, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _catchBody, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitCatchClause(this); + } + + } + + public class TryCatchStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _tryBody; + private SyntaxNode _catchClause; + + internal TryCatchStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken TryKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.TryCatchStatementSyntaxNode)_green)._tryKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.TryCatchStatementSyntaxNode)_green)._endKeyword); } + } + + public SyntaxNodeOrTokenList TryBody + { + get + { + var red = this.GetRed(ref this._tryBody, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public CatchClauseSyntaxNode CatchClause + { + get + { + var red = this.GetRed(ref this._catchClause, 2); + if (red != null) + return (CatchClauseSyntaxNode)red; + + return default(CatchClauseSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _tryBody, 1); + case 2: return GetRed(ref _catchClause, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitTryCatchStatement(this); + } + + } + + public class ExpressionStatementSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _expression; + + internal ExpressionStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public ExpressionSyntaxNode Expression + { + get + { + var red = this.GetRed(ref this._expression, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _expression, 0); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitExpressionStatement(this); + } + + } + + public class EmptyStatementSyntaxNode : StatementSyntaxNode + { + + internal EmptyStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Semicolon + { + get { return new SyntaxToken(this, ((Parser.Internal.EmptyStatementSyntaxNode)_green)._semicolon); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEmptyStatement(this); + } + + } + + public class EmptyExpressionSyntaxNode : ExpressionSyntaxNode + { + + internal EmptyExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEmptyExpression(this); + } + + } + + public class UnaryPrefixOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _operand; + + internal UnaryPrefixOperationExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Operation + { + get { return new SyntaxToken(this, ((Parser.Internal.UnaryPrefixOperationExpressionSyntaxNode)_green)._operation); } + } + + public ExpressionSyntaxNode Operand + { + get + { + var red = this.GetRed(ref this._operand, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _operand, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitUnaryPrefixOperationExpression(this); + } + + } + + public class CompoundNameSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _nodes; + + internal CompoundNameSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 0); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _nodes, 0); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitCompoundName(this); + } + + } + + public class NamedFunctionHandleSyntaxNode : FunctionHandleSyntaxNode + { + private SyntaxNode _functionName; + + internal NamedFunctionHandleSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AtSign + { + get { return new SyntaxToken(this, ((Parser.Internal.NamedFunctionHandleSyntaxNode)_green)._atSign); } + } + + public CompoundNameSyntaxNode FunctionName + { + get + { + var red = this.GetRed(ref this._functionName, 1); + if (red != null) + return (CompoundNameSyntaxNode)red; + + return default(CompoundNameSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _functionName, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitNamedFunctionHandle(this); + } + + } + + public class LambdaSyntaxNode : FunctionHandleSyntaxNode + { + private SyntaxNode _input; + private SyntaxNode _body; + + internal LambdaSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AtSign + { + get { return new SyntaxToken(this, ((Parser.Internal.LambdaSyntaxNode)_green)._atSign); } + } + + public FunctionInputDescriptionSyntaxNode Input + { + get + { + var red = this.GetRed(ref this._input, 1); + if (red != null) + return (FunctionInputDescriptionSyntaxNode)red; + + return default(FunctionInputDescriptionSyntaxNode); + } + } + + public ExpressionSyntaxNode Body + { + get + { + var red = this.GetRed(ref this._body, 2); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _input, 1); + case 2: return GetRed(ref _body, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitLambda(this); + } + + } + + public class BinaryOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _lhs; + private SyntaxNode _rhs; + + internal BinaryOperationExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Operation + { + get { return new SyntaxToken(this, ((Parser.Internal.BinaryOperationExpressionSyntaxNode)_green)._operation); } + } + + public ExpressionSyntaxNode Lhs + { + get + { + var red = this.GetRed(ref this._lhs, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public ExpressionSyntaxNode Rhs + { + get + { + var red = this.GetRed(ref this._rhs, 2); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _lhs, 0); + case 2: return GetRed(ref _rhs, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitBinaryOperationExpression(this); + } + + } + + public class IdentifierNameSyntaxNode : ExpressionSyntaxNode + { + + internal IdentifierNameSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Name + { + get { return new SyntaxToken(this, ((Parser.Internal.IdentifierNameSyntaxNode)_green)._name); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitIdentifierName(this); + } + + } + + public class NumberLiteralSyntaxNode : ExpressionSyntaxNode + { + + internal NumberLiteralSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Number + { + get { return new SyntaxToken(this, ((Parser.Internal.NumberLiteralSyntaxNode)_green)._number); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitNumberLiteral(this); + } + + } + + public class StringLiteralSyntaxNode : ExpressionSyntaxNode + { + + internal StringLiteralSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken StringToken + { + get { return new SyntaxToken(this, ((Parser.Internal.StringLiteralSyntaxNode)_green)._stringToken); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitStringLiteral(this); + } + + } + + public class DoubleQuotedStringLiteralSyntaxNode : ExpressionSyntaxNode + { + + internal DoubleQuotedStringLiteralSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken StringToken + { + get { return new SyntaxToken(this, ((Parser.Internal.DoubleQuotedStringLiteralSyntaxNode)_green)._stringToken); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitDoubleQuotedStringLiteral(this); + } + + } + + public class UnquotedStringLiteralSyntaxNode : ExpressionSyntaxNode + { + + internal UnquotedStringLiteralSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken StringToken + { + get { return new SyntaxToken(this, ((Parser.Internal.UnquotedStringLiteralSyntaxNode)_green)._stringToken); } + } + + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitUnquotedStringLiteral(this); + } + + } + + public class ArrayLiteralExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _nodes; + + internal ArrayLiteralExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningSquareBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.ArrayLiteralExpressionSyntaxNode)_green)._openingSquareBracket); } + } + + public SyntaxToken ClosingSquareBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.ArrayLiteralExpressionSyntaxNode)_green)._closingSquareBracket); } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _nodes, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitArrayLiteralExpression(this); + } + + } + + public class CellArrayLiteralExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _nodes; + + internal CellArrayLiteralExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBrace + { + get { return new SyntaxToken(this, ((Parser.Internal.CellArrayLiteralExpressionSyntaxNode)_green)._openingBrace); } + } + + public SyntaxToken ClosingBrace + { + get { return new SyntaxToken(this, ((Parser.Internal.CellArrayLiteralExpressionSyntaxNode)_green)._closingBrace); } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _nodes, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitCellArrayLiteralExpression(this); + } + + } + + public class ParenthesizedExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _expression; + + internal ParenthesizedExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.ParenthesizedExpressionSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.ParenthesizedExpressionSyntaxNode)_green)._closingBracket); } + } + + public ExpressionSyntaxNode Expression + { + get + { + var red = this.GetRed(ref this._expression, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _expression, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitParenthesizedExpression(this); + } + + } + + public class CellArrayElementAccessExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _expression; + private SyntaxNode _nodes; + + internal CellArrayElementAccessExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBrace + { + get { return new SyntaxToken(this, ((Parser.Internal.CellArrayElementAccessExpressionSyntaxNode)_green)._openingBrace); } + } + + public SyntaxToken ClosingBrace + { + get { return new SyntaxToken(this, ((Parser.Internal.CellArrayElementAccessExpressionSyntaxNode)_green)._closingBrace); } + } + + public ExpressionSyntaxNode Expression + { + get + { + var red = this.GetRed(ref this._expression, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _expression, 0); + case 2: return GetRed(ref _nodes, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitCellArrayElementAccessExpression(this); + } + + } + + public class FunctionCallExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _functionName; + private SyntaxNode _nodes; + + internal FunctionCallExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionCallExpressionSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.FunctionCallExpressionSyntaxNode)_green)._closingBracket); } + } + + public ExpressionSyntaxNode FunctionName + { + get + { + var red = this.GetRed(ref this._functionName, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _functionName, 0); + case 2: return GetRed(ref _nodes, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitFunctionCallExpression(this); + } + + } + + public class MemberAccessSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _leftOperand; + private SyntaxNode _rightOperand; + + internal MemberAccessSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Dot + { + get { return new SyntaxToken(this, ((Parser.Internal.MemberAccessSyntaxNode)_green)._dot); } + } + + public SyntaxNode LeftOperand + { + get + { + var red = this.GetRed(ref this._leftOperand, 0); + if (red != null) + return (SyntaxNode)red; + + return default(SyntaxNode); + } + } + + public SyntaxNode RightOperand + { + get + { + var red = this.GetRed(ref this._rightOperand, 2); + if (red != null) + return (SyntaxNode)red; + + return default(SyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _leftOperand, 0); + case 2: return GetRed(ref _rightOperand, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitMemberAccess(this); + } + + } + + public class UnaryPostixOperationExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _operand; + + internal UnaryPostixOperationExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken Operation + { + get { return new SyntaxToken(this, ((Parser.Internal.UnaryPostixOperationExpressionSyntaxNode)_green)._operation); } + } + + public ExpressionSyntaxNode Operand + { + get + { + var red = this.GetRed(ref this._operand, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _operand, 0); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitUnaryPostixOperationExpression(this); + } + + } + + public class IndirectMemberAccessSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _expression; + + internal IndirectMemberAccessSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.IndirectMemberAccessSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.IndirectMemberAccessSyntaxNode)_green)._closingBracket); } + } + + public ExpressionSyntaxNode Expression + { + get + { + var red = this.GetRed(ref this._expression, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _expression, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitIndirectMemberAccess(this); + } + + } + + public class CommandExpressionSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _commandName; + private SyntaxNode _arguments; + + internal CommandExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public IdentifierNameSyntaxNode CommandName + { + get + { + var red = this.GetRed(ref this._commandName, 0); + if (red != null) + return (IdentifierNameSyntaxNode)red; + + return default(IdentifierNameSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Arguments + { + get + { + var red = this.GetRed(ref this._arguments, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _commandName, 0); + case 1: return GetRed(ref _arguments, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitCommandExpression(this); + } + + } + + public class BaseClassInvokationSyntaxNode : ExpressionSyntaxNode + { + private SyntaxNode _methodName; + private SyntaxNode _baseClassNameAndArguments; + + internal BaseClassInvokationSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AtSign + { + get { return new SyntaxToken(this, ((Parser.Internal.BaseClassInvokationSyntaxNode)_green)._atSign); } + } + + public ExpressionSyntaxNode MethodName + { + get + { + var red = this.GetRed(ref this._methodName, 0); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + public ExpressionSyntaxNode BaseClassNameAndArguments + { + get + { + var red = this.GetRed(ref this._baseClassNameAndArguments, 2); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _methodName, 0); + case 2: return GetRed(ref _baseClassNameAndArguments, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitBaseClassInvokation(this); + } + + } + + public class AttributeAssignmentSyntaxNode : SyntaxNode + { + private SyntaxNode _value; + + internal AttributeAssignmentSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken AssignmentSign + { + get { return new SyntaxToken(this, ((Parser.Internal.AttributeAssignmentSyntaxNode)_green)._assignmentSign); } + } + + public ExpressionSyntaxNode Value + { + get + { + var red = this.GetRed(ref this._value, 1); + if (red != null) + return (ExpressionSyntaxNode)red; + + return default(ExpressionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _value, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitAttributeAssignment(this); + } + + } + + public class AttributeSyntaxNode : SyntaxNode + { + private SyntaxNode _name; + private SyntaxNode _assignment; + + internal AttributeSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public IdentifierNameSyntaxNode Name + { + get + { + var red = this.GetRed(ref this._name, 0); + if (red != null) + return (IdentifierNameSyntaxNode)red; + + return default(IdentifierNameSyntaxNode); + } + } + + public AttributeAssignmentSyntaxNode Assignment + { + get + { + var red = this.GetRed(ref this._assignment, 1); + if (red != null) + return (AttributeAssignmentSyntaxNode)red; + + return default(AttributeAssignmentSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _name, 0); + case 1: return GetRed(ref _assignment, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitAttribute(this); + } + + } + + public class AttributeListSyntaxNode : SyntaxNode + { + private SyntaxNode _nodes; + + internal AttributeListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.AttributeListSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.AttributeListSyntaxNode)_green)._closingBracket); } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _nodes, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitAttributeList(this); + } + + } + + public class MethodDefinitionSyntaxNode : MethodDeclarationSyntaxNode + { + private SyntaxNode _outputDescription; + private SyntaxNode _name; + private SyntaxNode _inputDescription; + private SyntaxNode _commas; + private SyntaxNode _body; + + internal MethodDefinitionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken FunctionKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.MethodDefinitionSyntaxNode)_green)._functionKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.MethodDefinitionSyntaxNode)_green)._endKeyword); } + } + + public FunctionOutputDescriptionSyntaxNode OutputDescription + { + get + { + var red = this.GetRed(ref this._outputDescription, 1); + if (red != null) + return (FunctionOutputDescriptionSyntaxNode)red; + + return default(FunctionOutputDescriptionSyntaxNode); + } + } + + public CompoundNameSyntaxNode Name + { + get + { + var red = this.GetRed(ref this._name, 2); + if (red != null) + return (CompoundNameSyntaxNode)red; + + return default(CompoundNameSyntaxNode); + } + } + + public FunctionInputDescriptionSyntaxNode InputDescription + { + get + { + var red = this.GetRed(ref this._inputDescription, 3); + if (red != null) + return (FunctionInputDescriptionSyntaxNode)red; + + return default(FunctionInputDescriptionSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Commas + { + get + { + var red = this.GetRed(ref this._commas, 4); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + public SyntaxNodeOrTokenList Body + { + get + { + var red = this.GetRed(ref this._body, 5); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _outputDescription, 1); + case 2: return GetRed(ref _name, 2); + case 3: return GetRed(ref _inputDescription, 3); + case 4: return GetRed(ref _commas, 4); + case 5: return GetRed(ref _body, 5); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitMethodDefinition(this); + } + + } + + public class AbstractMethodDeclarationSyntaxNode : MethodDeclarationSyntaxNode + { + private SyntaxNode _outputDescription; + private SyntaxNode _name; + private SyntaxNode _inputDescription; + + internal AbstractMethodDeclarationSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public FunctionOutputDescriptionSyntaxNode OutputDescription + { + get + { + var red = this.GetRed(ref this._outputDescription, 0); + if (red != null) + return (FunctionOutputDescriptionSyntaxNode)red; + + return default(FunctionOutputDescriptionSyntaxNode); + } + } + + public CompoundNameSyntaxNode Name + { + get + { + var red = this.GetRed(ref this._name, 1); + if (red != null) + return (CompoundNameSyntaxNode)red; + + return default(CompoundNameSyntaxNode); + } + } + + public FunctionInputDescriptionSyntaxNode InputDescription + { + get + { + var red = this.GetRed(ref this._inputDescription, 2); + if (red != null) + return (FunctionInputDescriptionSyntaxNode)red; + + return default(FunctionInputDescriptionSyntaxNode); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _outputDescription, 0); + case 1: return GetRed(ref _name, 1); + case 2: return GetRed(ref _inputDescription, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitAbstractMethodDeclaration(this); + } + + } + + public class MethodsListSyntaxNode : SyntaxNode + { + private SyntaxNode _attributes; + private SyntaxNode _methods; + + internal MethodsListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken MethodsKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.MethodsListSyntaxNode)_green)._methodsKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.MethodsListSyntaxNode)_green)._endKeyword); } + } + + public AttributeListSyntaxNode Attributes + { + get + { + var red = this.GetRed(ref this._attributes, 1); + if (red != null) + return (AttributeListSyntaxNode)red; + + return default(AttributeListSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Methods + { + get + { + var red = this.GetRed(ref this._methods, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _attributes, 1); + case 2: return GetRed(ref _methods, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitMethodsList(this); + } + + } + + public class PropertiesListSyntaxNode : SyntaxNode + { + private SyntaxNode _attributes; + private SyntaxNode _properties; + + internal PropertiesListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken PropertiesKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.PropertiesListSyntaxNode)_green)._propertiesKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.PropertiesListSyntaxNode)_green)._endKeyword); } + } + + public AttributeListSyntaxNode Attributes + { + get + { + var red = this.GetRed(ref this._attributes, 1); + if (red != null) + return (AttributeListSyntaxNode)red; + + return default(AttributeListSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Properties + { + get + { + var red = this.GetRed(ref this._properties, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _attributes, 1); + case 2: return GetRed(ref _properties, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitPropertiesList(this); + } + + } + + public class BaseClassListSyntaxNode : SyntaxNode + { + private SyntaxNode _baseClasses; + + internal BaseClassListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken LessSign + { + get { return new SyntaxToken(this, ((Parser.Internal.BaseClassListSyntaxNode)_green)._lessSign); } + } + + public SyntaxNodeOrTokenList BaseClasses + { + get + { + var red = this.GetRed(ref this._baseClasses, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _baseClasses, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitBaseClassList(this); + } + + } + + public class ClassDeclarationSyntaxNode : StatementSyntaxNode + { + private SyntaxNode _attributes; + private SyntaxNode _className; + private SyntaxNode _baseClassList; + private SyntaxNode _nodes; + + internal ClassDeclarationSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken ClassdefKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ClassDeclarationSyntaxNode)_green)._classdefKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.ClassDeclarationSyntaxNode)_green)._endKeyword); } + } + + public AttributeListSyntaxNode Attributes + { + get + { + var red = this.GetRed(ref this._attributes, 1); + if (red != null) + return (AttributeListSyntaxNode)red; + + return default(AttributeListSyntaxNode); + } + } + + public IdentifierNameSyntaxNode ClassName + { + get + { + var red = this.GetRed(ref this._className, 2); + if (red != null) + return (IdentifierNameSyntaxNode)red; + + return default(IdentifierNameSyntaxNode); + } + } + + public BaseClassListSyntaxNode BaseClassList + { + get + { + var red = this.GetRed(ref this._baseClassList, 3); + if (red != null) + return (BaseClassListSyntaxNode)red; + + return default(BaseClassListSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Nodes + { + get + { + var red = this.GetRed(ref this._nodes, 4); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _attributes, 1); + case 2: return GetRed(ref _className, 2); + case 3: return GetRed(ref _baseClassList, 3); + case 4: return GetRed(ref _nodes, 4); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitClassDeclaration(this); + } + + } + + public class EnumerationItemValueSyntaxNode : SyntaxNode + { + private SyntaxNode _values; + + internal EnumerationItemValueSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken OpeningBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.EnumerationItemValueSyntaxNode)_green)._openingBracket); } + } + + public SyntaxToken ClosingBracket + { + get { return new SyntaxToken(this, ((Parser.Internal.EnumerationItemValueSyntaxNode)_green)._closingBracket); } + } + + public SyntaxNodeOrTokenList Values + { + get + { + var red = this.GetRed(ref this._values, 1); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _values, 1); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEnumerationItemValue(this); + } + + } + + public class EnumerationItemSyntaxNode : SyntaxNode + { + private SyntaxNode _name; + private SyntaxNode _values; + private SyntaxNode _commas; + + internal EnumerationItemSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + + public IdentifierNameSyntaxNode Name + { + get + { + var red = this.GetRed(ref this._name, 0); + if (red != null) + return (IdentifierNameSyntaxNode)red; + + return default(IdentifierNameSyntaxNode); + } + } + + public EnumerationItemValueSyntaxNode Values + { + get + { + var red = this.GetRed(ref this._values, 1); + if (red != null) + return (EnumerationItemValueSyntaxNode)red; + + return default(EnumerationItemValueSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Commas + { + get + { + var red = this.GetRed(ref this._commas, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 0: return GetRed(ref _name, 0); + case 1: return GetRed(ref _values, 1); + case 2: return GetRed(ref _commas, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEnumerationItem(this); + } + + } + + public class EnumerationListSyntaxNode : SyntaxNode + { + private SyntaxNode _attributes; + private SyntaxNode _items; + + internal EnumerationListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken EnumerationKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.EnumerationListSyntaxNode)_green)._enumerationKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.EnumerationListSyntaxNode)_green)._endKeyword); } + } + + public AttributeListSyntaxNode Attributes + { + get + { + var red = this.GetRed(ref this._attributes, 1); + if (red != null) + return (AttributeListSyntaxNode)red; + + return default(AttributeListSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Items + { + get + { + var red = this.GetRed(ref this._items, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _attributes, 1); + case 2: return GetRed(ref _items, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEnumerationList(this); + } + + } + + public class EventsListSyntaxNode : SyntaxNode + { + private SyntaxNode _attributes; + private SyntaxNode _events; + + internal EventsListSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) + { + } + + public SyntaxToken EventsKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.EventsListSyntaxNode)_green)._eventsKeyword); } + } + + public SyntaxToken EndKeyword + { + get { return new SyntaxToken(this, ((Parser.Internal.EventsListSyntaxNode)_green)._endKeyword); } + } + + public AttributeListSyntaxNode Attributes + { + get + { + var red = this.GetRed(ref this._attributes, 1); + if (red != null) + return (AttributeListSyntaxNode)red; + + return default(AttributeListSyntaxNode); + } + } + + public SyntaxNodeOrTokenList Events + { + get + { + var red = this.GetRed(ref this._events, 2); + if (red != null) + return (SyntaxNodeOrTokenList)red; + + return default(SyntaxNodeOrTokenList); + } + } + + internal override SyntaxNode GetNode(int i) + { + switch (i) + { + case 1: return GetRed(ref _attributes, 1); + case 2: return GetRed(ref _events, 2); + default: return null; + } + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitEventsList(this); + } + + } +} diff --git a/Parser/SyntaxNode.cs b/Parser/SyntaxNode.cs index f6476e8..4d63a1b 100644 --- a/Parser/SyntaxNode.cs +++ b/Parser/SyntaxNode.cs @@ -1,750 +1,100 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; -using Lexer; namespace Parser { - public class SyntaxNode + public abstract class SyntaxNode { - public SyntaxNode Parent { get; set; } - public List Children { get; } - - public virtual IEnumerable ChildTokens => - Children.SelectMany(c => c.ChildTokens); - - public SyntaxNode(List children) + private readonly SyntaxNode _parent; + internal readonly Internal.GreenNode _green; + internal SyntaxNode(SyntaxNode parent, Internal.GreenNode green) { - Children = children; - if (children != null) - { - foreach (var child in children) - { - child.Parent = this; - } - } + _parent = parent; + _green = green; } - public virtual string FullText => - string.Join("", Children.Select(c => c.FullText)); + public TokenKind Kind => _green.Kind; - public List TrailingTrivia - + public SyntaxNode Parent => _parent; + + public ChildNodesAndTokensList GetChildNodesAndTokens() + { + return new ChildNodesAndTokensList(this); + } + + internal abstract SyntaxNode GetNode(int index); + + internal SyntaxNode GetRed(ref SyntaxNode field, int slot) + { + if (field == null) + { + var green = _green.GetSlot(slot); + if (green != null) + { + field = green.CreateRed(this); + } + } + + return field; + } + + public override string ToString() + { + return Text; + } + + public virtual string Text => _green.Text; + + public virtual string FullText => _green.FullText; + + public virtual IReadOnlyList LeadingTrivia { get { - if (ChildTokens.Any()) - { - return ChildTokens.Last().TrailingTrivia; - } - else - { - return new List(); - } + var p = Parent; + return _green.LeadingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); } } + public virtual IReadOnlyList TrailingTrivia + { + get + { + var p = Parent; + return _green.TrailingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); + } + } + + public abstract void Accept(SyntaxVisitor visitor); } - - public class TokenNode : SyntaxNode + + public abstract class StatementSyntaxNode : SyntaxNode { - public Token Token { get; } - - public TokenNode(Token token) - : base(null) + internal StatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - } - - public class OutputIdentifierNode : SyntaxNode - { - public OutputIdentifierNode(List children) : base(children) - { - } - } - - public class FunctionOutputDescriptionNode : SyntaxNode - { - public List Outputs { get; } - public TokenNode EqualitySign { get; } - - public FunctionOutputDescriptionNode( - List children, - List outputs, - TokenNode equalitySign) : base(children) - { - Outputs = outputs; - EqualitySign = equalitySign; - } - } - - public class FunctionInputDescriptionNode : SyntaxNode - { - public TokenNode OpeningBracket { get; } - public ParameterListNode Parameters { get; } - public TokenNode ClosingBracket { get; } - public FunctionInputDescriptionNode( - List children, - TokenNode openingBracket, - ParameterListNode parameters, - TokenNode closingBracket) : base(children) - { - OpeningBracket = openingBracket; - Parameters = parameters; - ClosingBracket = closingBracket; - } - } - - public class FunctionDeclarationNode : StatementNode - { - public TokenNode Token { get; } - public FunctionOutputDescriptionNode OutputDescription { get; } - public TokenNode Name { get; } - public FunctionInputDescriptionNode InputDescription { get; } - public StatementListNode Body { get; } - public TokenNode End { get; } - - public FunctionDeclarationNode( - List children, - TokenNode token, - FunctionOutputDescriptionNode outputDescription, - TokenNode name, - FunctionInputDescriptionNode inputDescription, - StatementListNode body, - TokenNode end, - TokenNode semicolonOrComma - ) : base(children, semicolonOrComma) - { - Token = token; - OutputDescription = outputDescription; - Name = name; - InputDescription = inputDescription; - Body = body; - End = end; - } - } - - public class StatementListNode : SyntaxNode - { - public List Statements => Children; - - public StatementListNode(List children) : base(children) - { - } - } - - public class ParameterListNode : SyntaxNode - { - public List Parameters { get; } - - public ParameterListNode(List children, List parameters) : base(children) - { - Parameters = parameters; - } - } - - public class ExpressionNode : SyntaxNode - { - public ExpressionNode(List children) : base(children) - { - } - } - - public class AssignmentExpressionNode : ExpressionNode - { - public ExpressionNode Lhs { get; } - public TokenNode Assignment { get; } - public ExpressionNode Rhs { get; } - - public AssignmentExpressionNode( - List children, - ExpressionNode lhs, - TokenNode assignment, - ExpressionNode rhs) : base(children) - { - Lhs = lhs; - Assignment = assignment; - Rhs = rhs; - } - } - - public class UnaryPrefixOperationExpressionNode : ExpressionNode - { - public TokenNode Operation { get; } - public ExpressionNode Operand { get; } - - public UnaryPrefixOperationExpressionNode( - List children, - TokenNode operation, - ExpressionNode operand) : base(children) - { - Operation = operation; - Operand = operand; - } - } - - public class UnaryPostfixOperationExpressionNode : ExpressionNode - { - public ExpressionNode Operand { get; } - public TokenNode Operation { get; } - public UnaryPostfixOperationExpressionNode( - List children, - ExpressionNode operand, - TokenNode operation) : base(children) - { - Operand = operand; - Operation = operation; - } - } - - public class BinaryOperationExpressionNode : ExpressionNode - { - public ExpressionNode Lhs { get; } - public TokenNode Operation { get; } - public ExpressionNode Rhs { get; } - - public BinaryOperationExpressionNode( - List children, - ExpressionNode lhs, - TokenNode operation, - ExpressionNode rhs) : base(children) - { - Lhs = lhs; - Operation = operation; - Rhs = rhs; - } - } - - public class SwitchStatementNode : StatementNode - { - public TokenNode SwitchKeyword { get; } - public ExpressionNode SwitchExpression { get; } - public List OptionalCommasAfterExpression { get; } - public List Cases { get; } - public TokenNode EndKeyword { get; } - - public SwitchStatementNode( - List children, - TokenNode switchKeyword, - ExpressionNode switchExpression, - List cases, - TokenNode endKeyword, - TokenNode semicolonOrComma, - List optionalCommasAfterExpression = null - ) : base(children, semicolonOrComma) - { - SwitchKeyword = switchKeyword; - SwitchExpression = switchExpression; - OptionalCommasAfterExpression = optionalCommasAfterExpression; - Cases = cases; - EndKeyword = endKeyword; - } - } - - public class SwitchCaseNode : SyntaxNode - { - public TokenNode CaseKeyword { get; } - public ExpressionNode CaseIdentifier { get; } - public List OptionalCommasAfterIdentifier { get; } - public StatementListNode StatementList { get; } - - public SwitchCaseNode( - List children, - TokenNode caseKeyword, - ExpressionNode caseIdentifier, - StatementListNode statementList, - List optionalCommasAfterIdentifier = null - ) : base(children) - { - CaseKeyword = caseKeyword; - CaseIdentifier = caseIdentifier; - StatementList = statementList; - OptionalCommasAfterIdentifier = optionalCommasAfterIdentifier; - } - } - - public class IdentifierNameNode : ExpressionNode - { - public Token Token { get; } - - public IdentifierNameNode(Token token) - : base(null) - { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - - } - - public class NumberLiteralNode : ExpressionNode - { - public Token Token { get; } - - public NumberLiteralNode(Token token) : base(null) - { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - - } - - public class StringLiteralNode : ExpressionNode - { - public Token Token { get; } - - public StringLiteralNode(Token token) : base(null) - { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - - } - - public class DoubleQuotedStringLiteralNode : ExpressionNode - { - public Token Token { get; } - - public DoubleQuotedStringLiteralNode(Token token) : base(null) - { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - } - - public class UnquotedStringLiteralNode : ExpressionNode - { - public Token Token { get; } - - public UnquotedStringLiteralNode(Token token) : base(null) - { - Token = token; - } - - public override string FullText => Token.FullText; - - public override IEnumerable ChildTokens - { - get { yield return Token; } - } - - } - - public class StatementNode : SyntaxNode - { - public TokenNode SemicolonOrComma { get; set; } - - public StatementNode(List children, TokenNode semicolonOrComma = null) : base(children) - { - SemicolonOrComma = semicolonOrComma; - } - } - - public class ExpressionStatementNode : StatementNode - { - public ExpressionNode Expression { get; } - - public ExpressionStatementNode(List children, ExpressionNode expression, TokenNode semicolonOrComma) - : base(children, semicolonOrComma) - { - Expression = expression; - } - } - - public class CellArrayElementAccessExpressionNode : ExpressionNode - { - public ExpressionNode CellArray { get; } - public TokenNode OpeningBrace { get; } - public ArrayElementListNode Indices { get; } - public TokenNode ClosingBrace { get; } - - public CellArrayElementAccessExpressionNode( - List children, - ExpressionNode cellArray, - TokenNode openingBrace, - ArrayElementListNode indices, - TokenNode closingBrace) : base(children) - { - CellArray = cellArray; - OpeningBrace = openingBrace; - Indices = indices; - ClosingBrace = closingBrace; - } - } - - public class FunctionCallExpressionNode : ExpressionNode - { - public ExpressionNode FunctionName { get; } - public TokenNode OpeningBracket { get; } - public FunctionCallParameterListNode Parameters { get; } - public TokenNode ClosingBracket { get; } - - public FunctionCallExpressionNode( - List children, - ExpressionNode functionName, - TokenNode openingBracket, - FunctionCallParameterListNode parameters, - TokenNode closingBracket) : base(children) - { - FunctionName = functionName; - OpeningBracket = openingBracket; - Parameters = parameters; - ClosingBracket = closingBracket; - } - } - - public class FunctionCallParameterListNode : SyntaxNode - { - public List Parameters; - - public FunctionCallParameterListNode( - List children, - List parameters) : base(children) - { - Parameters = parameters; } } - public class ArrayElementListNode : SyntaxNode + public abstract class ExpressionSyntaxNode : SyntaxNode { - public List Elements; - - public ArrayElementListNode( - List children, - List elements) : base(children) - { - Elements = elements; - } - } - - public class ArrayLiteralExpressionNode : ExpressionNode - { - public TokenNode OpeningSquareBracket { get; } - public ArrayElementListNode Elements { get; } - public TokenNode ClosingSquareBracket { get; } - - public ArrayLiteralExpressionNode( - List children, - TokenNode openingSquareBracket, - ArrayElementListNode elements, - TokenNode closingSquareBracket) : base(children) - { - OpeningSquareBracket = openingSquareBracket; - Elements = elements; - ClosingSquareBracket = closingSquareBracket; - } - } - - public class CellArrayLiteralExpressionNode : ExpressionNode - { - public TokenNode OpeningBrace { get; } - public ArrayElementListNode Elements { get; } - public TokenNode ClosingBrace { get; } - - public CellArrayLiteralExpressionNode( - List children, - TokenNode openingBrace, - ArrayElementListNode elements, - TokenNode closingBrace) : base(children) - { - OpeningBrace = openingBrace; - Elements = elements; - ClosingBrace = closingBrace; - } - } - - public class EmptyExpressionNode : ExpressionNode - { - public EmptyExpressionNode() : base(null) - { - } - - public override IEnumerable ChildTokens - { - get { yield break; } - } - - public override string FullText => ""; - } - - public class CompoundNameNode : ExpressionNode - { - public List Names; - - public CompoundNameNode( - List children, - List names - ) : base(children) - { - Names = names; - } - } - - public class MemberAccessNode : ExpressionNode - { - public SyntaxNode LeftOperand { get; } - public TokenNode Dot { get; } - public SyntaxNode RightOperand { get; } - - public MemberAccessNode( - List children, - SyntaxNode leftOperand, - TokenNode dot, - SyntaxNode rightOperand) : base(children) - { - LeftOperand = leftOperand; - Dot = dot; - RightOperand = rightOperand; - } - } - - public class WhileStatementNode : StatementNode - { - public TokenNode WhileKeyword { get; } - public ExpressionNode Condition { get; } - public List OptionalCommasAfterCondition { get; } - public StatementListNode Body { get; } - public TokenNode End { get; } - - public WhileStatementNode( - List children, - TokenNode whileKeyword, - ExpressionNode condition, - List optionalCommasAfterCondition, - StatementListNode body, - TokenNode end, - TokenNode semicolonOrComma - ) : base(children, semicolonOrComma) - { - WhileKeyword = whileKeyword; - Condition = condition; - OptionalCommasAfterCondition = optionalCommasAfterCondition; - Body = body; - End = end; - } - } - - public class IfStatementNode : StatementNode - { - public TokenNode IfKeyword { get; } - public ExpressionNode Condition { get; } - public List OptionalCommasAfterCondition { get; } - public StatementListNode Body { get; } - public TokenNode ElseKeyword { get; } - public StatementListNode ElseBody { get; } - public TokenNode EndKeyword { get; } - - public IfStatementNode( - List children, - TokenNode ifKeyword, - ExpressionNode condition, - List optionalCommasAfterCondition, - StatementListNode body, - TokenNode elseKeyword, - StatementListNode elseBody, - TokenNode endKeyword, - TokenNode possibleSemicolonOrComma - ) : base(children, possibleSemicolonOrComma) - { - IfKeyword = ifKeyword; - Condition = condition; - OptionalCommasAfterCondition = optionalCommasAfterCondition; - Body = body; - ElseKeyword = elseKeyword; - ElseBody = elseBody; - EndKeyword = endKeyword; - } - } - - public class ParenthesizedExpressionNode : ExpressionNode - { - public TokenNode OpenParen { get; } - public ExpressionNode Expression { get; } - public TokenNode CloseParen { get; } - - public ParenthesizedExpressionNode( - List children, - TokenNode openParen, - ExpressionNode expression, - TokenNode closeParen) : base(children) - { - OpenParen = openParen; - Expression = expression; - CloseParen = closeParen; - } - } - - public class ForStatementNode : StatementNode - { - public TokenNode ForKeyword { get; } - public AssignmentExpressionNode ForAssignment { get; } - public List OptionalCommasAfterAssignment { get; } - public StatementListNode Body { get; } - public TokenNode EndKeyword { get; } - - public ForStatementNode( - List children, - TokenNode forKeyword, - AssignmentExpressionNode forAssignment, - StatementListNode body, - TokenNode endKeyword, - List optionalCommasAfterAssignment - ) : base(children) - { - ForKeyword = forKeyword; - ForAssignment = forAssignment; - Body = body; - EndKeyword = endKeyword; - OptionalCommasAfterAssignment = optionalCommasAfterAssignment; - } - } - - public class IndirectMemberAccessNode : ExpressionNode - { - public TokenNode OpeningBracket { get; } - public ExpressionNode IndirectMemberName { get; } - public TokenNode ClosingBracket { get; } - - public IndirectMemberAccessNode( - List children, - TokenNode openingBracket, - ExpressionNode indirectMemberName, - TokenNode closingBracket) : base(children) - { - OpeningBracket = openingBracket; - IndirectMemberName = indirectMemberName; - ClosingBracket = closingBracket; - } - } - - public abstract class FunctionHandleNode : ExpressionNode - { - protected FunctionHandleNode( - List children) : base(children) + internal ExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) { } } - public class NamedFunctionHandleNode : FunctionHandleNode + public abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode { - public TokenNode AtSign { get; } - public CompoundNameNode FunctionName { get; } - - public NamedFunctionHandleNode( - List children, - TokenNode atSign, - CompoundNameNode functionName) : base(children) + internal FunctionHandleSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) { - AtSign = atSign; - FunctionName = functionName; } } - public class LambdaNode : FunctionHandleNode + public abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode { - public TokenNode AtSign { get; } - public FunctionInputDescriptionNode Input { get; } - public ExpressionNode Body { get; } - - public LambdaNode( - List children, - TokenNode atSign, - FunctionInputDescriptionNode input, - ExpressionNode body) : base(children) + internal MethodDeclarationSyntaxNode(SyntaxNode parent, Internal.GreenNode green) : base(parent, green) { - AtSign = atSign; - Input = input; - Body = body; } } - public class TryCatchStatementNode : StatementNode - { - public TokenNode TryKeyword { get; } - public StatementListNode TryBody { get; } - public TokenNode CatchKeyword { get; } - public StatementListNode CatchBody { get; } - public TokenNode EndKeyword { get; } - - public TryCatchStatementNode( - List children, - TokenNode tryKeyword, - StatementListNode tryBody, - TokenNode catchKeyword, - StatementListNode catchBody, - TokenNode endKeyword - ) : base(children) - { - TryKeyword = tryKeyword; - TryBody = tryBody; - CatchKeyword = catchKeyword; - CatchBody = catchBody; - EndKeyword = endKeyword; - } - } - - public class CommandExpressionNode : ExpressionNode - { - public IdentifierNameNode CommandName { get; } - public List Arguments { get; } - - public CommandExpressionNode( - List children, - IdentifierNameNode commandName, - List arguments - ) : base(children) - { - CommandName = commandName; - Arguments = arguments; - } - } - - public class BaseClassInvokationNode : ExpressionNode - { - public IdentifierNameNode MethodName { get; } - public TokenNode AtToken { get; } - public ExpressionNode BaseClassNameAndArguments { get; } - - public BaseClassInvokationNode( - List children, - IdentifierNameNode methodName, - TokenNode atToken, - ExpressionNode baseClassNameAndArguments - ) : base(children) - { - MethodName = methodName; - AtToken = atToken; - BaseClassNameAndArguments = baseClassNameAndArguments; - } - } } \ No newline at end of file diff --git a/Parser/SyntaxNodeOrToken.cs b/Parser/SyntaxNodeOrToken.cs new file mode 100644 index 0000000..17a54a6 --- /dev/null +++ b/Parser/SyntaxNodeOrToken.cs @@ -0,0 +1,55 @@ +namespace Parser +{ + public struct SyntaxNodeOrToken + { + private readonly Internal.GreenNode _token; + private readonly SyntaxNode _nodeOrParent; + private readonly bool _isToken; + + internal SyntaxNodeOrToken(SyntaxNode node) + { + _token = null; + _nodeOrParent = node; + _isToken = false; + } + + internal SyntaxNodeOrToken(SyntaxNode parent, Internal.GreenNode token) + { + _token = token; + _nodeOrParent = parent; + _isToken = true; + } + + public bool IsToken => _isToken; + public bool IsNode => !IsToken; + + public SyntaxNode AsNode() + { + if (_isToken) + { + return default(SyntaxNode); + } + + return _nodeOrParent; + } + + public SyntaxToken AsToken() + { + if (!_isToken) + { + return default(SyntaxToken); + } + return new SyntaxToken(_nodeOrParent, _token); + } + + public static implicit operator SyntaxNodeOrToken(SyntaxToken token) + { + return new SyntaxNodeOrToken(token.Parent, token.Token); + } + + public static implicit operator SyntaxNodeOrToken(SyntaxNode node) + { + return new SyntaxNodeOrToken(node); + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxNodeOrTokenList.cs b/Parser/SyntaxNodeOrTokenList.cs new file mode 100644 index 0000000..7e6fdef --- /dev/null +++ b/Parser/SyntaxNodeOrTokenList.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Parser.Internal; + +namespace Parser +{ + public class SyntaxNodeOrTokenList : SyntaxNode, IReadOnlyCollection + { + internal SyntaxNodeOrTokenList(SyntaxNode parent, GreenNode green) : base(parent, green) + { + } + + public SyntaxNodeOrToken this[int index] + { + get + { + if (_green != null && index < _green.Slots) + { + var green = _green.GetSlot(index); + if (green is Internal.SyntaxToken) + { + return new SyntaxToken(this, green); + } + else + { + return green.CreateRed(this); + } + } + throw new ArgumentOutOfRangeException(); + } + } + + internal class Enumerator : IEnumerator + { + private int _index; + private readonly SyntaxNodeOrTokenList _list; + + internal Enumerator(SyntaxNodeOrTokenList list) + { + _index = -1; + _list = list; + } + + + public bool MoveNext() + { + var newIndex = _index + 1; + if (newIndex < _list.Count) + { + _index = newIndex; + return true; + } + + return false; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public SyntaxNodeOrToken Current => _list[_index]; + + object IEnumerator.Current => Current; + + public void Dispose() + { + } + } + + public IEnumerator GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int Count => _green.Slots; + + internal override SyntaxNode GetNode(int index) + { + if (index < _green.Slots) + { + var node = this[index]; + if (node.IsNode) + { + return node.AsNode(); + } + } + + return null; + } + + public override void Accept(SyntaxVisitor visitor) + { + visitor.VisitList(this); + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxToken.cs b/Parser/SyntaxToken.cs new file mode 100644 index 0000000..5e98c11 --- /dev/null +++ b/Parser/SyntaxToken.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Parser +{ + public struct SyntaxToken : IEquatable + { + private readonly SyntaxNode _parent; + private readonly Internal.GreenNode _token; + + public TokenKind Kind => _token.Kind; + + public override string ToString() + { + return _token.ToString(); + } + + internal SyntaxToken(SyntaxNode parent, Internal.GreenNode token) + { + _parent = parent; + _token = token ?? throw new ArgumentNullException(nameof(token)); + } + + public SyntaxNode Parent => _parent; + internal Internal.GreenNode Token => _token; + + public bool Equals(SyntaxToken other) + { + return Equals(_parent, other._parent) && Equals(_token, other._token); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is SyntaxToken token && Equals(token); + } + + public override int GetHashCode() + { + unchecked + { + return ((_parent != null ? _parent.GetHashCode() : 0) * 397) ^ (_token != null ? _token.GetHashCode() : 0); + } + } + + public static bool operator ==(SyntaxToken left, SyntaxToken right) + { + return left.Equals(right); + } + + public static bool operator !=(SyntaxToken left, SyntaxToken right) + { + return !left.Equals(right); + } + + public string Text => _token.Text; + public string FullText => _token.FullText; + public bool IsMissing => _token.IsMissing; + + public IReadOnlyList LeadingTrivia + { + get + { + var p = _parent; + return _token.LeadingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); + } + } + + public IReadOnlyList TrailingTrivia + { + get + { + var p = _parent; + return _token.TrailingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); + } + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxTrivia.cs b/Parser/SyntaxTrivia.cs new file mode 100644 index 0000000..0b4a8c0 --- /dev/null +++ b/Parser/SyntaxTrivia.cs @@ -0,0 +1,57 @@ +using System; + +namespace Parser +{ + public struct SyntaxTrivia : IEquatable + { + private readonly SyntaxNode _parent; + private readonly Internal.GreenNode _trivia; + + internal SyntaxTrivia(SyntaxNode parent, Internal.GreenNode trivia) + { + _parent = parent; + _trivia = trivia; + } + + public SyntaxNode Parent => _parent; + + internal Internal.GreenNode Trivia => _trivia; + + public bool Equals(SyntaxTrivia other) + { + return Equals(_parent, other._parent) && Equals(_trivia, other._trivia); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is SyntaxTrivia trivia && Equals(trivia); + } + + public override int GetHashCode() + { + unchecked + { + return ((_parent != null ? _parent.GetHashCode() : 0) * 397) ^ (_trivia != null ? _trivia.GetHashCode() : 0); + } + } + + public static bool operator ==(SyntaxTrivia left, SyntaxTrivia right) + { + return left.Equals(right); + } + + public static bool operator !=(SyntaxTrivia left, SyntaxTrivia right) + { + return !left.Equals(right); + } + + public string Text => _trivia.Text; + public string FullText => _trivia.FullText; + + public override string ToString() + { + return Text; + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxVisitor.Generated.cs b/Parser/SyntaxVisitor.Generated.cs new file mode 100644 index 0000000..41e133b --- /dev/null +++ b/Parser/SyntaxVisitor.Generated.cs @@ -0,0 +1,255 @@ +namespace Parser +{ + public partial class SyntaxVisitor + { + public virtual void VisitFile(FileSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitFunctionOutputDescription(FunctionOutputDescriptionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitFunctionInputDescription(FunctionInputDescriptionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitSwitchStatement(SwitchStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitSwitchCase(SwitchCaseSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitWhileStatement(WhileStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitElseifClause(ElseifClause node) + { + DefaultVisit(node); + } + + public virtual void VisitElseClause(ElseClause node) + { + DefaultVisit(node); + } + + public virtual void VisitIfStatement(IfStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitForStatement(ForStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitAssignmentExpression(AssignmentExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitCatchClause(CatchClauseSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitTryCatchStatement(TryCatchStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitExpressionStatement(ExpressionStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEmptyStatement(EmptyStatementSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEmptyExpression(EmptyExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitCompoundName(CompoundNameSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitNamedFunctionHandle(NamedFunctionHandleSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitLambda(LambdaSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitIdentifierName(IdentifierNameSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitNumberLiteral(NumberLiteralSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitStringLiteral(StringLiteralSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitDoubleQuotedStringLiteral(DoubleQuotedStringLiteralSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitUnquotedStringLiteral(UnquotedStringLiteralSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitArrayLiteralExpression(ArrayLiteralExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitCellArrayLiteralExpression(CellArrayLiteralExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitParenthesizedExpression(ParenthesizedExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitFunctionCallExpression(FunctionCallExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitMemberAccess(MemberAccessSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitUnaryPostixOperationExpression(UnaryPostixOperationExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitIndirectMemberAccess(IndirectMemberAccessSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitCommandExpression(CommandExpressionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitBaseClassInvokation(BaseClassInvokationSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitAttributeAssignment(AttributeAssignmentSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitAttribute(AttributeSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitAttributeList(AttributeListSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitMethodDefinition(MethodDefinitionSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitAbstractMethodDeclaration(AbstractMethodDeclarationSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitMethodsList(MethodsListSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitPropertiesList(PropertiesListSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitBaseClassList(BaseClassListSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitClassDeclaration(ClassDeclarationSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEnumerationItemValue(EnumerationItemValueSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEnumerationItem(EnumerationItemSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEnumerationList(EnumerationListSyntaxNode node) + { + DefaultVisit(node); + } + + public virtual void VisitEventsList(EventsListSyntaxNode node) + { + DefaultVisit(node); + } + } +}; \ No newline at end of file diff --git a/Parser/SyntaxVisitor.cs b/Parser/SyntaxVisitor.cs new file mode 100644 index 0000000..fc81561 --- /dev/null +++ b/Parser/SyntaxVisitor.cs @@ -0,0 +1,19 @@ +namespace Parser +{ + public abstract partial class SyntaxVisitor + { + public virtual void Visit(SyntaxNode node) + { + node?.Accept(this); + } + + public virtual void DefaultVisit(SyntaxNode node) + { + } + + public virtual void VisitList(SyntaxNodeOrTokenList list) + { + DefaultVisit(list); + } + } +} \ No newline at end of file diff --git a/Parser/SyntaxWalker.cs b/Parser/SyntaxWalker.cs new file mode 100644 index 0000000..f565b14 --- /dev/null +++ b/Parser/SyntaxWalker.cs @@ -0,0 +1,24 @@ +namespace Parser +{ + public abstract class SyntaxWalker : SyntaxVisitor + { + public override void DefaultVisit(SyntaxNode node) + { + foreach (var nodeOrToken in node.GetChildNodesAndTokens()) + { + if (nodeOrToken.IsNode) + { + Visit(nodeOrToken.AsNode()); + } + else + { + VisitToken(nodeOrToken.AsToken()); + } + } + } + + public virtual void VisitToken(SyntaxToken token) + { + } + } +} \ No newline at end of file diff --git a/Lexer/TextWindow.cs b/Parser/TextWindow.cs similarity index 90% rename from Lexer/TextWindow.cs rename to Parser/TextWindow.cs index 679a172..befc40f 100644 --- a/Lexer/TextWindow.cs +++ b/Parser/TextWindow.cs @@ -1,19 +1,19 @@ -namespace Lexer +namespace Parser { public class TextWindow : ITextWindow { protected readonly string Text; protected int Offset { get; set; } - private PositionInsideFile _position; - public IPosition Position => _position; + private Position _position; + public Position Position => _position; public TextWindow(string text, string fileName = null) { Text = text; Offset = 0; - _position = new PositionInsideFile + _position = new Position { - File = fileName, + FileName = fileName, Line = 0, Column = 0 }; diff --git a/Lexer/TextWindowWithNull.cs b/Parser/TextWindowWithNull.cs similarity index 95% rename from Lexer/TextWindowWithNull.cs rename to Parser/TextWindowWithNull.cs index 38e1411..47ce283 100644 --- a/Lexer/TextWindowWithNull.cs +++ b/Parser/TextWindowWithNull.cs @@ -1,4 +1,4 @@ -namespace Lexer +namespace Parser { public class TextWindowWithNull : TextWindow { diff --git a/Parser/TokenKind.cs b/Parser/TokenKind.cs new file mode 100644 index 0000000..f9696d3 --- /dev/null +++ b/Parser/TokenKind.cs @@ -0,0 +1,115 @@ +namespace Parser +{ + public enum TokenKind + { + None = 0, + EndOfFile = 1, + Identifier = 2, + NumberLiteral = 3, + StringLiteral = 4, + DoubleQuotedStringLiteral = 5, + UnquotedStringLiteral = 6, + + // trivia + + Whitespace = 10, + Newline = 11, + Comment = 12, + MultilineComment = 13, + + Assignment = 20, + Equality = 21, + Inequality = 22, + LogicalAnd = 23, + LogicalOr = 24, + BitwiseAnd = 25, + BitwiseOr = 26, + Less = 27, + LessOrEqual = 28, + Greater = 29, + GreaterOrEqual = 30, + Not = 31, + Plus = 32, + Minus = 33, + Multiply = 34, + Divide = 35, + Power = 36, + Backslash = 37, + Transpose = 38, + DotMultiply = 39, + DotDivide = 40, + DotPower = 41, + DotBackslash = 42, + DotTranspose = 43, + At = 44, + Colon = 45, + QuestionMark = 46, + Comma = 47, + Semicolon = 48, + OpeningBrace = 49, + ClosingBrace = 50, + OpeningSquareBracket = 51, + ClosingSquareBracket = 52, + OpeningBracket = 53, + ClosingBracket = 54, + Dot = 55, + DotDotDot = 56, + // unary tokens are not recognized during lexing; they are contextually recognized while parsing. + UnaryPlus = 57, + UnaryMinus = 58, + UnaryNot = 59, + UnaryQuestionMark = 60, + // syntax nodes + File = 100, + List, + FunctionDeclaration, + FunctionInputDescription, + FunctionOutputDescription, + SwitchStatement, + SwitchCase, + WhileStatement, + IfStatement, + ElseifClause, + ElseClause, + ForStatement, + AssignmentExpression, + CatchClause, + TryCatchStatement, + ExpressionStatement, + EmptyStatement, + EmptyExpression, + UnaryPrefixOperationExpression, + CompoundName, + NamedFunctionHandle, + Lambda, + BinaryOperation, + IdentifierName, + NumberLiteralExpression, + StringLiteralExpression, + DoubleQuotedStringLiteralExpression, + UnquotedStringLiteralExpression, + ArrayLiteralExpression, + CellArrayLiteralExpression, + ParenthesizedExpression, + CellArrayElementAccess, + FunctionCall, + MemberAccess, + UnaryPostfixOperationExpression, + IndirectMemberAccess, + Command, + ClassInvokation, + AttributeAssignment, + Attribute, + AttributeList, + MethodDefinition, + MethodsList, + PropertiesList, + BaseClassList, + ClassDeclaration, + EnumerationItemValue, + EnumerationItem, + EnumerationList, + AbstractMethodDeclaration, + EventsList, + } +} \ No newline at end of file diff --git a/Semantics/ClassContext.cs b/Semantics/ClassContext.cs new file mode 100644 index 0000000..c2fac42 --- /dev/null +++ b/Semantics/ClassContext.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Semantics +{ + internal class ClassContext + { + public string Path { get; } + public Dictionary SubClasses { get; } + public Dictionary Methods { get; } + public Dictionary PrivateMethods { get; } + + public ClassContext( + string path, + Dictionary subClasses, + Dictionary methods, + Dictionary privateMethods) + { + Path = path; + SubClasses = subClasses; + Methods = methods; + PrivateMethods = privateMethods; + } + + public ClassContext(string path) + { + Path = path; + SubClasses = new Dictionary(); + Methods = new Dictionary(); + PrivateMethods = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/Semantics/Context.cs b/Semantics/Context.cs new file mode 100644 index 0000000..21be9e8 --- /dev/null +++ b/Semantics/Context.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Semantics +{ + public class Context + { + internal PackageContext Root { get; } + + public Context() + { + Root = new PackageContext( + null, + new Dictionary(), + new Dictionary(), + new Dictionary()); + } + + public bool FindFunction(string name) + { + return Root.Functions.ContainsKey(name); + } + + private void ScanFunction(PackageContext context, string fileName) + { + var functionName = Path.GetFileNameWithoutExtension(fileName); + context.Functions[functionName] = new FunctionContext(fileName); + } + + private void ScanMethod(ClassContext context, string fileName) + { + var methodName = Path.GetFileNameWithoutExtension(fileName); + context.Methods[methodName] = new FunctionContext(fileName); + } + + private void ScanPrivateMethod(ClassContext context, string fileName) + { + var methodName = Path.GetFileNameWithoutExtension(fileName); + context.PrivateMethods[methodName] = new FunctionContext(fileName); + } + + private string GetPackageNameFromFolder(string folderName) + { + return folderName.StartsWith('+') ? folderName.Substring(1, folderName.Length - 1) : null; + } + + private string GetClassNameFromFolder(string folderName) + { + return folderName.StartsWith('@') ? folderName.Substring(1, folderName.Length - 1) : null; + } + + private void ScanPrivateDirectory(ClassContext currentContext, string directory) + { + var files = Directory.GetFiles(directory, "*.m"); + foreach (var fileName in files) + { + ScanPrivateMethod(currentContext, fileName); + } + + var subDirectories = Directory.GetDirectories(directory); + foreach (var subDirectory in subDirectories) + { + Console.WriteLine($"A FOLDER INSIDE A PRIVATE SUBFOLDER WHAT TO DO? {subDirectory}"); + } + + } + + private void ScanClassDirectory(ClassContext currentContext, string directory) + { + var files = Directory.GetFiles(directory, "*.m"); + foreach (var fileName in files) + { + ScanMethod(currentContext, fileName); + } + + var subDirectories = Directory.GetDirectories(directory); + foreach (var subDirectory in subDirectories) + { + var lastName = subDirectory.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last(); + if (lastName == "private") + { + ScanPrivateDirectory(currentContext, subDirectory); + continue; + } + var packageName = GetPackageNameFromFolder(lastName); + if (packageName != null) + { + Console.WriteLine($"A PACKAGE INSIDE A CLASS WHAT TO DO? {subDirectory}"); + continue; + } + + var className = GetClassNameFromFolder(lastName); + if (className != null) + { + currentContext.SubClasses[className] = new ClassContext(className); + ScanClassDirectory(currentContext.SubClasses[className], subDirectory); + continue; + } + ScanClassDirectory(currentContext, subDirectory); // Should this really work? + } + } + + private void ScanDirectory(PackageContext currentContext, string directory) + { + var files = Directory.GetFiles(directory, "*.m"); + foreach (var fileName in files) + { + ScanFunction(currentContext, fileName); + } + + var subDirectories = Directory.GetDirectories(directory); + foreach (var subDirectory in subDirectories) + { + var lastName = subDirectory.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last(); + var packageName = GetPackageNameFromFolder(lastName); + if (packageName != null) + { + currentContext.SubPackages[packageName] = new PackageContext(packageName); + ScanDirectory(currentContext.SubPackages[packageName], subDirectory); + continue; + } + + var className = GetClassNameFromFolder(lastName); + if (className != null) + { + currentContext.Classes[className] = new ClassContext(className); + ScanClassDirectory(currentContext.Classes[className], subDirectory); + continue; + } + ScanDirectory(currentContext, subDirectory); + } + } + + public void ScanPath(string path) + { + ScanDirectory(Root, path); + } + } +} \ No newline at end of file diff --git a/Semantics/FunctionContext.cs b/Semantics/FunctionContext.cs new file mode 100644 index 0000000..be0730a --- /dev/null +++ b/Semantics/FunctionContext.cs @@ -0,0 +1,12 @@ +namespace Semantics +{ + public class FunctionContext + { + public string FileName { get; } + + public FunctionContext(string fileName) + { + FileName = fileName; + } + } +} \ No newline at end of file diff --git a/Semantics/GetClass.cs b/Semantics/GetClass.cs new file mode 100644 index 0000000..d9c31c1 --- /dev/null +++ b/Semantics/GetClass.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Parser; + +namespace Semantics +{ + public class GetClass + { + private static MMethod MethodFromDefinition(MethodDefinitionSyntaxNode methodDefinition) + { + var name = methodDefinition.Name.Text; + var description = ""; + description += string.Join("", methodDefinition.LeadingTrivia.Select(x => x.FullText)); + if (methodDefinition.Body == null) + { + description += string.Join("", methodDefinition.EndKeyword.LeadingTrivia.Select(x => x.FullText)); + } + else + { + description += string.Join("", methodDefinition.Body.LeadingTrivia.Select(x => x.FullText)); + } + + return new MMethod(name, description); + } + + private static MMethod MethodFromDeclaration(AbstractMethodDeclarationSyntaxNode methodDeclaration) + { + var name = methodDeclaration.Name.Text; + var description = ""; + description += string.Join("", methodDeclaration.LeadingTrivia.Select(x => x.FullText)); + return new MMethod(name, description); + } + + private static List MethodsFromList(MethodsListSyntaxNode methodsList) + { + var result = new List(); + foreach (var method in methodsList.Methods) + { + if (method.IsToken) + { + continue; + } + + if (method.AsNode() is MethodDefinitionSyntaxNode methodDefinition) + { + result.Add(MethodFromDefinition(methodDefinition)); + } + + if (method.AsNode() is AbstractMethodDeclarationSyntaxNode methodDeclaration) + { + result.Add(MethodFromDeclaration(methodDeclaration)); + } + } + + return result; + } + + public static MClass FromTree(FileSyntaxNode tree, string fileName) + { + var classDeclaration = tree.StatementList[0].AsNode() as ClassDeclarationSyntaxNode; + if (classDeclaration == null) + { + return null; + } + var name = classDeclaration.ClassName.Text; + var methods = new List(); + foreach (var s in classDeclaration.Nodes) + { + if (s.IsToken) + { + continue; + } + if (s.AsNode() is MethodsListSyntaxNode methodsList) + { + methods.AddRange(MethodsFromList(methodsList)); + } + } + return new MClass(tree, name, fileName, methods); + } + } +} \ No newline at end of file diff --git a/Semantics/MClass.cs b/Semantics/MClass.cs new file mode 100644 index 0000000..29dfb15 --- /dev/null +++ b/Semantics/MClass.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Parser; + +namespace Semantics +{ + public class MClass + { + public string Name { get; } + public string FileName { get; } + public FileSyntaxNode Tree { get; } + public List Methods { get; } + + public MClass(FileSyntaxNode tree, string name, string fileName, List methods) + { + Tree = tree; + Name = name; + FileName = FileName; + Methods = methods; + } + } +} \ No newline at end of file diff --git a/Semantics/MMethod.cs b/Semantics/MMethod.cs new file mode 100644 index 0000000..408b8e4 --- /dev/null +++ b/Semantics/MMethod.cs @@ -0,0 +1,15 @@ +namespace Semantics +{ + public class MMethod + { + public string Name { get; } + public string Description { get; } + public MClass Class { get; internal set; } + + public MMethod(string name, string description) + { + Name = name; + Description = description; + } + } +} \ No newline at end of file diff --git a/Semantics/MethodAssignments.cs b/Semantics/MethodAssignments.cs new file mode 100644 index 0000000..f410c9b --- /dev/null +++ b/Semantics/MethodAssignments.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace Semantics +{ + public class MethodAssignments + { + public Context Context { get; } + + private readonly Dictionary _methods; + + public MethodAssignments() + { + _methods = new Dictionary(); + } + + public Variable Find(string name) + { + if (_methods.ContainsKey(name)) + { + return _methods[name]; + } + return null; + } + + public void Add(string name, Variable variable) + { + _methods[name] = variable; + } + } +} \ No newline at end of file diff --git a/Semantics/PackageContext.cs b/Semantics/PackageContext.cs new file mode 100644 index 0000000..1de63a6 --- /dev/null +++ b/Semantics/PackageContext.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Semantics +{ + internal class PackageContext + { + public string Path { get; } + public Dictionary SubPackages { get; } + public Dictionary Classes { get; } + public Dictionary Functions { get; } + + public PackageContext( + string path, + Dictionary subPackages, + Dictionary classes, + Dictionary functions) + { + Path = path; + SubPackages = subPackages; + Classes = classes; + Functions = functions; + } + + public PackageContext( + string path) + { + Path = path; + SubPackages = new Dictionary(); + Classes = new Dictionary(); + Functions = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/ProjectConsole/ProjectConsole.csproj b/Semantics/Semantics.csproj similarity index 66% rename from ProjectConsole/ProjectConsole.csproj rename to Semantics/Semantics.csproj index 3e31ff2..8d3ba26 100644 --- a/ProjectConsole/ProjectConsole.csproj +++ b/Semantics/Semantics.csproj @@ -1,7 +1,6 @@  - Exe - netcoreapp2.0 + netcoreapp2.1 diff --git a/Semantics/Variable.cs b/Semantics/Variable.cs new file mode 100644 index 0000000..0ddc020 --- /dev/null +++ b/Semantics/Variable.cs @@ -0,0 +1,7 @@ +namespace Semantics +{ + public class Variable + { + + } +} \ No newline at end of file diff --git a/Semantics/VariableAssignments.cs b/Semantics/VariableAssignments.cs new file mode 100644 index 0000000..cf29c5e --- /dev/null +++ b/Semantics/VariableAssignments.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace Semantics +{ + public class VariableAssignments + { + public Context Context { get; } + + private readonly Dictionary _variables; + + public VariableAssignments() + { + _variables = new Dictionary(); + } + + public Variable Find(string name) + { + if (_variables.ContainsKey(name)) + { + return _variables[name]; + } + return null; + } + + public void Add(string name, Variable variable) + { + _variables[name] = variable; + } + } +} \ No newline at end of file diff --git a/Solution.sln b/Solution.sln index 3d26b2d..f1333ca 100644 --- a/Solution.sln +++ b/Solution.sln @@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2026 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectConsole", "ProjectConsole\ProjectConsole.csproj", "{5025FD8F-0F1A-43E5-A996-7753BC703D62}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleDemo", "ConsoleDemo\ConsoleDemo.csproj", "{5025FD8F-0F1A-43E5-A996-7753BC703D62}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parser", "Parser\Parser.csproj", "{B20EDC10-E6E6-4430-8527-B95206DEF941}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Parser", "Parser\Parser.csproj", "{1B8E5BBC-E5CD-427B-A6C7-F30047AA4A39}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parser.Tests", "Parser.Tests\Parser.Tests.csproj", "{83008C72-2EFC-41EB-AC8D-023C6AE1709F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Parser.Tests", "Parser.Tests\Parser.Tests.csproj", "{7BFEAD86-EAC3-43C8-9388-EBAB377938D4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lexer", "Lexer\Lexer.csproj", "{1B8E5BBC-E5CD-427B-A6C7-F30047AA4A39}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyntaxGenerator", "SyntaxGenerator\SyntaxGenerator.csproj", "{03487753-C1F5-4753-B576-593294ED86D1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lexer.Tests", "Lexer.Tests\Lexer.Tests.csproj", "{7BFEAD86-EAC3-43C8-9388-EBAB377938D4}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semantics", "Semantics\Semantics.csproj", "{4595633B-7F9A-4771-B348-F12BB9DD7ABC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,14 +23,6 @@ Global {5025FD8F-0F1A-43E5-A996-7753BC703D62}.Debug|Any CPU.Build.0 = Debug|Any CPU {5025FD8F-0F1A-43E5-A996-7753BC703D62}.Release|Any CPU.ActiveCfg = Release|Any CPU {5025FD8F-0F1A-43E5-A996-7753BC703D62}.Release|Any CPU.Build.0 = Release|Any CPU - {B20EDC10-E6E6-4430-8527-B95206DEF941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B20EDC10-E6E6-4430-8527-B95206DEF941}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B20EDC10-E6E6-4430-8527-B95206DEF941}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B20EDC10-E6E6-4430-8527-B95206DEF941}.Release|Any CPU.Build.0 = Release|Any CPU - {83008C72-2EFC-41EB-AC8D-023C6AE1709F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83008C72-2EFC-41EB-AC8D-023C6AE1709F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {83008C72-2EFC-41EB-AC8D-023C6AE1709F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {83008C72-2EFC-41EB-AC8D-023C6AE1709F}.Release|Any CPU.Build.0 = Release|Any CPU {1B8E5BBC-E5CD-427B-A6C7-F30047AA4A39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B8E5BBC-E5CD-427B-A6C7-F30047AA4A39}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B8E5BBC-E5CD-427B-A6C7-F30047AA4A39}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -39,6 +31,14 @@ Global {7BFEAD86-EAC3-43C8-9388-EBAB377938D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {7BFEAD86-EAC3-43C8-9388-EBAB377938D4}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BFEAD86-EAC3-43C8-9388-EBAB377938D4}.Release|Any CPU.Build.0 = Release|Any CPU + {03487753-C1F5-4753-B576-593294ED86D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03487753-C1F5-4753-B576-593294ED86D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03487753-C1F5-4753-B576-593294ED86D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03487753-C1F5-4753-B576-593294ED86D1}.Release|Any CPU.Build.0 = Release|Any CPU + {4595633B-7F9A-4771-B348-F12BB9DD7ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4595633B-7F9A-4771-B348-F12BB9DD7ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4595633B-7F9A-4771-B348-F12BB9DD7ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4595633B-7F9A-4771-B348-F12BB9DD7ABC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SyntaxGenerator/GenerateSyntax.cs b/SyntaxGenerator/GenerateSyntax.cs new file mode 100644 index 0000000..bb67d32 --- /dev/null +++ b/SyntaxGenerator/GenerateSyntax.cs @@ -0,0 +1,360 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; + +namespace SyntaxGenerator +{ + public class GenerateSyntax + { + private const string SyntaxTokenClassName = "SyntaxToken"; + private const string InternalNamespace = "Parser.Internal"; + private const string OuterNamespace = "Parser"; + + private static readonly List<(string visitorMethodName, string className)> Visitors = new List<(string, string)>(); + + private static string _outputPath; + + static GenerateSyntax() + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.MacOSX: + case PlatformID.Unix: + _outputPath = Path.Combine("..", "Parser"); + break; + default: + _outputPath = Path.Combine("..", "..", "..", "..", "Parser"); + break; + } + } + + public static void TestOutput() + { + var field1 = new FieldDescription + { + FieldType = "SyntaxToken", + FieldName = "functionKeyword" + }; + var field2 = new FieldDescription + { + FieldType = "FunctionOutputDescriptionSyntaxNode", + FieldName = "outputDescription" + }; + var syntaxNode = new SyntaxNodeDescription + { + ClassName = "FunctionDeclarationSyntaxNode", + BaseClassName = "StatementSyntaxNode", + Fields = new[] {field1, field2} + }; + var syntax = new SyntaxDescription + { + Nodes = new[] {syntaxNode, syntaxNode} + }; + var serializer = new XmlSerializer(typeof(SyntaxDescription)); + using (var writer = new StreamWriter("output.xml")) + { + serializer.Serialize(writer, syntax); + } + } + + private static string GenerateInternalFieldDeclaration(FieldDescription field) + { + return $" internal readonly {field.FieldType} _{field.FieldName};\n"; + } + + private static string GeneratePrivateFieldDeclaration(FieldDescription field) + { + return $" private SyntaxNode _{field.FieldName};\n"; + } + + private static string GenerateFieldAssignmentInsideConstructor(FieldDescription field) + { + return $" _{field.FieldName} = {field.FieldName};\n"; + } + + private static string GenerateInternalConstructor(SyntaxNodeDescription node) + { + var arguments = string.Join( + ",", + node.Fields.Select(field => $"\n {field.FieldType} {field.FieldName}")); + + var header = + $" internal {node.ClassName}({arguments}) : base(TokenKind.{node.TokenKindName}, {node.Fields.Length})\n"; + var assignments = string.Join( + "", + node.Fields.Select(GenerateFieldAssignmentInsideConstructor)); + return header + " {\n" + assignments + " }\n"; + } + + private static string GenerateConstructor(SyntaxNodeDescription node) + { + var arguments = "SyntaxNode parent, Internal.GreenNode green"; + var header = + $" internal {node.ClassName}({arguments}) : base(parent, green)\n"; + return header + " {\n }\n"; + } + + private static string GenerateInternalGetSlot(SyntaxNodeDescription node) + { + var header = $" public override GreenNode GetSlot(int i)\n"; + var cases = string.Join( + "", + node.Fields.Select((f, i) => $" case {i}: return _{f.FieldName};\n")); + var defaultCase = " default: return null;\n"; + return header + + " {\n switch (i)\n {\n" + + cases + + defaultCase + + " }\n" + + " }\n"; + } + + private static string GenerateGetSlot(SyntaxNodeDescription node, List<(FieldDescription field, int index)> pairs) + { + var header = $" internal override SyntaxNode GetNode(int i)\n"; + var cases = string.Join( + "", + pairs.Select(pair => $" case {pair.index}: return GetRed(ref _{pair.field.FieldName}, {pair.index});\n")); + var defaultCase = " default: return null;\n"; + return header + + " {\n switch (i)\n {\n" + + cases + + defaultCase + + " }\n" + + " }\n"; + } + + private static string GenerateCreateRed(SyntaxNodeDescription node) + { + var header = $" internal override {OuterNamespace}.SyntaxNode CreateRed({OuterNamespace}.SyntaxNode parent)\n"; + var text = $" return new {OuterNamespace}.{node.ClassName}(parent, this);\n"; + return header + " {\n" + text + " }\n"; + } + + private static string GenerateInternalClass(SyntaxNodeDescription node) + { + var header = $" internal class {node.ClassName}"; + if (node.BaseClassName != null) + { + header += $" : {node.BaseClassName}"; + } + + var fields = string.Join( + "", + node.Fields.Select(GenerateInternalFieldDeclaration)); + var constructor = GenerateInternalConstructor(node); + var getSlot = GenerateInternalGetSlot(node); + var createRed = GenerateCreateRed(node); + return + header + + "\n {\n" + + fields + "\n" + + constructor + "\n" + + createRed + "\n" + + getSlot + " }\n"; + } + + private static string Capitalize(string s) + { + return s[0].ToString().ToUpper() + s.Substring(1, s.Length - 1); + } + + private static string GenerateTokenAccessor(SyntaxNodeDescription node, FieldDescription field) + { + var header = $" public SyntaxToken {Capitalize(field.FieldName)}\n"; + var text = + $" get {{ return new SyntaxToken(this, (({InternalNamespace}.{node.ClassName})_green)._{field.FieldName}); }}"; + return header + " {\n" + text + "\n }\n"; + } + + private static bool IsList(string type) + { + return type.StartsWith("SyntaxList"); + } + + private static string GenerateNodeAccessor(SyntaxNodeDescription node, FieldDescription field, int index) + { + var type = field.FieldType; + if (IsList(type)) + { + type = "SyntaxNodeOrTokenList"; + } + var header = $" public {type} {Capitalize(field.FieldName)}\n {{\n get\n {{\n"; + var text = + $" var red = this.GetRed(ref this._{field.FieldName}, {index});\n" + + $" if (red != null)\n" + + $" return ({type})red;\n\n" + + $" return default({type});\n"; + return header + text + " }\n }\n"; + } + + private static string ConvertClassNameToVisitorName(string name) + { + if (name.EndsWith("SyntaxNode")) + { + name = name.Substring(0, name.Length - "SyntaxNode".Length); + } + + return "Visit" + name; + } + + private static string GenerateAccessMethod(SyntaxNodeDescription node) + { + var visitorName = ConvertClassNameToVisitorName(node.ClassName); + Visitors.Add((visitorName, node.ClassName)); + var header = $" public override void Accept(SyntaxVisitor visitor)\n"; + var body = $" visitor.{visitorName}(this);\n"; + return header + " {\n" + body + " }\n"; + } + + private static string GenerateClass(SyntaxNodeDescription node) + { + var header = $" public class {node.ClassName}"; + if (node.BaseClassName != null) + { + header += $" : {node.BaseClassName}"; + } + + var tokenSlots = node.Fields + .Select((f, i) => (field: f, index: i)) + .Where(pair => pair.field.FieldType == SyntaxTokenClassName) + .ToList(); + var nodeSlots = node.Fields + .Select((f, i) => (field: f, index: i)) + .Where(pair => pair.field.FieldType != SyntaxTokenClassName) + .ToList(); + var fields = string.Join( + "", + nodeSlots.Select(pair => GeneratePrivateFieldDeclaration(pair.field))); + var constructor = GenerateConstructor(node); + var tokenAccessors = + string.Join( + "\n", + tokenSlots.Select(pair => GenerateTokenAccessor(node, pair.field))); + var nodeAccessors = + string.Join( + "\n", + nodeSlots.Select(pair => GenerateNodeAccessor(node, pair.field, pair.index))); + var getSlot = GenerateGetSlot(node, nodeSlots); + var access = GenerateAccessMethod(node); + return + header + + "\n {\n" + + fields + "\n" + + constructor + "\n" + + tokenAccessors + "\n" + + nodeAccessors + "\n" + + getSlot + "\n" + + access + "\n" + + " }\n"; + } + + private static string GenerateInternalSyntaxNodeFile(SyntaxDescription syntax) + { + var header = $"namespace {InternalNamespace}\n"; + var classes = string.Join( + "\n", + syntax.Nodes.Select(GenerateInternalClass) + ); + return header + "{\n" + classes + "}\n"; + } + + private static string GenerateSyntaxNodeFile(SyntaxDescription syntax) + { + var header = $"namespace {OuterNamespace}\n"; + var classes = string.Join( + "\n", + syntax.Nodes.Select(GenerateClass) + ); + return header + "{\n" + classes + "}\n"; + } + + private static string FactoryMethodNameFromClassName(string className) + { + if (className.EndsWith("Node")) + { + return className.Substring(0, className.Length - 4); + } + else + { + return className; + } + } + + 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}")); + var constructorParameters = string.Join( + ", ", + node.Fields.Select(field => $"\n {field.FieldName}")); + var returnStatement = + $" return new {node.ClassName}({constructorParameters});\n"; + + return header + "(" + arguments + ")\n {\n" + returnStatement + " }\n"; + } + + private static string GenerateSyntaxFactoryFile(SyntaxDescription syntax) + { + var header = $"namespace {InternalNamespace}\n{{\n internal partial class SyntaxFactory\n"; + var methods = string.Join( + "\n", + syntax.Nodes.Select(GenerateFactoryMethod) + ); + return header + " {\n" + methods + " }\n}"; + } + + private static string GenerateVisitor((string visitorMethodName, string className) info) + { + var header = $" public virtual void {info.visitorMethodName}({info.className} node)\n"; + var body = $" DefaultVisit(node);\n"; + return header + " {\n" + body + " }\n"; + } + + private static string GenerateSyntaxVisitorFile(SyntaxDescription syntax) + { + var header = $"namespace {OuterNamespace}\n{{\n public partial class SyntaxVisitor\n"; + var methods = string.Join( + "\n", + Visitors.Select(GenerateVisitor)); + return header + " {\n" + methods + " }\n};"; + } + + + public static void Input() + { + 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) + { + Console.WriteLine("Couldn't deserialize syntax."); + return; + } + + var internalSyntaxNodePath = Path.Combine(_outputPath, "Internal", "SyntaxNode.Generated.cs"); + File.WriteAllText(internalSyntaxNodePath, GenerateInternalSyntaxNodeFile(syntax)); + var internalSyntaxFactoryPath = Path.Combine(_outputPath, "Internal", "SyntaxFactory.Generated.cs"); + File.WriteAllText(internalSyntaxFactoryPath, GenerateSyntaxFactoryFile(syntax)); + var syntaxNodePath = Path.Combine(_outputPath, "SyntaxNode.Generated.cs"); + File.WriteAllText(syntaxNodePath, GenerateSyntaxNodeFile(syntax)); + var syntaxVisitorPath = Path.Combine(_outputPath, "SyntaxVisitor.Generated.cs"); + File.WriteAllText(syntaxVisitorPath, GenerateSyntaxVisitorFile(syntax)); + } + } + + static void Main(string[] args) + { + Console.Write("Generating syntax..."); + Input(); + Console.WriteLine("Done."); + } + } +} \ No newline at end of file diff --git a/SyntaxGenerator/SyntaxGenerator.csproj b/SyntaxGenerator/SyntaxGenerator.csproj new file mode 100644 index 0000000..4658176 --- /dev/null +++ b/SyntaxGenerator/SyntaxGenerator.csproj @@ -0,0 +1,11 @@ + + + Exe + netcoreapp2.0 + + + + PreserveNewest + + + \ No newline at end of file diff --git a/SyntaxGenerator/SyntaxNodeDescription.cs b/SyntaxGenerator/SyntaxNodeDescription.cs new file mode 100644 index 0000000..ef38a0c --- /dev/null +++ b/SyntaxGenerator/SyntaxNodeDescription.cs @@ -0,0 +1,38 @@ +using System.Xml.Serialization; + +namespace SyntaxGenerator +{ + [XmlRoot(ElementName = "Syntax")] + public class SyntaxDescription + { + [XmlElement(ElementName = "Class")] + public SyntaxNodeDescription[] Nodes { get; set; } + } + + public class SyntaxNodeDescription + { + [XmlAttribute("Name")] + public string ClassName { get; set; } + [XmlAttribute("BaseClass")] + public string BaseClassName { get; set; } + [XmlAttribute("Kind")] + public string TokenKindName { get; set; } + + [XmlElement(ElementName = "Field")] + public FieldDescription[] Fields + { + get => _fields; + set => _fields = value ?? new FieldDescription[0]; + } + + private FieldDescription[] _fields = new FieldDescription[0]; + } + + public class FieldDescription + { + [XmlAttribute("Type")] + public string FieldType { get; set; } + [XmlAttribute("Name")] + public string FieldName { get; set; } + } +} \ No newline at end of file diff --git a/SyntaxGenerator/input.xml b/SyntaxGenerator/input.xml new file mode 100644 index 0000000..1bd4142 --- /dev/null +++ b/SyntaxGenerator/input.xml @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +