2019-06-01 19:38:39 +00:00
|
|
|
#include <algorithm>
|
2019-05-20 15:45:03 +00:00
|
|
|
#include "Parser.hpp"
|
2019-06-01 12:56:28 +00:00
|
|
|
#include "ParsedStatements/ParsedStatement.hpp"
|
2019-05-20 15:45:03 +00:00
|
|
|
#include "UnaryOperatorKind.hpp"
|
|
|
|
#include "BinaryOperatorKind.hpp"
|
2019-05-31 13:00:14 +00:00
|
|
|
#include "TypedVariableIdentifier.hpp"
|
2019-06-12 13:19:28 +00:00
|
|
|
#include "ParsedExpressions/ParsedTableExpression.hpp"
|
2019-05-20 15:45:03 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
namespace Porygon::Parser {
|
|
|
|
ParsedScriptStatement *Parser::Parse() {
|
|
|
|
vector<const ParsedStatement *> statements;
|
|
|
|
while (this->_position < this->_tokens.size()) {
|
|
|
|
auto next = this->Next();
|
|
|
|
if (next->GetKind() == TokenKind::EndOfFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
statements.push_back(this->ParseStatement(next));
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
return new ParsedScriptStatement(statements);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
inline const Token *Parser::Peek() {
|
2019-06-17 16:35:12 +00:00
|
|
|
return this->_tokens[_position];
|
2019-05-26 12:20:40 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
inline const Token *Parser::PeekAt(int offset) {
|
2019-06-17 16:35:12 +00:00
|
|
|
return this->_tokens[_position + offset];
|
2019-05-26 12:20:40 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
inline const Token *Parser::Next() {
|
2019-06-17 16:35:12 +00:00
|
|
|
this->_position++;
|
2019-08-25 09:53:37 +00:00
|
|
|
if (_position > _tokens.size())
|
|
|
|
return nullptr;
|
2019-06-17 16:35:12 +00:00
|
|
|
return this->_tokens[_position - 1];
|
2019-05-26 12:20:40 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseStatement(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
auto currentKind = current->GetKind();
|
|
|
|
switch (currentKind) {
|
|
|
|
case TokenKind::LocalKeyword:
|
|
|
|
return this->ParseVariableAssignment(current);
|
|
|
|
case TokenKind::FunctionKeyword:
|
|
|
|
return this->ParseFunctionDeclaration(current);
|
|
|
|
case TokenKind::ReturnKeyword:
|
|
|
|
return this->ParseReturnStatement(current);
|
|
|
|
case TokenKind::IfKeyword:
|
|
|
|
return this->ParseIfStatement(current);
|
2019-06-22 15:35:33 +00:00
|
|
|
case TokenKind ::ForKeyword:
|
2019-06-27 13:55:46 +00:00
|
|
|
return this->ParseForStatement();
|
2019-06-28 11:28:39 +00:00
|
|
|
case TokenKind ::WhileKeyword:
|
|
|
|
return this->ParseWhileStatement(current);
|
2019-06-27 13:55:46 +00:00
|
|
|
case TokenKind ::BreakKeyword:
|
|
|
|
return new ParsedBreakStatement(current->GetStartPosition(), current -> GetLength());
|
2019-06-17 16:35:12 +00:00
|
|
|
default:
|
|
|
|
break;
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (this->Peek()->GetKind() == TokenKind::AssignmentToken) {
|
|
|
|
return ParseVariableAssignment(current);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
auto expression = this->ParseExpression(current);
|
|
|
|
auto expKind = expression->GetKind();
|
|
|
|
if ((expKind == ParsedExpressionKind::Indexer || expKind == ParsedExpressionKind::PeriodIndexer)
|
|
|
|
&& this->Peek()->GetKind() == TokenKind::AssignmentToken) {
|
|
|
|
return this->ParseIndexAssignment(expression);
|
|
|
|
}
|
|
|
|
return new ParsedExpressionStatement(expression);
|
2019-06-08 12:40:21 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseVariableAssignment(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
bool isLocal = false;
|
2019-07-04 17:08:13 +00:00
|
|
|
const Token *identifier;
|
2019-06-17 16:35:12 +00:00
|
|
|
if (current->GetKind() == TokenKind::LocalKeyword) {
|
|
|
|
isLocal = true;
|
|
|
|
identifier = this->Next();
|
|
|
|
} else {
|
|
|
|
identifier = current;
|
|
|
|
}
|
|
|
|
auto assignmentToken = this->Next();
|
|
|
|
auto expression = this->ParseExpression(this->Next());
|
|
|
|
|
|
|
|
if (identifier->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
identifier->GetLength());
|
|
|
|
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
|
|
|
}
|
|
|
|
if (assignmentToken->GetKind() != TokenKind::AssignmentToken) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
identifier->GetLength());
|
|
|
|
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto start = current->GetStartPosition();
|
2019-07-04 16:24:49 +00:00
|
|
|
return new ParsedAssignmentStatement(isLocal, (dynamic_cast<const IdentifierToken*>(identifier))->GetValue(), expression, start,
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetEndPosition() - start);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
ParsedStatement *Parser::ParseIndexAssignment(ParsedExpression *indexer) {
|
|
|
|
this->Next(); // Consume assignment token
|
|
|
|
auto valueExpression = this->ParseExpression(this->Next());
|
|
|
|
auto start = indexer->GetStartPosition();
|
|
|
|
return new ParsedIndexAssignmentStatement(indexer, valueExpression, start,
|
|
|
|
valueExpression->GetEndPosition() - start);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 16:24:49 +00:00
|
|
|
ParsedBlockStatement *
|
2019-06-17 16:35:12 +00:00
|
|
|
Parser::ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements) {
|
|
|
|
auto statements = openStatements;
|
|
|
|
auto start = this->_position;
|
|
|
|
while (this->_position < this->_tokens.size()) {
|
|
|
|
auto next = this->Next();
|
|
|
|
auto nextKind = next->GetKind();
|
|
|
|
if (std::find(endTokens.begin(), endTokens.end(), nextKind) != endTokens.end()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nextKind == TokenKind::EndOfFile) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
next->GetLength());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
statements.push_back(this->ParseStatement(next));
|
2019-06-08 12:42:23 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (statements.empty()) {
|
|
|
|
return new ParsedBlockStatement(statements, start);
|
|
|
|
}
|
|
|
|
return new ParsedBlockStatement(statements);
|
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseFunctionDeclaration(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
auto functionIdentifierToken = this->Next();
|
|
|
|
auto openParenthesis = this->Next();
|
|
|
|
vector<TypedVariableIdentifier *> parameters;
|
|
|
|
bool hasErrors = false;
|
|
|
|
if (functionIdentifierToken->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken,
|
2019-06-17 16:35:12 +00:00
|
|
|
functionIdentifierToken->GetStartPosition(),
|
|
|
|
functionIdentifierToken->GetLength());
|
2019-05-31 13:00:14 +00:00
|
|
|
hasErrors = true;
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken,
|
2019-06-17 16:35:12 +00:00
|
|
|
openParenthesis->GetStartPosition(), openParenthesis->GetLength());
|
2019-05-31 13:00:14 +00:00
|
|
|
hasErrors = true;
|
|
|
|
}
|
2019-06-08 12:40:21 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
while (this->_position < this->_tokens.size()) {
|
|
|
|
auto type = this->Next();
|
|
|
|
if (type->GetKind() == TokenKind::CloseParenthesis) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
auto identifier = this->Next();
|
|
|
|
auto next = this->Next();
|
2019-08-24 11:54:01 +00:00
|
|
|
if (!hasErrors && type->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
type->GetLength());
|
|
|
|
hasErrors = true;
|
|
|
|
continue;
|
|
|
|
}
|
2019-08-24 11:54:01 +00:00
|
|
|
if (!hasErrors && identifier->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
identifier->GetLength());
|
|
|
|
hasErrors = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type->GetKind() != TokenKind::Identifier || identifier->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
type->GetLength());
|
|
|
|
hasErrors = true;
|
|
|
|
continue;
|
|
|
|
}
|
2019-07-04 16:24:49 +00:00
|
|
|
auto typeToken = dynamic_cast<const IdentifierToken*>(type);
|
|
|
|
auto identifierToken = dynamic_cast<const IdentifierToken*>(identifier);
|
2019-06-17 16:35:12 +00:00
|
|
|
parameters.push_back(new TypedVariableIdentifier(typeToken->GetValue(), identifierToken->GetValue()));
|
|
|
|
|
|
|
|
auto nextKind = next->GetKind();
|
|
|
|
if (nextKind == TokenKind::CloseParenthesis || nextKind == TokenKind::EndOfFile) {
|
|
|
|
break;
|
|
|
|
} else if (nextKind != TokenKind::CommaToken && !hasErrors) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
next->GetLength());
|
|
|
|
hasErrors = true;
|
|
|
|
}
|
2019-06-08 12:40:21 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
auto block = this->ParseBlock({TokenKind::EndKeyword});
|
|
|
|
|
|
|
|
auto start = current->GetStartPosition();
|
2019-08-25 09:53:37 +00:00
|
|
|
auto end = block->GetEndPosition();
|
2019-06-17 16:35:12 +00:00
|
|
|
if (hasErrors) {
|
2019-08-25 09:53:37 +00:00
|
|
|
delete block;
|
|
|
|
return new ParsedBadStatement(start, end - start);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (block->GetKind() == ParsedStatementKind::Bad) {
|
2019-08-25 09:53:37 +00:00
|
|
|
delete block;
|
|
|
|
return new ParsedBadStatement(start, end - start);
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-07-04 16:24:49 +00:00
|
|
|
auto functionIdentifier = dynamic_cast<const IdentifierToken*>(functionIdentifierToken)->GetValue();
|
2019-06-17 16:35:12 +00:00
|
|
|
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters,
|
2019-07-04 16:24:49 +00:00
|
|
|
block, start,
|
2019-06-17 16:35:12 +00:00
|
|
|
block->GetEndPosition() - start);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseReturnStatement(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
auto start = current->GetStartPosition();
|
2019-06-19 14:21:21 +00:00
|
|
|
auto startLine = this -> ScriptData -> Diagnostics ->GetLineFromPosition(start);
|
|
|
|
if (startLine != this -> ScriptData -> Diagnostics -> GetLineFromPosition(this -> Peek() -> GetStartPosition())){
|
|
|
|
return new ParsedReturnStatement(nullptr, start, current->GetLength());
|
|
|
|
}
|
|
|
|
auto expression = this->ParseExpression(this->Next());
|
2019-06-17 16:35:12 +00:00
|
|
|
return new ParsedReturnStatement(expression, start, expression->GetEndPosition() - start);
|
2019-06-08 12:25:15 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseIfStatement(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
auto condition = this->ParseExpression(this->Next());
|
|
|
|
auto next = this->Next();
|
|
|
|
if (next->GetKind() != TokenKind::ThenKeyword) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
next->GetLength());
|
|
|
|
return new ParsedBadStatement(next->GetStartPosition(), next->GetLength());
|
2019-06-05 19:01:59 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
auto block = this->ParseBlock({TokenKind::EndKeyword, TokenKind::ElseKeyword, TokenKind::ElseIfKeyword});
|
|
|
|
auto closeToken = this->PeekAt(-1);
|
|
|
|
auto start = current->GetStartPosition();
|
|
|
|
if (closeToken->GetKind() == TokenKind::ElseIfKeyword) {
|
|
|
|
auto elseIfStatement = this->ParseIfStatement(closeToken);
|
|
|
|
return new ParsedConditionalStatement(condition, block, elseIfStatement, start,
|
|
|
|
elseIfStatement->GetEndPosition() - start);
|
|
|
|
} else if (closeToken->GetKind() == TokenKind::ElseKeyword) {
|
|
|
|
auto elseStatement = this->ParseBlock({TokenKind::EndKeyword});
|
|
|
|
return new ParsedConditionalStatement(condition, block, elseStatement, start,
|
|
|
|
elseStatement->GetEndPosition() - start);
|
|
|
|
}
|
|
|
|
return new ParsedConditionalStatement(condition, block, start, block->GetEndPosition() - start);
|
2019-05-31 13:00:14 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-06-27 13:55:46 +00:00
|
|
|
ParsedStatement *Parser::ParseForStatement() {
|
2019-06-22 15:35:33 +00:00
|
|
|
auto identifier = this -> Next();
|
|
|
|
if (this -> Peek()->GetKind() == TokenKind::AssignmentToken){
|
|
|
|
return ParseNumericForStatement(identifier);
|
|
|
|
} else {
|
|
|
|
return ParseGenericForStatement(identifier);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseNumericForStatement(const Token *current) {
|
2019-07-04 16:24:49 +00:00
|
|
|
auto identifier = dynamic_cast<const IdentifierToken*>(current);
|
2019-06-22 15:35:33 +00:00
|
|
|
this->Next(); // consume assignment token
|
|
|
|
bool hasErrors = false;
|
|
|
|
auto start = this ->ParseExpression(this ->Next());
|
|
|
|
auto comma = this -> Next(); // consume comma token
|
|
|
|
if (comma->GetKind() != TokenKind::CommaToken){
|
|
|
|
hasErrors = true;
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, comma->GetStartPosition(),
|
|
|
|
comma->GetLength());
|
|
|
|
}
|
|
|
|
auto end = this -> ParseExpression(this -> Next());
|
|
|
|
ParsedExpression *step = nullptr;
|
|
|
|
if (this -> Peek()->GetKind() == TokenKind::CommaToken){
|
|
|
|
this -> Next();
|
|
|
|
step = this -> ParseExpression(this -> Next());
|
|
|
|
}
|
|
|
|
auto doToken = this ->Next();
|
|
|
|
if (doToken->GetKind() != TokenKind::DoKeyword && !hasErrors){
|
|
|
|
hasErrors = true;
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, doToken->GetStartPosition(),
|
|
|
|
doToken->GetLength());
|
|
|
|
}
|
|
|
|
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
|
|
|
auto startPos = current->GetStartPosition();
|
|
|
|
if (hasErrors){
|
|
|
|
return new ParsedBadStatement(startPos, block -> GetEndPosition() - startPos);
|
|
|
|
}
|
|
|
|
return new ParsedNumericalForStatement(identifier->GetValue(), start, end, step, block, startPos, block->GetEndPosition() - startPos);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseGenericForStatement(const Token *current) {
|
2019-07-04 16:24:49 +00:00
|
|
|
auto keyIdentifier = dynamic_cast<const IdentifierToken*>(current)->GetValue();
|
|
|
|
const IdentifierToken* valueIdentifierToken = nullptr;
|
2019-06-26 14:19:34 +00:00
|
|
|
bool hasErrors = false;
|
|
|
|
auto next = this -> Next();
|
|
|
|
if (next -> GetKind() == TokenKind::CommaToken){
|
|
|
|
next = this -> Next();
|
|
|
|
if (next->GetKind() != TokenKind::Identifier){
|
|
|
|
hasErrors = true;
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
|
|
|
next->GetLength());
|
|
|
|
} else{
|
2019-07-04 16:24:49 +00:00
|
|
|
valueIdentifierToken = dynamic_cast<const IdentifierToken*>(next);
|
2019-06-26 14:19:34 +00:00
|
|
|
next = this -> Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (next->GetKind() != TokenKind::InKeyword && !hasErrors){
|
|
|
|
hasErrors = true;
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
|
|
|
next->GetLength());
|
|
|
|
}
|
|
|
|
auto expression = this -> ParseExpression(this -> Next());
|
|
|
|
next = this -> Next();
|
|
|
|
if (next -> GetKind() != TokenKind::DoKeyword && !hasErrors){
|
|
|
|
hasErrors = true;
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
|
|
|
next->GetLength());
|
|
|
|
}
|
|
|
|
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
|
|
|
auto startPos = current->GetStartPosition();
|
|
|
|
if (hasErrors){
|
|
|
|
return new ParsedBadStatement(startPos, block -> GetEndPosition() - startPos);
|
|
|
|
} else{
|
|
|
|
auto valueIdentifier = HashedString::CreateLookup(0);
|
|
|
|
if (valueIdentifierToken != nullptr){
|
|
|
|
return new ParsedGenericForStatement(keyIdentifier, valueIdentifierToken -> GetValue(), expression, block,
|
|
|
|
startPos, block -> GetEndPosition() - startPos);
|
|
|
|
} else{
|
|
|
|
return new ParsedGenericForStatement(keyIdentifier, HashedString::CreateLookup(0), expression, block,
|
|
|
|
startPos, block -> GetEndPosition() - startPos);
|
|
|
|
}
|
|
|
|
}
|
2019-06-22 15:35:33 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedStatement *Parser::ParseWhileStatement(const Token *current) {
|
2019-06-28 11:28:39 +00:00
|
|
|
auto condition = this -> ParseExpression(this -> Next());
|
|
|
|
auto doKeyword = this -> Next();
|
|
|
|
if (doKeyword -> GetKind() != TokenKind::DoKeyword){
|
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, doKeyword->GetStartPosition(),
|
|
|
|
doKeyword->GetLength());
|
|
|
|
return new ParsedBadStatement(doKeyword->GetStartPosition(), doKeyword->GetLength());
|
|
|
|
}
|
|
|
|
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
|
|
|
auto start = current -> GetStartPosition();
|
|
|
|
return new ParsedWhileStatement(condition, block, start, block->GetEndPosition() - start);
|
|
|
|
}
|
|
|
|
|
2019-06-22 15:35:33 +00:00
|
|
|
/////////////////
|
|
|
|
// Expressions //
|
|
|
|
/////////////////
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedExpression *Parser::ParseExpression(const Token *current) {
|
2019-08-18 13:44:55 +00:00
|
|
|
return this->ParseBinaryExpression(current, OperatorPrecedence::No);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParsedExpression* Parser::ParseComplexExpression(ParsedExpression* expression){
|
2019-06-17 16:35:12 +00:00
|
|
|
auto peekKind = this->Peek()->GetKind();
|
|
|
|
while (peekKind == TokenKind::OpenParenthesis ||
|
|
|
|
peekKind == TokenKind::OpenSquareBracket ||
|
|
|
|
peekKind == TokenKind::PeriodToken) {
|
|
|
|
if (peekKind == TokenKind::OpenParenthesis) {
|
|
|
|
expression = this->ParseFunctionCallExpression(expression);
|
|
|
|
} else if (peekKind == TokenKind::OpenSquareBracket) {
|
|
|
|
expression = this->ParseIndexExpression(expression);
|
|
|
|
} else {
|
|
|
|
expression = this->ParsePeriodIndexExpression(expression);
|
|
|
|
}
|
|
|
|
if (this->_position >= this->_tokens.size())
|
|
|
|
break;
|
|
|
|
peekKind = this->Peek()->GetKind();
|
|
|
|
}
|
|
|
|
return expression;
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
OperatorPrecedence GetUnaryPrecedence(TokenKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case TokenKind::PlusToken:
|
|
|
|
case TokenKind::MinusToken:
|
|
|
|
case TokenKind::NotKeyword:
|
|
|
|
return OperatorPrecedence::Unary;
|
|
|
|
default:
|
|
|
|
return OperatorPrecedence::No;
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case TokenKind::PlusToken:
|
|
|
|
return UnaryOperatorKind::Identity;
|
|
|
|
case TokenKind::MinusToken:
|
|
|
|
return UnaryOperatorKind::Negation;
|
|
|
|
case TokenKind::NotKeyword:
|
|
|
|
return UnaryOperatorKind::LogicalNegation;
|
|
|
|
default: // This should never trigger, so throw.
|
|
|
|
throw;
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
// Math operators
|
|
|
|
case TokenKind::PlusToken:
|
|
|
|
return BinaryOperatorKind::Addition;
|
|
|
|
case TokenKind::MinusToken:
|
|
|
|
return BinaryOperatorKind::Subtraction;
|
|
|
|
case TokenKind::StarToken:
|
|
|
|
return BinaryOperatorKind::Multiplication;
|
|
|
|
case TokenKind::SlashToken:
|
|
|
|
return BinaryOperatorKind::Division;
|
|
|
|
|
|
|
|
// Equality operators
|
|
|
|
case TokenKind::EqualityToken:
|
|
|
|
return BinaryOperatorKind::Equality;
|
|
|
|
case TokenKind::InequalityToken:
|
|
|
|
return BinaryOperatorKind::Inequality;
|
|
|
|
case TokenKind::Less:
|
|
|
|
return BinaryOperatorKind::Less;
|
|
|
|
case TokenKind::LessEquals:
|
|
|
|
return BinaryOperatorKind::LessOrEquals;
|
|
|
|
case TokenKind::Greater:
|
|
|
|
return BinaryOperatorKind::Greater;
|
|
|
|
case TokenKind::GreaterEquals:
|
|
|
|
return BinaryOperatorKind::GreaterOrEquals;
|
|
|
|
|
|
|
|
// logical operators
|
|
|
|
case TokenKind::AndKeyword:
|
|
|
|
return BinaryOperatorKind::LogicalAnd;
|
|
|
|
case TokenKind::OrKeyword:
|
|
|
|
return BinaryOperatorKind::LogicalOr;
|
|
|
|
default: // This should never trigger, so throw.
|
|
|
|
throw;
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
OperatorPrecedence GetBinaryPrecedence(TokenKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
// Math
|
|
|
|
case TokenKind::PlusToken:
|
|
|
|
return OperatorPrecedence::Additive;
|
|
|
|
case TokenKind::MinusToken:
|
|
|
|
return OperatorPrecedence::Additive;
|
|
|
|
case TokenKind::StarToken:
|
|
|
|
return OperatorPrecedence::Multiplication;
|
|
|
|
case TokenKind::SlashToken:
|
|
|
|
return OperatorPrecedence::Multiplication;
|
|
|
|
|
|
|
|
// Equality
|
|
|
|
case TokenKind::EqualityToken:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
case TokenKind::InequalityToken:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
case TokenKind::Less:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
case TokenKind::LessEquals:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
case TokenKind::Greater:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
case TokenKind::GreaterEquals:
|
|
|
|
return OperatorPrecedence::Equality;
|
|
|
|
|
|
|
|
// Logical
|
|
|
|
case TokenKind::AndKeyword:
|
|
|
|
return OperatorPrecedence::LogicalAnd;
|
|
|
|
case TokenKind::OrKeyword:
|
|
|
|
return OperatorPrecedence::LogicalOr;
|
|
|
|
default:
|
|
|
|
return OperatorPrecedence::No;
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedExpression *Parser::ParseBinaryExpression(const Token *current, OperatorPrecedence parentPrecedence) {
|
2019-06-17 16:35:12 +00:00
|
|
|
OperatorPrecedence unaryPrecedence = GetUnaryPrecedence(current->GetKind());
|
|
|
|
ParsedExpression *left;
|
|
|
|
if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence) {
|
|
|
|
UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current->GetKind());
|
|
|
|
auto next = this->Next();
|
|
|
|
auto operand = this->ParseBinaryExpression(next, unaryPrecedence);
|
|
|
|
auto startPos = current->GetStartPosition();
|
|
|
|
left = new UnaryExpression(operatorKind, operand, startPos, operand->GetEndPosition() - startPos);
|
2019-08-18 13:44:55 +00:00
|
|
|
left = this -> ParseComplexExpression(left);
|
2019-06-17 16:35:12 +00:00
|
|
|
} else {
|
|
|
|
left = this->ParsePrimaryExpression(current);
|
2019-08-18 13:44:55 +00:00
|
|
|
left = this -> ParseComplexExpression(left);
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
while (true) {
|
|
|
|
auto next = this->Peek();
|
|
|
|
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next->GetKind());
|
|
|
|
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
auto operatorKind = GetBinaryOperatorKind(next->GetKind());
|
|
|
|
this->Next();
|
|
|
|
auto right = this->ParseBinaryExpression(this->Next(), binaryPrecedence);
|
|
|
|
auto startPos = left->GetStartPosition();
|
|
|
|
left = new BinaryExpression(operatorKind, left, right, startPos, right->GetEndPosition() - startPos);
|
2019-08-18 13:44:55 +00:00
|
|
|
left = this -> ParseComplexExpression(left);
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-08-18 13:44:55 +00:00
|
|
|
return this -> ParseComplexExpression(left);
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedExpression *Parser::ParsePrimaryExpression(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
switch (current->GetKind()) {
|
|
|
|
case TokenKind::Integer:
|
2019-07-04 16:24:49 +00:00
|
|
|
return new LiteralIntegerExpression(dynamic_cast<const IntegerToken*>(current));
|
2019-06-17 16:35:12 +00:00
|
|
|
case TokenKind::Float:
|
2019-07-04 16:24:49 +00:00
|
|
|
return new LiteralFloatExpression(dynamic_cast<const FloatToken*>(current));
|
2019-06-17 16:35:12 +00:00
|
|
|
case TokenKind::String:
|
2019-07-04 16:24:49 +00:00
|
|
|
return new LiteralStringExpression(dynamic_cast<const StringToken*>(current));
|
2019-06-17 16:35:12 +00:00
|
|
|
case TokenKind::TrueKeyword:
|
|
|
|
return new LiteralBoolExpression(current);
|
|
|
|
case TokenKind::FalseKeyword:
|
|
|
|
return new LiteralBoolExpression(current);
|
2019-09-01 14:16:36 +00:00
|
|
|
case TokenKind::NilKeyword:
|
|
|
|
return new NilExpression(current);
|
2019-06-17 16:35:12 +00:00
|
|
|
case TokenKind::Identifier:
|
2019-07-04 16:24:49 +00:00
|
|
|
return new VariableExpression(dynamic_cast<const IdentifierToken*>(current));
|
2019-06-17 16:35:12 +00:00
|
|
|
case TokenKind::OpenParenthesis:
|
|
|
|
return this->ParseParenthesizedExpression(current);
|
|
|
|
case TokenKind::OpenCurlyBracket:
|
|
|
|
return this->ParseTableExpression(current);
|
|
|
|
// If we find a bad token here, we should have already logged it in the lexer, so don't log another error.
|
|
|
|
case TokenKind::BadToken:
|
|
|
|
return new BadExpression(current->GetStartPosition(), current->GetLength());
|
|
|
|
default:
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, current->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
current->GetLength());
|
|
|
|
return new BadExpression(current->GetStartPosition(), current->GetLength());
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedExpression *Parser::ParseParenthesizedExpression(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
auto next = this->Next();
|
|
|
|
auto expression = this->ParseExpression(next);
|
|
|
|
auto closeToken = this->Next();
|
|
|
|
if (closeToken->GetKind() != TokenKind::CloseParenthesis) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
closeToken->GetLength());
|
|
|
|
return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength());
|
|
|
|
}
|
|
|
|
auto start = current->GetStartPosition();
|
|
|
|
return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start);
|
2019-05-21 15:16:53 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
ParsedExpression *Parser::ParseFunctionCallExpression(ParsedExpression *functionExpression) {
|
|
|
|
this->Next(); // consume the open parenthesis
|
|
|
|
vector<const ParsedExpression *> parameters;
|
|
|
|
auto peeked = this->Peek();
|
|
|
|
auto peekedKind = peeked->GetKind();
|
|
|
|
if (peekedKind == TokenKind::CloseParenthesis) {
|
|
|
|
this->Next();
|
|
|
|
} else {
|
|
|
|
while (peekedKind != TokenKind::CloseParenthesis) {
|
|
|
|
if (peekedKind == TokenKind::EndOfFile) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
peeked->GetLength());
|
|
|
|
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
|
|
|
|
}
|
|
|
|
parameters.push_back(this->ParseExpression(this->Next()));
|
|
|
|
peeked = this->Next();
|
|
|
|
peekedKind = peeked->GetKind();
|
|
|
|
if (peekedKind != TokenKind::CloseParenthesis && peekedKind != TokenKind::CommaToken) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
peeked->GetLength());
|
|
|
|
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
|
|
|
|
}
|
2019-06-08 14:30:23 +00:00
|
|
|
}
|
2019-06-01 12:56:28 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
auto start = functionExpression->GetStartPosition();
|
|
|
|
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
|
2019-06-01 12:56:28 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
ParsedExpression *Parser::ParseIndexExpression(ParsedExpression *indexingExpression) {
|
|
|
|
this->Next(); // consume '[' token
|
|
|
|
auto indexExpression = this->ParseExpression(this->Next());
|
|
|
|
auto closeBracket = this->Next();
|
|
|
|
if (closeBracket->GetKind() != TokenKind::CloseSquareBracket) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, closeBracket->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
closeBracket->GetLength());
|
|
|
|
return new BadExpression(closeBracket->GetStartPosition(), closeBracket->GetLength());
|
|
|
|
}
|
|
|
|
auto start = indexingExpression->GetStartPosition();
|
|
|
|
return new IndexExpression(indexingExpression, indexExpression, start, closeBracket->GetEndPosition() - start);
|
2019-06-06 15:35:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
ParsedExpression *Parser::ParsePeriodIndexExpression(ParsedExpression *indexingExpression) {
|
|
|
|
this->Next(); // consume '.' token
|
|
|
|
auto identifier = this->Next();
|
|
|
|
if (identifier->GetKind() != TokenKind::Identifier) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
identifier->GetLength());
|
|
|
|
return new BadExpression(indexingExpression->GetStartPosition(),
|
|
|
|
identifier->GetEndPosition() - indexingExpression->GetStartPosition());
|
|
|
|
}
|
|
|
|
auto start = indexingExpression->GetStartPosition();
|
2019-07-04 16:24:49 +00:00
|
|
|
return new PeriodIndexExpression(indexingExpression, dynamic_cast<const IdentifierToken*>(identifier)->GetValue(), start,
|
2019-06-17 16:35:12 +00:00
|
|
|
identifier->GetEndPosition() - start);
|
2019-06-17 13:45:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-04 17:08:13 +00:00
|
|
|
ParsedExpression *Parser::ParseTableExpression(const Token *current) {
|
2019-06-17 16:35:12 +00:00
|
|
|
if (this->Peek()->GetKind() == TokenKind::CloseCurlyBracket) {
|
|
|
|
this->Next();
|
|
|
|
auto start = current->GetStartPosition();
|
|
|
|
return new ParsedNumericalTableExpression({}, start, this->Peek()->GetEndPosition() - start);
|
|
|
|
}
|
2019-06-09 18:15:09 +00:00
|
|
|
auto start = current->GetStartPosition();
|
2019-06-17 16:35:12 +00:00
|
|
|
auto firstItem = this->ParseStatement(this->Next());
|
|
|
|
// If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array
|
|
|
|
if (firstItem->GetKind() == ParsedStatementKind::Expression &&
|
|
|
|
(this->Peek()->GetKind() == TokenKind::CommaToken)) {
|
2019-07-04 16:24:49 +00:00
|
|
|
auto statement = dynamic_cast<ParsedExpressionStatement*>(firstItem);
|
2019-06-24 11:38:41 +00:00
|
|
|
auto expr = statement->GetExpression();
|
|
|
|
statement->NullifyExpression();
|
|
|
|
delete statement;
|
2019-06-17 16:35:12 +00:00
|
|
|
auto expressions = vector<const ParsedExpression *>{expr};
|
|
|
|
auto n = this->Next(); // consume the comma
|
|
|
|
bool hasErrors = false;
|
|
|
|
while (n->GetKind() != TokenKind::CloseCurlyBracket) {
|
|
|
|
auto expression = this->ParseExpression(this->Next());
|
|
|
|
expressions.push_back(expression);
|
|
|
|
n = this->Next();
|
|
|
|
if (n->GetKind() != TokenKind::CommaToken && n->GetKind() != TokenKind::CloseCurlyBracket &&
|
|
|
|
!hasErrors) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedToken, n->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
n->GetLength());
|
|
|
|
hasErrors = true;
|
|
|
|
}
|
2019-06-09 18:15:09 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (hasErrors) {
|
|
|
|
return new BadExpression(start, n->GetEndPosition() - start);
|
|
|
|
}
|
|
|
|
return new ParsedNumericalTableExpression(expressions, start, n->GetEndPosition() - start);
|
2019-06-09 18:15:09 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
// Otherwise we have a more complex table, which can be defined by a block
|
|
|
|
else {
|
2019-07-04 16:24:49 +00:00
|
|
|
auto block = this->ParseBlock({TokenKind::CloseCurlyBracket}, {firstItem});
|
2019-06-17 16:35:12 +00:00
|
|
|
auto closeToken = this->PeekAt(-1);
|
|
|
|
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
|
2019-06-09 18:15:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|