MalachScript/src/Parser/Parser.cpp

917 lines
41 KiB
C++

#include "Parser.hpp"
#include <iostream>
#include "../CoreData/PrimitiveTypes.hpp"
#define PROGRESS_TOKEN(token) \
token = (token)->GetNext().get(); \
while ((token)->GetKind() == LexTokenKind::Whitespace) { \
(token) = (token)->GetNext().get(); \
}
#define EXPECT_TOKEN(token, kind) \
if (token->GetKind() != LexTokenKind::kind) { \
LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan()); \
} else { \
PROGRESS_TOKEN(token); \
}
namespace MalachScript::Parser {
const ParsedScriptStatement* Parser::Parse() { return ParseScript(); }
const ParsedScriptStatement* Parser::ParseScript() {
std::vector<const ParsedStatement*> statements;
statements.reserve(32);
size_t current = 0;
const auto* currentToken = _firstToken;
while (true) {
while (currentToken->GetKind() == LexTokenKind::Whitespace) {
currentToken = currentToken->GetNext().get();
}
if (currentToken->GetKind() == LexTokenKind::EndOfFile) {
break;
}
ScopedPtr<const ParsedStatement> statement;
auto result = ParseClass(statement, currentToken) || ParseFunc(statement, currentToken) ||
ParseNamespace(statement, currentToken);
if (!result) {
// TODO: Log error
PROGRESS_TOKEN(currentToken);
continue;
}
statements.push_back(statement.TakeOwnership());
current++;
}
statements.resize(current);
auto end = 0;
if (current > 0) {
end = statements.back()->GetSpan().GetEnd();
}
return new ParsedScriptStatement(TextSpan(0, end), statements);
}
bool Parser::ParseClass(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
auto start = current->GetSpan().GetStart();
bool lookingForClass = true;
while (lookingForClass) {
switch (current->GetKind()) {
case LexTokenKind::SharedKeyword: break;
case LexTokenKind::AbstractKeyword: break;
case LexTokenKind::FinalKeyword: break;
case LexTokenKind::ExternalKeyword: break;
case LexTokenKind::ClassKeyword: lookingForClass = false; break;
default: return false;
}
PROGRESS_TOKEN(current);
}
// After class keyword, an identifier should always follow, if it doesn't, log an error.
Identifier identifier;
if (!ParseIdentifier(identifier, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
PROGRESS_TOKEN(current);
std::vector<Identifier> inherits;
std::vector<const ParsedStatement*> body;
body.reserve(16);
switch (current->GetKind()) {
case LexTokenKind::SemicolonSymbol: {
PROGRESS_TOKEN(current);
break;
}
case LexTokenKind::ColonSymbol: {
PROGRESS_TOKEN(current);
Identifier id;
if (!ParseIdentifier(id, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
inherits.push_back(id);
while (current->GetKind() == LexTokenKind::CommaSymbol) {
PROGRESS_TOKEN(current);
if (!ParseIdentifier(id, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
inherits.push_back(id);
PROGRESS_TOKEN(current);
}
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
[[fallthrough]];
// Intentionally don't break so we continue into the inner body statement.
}
case LexTokenKind::OpenCurlyParenthesisSymbol: {
PROGRESS_TOKEN(current);
while (true) {
// Cheapest operation, check first
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
PROGRESS_TOKEN(current);
break;
}
ScopedPtr<const ParsedStatement> statement = nullptr;
// TODO: Sort by complexity
if (!ParseVirtProp(statement, current) && !ParseFunc(statement, current) &&
!ParseVar(statement, current) && !ParseFuncDef(statement, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
break;
}
body.push_back(statement.TakeOwnership());
}
break;
}
default: throw;
}
out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), identifier, inherits, body);
currentToken = current;
return true;
}
bool Parser::ParseTypeDef(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::TypedefKeyword) {
return false;
}
auto start = current->GetSpan().GetStart();
PROGRESS_TOKEN(current);
Identifier defineFrom;
if (!ParsePrimType(defineFrom, current) && !ParseIdentifier(defineFrom, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
PROGRESS_TOKEN(current);
Identifier defineTo;
if (!ParseIdentifier(defineTo, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
PROGRESS_TOKEN(current);
EXPECT_TOKEN(current, SemicolonSymbol);
out = new ParsedTypeDefStatement(TextSpan(start, current->GetSpan().GetEnd()), defineFrom, defineTo);
return true;
}
bool Parser::ParseNamespace(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::NamespaceKeyword) {
return false;
}
auto start = current->GetSpan().GetStart();
PROGRESS_TOKEN(current);
Identifier identifier;
if (!ParseIdentifier(identifier, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
const auto* script = ParseScript();
auto end = current->GetSpan().GetEnd();
PROGRESS_TOKEN(current);
out = new ParsedNamespaceStatement(TextSpan(start, end), identifier, script);
currentToken = current;
return true;
}
bool Parser::ParseFunc(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
auto start = current->GetSpan().GetStart();
bool isShared = false;
bool isExternal = false;
bool modifiers = true;
while (modifiers) {
switch (current->GetKind()) {
case LexTokenKind::SharedKeyword:
isShared = true;
PROGRESS_TOKEN(current);
continue;
case LexTokenKind::ExternalKeyword:
isExternal = true;
PROGRESS_TOKEN(current);
continue;
default: modifiers = false; break;
}
}
AccessModifier accessModifier = AccessModifier::Public;
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
accessModifier = AccessModifier::Private;
PROGRESS_TOKEN(current);
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
accessModifier = AccessModifier::Protected;
PROGRESS_TOKEN(current);
}
ScopedPtr<const ParsedStatement> typeStatement = nullptr;
bool returnsReference = false;
if (current->GetKind() == LexTokenKind::TildeSymbol) {
// TODO: Handle destructor
throw std::logic_error("not implemented");
} else if (ParseType(typeStatement, current)) {
if (current->GetKind() == LexTokenKind::AmpersandSymbol) {
returnsReference = true;
PROGRESS_TOKEN(current);
}
}
Identifier identifier;
if (!ParseIdentifier(identifier, current)) {
return false;
}
PROGRESS_TOKEN(current);
ScopedPtr<const ParsedStatement> paramList = nullptr;
if (!ParseParamList(paramList, current)) {
return false;
}
bool isConst = false;
if (current->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(current);
}
FuncAttr funcAttr = FuncAttr::None;
ParseFuncAttr(funcAttr, current);
ScopedPtr<const ParsedStatement> statblock = nullptr;
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
if (!ParseStatBlock(statblock, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
} else {
PROGRESS_TOKEN(current);
}
out = new ParsedFuncStatement(TextSpan(start, current->GetSpan().GetEnd()), isShared, isExternal,
accessModifier, typeStatement.TakeOwnership(), returnsReference, identifier,
paramList.TakeOwnership(), isConst, funcAttr, statblock.TakeOwnership());
currentToken = current;
return true;
}
bool Parser::ParseType(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* token = currentToken;
auto start = token->GetSpan().GetStart();
bool isConst = false;
bool isArray = false;
bool isHandle = false;
if (token->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(token);
}
ScopedIdentifier scopedIdentifier;
ParseScope(scopedIdentifier.GetScope(), token);
if (!ParseDataType(scopedIdentifier.GetIdentifier(), token)) {
return false;
}
// TODO: Generics.
if (token->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) {
PROGRESS_TOKEN(token);
if (token->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan());
} else {
PROGRESS_TOKEN(token);
isArray = true;
}
} else if (token->GetKind() == LexTokenKind::AtSymbol) {
isHandle = true;
PROGRESS_TOKEN(token);
if (token->GetKind() == LexTokenKind::ConstKeyword) {
isConst = true;
PROGRESS_TOKEN(token);
}
}
auto end = token->GetSpan().GetEnd();
currentToken = token;
out = new ParsedTypeStatement(TextSpan(start, end), isConst, isArray, isHandle, scopedIdentifier);
return true;
}
bool Parser::ParseScope(std::vector<Identifier>& scope, const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() == LexTokenKind::ColonColonSymbol) {
scope.emplace_back();
PROGRESS_TOKEN(current);
}
Identifier identifier;
if (ParseIdentifier(identifier, current)) {
PROGRESS_TOKEN(current);
scope.push_back(identifier);
if (current->GetKind() != LexTokenKind::ColonColonSymbol) {
return false;
}
} else {
return false;
}
while (current->GetKind() == LexTokenKind::ColonColonSymbol) {
PROGRESS_TOKEN(current);
const auto* n = current;
if (ParseIdentifier(identifier, n)) {
PROGRESS_TOKEN(n);
if (n->GetKind() == LexTokenKind::ColonColonSymbol) {
current = n;
scope.push_back(identifier);
} else {
break;
}
} else {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
break;
}
}
// TODO: Handle generics in script class name.
currentToken = current;
return true;
}
bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken) {
bool lookingForFuncAttr = true;
const auto* current = currentToken;
while (lookingForFuncAttr) {
switch (current->GetKind()) {
case LexTokenKind::OverrideKeyword:
PROGRESS_TOKEN(current);
out = FuncAttrHelpers::Set(out, FuncAttr::Override);
continue;
case LexTokenKind::FinalKeyword:
PROGRESS_TOKEN(current);
out = FuncAttrHelpers::Set(out, FuncAttr::Final);
continue;
case LexTokenKind::ExplicitKeyword:
PROGRESS_TOKEN(current);
out = FuncAttrHelpers::Set(out, FuncAttr::Explicit);
continue;
case LexTokenKind::PropertyKeyword:
PROGRESS_TOKEN(current);
out = FuncAttrHelpers::Set(out, FuncAttr::Property);
continue;
default: lookingForFuncAttr = false; break;
}
}
currentToken = current;
return true;
}
bool Parser::ParseParamList(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) {
return false;
}
auto start = currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(currentToken);
std::vector<const ParsedParamListStatement::ParsedParameter*> parameters;
if (currentToken->GetKind() == LexTokenKind::VoidKeyword) {
PROGRESS_TOKEN(currentToken);
if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
}
PROGRESS_TOKEN(currentToken);
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
return true;
}
if (currentToken->GetKind() == LexTokenKind::CloseParenthesisSymbol) {
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
PROGRESS_TOKEN(currentToken);
return true;
}
while (true) {
ScopedPtr<const ParsedStatement> typeStatement = nullptr;
TypeMod typeMod = TypeMod::None;
Identifier identifier;
const ParsedStatement* defaultExpression = nullptr;
if (!ParseType(typeStatement, currentToken)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
}
ParseTypeMod(typeMod, currentToken);
ParseIdentifier(identifier, currentToken);
PROGRESS_TOKEN(currentToken);
// TODO: Default expression
parameters.push_back(new ParsedParamListStatement::ParsedParameter(
dynamic_cast<const ParsedTypeStatement*>(typeStatement.TakeOwnership()), typeMod, identifier,
defaultExpression));
if (currentToken->GetKind() != LexTokenKind::CommaSymbol) {
break;
}
PROGRESS_TOKEN(currentToken);
}
while (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan());
if (currentToken->GetKind() == LexTokenKind::EndOfFile) {
break;
}
if (currentToken->GetKind() == LexTokenKind::SemicolonSymbol) {
break;
}
PROGRESS_TOKEN(currentToken);
}
out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters);
if (currentToken->GetKind() != LexTokenKind::SemicolonSymbol) {
PROGRESS_TOKEN(currentToken);
}
return true;
}
bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken) {
switch (currentToken->GetKind()) {
case LexTokenKind::Identifier:
out = static_cast<const IdentifierToken*>(currentToken)->GetValue();
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::AutoKeyword:
out = PrimitiveTypes::AutoName();
PROGRESS_TOKEN(currentToken);
return true;
default:
if (ParsePrimType(out, currentToken)) {
PROGRESS_TOKEN(currentToken);
return true;
}
return false;
}
}
bool Parser::ParseVirtProp([[maybe_unused]] ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
AccessModifier access = AccessModifier::Public;
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
access = AccessModifier::Private;
PROGRESS_TOKEN(current);
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
access = AccessModifier::Protected;
PROGRESS_TOKEN(current);
}
ScopedPtr<const ParsedStatement> typeStatement = nullptr;
if (!ParseType(typeStatement, current)) {
return false;
}
bool ref = false;
if (current->GetKind() == LexTokenKind::AmpersandSymbol) {
ref = true;
PROGRESS_TOKEN(current);
}
Identifier identifier;
if (!ParseIdentifier(identifier, current)) {
return false;
}
PROGRESS_TOKEN(current);
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
return false;
}
bool hasGet = false;
bool getConst = false;
FuncAttr getAttr = FuncAttr::None;
ScopedPtr<const ParsedStatement> getStatement = nullptr;
bool hasSet = false;
bool setConst = false;
FuncAttr setAttr = FuncAttr::None;
ScopedPtr<const ParsedStatement> setStatement = nullptr;
PROGRESS_TOKEN(current);
while (true) {
auto start = current->GetSpan().GetStart();
if (current->GetKind() == LexTokenKind::GetKeyword) {
PROGRESS_TOKEN(current);
if (current->GetKind() == LexTokenKind::ConstKeyword) {
getConst = true;
PROGRESS_TOKEN(current);
}
ParseFuncAttr(getAttr, current);
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
if (!ParseStatBlock(getStatement, current)) {
this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
} else {
PROGRESS_TOKEN(current);
}
if (hasGet) {
this->LogError(Diagnostics::DiagnosticType::DoubleProperty,
TextSpan(start, current->GetSpan().GetEnd()));
}
hasGet = true;
} else if (current->GetKind() == LexTokenKind::SetKeyword) {
PROGRESS_TOKEN(current);
if (current->GetKind() == LexTokenKind::ConstKeyword) {
setConst = true;
PROGRESS_TOKEN(current);
}
ParseFuncAttr(setAttr, current);
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
if (!ParseStatBlock(setStatement, current)) {
this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
} else {
PROGRESS_TOKEN(current);
}
if (hasSet) {
this->LogError(Diagnostics::DiagnosticType::DoubleProperty,
TextSpan(start, current->GetSpan().GetEnd()));
}
hasSet = true;
} else {
break;
}
}
if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
} else {
PROGRESS_TOKEN(current);
}
out = new ParsedVirtPropStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
access, typeStatement.TakeOwnership(), ref, identifier, hasGet, getConst,
getAttr, getStatement.TakeOwnership(), hasSet, setConst, setAttr,
setStatement.TakeOwnership());
currentToken = current;
return true;
}
bool Parser::ParseIfStatement([[maybe_unused]] ScopedPtr<const ParsedStatement>& out,
const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::IfKeyword) {
return false;
}
PROGRESS_TOKEN(current);
EXPECT_TOKEN(current, OpenParenthesisSymbol);
ScopedPtr<const ParsedStatement> condition = nullptr;
if (!ParseAssign(condition, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
EXPECT_TOKEN(current, CloseParenthesisSymbol);
ScopedPtr<const ParsedStatement> body = nullptr;
if (!ParseStatement(body, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
ScopedPtr<const ParsedStatement> elseStatement = nullptr;
if (current->GetKind() == LexTokenKind::ElseKeyword) {
PROGRESS_TOKEN(current);
if (!ParseStatement(elseStatement, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
}
out = new ParsedIfStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
condition.TakeOwnership(), body.TakeOwnership(), elseStatement.TakeOwnership());
currentToken = current;
return true;
}
bool Parser::ParseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
// TODO: All the other statements.
return ParseIfStatement(out, currentToken) || ParseForStatement(out, currentToken) ||
ParseReturn(out, currentToken) || ParseStatBlock(out, currentToken) || ParseBreak(out, currentToken) ||
ParseContinue(out, currentToken) || ParseExprStat(out, currentToken);
}
bool Parser::ParseVar([[maybe_unused]] ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
AccessModifier access = AccessModifier::Public;
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
access = AccessModifier::Private;
PROGRESS_TOKEN(current);
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
access = AccessModifier::Protected;
PROGRESS_TOKEN(current);
}
ScopedPtr<const ParsedStatement> typeStatement = nullptr;
if (!ParseType(typeStatement, current)) {
return false;
}
Identifier identifier;
if (!ParseIdentifier(identifier, current)) {
return false;
}
PROGRESS_TOKEN(current);
// TODO: Default values
// TODO: Creating multiple vars in a single line (int a, b, c)
EXPECT_TOKEN(current, SemicolonSymbol);
out = new ParsedVarStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), access,
typeStatement.TakeOwnership(), identifier);
currentToken = current;
return true;
}
bool Parser::ParseStatBlock(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
return false;
}
PROGRESS_TOKEN(current);
std::vector<const ParsedStatement*> statements;
while (true) {
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
break;
}
ScopedPtr<const ParsedStatement> stat = nullptr;
if (ParseVar(stat, current) || ParseStatement(stat, current)) {
statements.push_back(stat.TakeOwnership());
} else {
break;
}
}
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
PROGRESS_TOKEN(current);
} else {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
out = new ParsedStatBlockStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
statements);
currentToken = current;
return true;
}
bool Parser::ParseFuncDef([[maybe_unused]] ScopedPtr<const ParsedStatement>& out,
[[maybe_unused]] const LexToken*& currentToken) {
return false;
}
bool Parser::ParsePrimType(Identifier& out, const LexToken*& token) {
switch (token->GetKind()) {
case LexTokenKind::VoidKeyword: out = PrimitiveTypes::VoidName(); return true;
case LexTokenKind::IntKeyword: out = PrimitiveTypes::IntName(); return true;
case LexTokenKind::Int8Keyword: out = PrimitiveTypes::Int8Name(); return true;
case LexTokenKind::Int16Keyword: out = PrimitiveTypes::Int16Name(); return true;
case LexTokenKind::Int32Keyword: out = PrimitiveTypes::Int32Name(); return true;
case LexTokenKind::Int64Keyword: out = PrimitiveTypes::Int64Name(); return true;
case LexTokenKind::UintKeyword: out = PrimitiveTypes::UintName(); return true;
case LexTokenKind::Uint8Keyword: out = PrimitiveTypes::Uint8Name(); return true;
case LexTokenKind::Uint16Keyword: out = PrimitiveTypes::Uint16Name(); return true;
case LexTokenKind::Uint32Keyword: out = PrimitiveTypes::Uint32Name(); return true;
case LexTokenKind::Uint64Keyword: out = PrimitiveTypes::Uint64Name(); return true;
case LexTokenKind::FloatKeyword: out = PrimitiveTypes::FloatName(); return true;
case LexTokenKind::DoubleKeyword: out = PrimitiveTypes::DoubleName(); return true;
case LexTokenKind::BoolKeyword: out = PrimitiveTypes::BoolName(); return true;
default: return false;
}
}
bool Parser::ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::AmpersandSymbol) {
return false;
}
PROGRESS_TOKEN(currentToken);
switch (currentToken->GetKind()) {
case LexTokenKind::InKeyword:
typeMod = TypeMod::RefIn;
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::OutKeyword:
typeMod = TypeMod::RefOut;
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::InoutKeyword:
typeMod = TypeMod::RefInOut;
PROGRESS_TOKEN(currentToken);
return true;
default: typeMod = TypeMod::RefInOut; return true;
}
}
bool Parser::ParseAssign(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
ScopedPtr<const ParsedStatement> leftHand = nullptr;
if (!ParseTernary(leftHand, current)) {
return false;
}
AssignmentOperator op;
if (!ParseAssignOp(op, current)) {
out = leftHand.TakeOwnership();
currentToken = current;
return true;
}
PROGRESS_TOKEN(current);
ScopedPtr<const ParsedStatement> rightHand = nullptr;
if (!ParseAssign(rightHand, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
out = leftHand.TakeOwnership();
currentToken = current;
return true;
}
out = new ParsedBinaryStatement<AssignmentOperator>(
TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand.TakeOwnership(), op,
rightHand.TakeOwnership());
currentToken = current;
return true;
}
bool Parser::ParseTernary(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
// TODO: implement ternary.
return ParseExpr(out, currentToken);
}
#define EXPR_PARSER(operator, name, func) \
operator name; \
if (func(name, current)) { \
PROGRESS_TOKEN(current); \
ScopedPtr<const ParsedStatement> rightHand = nullptr; \
if (!ParseExprTerm(rightHand, current)) { \
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); \
out = leftHand.TakeOwnership(); \
currentToken = current; \
return true; \
} \
out = new ParsedBinaryStatement < operator>(TextSpan(currentToken->GetSpan().GetStart(), \
current->GetSpan().GetEnd()), \
leftHand.TakeOwnership(), name, rightHand.TakeOwnership()); \
currentToken = current; \
return true; \
}
bool Parser::ParseExpr(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
ScopedPtr<const ParsedStatement> leftHand = nullptr;
if (!ParseExprTerm(leftHand, current)) {
return false;
}
EXPR_PARSER(MathOperator, mathOp, ParseMathOp);
EXPR_PARSER(ComparisonOperator, compOp, ParseCompOp);
EXPR_PARSER(LogicOperator, logicOp, ParseLogicOp);
EXPR_PARSER(BitOperator, bitOp, ParseBitOp);
out = leftHand.TakeOwnership();
currentToken = current;
return true;
}
bool Parser::ParseExprTerm(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
// TODO ([type '='] initlist)
PreOperator preOperator;
bool hasPreOp = ParsePreOp(preOperator, currentToken);
if (hasPreOp) {
PROGRESS_TOKEN(current);
}
ScopedPtr<const ParsedStatement> operand = nullptr;
if (!ParseExprValue(operand, current)) {
return false;
}
// TODO: remainder of
if (current->GetKind() == LexTokenKind::PlusPlusSymbol) {
operand = new ParsedIncrementStatement(TextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd()),
operand.TakeOwnership());
PROGRESS_TOKEN(current);
} else if (current->GetKind() == LexTokenKind::MinusMinusSymbol) {
operand = new ParsedDecrementStatement(TextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd()),
operand.TakeOwnership());
PROGRESS_TOKEN(current);
}
if (hasPreOp) {
// TODO: integrate pre operator
}
out = operand.TakeOwnership();
currentToken = current;
return true;
}
bool Parser::ParseExprValue(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
const auto* current = currentToken;
if (current->GetKind() == LexTokenKind::VoidKeyword) {
PROGRESS_TOKEN(current);
out = new ParsedVoidStatement(currentToken->GetSpan());
currentToken = current;
return true;
}
// TODO: constructcall
// TODO: funccall
if (ParseVarAccess(out, current)) {
currentToken = current;
return true;
}
// TODO: cast
if (ParseLiteral(out, current)) {
currentToken = current;
return true;
}
if (current->GetKind() == LexTokenKind::OpenParenthesisSymbol) {
PROGRESS_TOKEN(current);
if (!ParseAssign(out, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
}
EXPECT_TOKEN(current, CloseParenthesisSymbol);
return true;
}
// TODO: lambda
return false;
}
bool Parser::ParseLiteral(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
switch (currentToken->GetKind()) {
case LexTokenKind::IntegerLiteral:
out = new ParsedLiteralStatement<ParseInt>(
currentToken->GetSpan(), static_cast<const IntegerLiteral*>(currentToken)->GetValue());
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::FloatLiteral:
out = new ParsedLiteralStatement<ParseFloat>(
currentToken->GetSpan(), static_cast<const FloatLiteral*>(currentToken)->GetValue());
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::StringLiteral:
out = new ParsedLiteralStatement<ParseString>(
currentToken->GetSpan(), static_cast<const StringLiteral*>(currentToken)->GetValue());
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::TrueKeyword:
out = new ParsedLiteralStatement<bool>(currentToken->GetSpan(), true);
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::FalseKeyword:
out = new ParsedLiteralStatement<bool>(currentToken->GetSpan(), false);
PROGRESS_TOKEN(currentToken);
return true;
case LexTokenKind::NullKeyword:
out = new ParsedLiteralStatement<void*>(currentToken->GetSpan(), nullptr);
PROGRESS_TOKEN(currentToken);
return true;
default: return false;
}
}
bool Parser::ParseReturn(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
auto start = currentToken->GetSpan().GetStart();
if (currentToken->GetKind() != LexTokenKind::ReturnKeyword) {
return false;
}
PROGRESS_TOKEN(currentToken);
ScopedPtr<const ParsedStatement> returnBody;
ParseAssign(returnBody, currentToken);
EXPECT_TOKEN(currentToken, SemicolonSymbol);
out = new ParsedReturnStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), returnBody.TakeOwnership());
return true;
}
bool Parser::ParseExprStat(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
if (!ParseAssign(out, currentToken)) {
return false;
}
EXPECT_TOKEN(currentToken, SemicolonSymbol);
return true;
}
bool Parser::ParseVarAccess(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
std::vector<Identifier> scope;
auto start = currentToken->GetSpan().GetStart();
if (ParseScope(scope, currentToken)) {
out = new ParsedVarAccessStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), scope);
return true;
}
Identifier identifier;
if (ParseIdentifier(identifier, currentToken)) {
scope.clear();
scope.push_back(identifier);
out = new ParsedVarAccessStatement(currentToken->GetSpan(), scope);
PROGRESS_TOKEN(currentToken);
return true;
}
return false;
}
bool Parser::ParseContinue(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::ContinueKeyword) {
return false;
}
auto start = currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(currentToken);
EXPECT_TOKEN(currentToken, SemicolonSymbol);
out = new ParsedContinueStatement(TextSpan(start, currentToken->GetSpan().GetEnd()));
return true;
}
bool Parser::ParseBreak(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::BreakKeyword) {
return false;
}
auto start = currentToken->GetSpan().GetStart();
PROGRESS_TOKEN(currentToken);
EXPECT_TOKEN(currentToken, SemicolonSymbol);
out = new ParsedBreakStatement(TextSpan(start, currentToken->GetSpan().GetEnd()));
return true;
}
bool Parser::ParseForStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken) {
if (currentToken->GetKind() != LexTokenKind::ForKeyword) {
return false;
}
const auto* current = currentToken;
PROGRESS_TOKEN(current);
EXPECT_TOKEN(current, OpenParenthesisSymbol);
ScopedPtr<const ParsedStatement> init;
if (!ParseVar(init, current) && !ParseExprStat(init, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
ScopedPtr<const ParsedStatement> condition;
if (!ParseExprStat(condition, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
std::vector<const ParsedStatement*> increment;
while (true) {
ScopedPtr<const ParsedStatement> element;
if (ParseAssign(element, current)) {
increment.push_back(element.TakeOwnership());
}
if (current->GetKind() != LexTokenKind::CommaSymbol) {
break;
}
}
EXPECT_TOKEN(current, CloseParenthesisSymbol);
ScopedPtr<const ParsedStatement> statementBlock;
if (!ParseStatement(statementBlock, current)) {
LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan());
return false;
}
out = new ParsedForStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()),
init.TakeOwnership(), condition.TakeOwnership(), increment,
statementBlock.TakeOwnership());
currentToken = current;
return true;
}
}