MParser/Parser/Internal/MParserGreen.cs

1228 lines
44 KiB
C#

using System;
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 DiagnosticsBag Diagnostics { get; }
public MParserGreen(List<(SyntaxToken, Position)> pairs, SyntaxFactory factory)
{
Pairs = pairs;
Factory = factory;
Diagnostics = new DiagnosticsBag();
}
private SyntaxToken EatToken()
{
var token = CurrentToken;
_index++;
return token;
}
private SyntaxToken CreateMissingToken(TokenKind kind)
{
return TokenFactory
.CreateMissing(kind, null, null)
.WithDiagnostics(TokenDiagnostic.MissingToken(kind));
}
private SyntaxToken EatToken(TokenKind kind)
{
var token = CurrentToken;
if (token.Kind != kind)
{
Diagnostics.ReportUnexpectedToken(kind, token.Kind);
return CreateMissingToken(kind);
}
_index++;
return token;
}
private SyntaxToken EatIdentifier()
{
return EatToken(TokenKind.IdentifierToken);
}
private bool IsIdentifier(SyntaxToken token, string s)
{
return token.Kind == TokenKind.IdentifierToken && token.Text == s;
}
private SyntaxToken EatIdentifier(string s)
{
var token = CurrentToken;
if (token.Kind != TokenKind.IdentifierToken)
{
Diagnostics.ReportUnexpectedToken(TokenKind.IdentifierToken, token.Kind);
return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null);
}
if (token.Text != s)
{
Diagnostics.ReportUnexpectedToken(TokenKind.IdentifierToken, token.Kind);
return TokenFactory.CreateMissing(TokenKind.IdentifierToken, null, null);
}
_index++;
return token;
}
private SyntaxToken? PossiblyEatIdentifier(string s)
{
var token = CurrentToken;
if (token.Kind == TokenKind.IdentifierToken && token.Text == s)
{
return EatToken();
}
return null;
}
private SyntaxToken EatPossiblyMissingIdentifier(string s)
{
var token = CurrentToken;
if (token.Kind == TokenKind.IdentifierToken && token.Text == s)
{
return EatToken();
}
return TokenFactory.CreateMissing(
TokenKind.IdentifierToken,
new List<SyntaxTrivia>(),
new List<SyntaxTrivia>());
}
private SyntaxList? ParseFunctionOutputList()
{
var outputs = new SyntaxListBuilder();
var firstToken = true;
while (CurrentToken.Kind != TokenKind.CloseSquareBracketToken)
{
if (!firstToken && CurrentToken.Kind == TokenKind.CommaToken)
{
outputs.Add(EatToken());
}
firstToken = false;
outputs.Add(Factory.IdentifierNameExpressionSyntax(EatToken(TokenKind.IdentifierToken)));
}
return outputs.ToList();
}
private FunctionOutputDescriptionSyntaxNode? ParseFunctionOutputDescription()
{
SyntaxToken assignmentSign;
var builder = new SyntaxListBuilder();
if (CurrentToken.Kind == TokenKind.OpenSquareBracketToken)
{
builder.Add(EatToken());
var outputs = ParseFunctionOutputList();
if (outputs != null)
{
builder.AddRange(outputs);
}
builder.Add(EatToken(TokenKind.CloseSquareBracketToken));
assignmentSign = EatToken(TokenKind.EqualsToken);
}
else if (CurrentToken.Kind == TokenKind.IdentifierToken)
{
if (PeekToken(1).Kind == TokenKind.EqualsToken)
{
var identifierToken = EatIdentifier();
builder.Add(Factory.IdentifierNameExpressionSyntax(identifierToken));
assignmentSign = EatToken(TokenKind.EqualsToken);
}
else
{
return null;
}
}
else
{
return null;
}
return Factory.FunctionOutputDescriptionSyntax(builder.ToList(), assignmentSign);
}
private SyntaxList ParseParameterList()
{
var builder = new SyntaxListBuilder();
var firstToken = true;
while (CurrentToken.Kind != TokenKind.CloseParenthesisToken)
{
if (!firstToken)
{
builder.Add(EatToken(TokenKind.CommaToken));
}
else
{
firstToken = false;
}
if (CurrentToken.Kind == TokenKind.TildeToken)
{
var notToken = EatToken();
builder.Add(notToken);
}
else
{
var identifierToken = EatToken(TokenKind.IdentifierToken);
builder.Add(Factory.IdentifierNameExpressionSyntax(identifierToken));
}
}
return builder.ToList();
}
private FunctionInputDescriptionSyntaxNode? ParseFunctionInputDescription()
{
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
var openingBracket = EatToken(TokenKind.OpenParenthesisToken);
var parameterList = ParseParameterList();
var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
return Factory.FunctionInputDescriptionSyntax(
openingBracket,
parameterList,
closingBracket);
}
else
{
return null;
}
}
private FunctionDeclarationSyntaxNode ParseFunctionDeclaration()
{
var functionKeyword = EatIdentifier("function");
var outputDescription = ParseFunctionOutputDescription();
var name = EatToken(TokenKind.IdentifierToken);
var inputDescription = ParseFunctionInputDescription();
var commas = ParseOptionalCommas();
var body = ParseStatementList();
var endKeyword = ParseEndKeyword();
//var endKeyword =
return Factory.FunctionDeclarationSyntax(
functionKeyword,
outputDescription,
name,
inputDescription,
commas,
body,
endKeyword);
}
private EndKeywordSyntaxNode? ParseEndKeyword()
{
var keyword = EatPossiblyMissingIdentifier("end");
return keyword is null ? null : Factory.EndKeywordSyntax(keyword);
}
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.OpenSquareBracketToken);
var elements = ParseArrayElementList(TokenKind.CloseSquareBracketToken);
var closingSquareBracket = EatToken(TokenKind.CloseSquareBracketToken);
return Factory.ArrayLiteralExpressionSyntax(
openingSquareBracket,
elements,
closingSquareBracket);
}
private CellArrayLiteralExpressionSyntaxNode ParseCellArrayLiteral()
{
var openingBrace = EatToken(TokenKind.OpenBraceToken);
var elements = ParseArrayElementList(TokenKind.CloseBraceToken);
var closingBrace = EatToken(TokenKind.CloseBraceToken);
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.CommaToken
|| CurrentToken.Kind == TokenKind.SemicolonToken)
{
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.NumberLiteralToken:
expression = Factory.NumberLiteralSyntax(EatToken());
break;
case TokenKind.StringLiteralToken:
expression = Factory.StringLiteralSyntax(EatToken());
break;
case TokenKind.DoubleQuotedStringLiteralToken:
expression = Factory.DoubleQuotedStringLiteralSyntax(EatToken());
break;
case TokenKind.OpenSquareBracketToken:
expression = ParseArrayLiteral();
break;
case TokenKind.OpenBraceToken:
expression = ParseCellArrayLiteral();
break;
case TokenKind.ColonToken:
expression = Factory.EmptyExpressionSyntax();
break;
case TokenKind.OpenParenthesisToken:
expression = ParseParenthesizedExpression();
break;
default:
var id = EatToken(TokenKind.IdentifierToken);
expression = Factory.IdentifierNameExpressionSyntax(id);
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.OpenBraceToken: // cell array element access
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
{
return expression;
}
var openingBrace = EatToken();
var indices = ParseArrayElementList(TokenKind.CloseBraceToken);
var closingBrace = EatToken(TokenKind.CloseBraceToken);
expression = Factory.CellArrayElementAccessExpressionSyntax(
expression,
openingBrace,
indices,
closingBrace
);
break;
case TokenKind.OpenParenthesisToken: // function call
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
{
return expression;
}
var openingBracket = EatToken();
var parameters = ParseFunctionCallParameterList();
var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
expression = Factory.FunctionCallExpressionSyntax(
expression,
openingBracket,
parameters,
closingBracket);
break;
case TokenKind.DotToken: // member access
if (expression is IdentifierNameExpressionSyntaxNode
|| 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.ApostropheToken:
case TokenKind.DotApostropheToken:
var operation = EatToken();
expression = Factory.UnaryPostixOperationExpressionSyntax(expression, operation);
break;
case TokenKind.UnquotedStringLiteralToken:
return ParseCommandExpression(expression);
case TokenKind.AtToken:
if (expression.TrailingTrivia.Any())
{
return expression;
}
return ParseBaseClassInvokation(expression);
default:
return expression;
}
}
}
private CommandExpressionSyntaxNode ParseCommandExpression(ExpressionSyntaxNode expression)
{
if (expression is IdentifierNameExpressionSyntaxNode idNameNode)
{
var builder = new SyntaxListBuilder<UnquotedStringLiteralSyntaxNode>();
while (CurrentToken.Kind == TokenKind.UnquotedStringLiteralToken)
{
builder.Add(Factory.UnquotedStringLiteralSyntax(EatToken()));
}
return Factory.CommandExpressionSyntax(idNameNode._name, builder.ToList());
}
if (expression is null)
{
throw new Exception("Command expression identifier cannot be empty.");
}
throw new ParsingException($"Unexpected token \"{CurrentToken}\" while parsing expression \"{expression.FullText}\" at {CurrentPosition}.");
}
private BaseClassInvokationSyntaxNode ParseBaseClassInvokation(ExpressionSyntaxNode expression)
{
if (expression is IdentifierNameExpressionSyntaxNode methodName
&& !expression.TrailingTrivia.Any())
{
var atToken = EatToken();
var baseClassNameWithArguments = ParseExpression();
if (baseClassNameWithArguments is null)
{
throw new Exception($"Base class name cannot be empty.");
}
return Factory.BaseClassInvokationSyntax(methodName, atToken, baseClassNameWithArguments);
}
if (expression is MemberAccessSyntaxNode memberAccess
&& !expression.TrailingTrivia.Any())
{
var atToken = EatToken();
var baseClassNameWithArguments = ParseExpression();
if (baseClassNameWithArguments is null)
{
throw new Exception($"Base class name cannot be empty.");
}
return Factory.BaseClassInvokationSyntax(memberAccess, atToken, baseClassNameWithArguments);
}
throw new ParsingException($"Unexpected token \"{CurrentToken}\" at {CurrentPosition}.");
}
private ExpressionSyntaxNode ParseMemberAccess()
{
if (CurrentToken.Kind == TokenKind.IdentifierToken)
{
return Factory.IdentifierNameExpressionSyntax(EatToken());
}
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
var openingBracket = EatToken();
var indirectMember = ParseExpression();
if (indirectMember is null)
{
throw new Exception("Indirect member invokation cannot be empty.");
}
var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
return Factory.IndirectMemberAccessSyntax(
openingBracket,
indirectMember,
closingBracket);
}
throw new ParsingException($"Unexpected token {CurrentToken} at {CurrentPosition}.");
}
private SyntaxList ParseFunctionCallParameterList()
{
var builder = new SyntaxListBuilder();
var firstToken = true;
while (CurrentToken.Kind != TokenKind.CloseParenthesisToken)
{
if (!firstToken)
{
builder.Add(EatToken(TokenKind.CommaToken));
}
else
{
firstToken = false;
}
var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Function call parameter cannot be empty.");
}
builder.Add(expression);
}
return builder.ToList();
}
private ParenthesizedExpressionSyntaxNode ParseParenthesizedExpression()
{
var openParen = EatToken(TokenKind.OpenParenthesisToken);
var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Parenthesized expression cannot be empty.");
}
var closeParen = EatToken(TokenKind.CloseParenthesisToken);
return Factory.ParenthesizedExpressionSyntax(
openParen,
expression,
closeParen);
}
private CompoundNameExpressionSyntaxNode ParseCompoundName()
{
var lastToken = EatToken(TokenKind.IdentifierToken);
var firstName = lastToken;
var builder = new SyntaxListBuilder();
builder.Add(firstName);
while (CurrentToken.Kind == TokenKind.DotToken
&& !lastToken.TrailingTrivia.Any())
{
var dot = EatToken();
builder.Add(dot);
lastToken = EatToken(TokenKind.IdentifierToken);
builder.Add(lastToken);
}
return Factory.CompoundNameExpressionSyntax(builder.ToList());
}
private FunctionHandleExpressionSyntaxNode ParseFunctionHandle()
{
var atSign = EatToken();
if (CurrentToken.Kind == TokenKind.IdentifierToken)
{
var compoundName = ParseCompoundName();
return Factory.NamedFunctionHandleExpressionSyntax(
atSign,
compoundName);
}
else if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
var inputs = ParseFunctionInputDescription();
if (inputs is null)
{
throw new Exception($"Lambda expression inputs cannot be empty.");
}
var body = ParseExpression();
if (body is null)
{
throw new Exception($"Lambda expression body cannot be empty.");
}
return Factory.LambdaExpressionSyntax(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.TildeToken)
{
operand = Factory.EmptyExpressionSyntax();
}
else
{
throw new ParsingException($"Unexpected token {CurrentToken} at {CurrentPosition}.");
}
}
lhs = Factory.UnaryPrefixOperationExpressionSyntax(operation, operand);
}
else if (CurrentToken.Kind == TokenKind.AtToken)
{
return ParseFunctionHandle();
}
else
{
lhs = ParseTerm(options);
if (lhs is null)
{
throw new Exception("Left-hand side in subexpression cannot be empty.");
}
}
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)
{
if (token.Kind == TokenKind.ColonToken) // for parsing things like a{:}
{
rhs = Factory.EmptyExpressionSyntax();
}
else
{
throw new Exception("Right-hand side in subexpression cannot be empty.");
}
}
if (token.Kind == TokenKind.EqualsToken)
{
lhs = Factory.AssignmentExpressionSyntax(lhs, token, rhs);
}
else
{
lhs = Factory.BinaryOperationExpressionSyntax(lhs, token, rhs);
}
}
else
{
break;
}
}
return lhs;
}
private SyntaxList<SyntaxToken> ParseOptionalCommas()
{
var builder = new SyntaxListBuilder<SyntaxToken>();
while (CurrentToken.Kind == TokenKind.CommaToken)
{
builder.Add(EatToken());
}
return builder.ToList();
}
private SyntaxList<SyntaxToken> ParseOptionalSemicolonsOrCommas()
{
var builder = new SyntaxListBuilder<SyntaxToken>();
while (CurrentToken.Kind == TokenKind.CommaToken
|| CurrentToken.Kind == TokenKind.SemicolonToken)
{
builder.Add(EatToken());
}
return builder.ToList();
}
private SwitchCaseSyntaxNode ParseSwitchCase()
{
var caseKeyword = EatIdentifier("case");
var caseId = ParseExpression();
if (caseId is null)
{
throw new Exception("Case label cannot be empty.");
}
var commas = ParseOptionalCommas();
var statementList = ParseStatementList();
return Factory.SwitchCaseSyntax(caseKeyword, caseId, commas, statementList);
}
private SwitchStatementSyntaxNode ParseSwitchStatement()
{
var switchKeyword = EatIdentifier("switch");
var expression = ParseExpression();
if (expression is null)
{
throw new Exception("Match expression in switch statement cannot be empty.");
}
var commas = ParseOptionalCommas();
var builder = new SyntaxListBuilder<SwitchCaseSyntaxNode>();
while (IsIdentifier(CurrentToken, "case"))
{
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();
if (condition is null)
{
throw new Exception("Condition in while statement cannot be empty.");
}
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();
if (condition is null)
{
throw new Exception("Condition in elseif clause cannot be empty.");
}
var commas = ParseOptionalCommas();
var body = ParseStatementList();
return Factory.ElseifClause(elseifKeyword, condition, commas, body);
}
private ElseClause ParseElseClause()
{
var elseKeyword = EatIdentifier("else");
var body = ParseStatementList();
return Factory.ElseClause(elseKeyword, body);
}
private IfStatementSyntaxNode ParseIfStatement()
{
var ifKeyword = EatIdentifier();
var condition = ParseExpression();
if (condition is null)
{
throw new Exception("Condition in if statement cannot be empty.");
}
var commas = ParseOptionalSemicolonsOrCommas();
var body = ParseStatementList();
var elseifClauses = new SyntaxListBuilder<ElseifClause>();
ElseClause? elseClause = null;
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();
if (expression is null)
{
throw new Exception("Expression statement cannot be empty.");
}
return Factory.ExpressionStatementSyntax(expression);
}
private AttributeAssignmentSyntaxNode? ParseAttributeAssignment()
{
if (CurrentToken.Kind == TokenKind.EqualsToken)
{
var assignmentSign = EatToken();
var value = ParseExpression();
if (value is null)
{
throw new Exception("Right-hand side in attribute assignment cannot be empty.");
}
return Factory.AttributeAssignmentSyntax(assignmentSign, value);
}
return null;
}
private AttributeSyntaxNode ParseAttribute()
{
var name = EatToken(TokenKind.IdentifierToken);
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.CloseParenthesisToken)
{
if (!first)
{
var comma = EatToken(TokenKind.CommaToken);
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.OpenSquareBracketToken
|| CurrentToken.Kind == TokenKind.IdentifierToken)
{
return ParseAbstractMethodDeclaration();
}
if (CurrentToken.Kind == TokenKind.SemicolonToken)
{
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 = ParseEndKeyword();
return Factory.MethodDefinitionSyntax(
functionKeyword,
outputDescription,
name,
inputDescription,
commas,
body,
endKeyword);
}
private MethodsListSyntaxNode ParseMethods()
{
var methodsKeyword = EatToken();
AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
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.CommaToken)
{
return EatToken();
}
return ParseStatement();
}
private SyntaxNode? ParseEventDeclaration()
{
return ParseStatement();
}
private PropertiesListSyntaxNode ParseProperties()
{
var propertiesKeyword = EatToken();
AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
attributes = ParseAttributesList();
}
var builder = new SyntaxListBuilder();
while (!IsIdentifier(CurrentToken, "end"))
{
var declaration = ParsePropertyDeclaration();
if (declaration is null)
{
throw new Exception("Property declaration cannot be null.");
}
builder.Add(declaration);
}
var endKeyword = EatToken();
return Factory.PropertiesListSyntax(propertiesKeyword, attributes, builder.ToList(), endKeyword);
}
private EnumerationItemValueSyntaxNode? ParseEnumerationValue()
{
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
var builder = new SyntaxListBuilder();
var openingBracket = EatToken(TokenKind.OpenParenthesisToken);
var expression = ParseExpression() ?? Factory.EmptyExpressionSyntax();
builder.Add(expression);
while (CurrentToken.Kind == TokenKind.CommaToken)
{
builder.Add(EatToken());
var nextExpression = ParseExpression();
if (nextExpression is null)
{
throw new Exception("Enumeration identifier cannot be empty.");
}
builder.Add(nextExpression);
}
var closingBracket = EatToken(TokenKind.CloseParenthesisToken);
return Factory.EnumerationItemValueSyntax(openingBracket, builder.ToList(), closingBracket);
}
return null;
}
private EnumerationItemSyntaxNode ParseEnumerationItem()
{
var name = EatToken();
var values = ParseEnumerationValue();
var commas = ParseOptionalCommas();
return Factory.EnumerationItemSyntax(name, values, commas);
}
private EnumerationListSyntaxNode ParseEnumeration()
{
var enumerationKeyword = EatToken();
var builder = new SyntaxListBuilder<EnumerationItemSyntaxNode>();
AttributeListSyntaxNode? attributes = null;
if (CurrentToken.Kind == TokenKind.OpenParenthesisToken)
{
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.OpenParenthesisToken)
{
attributes = ParseAttributesList();
}
var builder = new SyntaxListBuilder();
while (!IsIdentifier(CurrentToken, "end"))
{
var eventDeclaration = ParseEventDeclaration();
if (eventDeclaration is null)
{
throw new Exception("Event declaration cannot be empty.");
}
builder.Add(eventDeclaration);
}
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.AmpersandToken)
{
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.OpenParenthesisToken)
{
attributes = ParseAttributesList();
}
var className = EatToken(TokenKind.IdentifierToken);
BaseClassListSyntaxNode? baseClassList = null;
if (CurrentToken.Kind == TokenKind.LessToken)
{
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.IdentifierToken)
{
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;
}
}
if (CurrentToken.Kind == TokenKind.OpenSquareBracketToken)
{
return ParseExpressionStatement();
}
if (CurrentToken.Kind == TokenKind.SemicolonToken)
{
return Factory.EmptyStatementSyntax(EatToken());
}
return ParseExpressionStatement();
}
private SyntaxList ParseStatementList()
{
var builder = new SyntaxListBuilder();
while (CurrentToken.Kind != TokenKind.EndOfFileToken)
{
var node = ParseStatement();
if (node == null)
{
break;
}
builder.Add(node);
while (CurrentToken.Kind == TokenKind.CommaToken
|| CurrentToken.Kind == TokenKind.SemicolonToken)
{
builder.Add(EatToken());
}
}
return builder.ToList();
}
public FileSyntaxNode ParseFile()
{
var statementList = ParseStatementList();
var endOfFileToken = EatToken();
return Factory.FileSyntax(statementList, endOfFileToken);
}
public RootSyntaxNode ParseRoot()
{
var file = ParseFile();
return Factory.RootSyntax(file);
}
}
}