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