Added namespaces to most classes, general cleanup
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -1,23 +1,26 @@
|
||||
|
||||
#ifndef PORYGONLANG_BINARYOPERATORKIND_HPP
|
||||
#define PORYGONLANG_BINARYOPERATORKIND_HPP
|
||||
enum class BinaryOperatorKind{
|
||||
// Math
|
||||
Addition,
|
||||
Subtraction,
|
||||
Multiplication,
|
||||
Division,
|
||||
|
||||
// Equality
|
||||
Equality,
|
||||
Inequality,
|
||||
Less,
|
||||
LessOrEquals,
|
||||
Greater,
|
||||
GreaterOrEquals,
|
||||
namespace Porygon::Parser {
|
||||
enum class BinaryOperatorKind {
|
||||
// Math
|
||||
Addition,
|
||||
Subtraction,
|
||||
Multiplication,
|
||||
Division,
|
||||
|
||||
// Logical
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
};
|
||||
// Equality
|
||||
Equality,
|
||||
Inequality,
|
||||
Less,
|
||||
LessOrEquals,
|
||||
Greater,
|
||||
GreaterOrEquals,
|
||||
|
||||
// Logical
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
};
|
||||
}
|
||||
#endif //PORYGONLANG_BINARYOPERATORKIND_HPP
|
||||
|
||||
@@ -5,270 +5,313 @@
|
||||
|
||||
#include "Lexer.hpp"
|
||||
|
||||
Lexer::Lexer(const u16string& scriptString, class Script* script)
|
||||
: _scriptString(scriptString)
|
||||
{
|
||||
this->_scriptSize = scriptString.size();
|
||||
this -> ScriptData = script;
|
||||
this -> _position = 0;
|
||||
}
|
||||
|
||||
|
||||
vector<const IToken*> Lexer::Lex() {
|
||||
vector<const IToken*> tokens;
|
||||
while (true){
|
||||
IToken* next = this -> LexNext(this -> Next());
|
||||
auto nextKind = next -> GetKind();
|
||||
if (nextKind != TokenKind::WhiteSpace)
|
||||
tokens.push_back(next);
|
||||
else
|
||||
delete next;
|
||||
if (nextKind == TokenKind::EndOfFile)
|
||||
break;
|
||||
namespace Porygon::Parser {
|
||||
Lexer::Lexer(const u16string &scriptString, Porygon::Script *script)
|
||||
: _scriptString(scriptString) {
|
||||
this->_scriptSize = scriptString.size();
|
||||
this->ScriptData = script;
|
||||
this->_position = 0;
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
char16_t Lexer::Peek(){
|
||||
if (Lexer::_position >= this -> _scriptSize)
|
||||
return '\0';
|
||||
return this -> _scriptString.at(Lexer::_position);
|
||||
}
|
||||
|
||||
char16_t Lexer::Next(){
|
||||
char16_t next = Peek();
|
||||
Lexer::_position++;
|
||||
return next;
|
||||
}
|
||||
vector<const IToken *> Lexer::Lex() {
|
||||
vector<const IToken *> tokens;
|
||||
while (true) {
|
||||
IToken *next = this->LexNext(this->Next());
|
||||
auto nextKind = next->GetKind();
|
||||
if (nextKind != TokenKind::WhiteSpace)
|
||||
tokens.push_back(next);
|
||||
else
|
||||
delete next;
|
||||
if (nextKind == TokenKind::EndOfFile)
|
||||
break;
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
IToken* Lexer::LexNext(char16_t c){
|
||||
switch (c) {
|
||||
case '\0':
|
||||
return new SimpleToken(TokenKind::EndOfFile, this -> _position - 1, 1);
|
||||
case ' ': case '\t': case '\n': case '\r': case '\v': case '\f':
|
||||
return new SimpleToken(TokenKind::WhiteSpace, this -> _position - 1, 1);
|
||||
case '+':
|
||||
return new SimpleToken(TokenKind::PlusToken, this -> _position - 1, 1);
|
||||
case '-':
|
||||
return new SimpleToken(TokenKind::MinusToken, this -> _position - 1, 1);
|
||||
case '/':
|
||||
return new SimpleToken(TokenKind::SlashToken, this -> _position - 1, 1);
|
||||
case '*':
|
||||
return new SimpleToken(TokenKind::StarToken, this -> _position - 1, 1);
|
||||
case '(':
|
||||
return new SimpleToken(TokenKind::OpenParenthesis, this -> _position - 1, 1);
|
||||
case ')':
|
||||
return new SimpleToken(TokenKind::CloseParenthesis, this -> _position - 1, 1);
|
||||
case '[':
|
||||
return new SimpleToken(TokenKind::OpenSquareBracket, this -> _position - 1, 1);
|
||||
case ']':
|
||||
return new SimpleToken(TokenKind::CloseSquareBracket, this -> _position - 1, 1);
|
||||
case '{':
|
||||
return new SimpleToken(TokenKind::OpenCurlyBracket, this -> _position - 1, 1);
|
||||
case '}':
|
||||
return new SimpleToken(TokenKind::CloseCurlyBracket, this -> _position - 1, 1);
|
||||
case ',':
|
||||
return new SimpleToken(TokenKind::CommaToken, this -> _position - 1, 1);
|
||||
case '.':
|
||||
return new SimpleToken(TokenKind::PeriodToken, this -> _position - 1, 1);
|
||||
case '=':
|
||||
if (Lexer::Peek() == '='){
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::EqualityToken, this -> _position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::AssignmentToken, this -> _position - 1, 1);
|
||||
case '<':
|
||||
if (Lexer::Peek() == '='){
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::LessEquals, this -> _position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::Less, this -> _position - 1, 1);
|
||||
case '>':
|
||||
if (Lexer::Peek() == '='){
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::GreaterEquals, this -> _position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::Greater, this -> _position - 1, 1);
|
||||
case '~':
|
||||
if (Lexer::Peek() == '='){
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::InequalityToken, this -> _position - 2, 2);
|
||||
}
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedCharacter, this -> _position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, this -> _position - 1, 1);
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
return LexNumber(c);
|
||||
case '"':
|
||||
return LexString(c);
|
||||
case '\'':
|
||||
return LexString(c);
|
||||
case '_':
|
||||
return LexIdentifierOrKeyword();
|
||||
default:
|
||||
if (isalpha(c) || c > 255){
|
||||
char16_t Lexer::Peek() {
|
||||
if (Lexer::_position >= this->_scriptSize)
|
||||
return '\0';
|
||||
return this->_scriptString.at(Lexer::_position);
|
||||
}
|
||||
|
||||
char16_t Lexer::Next() {
|
||||
char16_t next = Peek();
|
||||
Lexer::_position++;
|
||||
return next;
|
||||
}
|
||||
|
||||
IToken *Lexer::LexNext(char16_t c) {
|
||||
switch (c) {
|
||||
case '\0':
|
||||
return new SimpleToken(TokenKind::EndOfFile, this->_position - 1, 1);
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\v':
|
||||
case '\f':
|
||||
return new SimpleToken(TokenKind::WhiteSpace, this->_position - 1, 1);
|
||||
case '+':
|
||||
return new SimpleToken(TokenKind::PlusToken, this->_position - 1, 1);
|
||||
case '-':
|
||||
return new SimpleToken(TokenKind::MinusToken, this->_position - 1, 1);
|
||||
case '/':
|
||||
return new SimpleToken(TokenKind::SlashToken, this->_position - 1, 1);
|
||||
case '*':
|
||||
return new SimpleToken(TokenKind::StarToken, this->_position - 1, 1);
|
||||
case '(':
|
||||
return new SimpleToken(TokenKind::OpenParenthesis, this->_position - 1, 1);
|
||||
case ')':
|
||||
return new SimpleToken(TokenKind::CloseParenthesis, this->_position - 1, 1);
|
||||
case '[':
|
||||
return new SimpleToken(TokenKind::OpenSquareBracket, this->_position - 1, 1);
|
||||
case ']':
|
||||
return new SimpleToken(TokenKind::CloseSquareBracket, this->_position - 1, 1);
|
||||
case '{':
|
||||
return new SimpleToken(TokenKind::OpenCurlyBracket, this->_position - 1, 1);
|
||||
case '}':
|
||||
return new SimpleToken(TokenKind::CloseCurlyBracket, this->_position - 1, 1);
|
||||
case ',':
|
||||
return new SimpleToken(TokenKind::CommaToken, this->_position - 1, 1);
|
||||
case '.':
|
||||
return new SimpleToken(TokenKind::PeriodToken, this->_position - 1, 1);
|
||||
case '=':
|
||||
if (Lexer::Peek() == '=') {
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::EqualityToken, this->_position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::AssignmentToken, this->_position - 1, 1);
|
||||
case '<':
|
||||
if (Lexer::Peek() == '=') {
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::LessEquals, this->_position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::Less, this->_position - 1, 1);
|
||||
case '>':
|
||||
if (Lexer::Peek() == '=') {
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::GreaterEquals, this->_position - 2, 2);
|
||||
}
|
||||
return new SimpleToken(TokenKind::Greater, this->_position - 1, 1);
|
||||
case '~':
|
||||
if (Lexer::Peek() == '=') {
|
||||
Lexer::Next();
|
||||
return new SimpleToken(TokenKind::InequalityToken, this->_position - 2, 2);
|
||||
}
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1);
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return LexNumber(c);
|
||||
case '"':
|
||||
return LexString(c);
|
||||
case '\'':
|
||||
return LexString(c);
|
||||
case '_':
|
||||
return LexIdentifierOrKeyword();
|
||||
}
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedCharacter, this -> _position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, this -> _position - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int CharToInt(char16_t c){
|
||||
switch (c){
|
||||
case '0': return 0;
|
||||
case '1': return 1;
|
||||
case '2': return 2;
|
||||
case '3': return 3;
|
||||
case '4': return 4;
|
||||
case '5': return 5;
|
||||
case '6': return 6;
|
||||
case '7': return 7;
|
||||
case '8': return 8;
|
||||
case '9': return 9;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
IToken* Lexer::LexNumber(char16_t c){
|
||||
long int_value = CharToInt(c);
|
||||
double float_value = 0;
|
||||
short decimal_index = 0;
|
||||
bool has_point = false;
|
||||
bool is_searching = true;
|
||||
unsigned int start = this -> _position - 1;
|
||||
unsigned int length = 1;
|
||||
while (is_searching){
|
||||
char16_t next = this -> Peek();
|
||||
int next_val = CharToInt(next);
|
||||
if (next_val == -1){
|
||||
switch (next){
|
||||
case '_':
|
||||
this -> Next();
|
||||
length++;
|
||||
continue;
|
||||
case '.':
|
||||
this -> Next();
|
||||
has_point = true;
|
||||
decimal_index = 0;
|
||||
float_value = int_value;
|
||||
length++;
|
||||
continue;
|
||||
default:
|
||||
is_searching = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
this -> Next();
|
||||
length++;
|
||||
if (has_point){
|
||||
decimal_index++;
|
||||
float_value += next_val / pow(10, decimal_index);
|
||||
}
|
||||
else {
|
||||
int_value *= 10;
|
||||
int_value += next_val;
|
||||
}
|
||||
default:
|
||||
if (isalpha(c) || c > 255) {
|
||||
return LexIdentifierOrKeyword();
|
||||
}
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1);
|
||||
}
|
||||
}
|
||||
if (has_point){
|
||||
return new FloatToken(float_value, start, length);
|
||||
}
|
||||
else{
|
||||
return new IntegerToken(int_value, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
IToken * Lexer::LexIdentifierOrKeyword() {
|
||||
auto start = this -> _position - 1;
|
||||
auto end = start;
|
||||
while (true){
|
||||
char16_t next = this -> Peek();
|
||||
if (next == '\0') break;
|
||||
if (isalpha(next) || next == '_' || next > 255){
|
||||
this -> Next();
|
||||
int CharToInt(char16_t c) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
return 0;
|
||||
case '1':
|
||||
return 1;
|
||||
case '2':
|
||||
return 2;
|
||||
case '3':
|
||||
return 3;
|
||||
case '4':
|
||||
return 4;
|
||||
case '5':
|
||||
return 5;
|
||||
case '6':
|
||||
return 6;
|
||||
case '7':
|
||||
return 7;
|
||||
case '8':
|
||||
return 8;
|
||||
case '9':
|
||||
return 9;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
IToken *Lexer::LexNumber(char16_t c) {
|
||||
long int_value = CharToInt(c);
|
||||
double float_value = 0;
|
||||
short decimal_index = 0;
|
||||
bool has_point = false;
|
||||
bool is_searching = true;
|
||||
unsigned int start = this->_position - 1;
|
||||
unsigned int length = 1;
|
||||
while (is_searching) {
|
||||
char16_t next = this->Peek();
|
||||
int next_val = CharToInt(next);
|
||||
if (next_val == -1) {
|
||||
switch (next) {
|
||||
case '_':
|
||||
this->Next();
|
||||
length++;
|
||||
continue;
|
||||
case '.':
|
||||
this->Next();
|
||||
has_point = true;
|
||||
decimal_index = 0;
|
||||
float_value = int_value;
|
||||
length++;
|
||||
continue;
|
||||
default:
|
||||
is_searching = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
this->Next();
|
||||
length++;
|
||||
if (has_point) {
|
||||
decimal_index++;
|
||||
float_value += next_val / pow(10, decimal_index);
|
||||
} else {
|
||||
int_value *= 10;
|
||||
int_value += next_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (has_point) {
|
||||
return new FloatToken(float_value, start, length);
|
||||
} else {
|
||||
return new IntegerToken(int_value, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
IToken *Lexer::LexIdentifierOrKeyword() {
|
||||
auto start = this->_position - 1;
|
||||
auto end = start;
|
||||
while (true) {
|
||||
char16_t next = this->Peek();
|
||||
if (next == '\0') break;
|
||||
if (isalpha(next) || next == '_' || next > 255) {
|
||||
this->Next();
|
||||
end++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u16string s = this->_scriptString.substr(start, end - start + 1);
|
||||
switch (HashedString::ConstHash(s.c_str())) {
|
||||
case HashedString::ConstHash("and"):
|
||||
return new SimpleToken(TokenKind::AndKeyword, start, 3);
|
||||
case HashedString::ConstHash("break"):
|
||||
return new SimpleToken(TokenKind::BreakKeyword, start, 5);
|
||||
case HashedString::ConstHash("do"):
|
||||
return new SimpleToken(TokenKind::DoKeyword, start, 2);
|
||||
case HashedString::ConstHash("else"):
|
||||
return new SimpleToken(TokenKind::ElseKeyword, start, 4);
|
||||
case HashedString::ConstHash("elseif"):
|
||||
return new SimpleToken(TokenKind::ElseIfKeyword, start, 6);
|
||||
case HashedString::ConstHash("end"):
|
||||
return new SimpleToken(TokenKind::EndKeyword, start, 3);
|
||||
case HashedString::ConstHash("false"):
|
||||
return new SimpleToken(TokenKind::FalseKeyword, start, 5);
|
||||
case HashedString::ConstHash("for"):
|
||||
return new SimpleToken(TokenKind::ForKeyword, start, 3);
|
||||
case HashedString::ConstHash("function"):
|
||||
return new SimpleToken(TokenKind::FunctionKeyword, start, 8);
|
||||
case HashedString::ConstHash("if"):
|
||||
return new SimpleToken(TokenKind::IfKeyword, start, 2);
|
||||
case HashedString::ConstHash("in"):
|
||||
return new SimpleToken(TokenKind::InKeyword, start, 2);
|
||||
case HashedString::ConstHash("local"):
|
||||
return new SimpleToken(TokenKind::LocalKeyword, start, 5);
|
||||
case HashedString::ConstHash("nil"):
|
||||
return new SimpleToken(TokenKind::NilKeyword, start, 3);
|
||||
case HashedString::ConstHash("not"):
|
||||
return new SimpleToken(TokenKind::NotKeyword, start, 3);
|
||||
case HashedString::ConstHash("or"):
|
||||
return new SimpleToken(TokenKind::OrKeyword, start, 2);
|
||||
case HashedString::ConstHash("return"):
|
||||
return new SimpleToken(TokenKind::ReturnKeyword, start, 6);
|
||||
case HashedString::ConstHash("then"):
|
||||
return new SimpleToken(TokenKind::ThenKeyword, start, 4);
|
||||
case HashedString::ConstHash("true"):
|
||||
return new SimpleToken(TokenKind::TrueKeyword, start, 4);
|
||||
case HashedString::ConstHash("while"):
|
||||
return new SimpleToken(TokenKind::WhileKeyword, start, 5);
|
||||
default:
|
||||
return new IdentifierToken(HashedString(s), start, s.length());
|
||||
}
|
||||
}
|
||||
|
||||
const unordered_map<char16_t, char16_t> ControlCharacters{ // NOLINT(cert-err58-cpp)
|
||||
{'0', '\0'},
|
||||
{'a', '\a'},
|
||||
{'b', '\b'},
|
||||
{'t', '\t'},
|
||||
{'n', '\n'},
|
||||
{'v', '\v'},
|
||||
{'f', '\f'},
|
||||
{'r', '\r'},
|
||||
{'"', '\"'},
|
||||
{'\'', '\''},
|
||||
{'\?', '\?'},
|
||||
{'\\', '\\'},
|
||||
};
|
||||
|
||||
IToken *Lexer::LexString(char16_t c) {
|
||||
auto start = this->_position - 1;
|
||||
auto end = start;
|
||||
char16_t last = c;
|
||||
while (true) {
|
||||
char16_t next = this->Peek();
|
||||
if (next == '\0') break;
|
||||
if (next == c && last != '\\') break;
|
||||
this->Next();
|
||||
end++;
|
||||
last = next;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
auto closeToken = this->Next();
|
||||
if (closeToken != c) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, start, end - start + 1);
|
||||
}
|
||||
}
|
||||
|
||||
u16string s = this -> _scriptString.substr(start, end - start + 1);
|
||||
switch (HashedString::ConstHash(s.c_str())){
|
||||
case HashedString::ConstHash("and"): return new SimpleToken(TokenKind::AndKeyword, start, 3);
|
||||
case HashedString::ConstHash("break"): return new SimpleToken(TokenKind::BreakKeyword, start, 5);
|
||||
case HashedString::ConstHash("do"): return new SimpleToken(TokenKind::DoKeyword, start, 2);
|
||||
case HashedString::ConstHash("else"): return new SimpleToken(TokenKind::ElseKeyword, start, 4);
|
||||
case HashedString::ConstHash("elseif"): return new SimpleToken(TokenKind::ElseIfKeyword, start, 6);
|
||||
case HashedString::ConstHash("end"): return new SimpleToken(TokenKind::EndKeyword, start, 3);
|
||||
case HashedString::ConstHash("false"): return new SimpleToken(TokenKind::FalseKeyword, start, 5);
|
||||
case HashedString::ConstHash("for"): return new SimpleToken(TokenKind::ForKeyword, start, 3);
|
||||
case HashedString::ConstHash("function"): return new SimpleToken(TokenKind::FunctionKeyword, start, 8);
|
||||
case HashedString::ConstHash("if"): return new SimpleToken(TokenKind::IfKeyword, start, 2);
|
||||
case HashedString::ConstHash("in"): return new SimpleToken(TokenKind::InKeyword, start, 2);
|
||||
case HashedString::ConstHash("local"): return new SimpleToken(TokenKind::LocalKeyword, start, 5);
|
||||
case HashedString::ConstHash("nil"): return new SimpleToken(TokenKind::NilKeyword, start, 3);
|
||||
case HashedString::ConstHash("not"): return new SimpleToken(TokenKind::NotKeyword, start, 3);
|
||||
case HashedString::ConstHash("or"): return new SimpleToken(TokenKind::OrKeyword, start, 2);
|
||||
case HashedString::ConstHash("return"): return new SimpleToken(TokenKind::ReturnKeyword, start, 6);
|
||||
case HashedString::ConstHash("then"): return new SimpleToken(TokenKind::ThenKeyword, start, 4);
|
||||
case HashedString::ConstHash("true"): return new SimpleToken(TokenKind::TrueKeyword, start, 4);
|
||||
case HashedString::ConstHash("while"): return new SimpleToken(TokenKind::WhileKeyword, start, 5);
|
||||
default: return new IdentifierToken(HashedString(s), start, s.length());
|
||||
}
|
||||
}
|
||||
|
||||
const unordered_map<char16_t, char16_t> ControlCharacters{ // NOLINT(cert-err58-cpp)
|
||||
{'0', '\0'},
|
||||
{'a', '\a'},
|
||||
{'b', '\b'},
|
||||
{'t', '\t'},
|
||||
{'n', '\n'},
|
||||
{'v', '\v'},
|
||||
{'f', '\f'},
|
||||
{'r', '\r'},
|
||||
{'"', '\"'},
|
||||
{'\'', '\''},
|
||||
{'\?', '\?'},
|
||||
{'\\', '\\'},
|
||||
};
|
||||
|
||||
IToken* Lexer::LexString(char16_t c){
|
||||
auto start = this -> _position - 1;
|
||||
auto end = start;
|
||||
char16_t last = c;
|
||||
while (true){
|
||||
char16_t next = this -> Peek();
|
||||
if (next == '\0') break;
|
||||
if (next == c && last != '\\') break;
|
||||
this -> Next();
|
||||
end++;
|
||||
last = next;
|
||||
}
|
||||
auto closeToken = this -> Next();
|
||||
if (closeToken != c){
|
||||
this -> ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
|
||||
return new SimpleToken(TokenKind::BadToken, start, end -start + 1);
|
||||
}
|
||||
|
||||
u16string s = this -> _scriptString.substr(start + 1, end - start);
|
||||
std::basic_ostringstream<char16_t > stream;
|
||||
for (int i = 0; i < s.size(); i++){
|
||||
c = s[i];
|
||||
if (c == '\\'){
|
||||
i++;
|
||||
u16string s = this->_scriptString.substr(start + 1, end - start);
|
||||
std::basic_ostringstream<char16_t> stream;
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
c = s[i];
|
||||
if (ControlCharacters.find(c) != ControlCharacters.end()) {
|
||||
stream << ControlCharacters.at(c);
|
||||
} else{
|
||||
this -> ScriptData->Diagnostics->LogError(DiagnosticCode::InvalidStringControlCharacter, start + 1 + i, 1);
|
||||
if (c == '\\') {
|
||||
i++;
|
||||
c = s[i];
|
||||
if (ControlCharacters.find(c) != ControlCharacters.end()) {
|
||||
stream << ControlCharacters.at(c);
|
||||
} else {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::InvalidStringControlCharacter,
|
||||
start + 1 + i, 1);
|
||||
stream << c;
|
||||
}
|
||||
} else {
|
||||
stream << c;
|
||||
}
|
||||
} else{
|
||||
stream << c;
|
||||
}
|
||||
return new StringToken(stream.str(), start, end - start);
|
||||
}
|
||||
return new StringToken(stream.str(), start, end - start );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,26 +7,28 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Lexer {
|
||||
const u16string& _scriptString;
|
||||
namespace Porygon::Parser{
|
||||
class Lexer {
|
||||
const u16string& _scriptString;
|
||||
#ifdef TESTS_BUILD
|
||||
public:
|
||||
public:
|
||||
#endif
|
||||
unsigned int _position;
|
||||
unsigned int _scriptSize;
|
||||
char16_t Peek();
|
||||
char16_t Next();
|
||||
IToken* LexNext(char16_t c);
|
||||
IToken* LexNumber(char16_t c);
|
||||
IToken* LexIdentifierOrKeyword();
|
||||
IToken* LexString(char16_t c);
|
||||
public:
|
||||
Script* ScriptData;
|
||||
unsigned int _position;
|
||||
unsigned int _scriptSize;
|
||||
char16_t Peek();
|
||||
char16_t Next();
|
||||
IToken* LexNext(char16_t c);
|
||||
IToken* LexNumber(char16_t c);
|
||||
IToken* LexIdentifierOrKeyword();
|
||||
IToken* LexString(char16_t c);
|
||||
public:
|
||||
Porygon::Script* ScriptData;
|
||||
|
||||
vector<const IToken*> Lex();
|
||||
explicit Lexer(const u16string& scriptString, class Script* script);
|
||||
vector<const IToken*> Lex();
|
||||
explicit Lexer(const u16string& scriptString, Porygon::Script* script);
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //PORYGONLANG_LEXER_HPP
|
||||
|
||||
@@ -11,333 +11,332 @@
|
||||
#include "../BinaryOperatorKind.hpp"
|
||||
#include "../../Utilities/HashedString.hpp"
|
||||
|
||||
enum class ParsedExpressionKind{
|
||||
Bad,
|
||||
namespace Porygon::Parser {
|
||||
enum class ParsedExpressionKind {
|
||||
Bad,
|
||||
|
||||
LiteralInteger,
|
||||
LiteralFloat,
|
||||
LiteralString,
|
||||
LiteralBool,
|
||||
Variable,
|
||||
LiteralInteger,
|
||||
LiteralFloat,
|
||||
LiteralString,
|
||||
LiteralBool,
|
||||
Variable,
|
||||
|
||||
Unary,
|
||||
Binary,
|
||||
Parenthesized,
|
||||
FunctionCall,
|
||||
Indexer,
|
||||
PeriodIndexer,
|
||||
NumericalTable,
|
||||
Table,
|
||||
};
|
||||
Unary,
|
||||
Binary,
|
||||
Parenthesized,
|
||||
FunctionCall,
|
||||
Indexer,
|
||||
PeriodIndexer,
|
||||
NumericalTable,
|
||||
Table,
|
||||
};
|
||||
|
||||
class ParsedExpression {
|
||||
const unsigned int _position;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
ParsedExpression(unsigned int position, unsigned int length)
|
||||
: _position(position),
|
||||
_length(length)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ParsedExpression() = default;
|
||||
|
||||
virtual const ParsedExpressionKind GetKind() const = 0;
|
||||
|
||||
const unsigned int GetStartPosition() const{
|
||||
return _position;
|
||||
}
|
||||
|
||||
const unsigned int GetEndPosition() const{
|
||||
return _position + _length - 1;
|
||||
}
|
||||
|
||||
const unsigned int GetLength() const{
|
||||
return _length;
|
||||
}
|
||||
};
|
||||
|
||||
class BadExpression : public ParsedExpression{
|
||||
public:
|
||||
BadExpression(unsigned int position, unsigned int length) : ParsedExpression(position, length){}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Bad;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralIntegerExpression : public ParsedExpression{
|
||||
const long _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::LiteralInteger;
|
||||
}
|
||||
explicit LiteralIntegerExpression(IntegerToken* token)
|
||||
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
|
||||
_value(token -> GetValue())
|
||||
{
|
||||
}
|
||||
|
||||
const long GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralFloatExpression : public ParsedExpression{
|
||||
const double _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::LiteralFloat;
|
||||
}
|
||||
explicit LiteralFloatExpression(FloatToken* token)
|
||||
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
|
||||
_value(token -> GetValue())
|
||||
{
|
||||
}
|
||||
|
||||
const double GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralStringExpression : public ParsedExpression{
|
||||
const u16string _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::LiteralString;
|
||||
}
|
||||
explicit LiteralStringExpression(StringToken* token)
|
||||
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
|
||||
_value(std::move(token -> GetValue()))
|
||||
{
|
||||
}
|
||||
|
||||
const u16string& GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralBoolExpression : public ParsedExpression{
|
||||
const bool _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::LiteralBool;
|
||||
}
|
||||
explicit LiteralBoolExpression(const IToken* token)
|
||||
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
|
||||
_value(token -> GetKind() == TokenKind::TrueKeyword)
|
||||
{
|
||||
}
|
||||
|
||||
const bool GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class VariableExpression : public ParsedExpression{
|
||||
const HashedString _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Variable;
|
||||
}
|
||||
explicit VariableExpression(IdentifierToken* token) : ParsedExpression(token -> GetStartPosition(), token -> GetLength())
|
||||
, _value(HashedString(token -> GetValue()))
|
||||
{
|
||||
}
|
||||
|
||||
const HashedString GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ParenthesizedExpression : public ParsedExpression{
|
||||
const ParsedExpression* _expression;
|
||||
public:
|
||||
~ParenthesizedExpression() override {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Parenthesized;
|
||||
}
|
||||
|
||||
explicit ParenthesizedExpression(ParsedExpression* innerExpression, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length), _expression(innerExpression){
|
||||
}
|
||||
|
||||
const ParsedExpression* GetInnerExpression() const{
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class UnaryExpression : public ParsedExpression{
|
||||
const UnaryOperatorKind _kind;
|
||||
const ParsedExpression* _operand;
|
||||
public:
|
||||
~UnaryExpression() override {
|
||||
delete _operand;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Unary;
|
||||
}
|
||||
|
||||
UnaryExpression(UnaryOperatorKind kind, ParsedExpression* operand, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_kind(kind), _operand(operand)
|
||||
{
|
||||
}
|
||||
|
||||
const UnaryOperatorKind GetOperatorKind() const{
|
||||
return _kind;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetOperand() const{
|
||||
return _operand;
|
||||
}
|
||||
};
|
||||
|
||||
class BinaryExpression : public ParsedExpression{
|
||||
const BinaryOperatorKind _kind;
|
||||
const ParsedExpression* _left;
|
||||
const ParsedExpression* _right;
|
||||
public:
|
||||
~BinaryExpression() override {
|
||||
delete _left;
|
||||
delete _right;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Binary;
|
||||
}
|
||||
|
||||
BinaryExpression(BinaryOperatorKind kind, ParsedExpression* left, ParsedExpression* right, unsigned int start,
|
||||
unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_kind(kind), _left(left), _right(right)
|
||||
{
|
||||
}
|
||||
|
||||
const BinaryOperatorKind GetOperatorKind() const{
|
||||
return _kind;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetLeft() const{
|
||||
return _left;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetRight() const{
|
||||
return _right;
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionCallExpression : public ParsedExpression{
|
||||
const std::unique_ptr<ParsedExpression> _function;
|
||||
const vector<const ParsedExpression*> _parameters;
|
||||
public:
|
||||
FunctionCallExpression(ParsedExpression* function, vector<const ParsedExpression*> parameters, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_function(function), _parameters(std::move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
~FunctionCallExpression() final{
|
||||
for (auto p : _parameters){
|
||||
delete p;
|
||||
class ParsedExpression {
|
||||
const unsigned int _position;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
ParsedExpression(unsigned int position, unsigned int length)
|
||||
: _position(position),
|
||||
_length(length) {
|
||||
}
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::FunctionCall;
|
||||
}
|
||||
virtual ~ParsedExpression() = default;
|
||||
|
||||
const ParsedExpression* GetFunction() const{
|
||||
return _function.get();
|
||||
}
|
||||
const vector<const ParsedExpression*>* GetParameters() const{
|
||||
return &_parameters;
|
||||
}
|
||||
};
|
||||
virtual const ParsedExpressionKind GetKind() const = 0;
|
||||
|
||||
class IndexExpression : public ParsedExpression{
|
||||
const ParsedExpression* _indexerExpression;
|
||||
const ParsedExpression* _indexExpression;
|
||||
public:
|
||||
IndexExpression(ParsedExpression* indexer, ParsedExpression* index, unsigned int start, unsigned int length)
|
||||
:ParsedExpression(start, length),
|
||||
_indexerExpression(indexer), _indexExpression(index)
|
||||
{
|
||||
}
|
||||
|
||||
~IndexExpression() final{
|
||||
delete _indexerExpression;
|
||||
delete _indexExpression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Indexer;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetIndexer() const{
|
||||
return _indexerExpression;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetIndex() const{
|
||||
return _indexExpression;
|
||||
}
|
||||
};
|
||||
|
||||
class PeriodIndexExpression : public ParsedExpression{
|
||||
const ParsedExpression* _indexerExpression;
|
||||
const HashedString _index;
|
||||
public:
|
||||
PeriodIndexExpression(ParsedExpression* indexer, HashedString index, unsigned int start, unsigned int length)
|
||||
:ParsedExpression(start, length),
|
||||
_indexerExpression(indexer), _index(index)
|
||||
{
|
||||
}
|
||||
|
||||
~PeriodIndexExpression() final{
|
||||
delete _indexerExpression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::PeriodIndexer;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetIndexer() const{
|
||||
return _indexerExpression;
|
||||
}
|
||||
|
||||
const HashedString& GetIndex() const{
|
||||
return _index;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ParsedNumericalTableExpression : public ParsedExpression{
|
||||
vector<const ParsedExpression*> _expressions;
|
||||
public:
|
||||
ParsedNumericalTableExpression(vector<const ParsedExpression*> expressions, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length){
|
||||
_expressions = std::move(expressions);
|
||||
}
|
||||
|
||||
~ParsedNumericalTableExpression() final{
|
||||
for (auto s: _expressions){
|
||||
delete s;
|
||||
const unsigned int GetStartPosition() const {
|
||||
return _position;
|
||||
}
|
||||
}
|
||||
|
||||
const vector<const ParsedExpression*>* GetExpressions() const{
|
||||
return &_expressions;
|
||||
}
|
||||
const unsigned int GetEndPosition() const {
|
||||
return _position + _length - 1;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::NumericalTable;
|
||||
}
|
||||
};
|
||||
const unsigned int GetLength() const {
|
||||
return _length;
|
||||
}
|
||||
};
|
||||
|
||||
class BadExpression : public ParsedExpression {
|
||||
public:
|
||||
BadExpression(unsigned int position, unsigned int length) : ParsedExpression(position, length) {}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Bad;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralIntegerExpression : public ParsedExpression {
|
||||
const long _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::LiteralInteger;
|
||||
}
|
||||
|
||||
explicit LiteralIntegerExpression(IntegerToken *token)
|
||||
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
|
||||
_value(token->GetValue()) {
|
||||
}
|
||||
|
||||
const long GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralFloatExpression : public ParsedExpression {
|
||||
const double _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::LiteralFloat;
|
||||
}
|
||||
|
||||
explicit LiteralFloatExpression(FloatToken *token)
|
||||
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
|
||||
_value(token->GetValue()) {
|
||||
}
|
||||
|
||||
const double GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralStringExpression : public ParsedExpression {
|
||||
const u16string _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::LiteralString;
|
||||
}
|
||||
|
||||
explicit LiteralStringExpression(StringToken *token)
|
||||
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
|
||||
_value(std::move(token->GetValue())) {
|
||||
}
|
||||
|
||||
const u16string &GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class LiteralBoolExpression : public ParsedExpression {
|
||||
const bool _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::LiteralBool;
|
||||
}
|
||||
|
||||
explicit LiteralBoolExpression(const IToken *token)
|
||||
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
|
||||
_value(token->GetKind() == TokenKind::TrueKeyword) {
|
||||
}
|
||||
|
||||
const bool GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class VariableExpression : public ParsedExpression {
|
||||
const HashedString _value;
|
||||
public:
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Variable;
|
||||
}
|
||||
|
||||
explicit VariableExpression(IdentifierToken *token) : ParsedExpression(token->GetStartPosition(),
|
||||
token->GetLength()),
|
||||
_value(HashedString(token->GetValue())) {
|
||||
}
|
||||
|
||||
const HashedString GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ParenthesizedExpression : public ParsedExpression {
|
||||
const ParsedExpression *_expression;
|
||||
public:
|
||||
~ParenthesizedExpression() override {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Parenthesized;
|
||||
}
|
||||
|
||||
explicit ParenthesizedExpression(ParsedExpression *innerExpression, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length), _expression(innerExpression) {
|
||||
}
|
||||
|
||||
const ParsedExpression *GetInnerExpression() const {
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class UnaryExpression : public ParsedExpression {
|
||||
const UnaryOperatorKind _kind;
|
||||
const ParsedExpression *_operand;
|
||||
public:
|
||||
~UnaryExpression() override {
|
||||
delete _operand;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Unary;
|
||||
}
|
||||
|
||||
UnaryExpression(UnaryOperatorKind kind, ParsedExpression *operand, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_kind(kind), _operand(operand) {
|
||||
}
|
||||
|
||||
const UnaryOperatorKind GetOperatorKind() const {
|
||||
return _kind;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetOperand() const {
|
||||
return _operand;
|
||||
}
|
||||
};
|
||||
|
||||
class BinaryExpression : public ParsedExpression {
|
||||
const BinaryOperatorKind _kind;
|
||||
const ParsedExpression *_left;
|
||||
const ParsedExpression *_right;
|
||||
public:
|
||||
~BinaryExpression() override {
|
||||
delete _left;
|
||||
delete _right;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Binary;
|
||||
}
|
||||
|
||||
BinaryExpression(BinaryOperatorKind kind, ParsedExpression *left, ParsedExpression *right, unsigned int start,
|
||||
unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_kind(kind), _left(left), _right(right) {
|
||||
}
|
||||
|
||||
const BinaryOperatorKind GetOperatorKind() const {
|
||||
return _kind;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetLeft() const {
|
||||
return _left;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetRight() const {
|
||||
return _right;
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionCallExpression : public ParsedExpression {
|
||||
const std::unique_ptr<ParsedExpression> _function;
|
||||
const vector<const ParsedExpression *> _parameters;
|
||||
public:
|
||||
FunctionCallExpression(ParsedExpression *function, vector<const ParsedExpression *> parameters,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_function(function), _parameters(std::move(parameters)) {
|
||||
}
|
||||
|
||||
~FunctionCallExpression() final {
|
||||
for (auto p : _parameters) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::FunctionCall;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetFunction() const {
|
||||
return _function.get();
|
||||
}
|
||||
|
||||
const vector<const ParsedExpression *> *GetParameters() const {
|
||||
return &_parameters;
|
||||
}
|
||||
};
|
||||
|
||||
class IndexExpression : public ParsedExpression {
|
||||
const ParsedExpression *_indexerExpression;
|
||||
const ParsedExpression *_indexExpression;
|
||||
public:
|
||||
IndexExpression(ParsedExpression *indexer, ParsedExpression *index, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_indexerExpression(indexer), _indexExpression(index) {
|
||||
}
|
||||
|
||||
~IndexExpression() final {
|
||||
delete _indexerExpression;
|
||||
delete _indexExpression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Indexer;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetIndexer() const {
|
||||
return _indexerExpression;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetIndex() const {
|
||||
return _indexExpression;
|
||||
}
|
||||
};
|
||||
|
||||
class PeriodIndexExpression : public ParsedExpression {
|
||||
const ParsedExpression *_indexerExpression;
|
||||
const HashedString _index;
|
||||
public:
|
||||
PeriodIndexExpression(ParsedExpression *indexer, HashedString index, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length),
|
||||
_indexerExpression(indexer), _index(index) {
|
||||
}
|
||||
|
||||
~PeriodIndexExpression() final {
|
||||
delete _indexerExpression;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::PeriodIndexer;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetIndexer() const {
|
||||
return _indexerExpression;
|
||||
}
|
||||
|
||||
const HashedString &GetIndex() const {
|
||||
return _index;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ParsedNumericalTableExpression : public ParsedExpression {
|
||||
vector<const ParsedExpression *> _expressions;
|
||||
public:
|
||||
ParsedNumericalTableExpression(vector<const ParsedExpression *> expressions, unsigned int start,
|
||||
unsigned int length)
|
||||
: ParsedExpression(start, length) {
|
||||
_expressions = std::move(expressions);
|
||||
}
|
||||
|
||||
~ParsedNumericalTableExpression() final {
|
||||
for (auto s: _expressions) {
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
const vector<const ParsedExpression *> *GetExpressions() const {
|
||||
return &_expressions;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::NumericalTable;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PORYGONLANG_PARSEDEXPRESSION_HPP
|
||||
|
||||
@@ -5,27 +5,27 @@
|
||||
#include "ParsedExpression.hpp"
|
||||
#include "../ParsedStatements/ParsedStatement.hpp"
|
||||
|
||||
class ParsedTableExpression : public ParsedExpression{
|
||||
const ParsedBlockStatement* _block;
|
||||
public:
|
||||
ParsedTableExpression(ParsedBlockStatement* block, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length), _block(block)
|
||||
{
|
||||
}
|
||||
namespace Porygon::Parser {
|
||||
class ParsedTableExpression : public ParsedExpression {
|
||||
const ParsedBlockStatement *_block;
|
||||
public:
|
||||
ParsedTableExpression(ParsedBlockStatement *block, unsigned int start, unsigned int length)
|
||||
: ParsedExpression(start, length), _block(block) {
|
||||
}
|
||||
|
||||
~ParsedTableExpression() final{
|
||||
delete _block;
|
||||
}
|
||||
~ParsedTableExpression() final {
|
||||
delete _block;
|
||||
}
|
||||
|
||||
const ParsedBlockStatement* GetBlock() const{
|
||||
return _block;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final{
|
||||
return ParsedExpressionKind::Table;
|
||||
}
|
||||
};
|
||||
const ParsedBlockStatement *GetBlock() const {
|
||||
return _block;
|
||||
}
|
||||
|
||||
const ParsedExpressionKind GetKind() const final {
|
||||
return ParsedExpressionKind::Table;
|
||||
}
|
||||
};
|
||||
}
|
||||
#include "ParsedExpression.hpp"
|
||||
|
||||
#endif //PORYGONLANG_PARSEDTABLEEXPRESSION_HPP
|
||||
|
||||
@@ -13,263 +13,270 @@
|
||||
#include "../../Utilities/HashedString.hpp"
|
||||
#include "../TypedVariableIdentifier.hpp"
|
||||
|
||||
enum class ParsedStatementKind{
|
||||
Bad,
|
||||
Script,
|
||||
Block,
|
||||
Expression,
|
||||
Assignment,
|
||||
IndexAssignment,
|
||||
FunctionDeclaration,
|
||||
Return,
|
||||
Conditional
|
||||
};
|
||||
namespace Porygon::Parser {
|
||||
enum class ParsedStatementKind {
|
||||
Bad,
|
||||
Script,
|
||||
Block,
|
||||
Expression,
|
||||
Assignment,
|
||||
IndexAssignment,
|
||||
FunctionDeclaration,
|
||||
Return,
|
||||
Conditional
|
||||
};
|
||||
|
||||
class ParsedStatement {
|
||||
const unsigned int _start;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
ParsedStatement(unsigned int start, unsigned int length)
|
||||
:_start(start), _length(length)
|
||||
{
|
||||
}
|
||||
virtual ~ParsedStatement() = default;
|
||||
virtual const ParsedStatementKind GetKind() const = 0;
|
||||
|
||||
const unsigned int GetStartPosition() const {
|
||||
return _start;
|
||||
}
|
||||
|
||||
const unsigned int GetLength() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
const unsigned int GetEndPosition() const {
|
||||
return _start + _length - 1;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedBadStatement : public ParsedStatement{
|
||||
public:
|
||||
ParsedBadStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length){};
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Bad;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedBlockStatement : public ParsedStatement{
|
||||
const std::vector<const ParsedStatement*> _statements;
|
||||
public:
|
||||
explicit ParsedBlockStatement(std::vector<const ParsedStatement*> statements)
|
||||
: ParsedStatement(statements.front()->GetStartPosition(), statements.back()->GetEndPosition() - statements.front()->GetStartPosition()),
|
||||
_statements(statements)
|
||||
{}
|
||||
|
||||
ParsedBlockStatement(std::vector<const ParsedStatement*> statements, unsigned int start) : ParsedStatement(start, 0),
|
||||
_statements(std::move(statements))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~ParsedBlockStatement() override {
|
||||
for (auto s: _statements){
|
||||
delete s;
|
||||
class ParsedStatement {
|
||||
const unsigned int _start;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
ParsedStatement(unsigned int start, unsigned int length)
|
||||
: _start(start), _length(length) {
|
||||
}
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const override {
|
||||
return ParsedStatementKind ::Block;
|
||||
}
|
||||
virtual ~ParsedStatement() = default;
|
||||
|
||||
const std::vector<const ParsedStatement*>* GetStatements() const{
|
||||
return &_statements;
|
||||
}
|
||||
};
|
||||
virtual const ParsedStatementKind GetKind() const = 0;
|
||||
|
||||
class ParsedScriptStatement : public ParsedBlockStatement{
|
||||
public:
|
||||
explicit ParsedScriptStatement(vector<const ParsedStatement*> statements) : ParsedBlockStatement(move(statements)){}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Script;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedExpressionStatement : public ParsedStatement{
|
||||
const ParsedExpression* _expression;
|
||||
public:
|
||||
explicit ParsedExpressionStatement(ParsedExpression* expression)
|
||||
: ParsedStatement(expression->GetStartPosition(), expression->GetLength()),
|
||||
_expression(expression)
|
||||
{
|
||||
}
|
||||
|
||||
~ParsedExpressionStatement() override {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Expression;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetExpression() const{
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedFunctionDeclarationStatement : public ParsedStatement{
|
||||
const HashedString _identifier;
|
||||
const vector<TypedVariableIdentifier*> _parameters;
|
||||
const ParsedBlockStatement* _block;
|
||||
public:
|
||||
ParsedFunctionDeclarationStatement(HashedString identifier, vector<TypedVariableIdentifier*> parameters, ParsedBlockStatement* block,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)), _block(block){};
|
||||
|
||||
~ParsedFunctionDeclarationStatement() override {
|
||||
for (auto v : _parameters){
|
||||
delete v;
|
||||
const unsigned int GetStartPosition() const {
|
||||
return _start;
|
||||
}
|
||||
delete _block;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::FunctionDeclaration;
|
||||
}
|
||||
const unsigned int GetLength() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
const HashedString GetIdentifier() const{
|
||||
return _identifier;
|
||||
}
|
||||
const unsigned int GetEndPosition() const {
|
||||
return _start + _length - 1;
|
||||
}
|
||||
};
|
||||
|
||||
const vector<TypedVariableIdentifier*>* GetParameters() const{
|
||||
return &_parameters;
|
||||
}
|
||||
class ParsedBadStatement : public ParsedStatement {
|
||||
public:
|
||||
ParsedBadStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length) {};
|
||||
|
||||
const ParsedBlockStatement* GetBlock() const{
|
||||
return _block;
|
||||
}
|
||||
};
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Bad;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedAssignmentStatement : public ParsedStatement{
|
||||
const bool _local;
|
||||
const HashedString _identifier;
|
||||
const ParsedExpression* _expression;
|
||||
public:
|
||||
ParsedAssignmentStatement(bool local, const HashedString identifier, ParsedExpression* expression, unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _local(local), _identifier(identifier), _expression(expression)
|
||||
{
|
||||
}
|
||||
class ParsedBlockStatement : public ParsedStatement {
|
||||
const std::vector<const ParsedStatement *> _statements;
|
||||
public:
|
||||
explicit ParsedBlockStatement(std::vector<const ParsedStatement *> statements)
|
||||
: ParsedStatement(statements.front()->GetStartPosition(),
|
||||
statements.back()->GetEndPosition() - statements.front()->GetStartPosition()),
|
||||
_statements(statements) {}
|
||||
|
||||
~ParsedAssignmentStatement() final{
|
||||
delete _expression;
|
||||
}
|
||||
ParsedBlockStatement(std::vector<const ParsedStatement *> statements, unsigned int start) : ParsedStatement(
|
||||
start, 0),
|
||||
_statements(
|
||||
std::move(
|
||||
statements)) {
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Assignment;
|
||||
}
|
||||
|
||||
const bool IsLocal() const{
|
||||
return _local;
|
||||
}
|
||||
~ParsedBlockStatement() override {
|
||||
for (auto s: _statements) {
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
const HashedString GetIdentifier() const{
|
||||
return _identifier;
|
||||
}
|
||||
const ParsedStatementKind GetKind() const override {
|
||||
return ParsedStatementKind::Block;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetExpression() const{
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
const std::vector<const ParsedStatement *> *GetStatements() const {
|
||||
return &_statements;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedIndexAssignmentStatement : public ParsedStatement{
|
||||
const ParsedExpression* _indexExpression;
|
||||
const ParsedExpression* _valueExpression;
|
||||
public:
|
||||
ParsedIndexAssignmentStatement(ParsedExpression* indexExpression, ParsedExpression* valueExpression, unsigned int start,
|
||||
class ParsedScriptStatement : public ParsedBlockStatement {
|
||||
public:
|
||||
explicit ParsedScriptStatement(vector<const ParsedStatement *> statements) : ParsedBlockStatement(
|
||||
move(statements)) {}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Script;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedExpressionStatement : public ParsedStatement {
|
||||
const ParsedExpression *_expression;
|
||||
public:
|
||||
explicit ParsedExpressionStatement(ParsedExpression *expression)
|
||||
: ParsedStatement(expression->GetStartPosition(), expression->GetLength()),
|
||||
_expression(expression) {
|
||||
}
|
||||
|
||||
~ParsedExpressionStatement() override {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Expression;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetExpression() const {
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedFunctionDeclarationStatement : public ParsedStatement {
|
||||
const HashedString _identifier;
|
||||
const vector<TypedVariableIdentifier *> _parameters;
|
||||
const ParsedBlockStatement *_block;
|
||||
public:
|
||||
ParsedFunctionDeclarationStatement(HashedString identifier, vector<TypedVariableIdentifier *> parameters,
|
||||
ParsedBlockStatement *block,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)),
|
||||
_block(block) {};
|
||||
|
||||
~ParsedFunctionDeclarationStatement() override {
|
||||
for (auto v : _parameters) {
|
||||
delete v;
|
||||
}
|
||||
delete _block;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::FunctionDeclaration;
|
||||
}
|
||||
|
||||
const HashedString GetIdentifier() const {
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
const vector<TypedVariableIdentifier *> *GetParameters() const {
|
||||
return &_parameters;
|
||||
}
|
||||
|
||||
const ParsedBlockStatement *GetBlock() const {
|
||||
return _block;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedAssignmentStatement : public ParsedStatement {
|
||||
const bool _local;
|
||||
const HashedString _identifier;
|
||||
const ParsedExpression *_expression;
|
||||
public:
|
||||
ParsedAssignmentStatement(bool local, const HashedString identifier, ParsedExpression *expression,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _local(local), _identifier(identifier), _expression(expression) {
|
||||
}
|
||||
|
||||
~ParsedAssignmentStatement() final {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Assignment;
|
||||
}
|
||||
|
||||
const bool IsLocal() const {
|
||||
return _local;
|
||||
}
|
||||
|
||||
const HashedString GetIdentifier() const {
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetExpression() const {
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedIndexAssignmentStatement : public ParsedStatement {
|
||||
const ParsedExpression *_indexExpression;
|
||||
const ParsedExpression *_valueExpression;
|
||||
public:
|
||||
ParsedIndexAssignmentStatement(ParsedExpression *indexExpression, ParsedExpression *valueExpression,
|
||||
unsigned int start,
|
||||
unsigned int length)
|
||||
: ParsedStatement(start, length),
|
||||
_indexExpression(indexExpression), _valueExpression(valueExpression) {}
|
||||
|
||||
~ParsedIndexAssignmentStatement() final {
|
||||
delete _indexExpression;
|
||||
delete _valueExpression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::IndexAssignment;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetIndexExpression() const {
|
||||
return _indexExpression;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetValueExpression() const {
|
||||
return _valueExpression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedReturnStatement : public ParsedStatement {
|
||||
const ParsedExpression *_expression;
|
||||
public:
|
||||
ParsedReturnStatement(ParsedExpression *expression, unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length),
|
||||
_expression(expression) {
|
||||
}
|
||||
|
||||
~ParsedReturnStatement() final {
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Return;
|
||||
}
|
||||
|
||||
const ParsedExpression *GetExpression() const {
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedConditionalStatement : public ParsedStatement {
|
||||
const ParsedExpression *_condition;
|
||||
const ParsedStatement *_block;
|
||||
// This can be either else if or else
|
||||
const ParsedStatement *_elseStatement;
|
||||
public:
|
||||
ParsedConditionalStatement(ParsedExpression *condition, ParsedStatement *block, unsigned int start,
|
||||
unsigned int length)
|
||||
: ParsedStatement(start, length),
|
||||
_indexExpression(indexExpression), _valueExpression(valueExpression){}
|
||||
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nullptr) {
|
||||
}
|
||||
|
||||
~ParsedIndexAssignmentStatement() final{
|
||||
delete _indexExpression;
|
||||
delete _valueExpression;
|
||||
}
|
||||
ParsedConditionalStatement(ParsedExpression *condition, ParsedStatement *block, ParsedStatement *nextStatement,
|
||||
unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nextStatement) {
|
||||
_condition = condition;
|
||||
_block = block;
|
||||
_elseStatement = nextStatement;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::IndexAssignment;
|
||||
}
|
||||
~ParsedConditionalStatement() final {
|
||||
delete _condition;
|
||||
delete _block;
|
||||
delete _elseStatement;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetIndexExpression() const{
|
||||
return _indexExpression;
|
||||
}
|
||||
const ParsedStatementKind GetKind() const final {
|
||||
return ParsedStatementKind::Conditional;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetValueExpression() const{
|
||||
return _valueExpression;
|
||||
}
|
||||
};
|
||||
const ParsedExpression *GetCondition() const {
|
||||
return _condition;
|
||||
}
|
||||
|
||||
class ParsedReturnStatement : public ParsedStatement{
|
||||
const ParsedExpression* _expression;
|
||||
public:
|
||||
ParsedReturnStatement(ParsedExpression* expression, unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length),
|
||||
_expression(expression)
|
||||
{
|
||||
}
|
||||
|
||||
~ParsedReturnStatement() final{
|
||||
delete _expression;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Return;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetExpression() const{
|
||||
return _expression;
|
||||
}
|
||||
};
|
||||
|
||||
class ParsedConditionalStatement : public ParsedStatement{
|
||||
const ParsedExpression* _condition;
|
||||
const ParsedStatement* _block;
|
||||
// This can be either else if or else
|
||||
const ParsedStatement* _elseStatement;
|
||||
public:
|
||||
ParsedConditionalStatement(ParsedExpression* condition, ParsedStatement* block, unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ParsedConditionalStatement(ParsedExpression* condition, ParsedStatement* block, ParsedStatement* nextStatement, unsigned int start, unsigned int length)
|
||||
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nextStatement)
|
||||
{
|
||||
_condition = condition;
|
||||
_block = block;
|
||||
_elseStatement = nextStatement;
|
||||
}
|
||||
|
||||
~ParsedConditionalStatement() final{
|
||||
delete _condition;
|
||||
delete _block;
|
||||
delete _elseStatement;
|
||||
}
|
||||
|
||||
const ParsedStatementKind GetKind() const final{
|
||||
return ParsedStatementKind ::Conditional;
|
||||
}
|
||||
|
||||
const ParsedExpression* GetCondition() const {
|
||||
return _condition;
|
||||
}
|
||||
|
||||
const ParsedStatement* GetBlock() const {
|
||||
return _block;
|
||||
}
|
||||
|
||||
const ParsedStatement* GetElseStatement() const {
|
||||
return _elseStatement;
|
||||
}
|
||||
};
|
||||
const ParsedStatement *GetBlock() const {
|
||||
return _block;
|
||||
}
|
||||
|
||||
const ParsedStatement *GetElseStatement() const {
|
||||
return _elseStatement;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif //PORYGONLANG_PARSEDSTATEMENT_HPP
|
||||
|
||||
@@ -7,426 +7,496 @@
|
||||
#include "TypedVariableIdentifier.hpp"
|
||||
#include "ParsedExpressions/ParsedTableExpression.hpp"
|
||||
|
||||
|
||||
ParsedScriptStatement* Parser::Parse() {
|
||||
vector<const ParsedStatement*> statements;
|
||||
while (this->_position < this->_tokens.size()){
|
||||
auto next = this -> Next();
|
||||
if (next->GetKind() == TokenKind::EndOfFile){
|
||||
break;
|
||||
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));
|
||||
}
|
||||
statements.push_back(this -> ParseStatement(next));
|
||||
}
|
||||
return new ParsedScriptStatement(statements);
|
||||
}
|
||||
|
||||
const IToken *Parser::Peek() {
|
||||
return this -> _tokens[_position];
|
||||
}
|
||||
|
||||
const IToken *Parser::PeekAt(int offset) {
|
||||
return this -> _tokens[_position + offset];
|
||||
}
|
||||
|
||||
const IToken *Parser::Next() {
|
||||
this -> _position++;
|
||||
return this -> _tokens[_position - 1];
|
||||
}
|
||||
|
||||
ParsedStatement* Parser::ParseStatement(const IToken* current){
|
||||
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);
|
||||
default: break;
|
||||
}
|
||||
if (this->Peek()->GetKind() == TokenKind::AssignmentToken){
|
||||
return ParseVariableAssignment(current);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseVariableAssignment(const IToken *current) {
|
||||
bool isLocal = false;
|
||||
const IToken* identifier;
|
||||
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){
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
|
||||
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
||||
}
|
||||
if (assignmentToken -> GetKind() != TokenKind::AssignmentToken){
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
|
||||
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
||||
return new ParsedScriptStatement(statements);
|
||||
}
|
||||
|
||||
auto start = current -> GetStartPosition();
|
||||
return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> GetValue(), expression, start, expression->GetEndPosition() - start);
|
||||
}
|
||||
const IToken *Parser::Peek() {
|
||||
return this->_tokens[_position];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
const IToken *Parser::PeekAt(int offset) {
|
||||
return this->_tokens[_position + offset];
|
||||
}
|
||||
|
||||
const IToken *Parser::Next() {
|
||||
this->_position++;
|
||||
return this->_tokens[_position - 1];
|
||||
}
|
||||
|
||||
ParsedStatement *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;
|
||||
ParsedStatement *Parser::ParseStatement(const IToken *current) {
|
||||
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);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (nextKind == TokenKind::EndOfFile){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
|
||||
break;
|
||||
if (this->Peek()->GetKind() == TokenKind::AssignmentToken) {
|
||||
return ParseVariableAssignment(current);
|
||||
}
|
||||
statements.push_back(this -> ParseStatement(next));
|
||||
}
|
||||
if (statements.empty()){
|
||||
return new ParsedBlockStatement(statements,start);
|
||||
}
|
||||
return new ParsedBlockStatement(statements);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseFunctionDeclaration(const IToken *current) {
|
||||
auto functionIdentifierToken = this->Next();
|
||||
auto openParenthesis = this->Next();
|
||||
vector<TypedVariableIdentifier*> parameters;
|
||||
bool hasErrors = false;
|
||||
if (functionIdentifierToken->GetKind() != TokenKind::Identifier){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, functionIdentifierToken->GetStartPosition(), functionIdentifierToken->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, openParenthesis->GetStartPosition(), openParenthesis->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
while (this -> _position < this->_tokens.size()){
|
||||
auto type = this->Next();
|
||||
if (type->GetKind() == TokenKind::CloseParenthesis){
|
||||
break;
|
||||
}
|
||||
auto identifier = this->Next();
|
||||
auto next = this->Next();
|
||||
if (type->GetKind() != TokenKind::Identifier &&!hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
if (identifier->GetKind() != TokenKind::Identifier &&!hasErrors){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type->GetKind() != TokenKind::Identifier || identifier->GetKind() != TokenKind::Identifier){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
auto typeToken = (IdentifierToken*)type;
|
||||
auto identifierToken = (IdentifierToken*)identifier;
|
||||
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){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
|
||||
hasErrors = true;
|
||||
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);
|
||||
}
|
||||
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
|
||||
|
||||
auto start = current->GetStartPosition();
|
||||
if (hasErrors){
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
if (block->GetKind() == ParsedStatementKind::Bad){
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
auto functionIdentifier = ((IdentifierToken*) functionIdentifierToken)->GetValue();
|
||||
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters, (ParsedBlockStatement*)block, start, block->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement* Parser::ParseReturnStatement(const IToken* current){
|
||||
//TODO: if next token is on a different line, don't parse it as return expression.
|
||||
auto expression = this->ParseExpression(this->Next());
|
||||
auto start = current->GetStartPosition();
|
||||
return new ParsedReturnStatement(expression, start, expression->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement* Parser::ParseIfStatement(const IToken* current){
|
||||
auto condition = this->ParseExpression(this->Next());
|
||||
auto next = this -> Next();
|
||||
if (next->GetKind() != TokenKind::ThenKeyword){
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
|
||||
return new ParsedBadStatement(next->GetStartPosition(), next->GetLength());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
ParsedExpression* Parser::ParseExpression(const IToken* current){
|
||||
auto expression = this -> ParseBinaryExpression(current, OperatorPrecedence::No);
|
||||
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);
|
||||
ParsedStatement *Parser::ParseVariableAssignment(const IToken *current) {
|
||||
bool isLocal = false;
|
||||
const IToken *identifier;
|
||||
if (current->GetKind() == TokenKind::LocalKeyword) {
|
||||
isLocal = true;
|
||||
identifier = this->Next();
|
||||
} else {
|
||||
expression = this -> ParsePeriodIndexExpression(expression);
|
||||
identifier = current;
|
||||
}
|
||||
if (this -> _position >= this->_tokens.size())
|
||||
break;
|
||||
peekKind = this->Peek()->GetKind();
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
auto assignmentToken = this->Next();
|
||||
auto expression = this->ParseExpression(this->Next());
|
||||
|
||||
OperatorPrecedence GetUnaryPrecedence(TokenKind kind){
|
||||
switch (kind){
|
||||
case TokenKind::PlusToken:
|
||||
case TokenKind::MinusToken:
|
||||
case TokenKind::NotKeyword:
|
||||
return OperatorPrecedence::Unary;
|
||||
default:
|
||||
return OperatorPrecedence::No;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
ParsedExpression* Parser::ParseBinaryExpression(const IToken* current, OperatorPrecedence parentPrecedence){
|
||||
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);
|
||||
} else{
|
||||
left = this -> ParsePrimaryExpression(current);
|
||||
}
|
||||
while (true){
|
||||
auto next = this -> Peek();
|
||||
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind());
|
||||
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){
|
||||
break;
|
||||
if (identifier->GetKind() != TokenKind::Identifier) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
||||
identifier->GetLength());
|
||||
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
||||
}
|
||||
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);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParsePrimaryExpression(const IToken *current) {
|
||||
switch (current -> GetKind()){
|
||||
case TokenKind ::Integer: return new LiteralIntegerExpression((IntegerToken*)current);
|
||||
case TokenKind ::Float: return new LiteralFloatExpression((FloatToken*)current);
|
||||
case TokenKind ::String: return new LiteralStringExpression((StringToken*)current);
|
||||
case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current);
|
||||
case TokenKind ::FalseKeyword: return new LiteralBoolExpression(current);
|
||||
case TokenKind ::Identifier: return new VariableExpression((IdentifierToken*)current);
|
||||
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:
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(), current->GetLength());
|
||||
return new BadExpression(current->GetStartPosition(), current->GetLength());
|
||||
}
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParseParenthesizedExpression(const IToken *current) {
|
||||
auto next = this -> Next();
|
||||
auto expression = this -> ParseExpression(next);
|
||||
auto closeToken = this -> Next();
|
||||
if (closeToken -> GetKind() != TokenKind::CloseParenthesis){
|
||||
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(), closeToken->GetLength());
|
||||
return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength());
|
||||
}
|
||||
auto start = current -> GetStartPosition();
|
||||
return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
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){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(), 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){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(), peeked->GetLength());
|
||||
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
|
||||
}
|
||||
if (assignmentToken->GetKind() != TokenKind::AssignmentToken) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
||||
identifier->GetLength());
|
||||
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
|
||||
}
|
||||
}
|
||||
auto start = functionExpression->GetStartPosition();
|
||||
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedExpression* Parser::ParseIndexExpression(ParsedExpression* indexingExpression){
|
||||
this->Next(); // consume '[' token
|
||||
auto indexExpression = this -> ParseExpression(this -> Next());
|
||||
auto closeBracket = this->Next();
|
||||
if (closeBracket->GetKind() != TokenKind::CloseSquareBracket){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeBracket->GetStartPosition(), closeBracket->GetLength());
|
||||
return new BadExpression(closeBracket->GetStartPosition(), closeBracket->GetLength());
|
||||
}
|
||||
auto start = indexingExpression->GetStartPosition();
|
||||
return new IndexExpression(indexingExpression, indexExpression, start, closeBracket->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedExpression* Parser::ParsePeriodIndexExpression(ParsedExpression* indexingExpression){
|
||||
this->Next(); // consume '.' token
|
||||
auto identifier = this -> Next();
|
||||
if (identifier->GetKind() != TokenKind::Identifier){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
|
||||
return new BadExpression(indexingExpression->GetStartPosition(), identifier->GetEndPosition() - indexingExpression->GetStartPosition());
|
||||
}
|
||||
auto start = indexingExpression->GetStartPosition();
|
||||
return new PeriodIndexExpression(indexingExpression, ((IdentifierToken*)identifier)->GetValue(), start, identifier->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
|
||||
ParsedExpression* Parser::ParseTableExpression(const IToken* current){
|
||||
if (this -> Peek() -> GetKind() == TokenKind::CloseCurlyBracket){
|
||||
this -> Next();
|
||||
auto start = current->GetStartPosition();
|
||||
return new ParsedNumericalTableExpression({}, start, this -> Peek()->GetEndPosition() - start);
|
||||
return new ParsedAssignmentStatement(isLocal, ((IdentifierToken *) identifier)->GetValue(), expression, start,
|
||||
expression->GetEndPosition() - start);
|
||||
}
|
||||
auto start = current->GetStartPosition();
|
||||
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 )){
|
||||
auto expr = ((ParsedExpressionStatement*)firstItem)->GetExpression();
|
||||
auto expressions = vector<const ParsedExpression*>{expr};
|
||||
auto n = this -> Next(); // consume the comma
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
ParsedStatement *
|
||||
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) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
||||
next->GetLength());
|
||||
break;
|
||||
}
|
||||
statements.push_back(this->ParseStatement(next));
|
||||
}
|
||||
if (statements.empty()) {
|
||||
return new ParsedBlockStatement(statements, start);
|
||||
}
|
||||
return new ParsedBlockStatement(statements);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseFunctionDeclaration(const IToken *current) {
|
||||
auto functionIdentifierToken = this->Next();
|
||||
auto openParenthesis = this->Next();
|
||||
vector<TypedVariableIdentifier *> parameters;
|
||||
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){
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, n->GetStartPosition(), n->GetLength());
|
||||
if (functionIdentifierToken->GetKind() != TokenKind::Identifier) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken,
|
||||
functionIdentifierToken->GetStartPosition(),
|
||||
functionIdentifierToken->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken,
|
||||
openParenthesis->GetStartPosition(), openParenthesis->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
while (this->_position < this->_tokens.size()) {
|
||||
auto type = this->Next();
|
||||
if (type->GetKind() == TokenKind::CloseParenthesis) {
|
||||
break;
|
||||
}
|
||||
auto identifier = this->Next();
|
||||
auto next = this->Next();
|
||||
if (type->GetKind() != TokenKind::Identifier && !hasErrors) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
|
||||
type->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
if (identifier->GetKind() != TokenKind::Identifier && !hasErrors) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
||||
identifier->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type->GetKind() != TokenKind::Identifier || identifier->GetKind() != TokenKind::Identifier) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
|
||||
type->GetLength());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
auto typeToken = (IdentifierToken *) type;
|
||||
auto identifierToken = (IdentifierToken *) identifier;
|
||||
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) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
||||
next->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
if (hasErrors){
|
||||
return new BadExpression(start, n->GetEndPosition() - start);
|
||||
}
|
||||
return new ParsedNumericalTableExpression(expressions, start, n->GetEndPosition() - start);
|
||||
}
|
||||
// Otherwise we have a more complex table, which can be defined by a block
|
||||
else {
|
||||
auto block = (ParsedBlockStatement*)this -> ParseBlock({TokenKind ::CloseCurlyBracket}, {firstItem});
|
||||
auto closeToken = this -> PeekAt(-1);
|
||||
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
|
||||
}
|
||||
}
|
||||
auto block = this->ParseBlock({TokenKind::EndKeyword});
|
||||
|
||||
auto start = current->GetStartPosition();
|
||||
if (hasErrors) {
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
if (block->GetKind() == ParsedStatementKind::Bad) {
|
||||
return new ParsedBadStatement(start, block->GetEndPosition() - start);
|
||||
}
|
||||
auto functionIdentifier = ((IdentifierToken *) functionIdentifierToken)->GetValue();
|
||||
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters,
|
||||
(ParsedBlockStatement *) block, start,
|
||||
block->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseReturnStatement(const IToken *current) {
|
||||
//TODO: if next token is on a different line, don't parse it as return expression.
|
||||
auto expression = this->ParseExpression(this->Next());
|
||||
auto start = current->GetStartPosition();
|
||||
return new ParsedReturnStatement(expression, start, expression->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedStatement *Parser::ParseIfStatement(const IToken *current) {
|
||||
auto condition = this->ParseExpression(this->Next());
|
||||
auto next = this->Next();
|
||||
if (next->GetKind() != TokenKind::ThenKeyword) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
|
||||
next->GetLength());
|
||||
return new ParsedBadStatement(next->GetStartPosition(), next->GetLength());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParseExpression(const IToken *current) {
|
||||
auto expression = this->ParseBinaryExpression(current, OperatorPrecedence::No);
|
||||
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;
|
||||
}
|
||||
|
||||
OperatorPrecedence GetUnaryPrecedence(TokenKind kind) {
|
||||
switch (kind) {
|
||||
case TokenKind::PlusToken:
|
||||
case TokenKind::MinusToken:
|
||||
case TokenKind::NotKeyword:
|
||||
return OperatorPrecedence::Unary;
|
||||
default:
|
||||
return OperatorPrecedence::No;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence) {
|
||||
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);
|
||||
} else {
|
||||
left = this->ParsePrimaryExpression(current);
|
||||
}
|
||||
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);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParsePrimaryExpression(const IToken *current) {
|
||||
switch (current->GetKind()) {
|
||||
case TokenKind::Integer:
|
||||
return new LiteralIntegerExpression((IntegerToken *) current);
|
||||
case TokenKind::Float:
|
||||
return new LiteralFloatExpression((FloatToken *) current);
|
||||
case TokenKind::String:
|
||||
return new LiteralStringExpression((StringToken *) current);
|
||||
case TokenKind::TrueKeyword:
|
||||
return new LiteralBoolExpression(current);
|
||||
case TokenKind::FalseKeyword:
|
||||
return new LiteralBoolExpression(current);
|
||||
case TokenKind::Identifier:
|
||||
return new VariableExpression((IdentifierToken *) current);
|
||||
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:
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(),
|
||||
current->GetLength());
|
||||
return new BadExpression(current->GetStartPosition(), current->GetLength());
|
||||
}
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParseParenthesizedExpression(const IToken *current) {
|
||||
auto next = this->Next();
|
||||
auto expression = this->ParseExpression(next);
|
||||
auto closeToken = this->Next();
|
||||
if (closeToken->GetKind() != TokenKind::CloseParenthesis) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(),
|
||||
closeToken->GetLength());
|
||||
return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength());
|
||||
}
|
||||
auto start = current->GetStartPosition();
|
||||
return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
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) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
|
||||
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) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
|
||||
peeked->GetLength());
|
||||
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
auto start = functionExpression->GetStartPosition();
|
||||
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParseIndexExpression(ParsedExpression *indexingExpression) {
|
||||
this->Next(); // consume '[' token
|
||||
auto indexExpression = this->ParseExpression(this->Next());
|
||||
auto closeBracket = this->Next();
|
||||
if (closeBracket->GetKind() != TokenKind::CloseSquareBracket) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeBracket->GetStartPosition(),
|
||||
closeBracket->GetLength());
|
||||
return new BadExpression(closeBracket->GetStartPosition(), closeBracket->GetLength());
|
||||
}
|
||||
auto start = indexingExpression->GetStartPosition();
|
||||
return new IndexExpression(indexingExpression, indexExpression, start, closeBracket->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
ParsedExpression *Parser::ParsePeriodIndexExpression(ParsedExpression *indexingExpression) {
|
||||
this->Next(); // consume '.' token
|
||||
auto identifier = this->Next();
|
||||
if (identifier->GetKind() != TokenKind::Identifier) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
|
||||
identifier->GetLength());
|
||||
return new BadExpression(indexingExpression->GetStartPosition(),
|
||||
identifier->GetEndPosition() - indexingExpression->GetStartPosition());
|
||||
}
|
||||
auto start = indexingExpression->GetStartPosition();
|
||||
return new PeriodIndexExpression(indexingExpression, ((IdentifierToken *) identifier)->GetValue(), start,
|
||||
identifier->GetEndPosition() - start);
|
||||
}
|
||||
|
||||
|
||||
ParsedExpression *Parser::ParseTableExpression(const IToken *current) {
|
||||
if (this->Peek()->GetKind() == TokenKind::CloseCurlyBracket) {
|
||||
this->Next();
|
||||
auto start = current->GetStartPosition();
|
||||
return new ParsedNumericalTableExpression({}, start, this->Peek()->GetEndPosition() - start);
|
||||
}
|
||||
auto start = current->GetStartPosition();
|
||||
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)) {
|
||||
auto expr = ((ParsedExpressionStatement *) firstItem)->GetExpression();
|
||||
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) {
|
||||
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, n->GetStartPosition(),
|
||||
n->GetLength());
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
if (hasErrors) {
|
||||
return new BadExpression(start, n->GetEndPosition() - start);
|
||||
}
|
||||
return new ParsedNumericalTableExpression(expressions, start, n->GetEndPosition() - start);
|
||||
}
|
||||
// Otherwise we have a more complex table, which can be defined by a block
|
||||
else {
|
||||
auto block = (ParsedBlockStatement *) this->ParseBlock({TokenKind::CloseCurlyBracket}, {firstItem});
|
||||
auto closeToken = this->PeekAt(-1);
|
||||
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,51 +7,69 @@
|
||||
#include "ParsedStatements/ParsedStatement.hpp"
|
||||
#include "../Script.hpp"
|
||||
|
||||
enum class OperatorPrecedence {
|
||||
No,
|
||||
LogicalOr,
|
||||
LogicalAnd,
|
||||
Equality,
|
||||
Additive,
|
||||
Multiplication,
|
||||
Unary,
|
||||
};
|
||||
namespace Porygon::Parser {
|
||||
enum class OperatorPrecedence {
|
||||
No,
|
||||
LogicalOr,
|
||||
LogicalAnd,
|
||||
Equality,
|
||||
Additive,
|
||||
Multiplication,
|
||||
Unary,
|
||||
};
|
||||
|
||||
class Parser {
|
||||
vector<const IToken*> _tokens;
|
||||
unsigned int _position;
|
||||
Script* ScriptData;
|
||||
class Parser {
|
||||
vector<const IToken *> _tokens;
|
||||
unsigned int _position;
|
||||
Porygon::Script *ScriptData;
|
||||
|
||||
const IToken* Peek();
|
||||
const IToken *PeekAt(int offset);
|
||||
const IToken* Next();
|
||||
const IToken *Peek();
|
||||
|
||||
ParsedStatement* ParseStatement(const IToken* current);
|
||||
ParsedStatement* ParseVariableAssignment(const IToken *current);
|
||||
ParsedStatement* ParseIndexAssignment(ParsedExpression *indexer);
|
||||
ParsedStatement *ParseBlock(const vector<TokenKind>& endTokens, const vector<const ParsedStatement*>& openStatements = {});
|
||||
ParsedStatement* ParseFunctionDeclaration(const IToken* current);
|
||||
ParsedStatement *ParseReturnStatement(const IToken *current);
|
||||
ParsedStatement *ParseIfStatement(const IToken *current);
|
||||
const IToken *PeekAt(int offset);
|
||||
|
||||
ParsedExpression* ParseExpression(const IToken* current);
|
||||
ParsedExpression* ParseBinaryExpression(const IToken* current, OperatorPrecedence parentPrecedence);
|
||||
ParsedExpression* ParsePrimaryExpression(const IToken* current);
|
||||
ParsedExpression* ParseParenthesizedExpression(const IToken *current);
|
||||
const IToken *Next();
|
||||
|
||||
ParsedExpression* ParseFunctionCallExpression(ParsedExpression* functionExpression);
|
||||
ParsedExpression *ParseIndexExpression(ParsedExpression *indexingExpression);
|
||||
ParsedExpression *ParsePeriodIndexExpression(ParsedExpression *indexingExpression);
|
||||
ParsedExpression *ParseTableExpression(const IToken *current);
|
||||
public:
|
||||
ParsedScriptStatement* Parse();
|
||||
explicit Parser(const vector<const IToken*>& tokens, Script* scriptData){
|
||||
_tokens = tokens;
|
||||
_position = 0;
|
||||
ScriptData = scriptData;
|
||||
}
|
||||
ParsedStatement *ParseStatement(const IToken *current);
|
||||
|
||||
};
|
||||
ParsedStatement *ParseVariableAssignment(const IToken *current);
|
||||
|
||||
ParsedStatement *ParseIndexAssignment(ParsedExpression *indexer);
|
||||
|
||||
ParsedStatement *
|
||||
ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
|
||||
|
||||
ParsedStatement *ParseFunctionDeclaration(const IToken *current);
|
||||
|
||||
ParsedStatement *ParseReturnStatement(const IToken *current);
|
||||
|
||||
ParsedStatement *ParseIfStatement(const IToken *current);
|
||||
|
||||
ParsedExpression *ParseExpression(const IToken *current);
|
||||
|
||||
ParsedExpression *ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence);
|
||||
|
||||
ParsedExpression *ParsePrimaryExpression(const IToken *current);
|
||||
|
||||
ParsedExpression *ParseParenthesizedExpression(const IToken *current);
|
||||
|
||||
ParsedExpression *ParseFunctionCallExpression(ParsedExpression *functionExpression);
|
||||
|
||||
ParsedExpression *ParseIndexExpression(ParsedExpression *indexingExpression);
|
||||
|
||||
ParsedExpression *ParsePeriodIndexExpression(ParsedExpression *indexingExpression);
|
||||
|
||||
ParsedExpression *ParseTableExpression(const IToken *current);
|
||||
|
||||
public:
|
||||
ParsedScriptStatement *Parse();
|
||||
|
||||
explicit Parser(const vector<const IToken *> &tokens, Porygon::Script *scriptData) {
|
||||
_tokens = tokens;
|
||||
_position = 0;
|
||||
ScriptData = scriptData;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PORYGONLANG_PARSER_HPP
|
||||
|
||||
@@ -10,122 +10,119 @@
|
||||
#include "../Utilities/HashedString.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace Porygon::Utilities;
|
||||
|
||||
class IToken{
|
||||
const unsigned int _position;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
virtual const TokenKind GetKind() const = 0;
|
||||
namespace Porygon::Parser {
|
||||
class IToken {
|
||||
const unsigned int _position;
|
||||
const unsigned int _length;
|
||||
public:
|
||||
virtual const TokenKind GetKind() const = 0;
|
||||
|
||||
IToken(unsigned int position, unsigned int length)
|
||||
: _position(position), _length(length)
|
||||
{
|
||||
}
|
||||
IToken(unsigned int position, unsigned int length)
|
||||
: _position(position), _length(length) {
|
||||
}
|
||||
|
||||
const unsigned int GetStartPosition() const{
|
||||
return _position;
|
||||
}
|
||||
const unsigned int GetStartPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
const unsigned int GetEndPosition() const{
|
||||
return _position + _length - 1;
|
||||
}
|
||||
const unsigned int GetEndPosition() const {
|
||||
return _position + _length - 1;
|
||||
}
|
||||
|
||||
const unsigned int GetLength() const{
|
||||
return _length;
|
||||
}
|
||||
const unsigned int GetLength() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
virtual ~IToken() = default;
|
||||
};
|
||||
virtual ~IToken() = default;
|
||||
};
|
||||
|
||||
class SimpleToken : public IToken{
|
||||
const TokenKind _kind;
|
||||
public:
|
||||
class SimpleToken : public IToken {
|
||||
const TokenKind _kind;
|
||||
public:
|
||||
|
||||
explicit SimpleToken(TokenKind kind, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_kind(kind)
|
||||
{
|
||||
}
|
||||
explicit SimpleToken(TokenKind kind, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_kind(kind) {
|
||||
}
|
||||
|
||||
const TokenKind GetKind() const final{
|
||||
return _kind;
|
||||
}
|
||||
};
|
||||
const TokenKind GetKind() const final {
|
||||
return _kind;
|
||||
}
|
||||
};
|
||||
|
||||
class IntegerToken : public IToken{
|
||||
const long _value;
|
||||
public:
|
||||
class IntegerToken : public IToken {
|
||||
const long _value;
|
||||
public:
|
||||
|
||||
explicit IntegerToken(long value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value)
|
||||
{
|
||||
}
|
||||
explicit IntegerToken(long value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value) {
|
||||
}
|
||||
|
||||
const TokenKind GetKind() const final{
|
||||
return TokenKind::Integer;
|
||||
}
|
||||
const TokenKind GetKind() const final {
|
||||
return TokenKind::Integer;
|
||||
}
|
||||
|
||||
const long GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
const long GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class FloatToken : public IToken{
|
||||
const double _value;
|
||||
public:
|
||||
class FloatToken : public IToken {
|
||||
const double _value;
|
||||
public:
|
||||
|
||||
explicit FloatToken(double value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value)
|
||||
{
|
||||
}
|
||||
explicit FloatToken(double value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value) {
|
||||
}
|
||||
|
||||
const TokenKind GetKind() const final{
|
||||
return TokenKind::Float;
|
||||
}
|
||||
const TokenKind GetKind() const final {
|
||||
return TokenKind::Float;
|
||||
}
|
||||
|
||||
const double GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
const double GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class StringToken : public IToken{
|
||||
const u16string _value;
|
||||
public:
|
||||
class StringToken : public IToken {
|
||||
const u16string _value;
|
||||
public:
|
||||
|
||||
explicit StringToken(u16string value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(std::move(value))
|
||||
{
|
||||
}
|
||||
explicit StringToken(u16string value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(std::move(value)) {
|
||||
}
|
||||
|
||||
const TokenKind GetKind() const final{
|
||||
return TokenKind::String;
|
||||
}
|
||||
const TokenKind GetKind() const final {
|
||||
return TokenKind::String;
|
||||
}
|
||||
|
||||
const u16string& GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
const u16string &GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
class IdentifierToken : public IToken{
|
||||
const HashedString _value;
|
||||
public:
|
||||
class IdentifierToken : public IToken {
|
||||
const Utilities::HashedString _value;
|
||||
public:
|
||||
|
||||
explicit IdentifierToken(const HashedString value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value)
|
||||
{
|
||||
}
|
||||
explicit IdentifierToken(const HashedString value, unsigned int position, unsigned int length)
|
||||
: IToken(position, length),
|
||||
_value(value) {
|
||||
}
|
||||
|
||||
const TokenKind GetKind() const final{
|
||||
return TokenKind::Identifier;
|
||||
}
|
||||
const TokenKind GetKind() const final {
|
||||
return TokenKind::Identifier;
|
||||
}
|
||||
|
||||
const HashedString GetValue() const{
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
const HashedString GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PORYGONLANG_TOKEN_HPP
|
||||
|
||||
@@ -1,59 +1,60 @@
|
||||
#ifndef PORYGONLANG_TOKENKIND_HPP
|
||||
#define PORYGONLANG_TOKENKIND_HPP
|
||||
|
||||
enum class TokenKind{
|
||||
EndOfFile,
|
||||
BadToken,
|
||||
WhiteSpace,
|
||||
namespace Porygon::Parser {
|
||||
enum class TokenKind {
|
||||
EndOfFile,
|
||||
BadToken,
|
||||
WhiteSpace,
|
||||
|
||||
PlusToken,
|
||||
MinusToken,
|
||||
SlashToken,
|
||||
StarToken,
|
||||
AssignmentToken,
|
||||
EqualityToken,
|
||||
InequalityToken,
|
||||
Less,
|
||||
LessEquals,
|
||||
Greater,
|
||||
GreaterEquals,
|
||||
PlusToken,
|
||||
MinusToken,
|
||||
SlashToken,
|
||||
StarToken,
|
||||
AssignmentToken,
|
||||
EqualityToken,
|
||||
InequalityToken,
|
||||
Less,
|
||||
LessEquals,
|
||||
Greater,
|
||||
GreaterEquals,
|
||||
|
||||
OpenParenthesis,
|
||||
CloseParenthesis,
|
||||
OpenSquareBracket,
|
||||
CloseSquareBracket,
|
||||
OpenCurlyBracket,
|
||||
CloseCurlyBracket,
|
||||
OpenParenthesis,
|
||||
CloseParenthesis,
|
||||
OpenSquareBracket,
|
||||
CloseSquareBracket,
|
||||
OpenCurlyBracket,
|
||||
CloseCurlyBracket,
|
||||
|
||||
PeriodToken,
|
||||
CommaToken,
|
||||
PeriodToken,
|
||||
CommaToken,
|
||||
|
||||
Identifier,
|
||||
Identifier,
|
||||
|
||||
Integer,
|
||||
Float,
|
||||
String,
|
||||
|
||||
AndKeyword,
|
||||
BreakKeyword,
|
||||
DoKeyword,
|
||||
ElseKeyword,
|
||||
ElseIfKeyword,
|
||||
EndKeyword,
|
||||
FalseKeyword,
|
||||
ForKeyword,
|
||||
FunctionKeyword,
|
||||
IfKeyword,
|
||||
InKeyword,
|
||||
LocalKeyword,
|
||||
NilKeyword,
|
||||
NotKeyword,
|
||||
OrKeyword,
|
||||
ReturnKeyword,
|
||||
ThenKeyword,
|
||||
TrueKeyword,
|
||||
WhileKeyword,
|
||||
};
|
||||
Integer,
|
||||
Float,
|
||||
String,
|
||||
|
||||
AndKeyword,
|
||||
BreakKeyword,
|
||||
DoKeyword,
|
||||
ElseKeyword,
|
||||
ElseIfKeyword,
|
||||
EndKeyword,
|
||||
FalseKeyword,
|
||||
ForKeyword,
|
||||
FunctionKeyword,
|
||||
IfKeyword,
|
||||
InKeyword,
|
||||
LocalKeyword,
|
||||
NilKeyword,
|
||||
NotKeyword,
|
||||
OrKeyword,
|
||||
ReturnKeyword,
|
||||
ThenKeyword,
|
||||
TrueKeyword,
|
||||
WhileKeyword,
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PORYGONLANG_TOKENKIND_HPP
|
||||
|
||||
@@ -4,22 +4,23 @@
|
||||
|
||||
#include "../Utilities/HashedString.hpp"
|
||||
|
||||
class TypedVariableIdentifier{
|
||||
HashedString _type;
|
||||
HashedString _identifier;
|
||||
public:
|
||||
TypedVariableIdentifier(HashedString type, HashedString identifier)
|
||||
: _type(type), _identifier(identifier)
|
||||
{
|
||||
}
|
||||
namespace Porygon::Parser {
|
||||
class TypedVariableIdentifier {
|
||||
HashedString _type;
|
||||
HashedString _identifier;
|
||||
public:
|
||||
TypedVariableIdentifier(HashedString type, HashedString identifier)
|
||||
: _type(type), _identifier(identifier) {
|
||||
}
|
||||
|
||||
HashedString GetType(){
|
||||
return _type;
|
||||
}
|
||||
HashedString GetType() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
HashedString GetIdentifier(){
|
||||
return _identifier;
|
||||
}
|
||||
};
|
||||
HashedString GetIdentifier() {
|
||||
return _identifier;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
#ifndef PORYGONLANG_UNARYOPERATORKIND_HPP
|
||||
#define PORYGONLANG_UNARYOPERATORKIND_HPP
|
||||
|
||||
enum class UnaryOperatorKind{
|
||||
Identity,
|
||||
Negation,
|
||||
LogicalNegation,
|
||||
};
|
||||
namespace Porygon::Parser {
|
||||
enum class UnaryOperatorKind {
|
||||
Identity,
|
||||
Negation,
|
||||
LogicalNegation,
|
||||
};
|
||||
}
|
||||
#endif //PORYGONLANG_UNARYOPERATORKIND_HPP
|
||||
|
||||
Reference in New Issue
Block a user