Upsilon/Upsilon/Parser/Parser.cs

216 lines
8.2 KiB
C#
Raw Normal View History

2018-11-13 11:48:50 +00:00
using System;
2018-11-10 12:11:36 +00:00
using System.Collections.Immutable;
2018-11-13 12:54:51 +00:00
using System.Linq;
2018-11-11 09:26:52 +00:00
using Upsilon.Text;
2018-11-10 12:11:36 +00:00
namespace Upsilon.Parser
{
public class Parser
{
private readonly ImmutableArray<SyntaxToken> _tokens;
2018-11-11 09:26:52 +00:00
private readonly Diagnostics _diagnostics;
2018-11-10 12:11:36 +00:00
private int _position;
2018-11-11 09:26:52 +00:00
private Parser(ImmutableArray<SyntaxToken> tokens, Diagnostics diagnostics)
2018-11-10 12:11:36 +00:00
{
_tokens = tokens;
2018-11-11 09:26:52 +00:00
_diagnostics = diagnostics;
2018-11-10 12:11:36 +00:00
}
public static BlockStatementSyntax Parse(string text, Diagnostics diagnostics)
2018-11-10 12:11:36 +00:00
{
2018-11-11 09:26:52 +00:00
var tokens = Lexer.Lex(text, diagnostics);
return (BlockStatementSyntax) new Parser(tokens, diagnostics).ParseScriptSyntax();
2018-11-10 12:11:36 +00:00
}
private SyntaxToken Current => Get(0);
private SyntaxToken Next => Get(1);
private SyntaxToken Get(int offset)
{
if (_position + offset >= _tokens.Length)
return new SyntaxToken(SyntaxKind.EndOfFile, _position + offset, "\0", null);
return _tokens[_position + offset];
}
private SyntaxToken NextToken()
{
var current = Current;
_position++;
return current;
}
private SyntaxToken MatchToken(SyntaxKind kind)
{
if (Current.Kind == kind)
return NextToken();
2018-11-13 11:48:50 +00:00
_diagnostics.LogBadCharacter(Current.Span, kind);
2018-11-10 12:11:36 +00:00
return new SyntaxToken(kind, Current.Span.Start, "", null);
}
2018-11-13 12:54:51 +00:00
private StatementSyntax ParseScriptSyntax()
2018-11-10 12:11:36 +00:00
{
2018-11-13 12:54:51 +00:00
var statement = ParseBlockStatement(new []{SyntaxKind.EndOfFile});
2018-11-13 11:48:50 +00:00
MatchToken(SyntaxKind.EndOfFile);
return statement;
2018-11-10 12:11:36 +00:00
}
2018-11-13 12:54:51 +00:00
private StatementSyntax ParseStatement()
2018-11-10 12:11:36 +00:00
{
2018-11-10 16:00:39 +00:00
if (Current.Kind == SyntaxKind.Identifier && Next.Kind == SyntaxKind.Equals)
{
return ParseAssignmentExpression();
2018-11-10 16:00:39 +00:00
}
if (Current.Kind == SyntaxKind.LocalKeyword && Next.Kind == SyntaxKind.Identifier)
{
return ParseAssignmentExpression();
2018-11-10 16:00:39 +00:00
}
2018-11-13 11:48:50 +00:00
if (Current.Kind == SyntaxKind.IfKeyword)
{
2018-11-13 14:15:44 +00:00
return ParseIfStatement(SyntaxKind.IfKeyword);
2018-11-13 12:54:51 +00:00
}
return ParseExpressionStatement();
}
2018-11-13 12:54:51 +00:00
private StatementSyntax ParseBlockStatement(SyntaxKind[] endTokens)
{
var statements = ImmutableArray.CreateBuilder<StatementSyntax>();
2018-11-13 12:54:51 +00:00
while (!endTokens.Contains(Current.Kind))
{
var next = ParseStatement();
statements.Add(next);
}
2018-11-13 11:48:50 +00:00
return new BlockStatementSyntax(statements.ToImmutable());
}
2018-11-13 14:15:44 +00:00
private StatementSyntax ParseIfStatement(SyntaxKind requiredToken)
2018-11-13 11:48:50 +00:00
{
2018-11-13 14:15:44 +00:00
var ifToken = MatchToken(requiredToken);
2018-11-13 11:48:50 +00:00
var condition = ParseExpressionStatement();
var thenToken = MatchToken(SyntaxKind.ThenKeyword);
2018-11-13 12:54:51 +00:00
var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword, SyntaxKind.ElseIfKeyword, SyntaxKind.ElseKeyword});
2018-11-13 14:15:44 +00:00
switch (Current.Kind)
2018-11-13 12:54:51 +00:00
{
2018-11-13 14:15:44 +00:00
case SyntaxKind.ElseIfKeyword:
var nextElseIf =
new ElseIfStatementSyntax((IfStatementSyntax) ParseIfStatement(SyntaxKind.ElseIfKeyword));
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block,
nextElseIf);
2018-11-13 12:54:51 +00:00
case SyntaxKind.ElseKeyword:
{
2018-11-13 14:15:44 +00:00
var elseToken = MatchToken(SyntaxKind.ElseKeyword);
2018-11-13 12:54:51 +00:00
var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword});
var endEndToken = MatchToken(SyntaxKind.EndKeyword);
2018-11-13 14:15:44 +00:00
var elseStatement = new ElseStatementSyntax(elseToken, (BlockStatementSyntax) elseBlock, endEndToken);
2018-11-13 12:54:51 +00:00
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, elseStatement);
}
2018-11-13 14:15:44 +00:00
case SyntaxKind.EndKeyword:
var endToken = MatchToken(SyntaxKind.EndKeyword);
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
2018-11-13 12:54:51 +00:00
default:
2018-11-13 14:15:44 +00:00
throw new ArgumentOutOfRangeException();
2018-11-13 12:54:51 +00:00
}
}
2018-11-13 12:54:51 +00:00
private ExpressionStatementSyntax ParseExpressionStatement()
{
var expression = ParseExpression();
return new ExpressionStatementSyntax(expression);
}
2018-11-13 12:54:51 +00:00
private ExpressionSyntax ParseExpression()
{
2018-11-10 12:11:36 +00:00
return ParseBinaryExpression();
}
private AssignmentExpressionSyntax ParseAssignmentExpression()
2018-11-10 16:00:39 +00:00
{
SyntaxToken localKeyword = null;
if (Current.Kind == SyntaxKind.LocalKeyword)
{
localKeyword = MatchToken(SyntaxKind.LocalKeyword);
}
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
var assignmentToken = MatchToken(SyntaxKind.Equals);
var expression = ParseExpression();
return new AssignmentExpressionSyntax(localKeyword, identifier, assignmentToken, expression);
}
2018-11-10 12:11:36 +00:00
private ExpressionSyntax ParseBinaryExpression(SyntaxKindPrecedence.Precedence parentPrecedence = SyntaxKindPrecedence.Precedence.None)
{
ExpressionSyntax left;
var unaryOperatorPrecedence = Current.Kind.UnaryOperatorPrecedence();
if (unaryOperatorPrecedence != SyntaxKindPrecedence.Precedence.None
&& unaryOperatorPrecedence >= parentPrecedence)
{
var operatorToken = NextToken();
var operand = ParseBinaryExpression(unaryOperatorPrecedence);
left = new UnaryExpressionSyntax(operatorToken, operand);
}
else
{
left = ParsePrimaryExpression();
}
while (true)
{
var precedence = Current.Kind.BinaryOperatorPrecedence();
if (precedence == SyntaxKindPrecedence.Precedence.None || precedence <= parentPrecedence)
break;
var op = NextToken();
var right = ParseBinaryExpression(precedence);
left = new BinaryExpressionSyntax(left, op, right);
}
return left;
}
private ExpressionSyntax ParsePrimaryExpression()
{
switch (Current.Kind)
{
case SyntaxKind.OpenParenthesis:
return ParseParenthesizedExpression();
case SyntaxKind.Number:
return ParseNumber();
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
return ParseBoolean();
2018-11-10 16:00:39 +00:00
case SyntaxKind.Identifier:
var token = MatchToken(SyntaxKind.Identifier);
return new VariableExpressionSyntax((IdentifierToken) token);
2018-11-14 12:45:49 +00:00
case SyntaxKind.NilKeyword:
var nilToken = MatchToken(SyntaxKind.NilKeyword);
return new LiteralExpressionSyntax(nilToken, null);
2018-11-10 12:11:36 +00:00
default:
2018-11-13 11:48:50 +00:00
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
2018-11-11 09:26:52 +00:00
NextToken();
return new BadExpressionSyntax();
2018-11-10 12:11:36 +00:00
}
}
private ExpressionSyntax ParseParenthesizedExpression()
{
var l = MatchToken(SyntaxKind.OpenParenthesis);
var e = ParseExpression();
var r = MatchToken(SyntaxKind.CloseParenthesis);
return new ParenthesizedExpressionSyntax(l, e, r);
}
private ExpressionSyntax ParseNumber()
{
var numberToken = MatchToken(SyntaxKind.Number);
return new LiteralExpressionSyntax(numberToken, numberToken.Value);
}
private ExpressionSyntax ParseBoolean()
{
var isTrue = Current.Kind == SyntaxKind.TrueKeyword;
var token = MatchToken(isTrue ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
return new LiteralExpressionSyntax(token, isTrue);
}
}
}