2020-10-05 15:45:00 +00:00
|
|
|
#include "Parser.hpp"
|
2020-10-07 20:11:18 +00:00
|
|
|
#include <iostream>
|
2020-10-08 17:53:02 +00:00
|
|
|
#include "../CoreData/PrimitiveTypes.hpp"
|
2021-01-05 23:06:39 +00:00
|
|
|
#include "../Diagnostics/DiagnosticTypeEN_US.hpp"
|
2020-10-07 20:11:18 +00:00
|
|
|
|
|
|
|
#define PROGRESS_TOKEN(token) \
|
2020-10-08 17:53:02 +00:00
|
|
|
token = (token)->GetNext().get(); \
|
2021-01-09 12:43:29 +00:00
|
|
|
while ((token)->GetKind() == LexTokenKind::Whitespace || (token)->GetKind() == LexTokenKind::Comment) { \
|
2020-10-08 17:53:02 +00:00
|
|
|
(token) = (token)->GetNext().get(); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EXPECT_TOKEN(token, kind) \
|
2021-01-01 22:41:37 +00:00
|
|
|
if ((token)->GetKind() != LexTokenKind::kind) { \
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(kind, token); \
|
2021-01-05 12:20:34 +00:00
|
|
|
if ((token)->GetNext() != nullptr && (token)->GetNext()->GetNext() != nullptr && \
|
|
|
|
(token)->GetNext()->GetKind() == LexTokenKind::kind) { \
|
|
|
|
(token) = (token)->GetNext()->GetNext().get(); \
|
|
|
|
} \
|
2020-11-01 17:43:35 +00:00
|
|
|
} else { \
|
|
|
|
PROGRESS_TOKEN(token); \
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2020-10-05 15:45:00 +00:00
|
|
|
|
2021-01-05 23:06:39 +00:00
|
|
|
#define logError(type, span, formats) log(DiagnosticLevel::Error, type, span, formats)
|
2021-01-06 12:32:06 +00:00
|
|
|
#define logUnexpectedToken(expected, found) \
|
|
|
|
log(DiagnosticLevel::Error, DiagnosticType::UnexpectedToken, (found)->GetSpan(), \
|
|
|
|
{LexTokenKindHelper::ToString(LexTokenKind::expected), (found)->ToString()});
|
|
|
|
#define logUnexpectedTokenWithAnyOf(found, ...) \
|
|
|
|
std::vector<LexTokenKind> vars = {__VA_ARGS__}; \
|
|
|
|
auto expectedTokens = std::vector<std::string>(vars.size() + 1); \
|
|
|
|
for (size_t i = 0; i < vars.size(); i++) { \
|
|
|
|
expectedTokens[i] = LexTokenKindHelper::ToString(vars[i]); \
|
|
|
|
} \
|
|
|
|
expectedTokens[expectedTokens.size() - 1] = (found)->ToString(); \
|
|
|
|
log(DiagnosticLevel::Error, DiagnosticType::UnexpectedToken, (found)->GetSpan(), expectedTokens);
|
|
|
|
#define logUnexpectedTokenWithoutExpected(found) \
|
|
|
|
log(DiagnosticLevel::Error, DiagnosticType::UnexpectedToken, (found)->GetSpan(), {(found)->ToString()});
|
2021-01-01 22:31:30 +00:00
|
|
|
|
2020-10-05 15:45:00 +00:00
|
|
|
namespace MalachScript::Parser {
|
2021-01-01 22:31:30 +00:00
|
|
|
using namespace Diagnostics;
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, Logger* diagnostics) {
|
|
|
|
const log_func& log = [diagnostics](DiagnosticLevel level, DiagnosticType type, const ScriptTextSpan& span,
|
|
|
|
const std::vector<std::string>& formats) {
|
|
|
|
diagnostics->Log(level, type, span, formats);
|
2021-01-01 22:17:34 +00:00
|
|
|
};
|
2020-10-09 09:54:43 +00:00
|
|
|
|
2021-01-05 18:21:06 +00:00
|
|
|
ScopedPtr<const ParsedStatement> s = nullptr;
|
|
|
|
ParseScript(s, firstToken, log);
|
|
|
|
return dynamic_cast<const ParsedScriptStatement*>(s.TakeOwnership());
|
2021-01-01 22:17:34 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 18:21:06 +00:00
|
|
|
bool Parser::ParseScript(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
|
|
|
const log_func& log) {
|
2020-10-07 20:11:18 +00:00
|
|
|
std::vector<const ParsedStatement*> statements;
|
2021-01-01 22:41:37 +00:00
|
|
|
const size_t reservedScriptSize = 32;
|
|
|
|
statements.reserve(reservedScriptSize);
|
2021-01-05 18:21:06 +00:00
|
|
|
size_t currentAmount = 0;
|
|
|
|
const auto* current = currentToken;
|
2020-10-05 15:45:00 +00:00
|
|
|
while (true) {
|
2021-01-09 12:43:29 +00:00
|
|
|
while (current->GetKind() == LexTokenKind::Whitespace || current->GetKind() == LexTokenKind::Comment) {
|
2021-01-05 18:21:06 +00:00
|
|
|
current = current->GetNext().get();
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2021-01-05 18:21:06 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::EndOfFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (current->GetKind() == LexTokenKind::SemicolonSymbol) {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Deal with namespace
|
|
|
|
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
2020-10-05 15:45:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> statement;
|
2021-01-01 22:44:58 +00:00
|
|
|
// TODO: Sort by performance
|
2021-01-05 18:21:06 +00:00
|
|
|
auto result = ParseTypeDef(statement, current, log) || ParseClass(statement, current, log) ||
|
|
|
|
ParseFunc(statement, current, log) || ParseNamespace(statement, current, log);
|
2020-10-09 09:54:43 +00:00
|
|
|
if (!result) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-05 18:21:06 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-09 09:54:43 +00:00
|
|
|
continue;
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
statements.push_back(statement.TakeOwnership());
|
2021-01-05 18:21:06 +00:00
|
|
|
currentAmount++;
|
2020-10-05 15:45:00 +00:00
|
|
|
}
|
2021-01-05 18:21:06 +00:00
|
|
|
statements.resize(currentAmount);
|
2020-10-05 15:45:00 +00:00
|
|
|
auto end = 0;
|
2021-01-05 18:21:06 +00:00
|
|
|
if (currentAmount > 0) {
|
2020-10-05 15:45:00 +00:00
|
|
|
end = statements.back()->GetSpan().GetEnd();
|
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedScriptStatement(ScriptTextSpan(0, end, currentToken->GetSpan().GetScriptName()), statements);
|
2021-01-05 18:21:06 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
2020-10-05 15:45:00 +00:00
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseClass(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
2020-10-07 20:11:18 +00:00
|
|
|
auto start = current->GetSpan().GetStart();
|
|
|
|
bool lookingForClass = true;
|
2021-01-01 22:41:37 +00:00
|
|
|
ClassAttr classAttr = ClassAttr::None;
|
2020-10-07 20:11:18 +00:00
|
|
|
while (lookingForClass) {
|
|
|
|
switch (current->GetKind()) {
|
2021-01-01 22:41:37 +00:00
|
|
|
case LexTokenKind::SharedKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Shared); break;
|
|
|
|
case LexTokenKind::AbstractKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Abstract); break;
|
|
|
|
case LexTokenKind::FinalKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Final); break;
|
|
|
|
case LexTokenKind::ExternalKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::External); break;
|
2020-10-07 20:11:18 +00:00
|
|
|
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.
|
2020-10-08 17:53:02 +00:00
|
|
|
Identifier identifier;
|
2020-10-10 12:29:37 +00:00
|
|
|
if (!ParseIdentifier(identifier, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2021-01-02 16:41:53 +00:00
|
|
|
return false;
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-10-07 20:11:18 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-08 17:53:02 +00:00
|
|
|
std::vector<Identifier> inherits;
|
2020-10-07 20:11:18 +00:00
|
|
|
std::vector<const ParsedStatement*> body;
|
|
|
|
|
|
|
|
switch (current->GetKind()) {
|
|
|
|
case LexTokenKind::SemicolonSymbol: {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LexTokenKind::ColonSymbol: {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-08 17:53:02 +00:00
|
|
|
Identifier id;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (!ParseIdentifier(id, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2021-01-02 16:41:53 +00:00
|
|
|
return false;
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-10-07 20:11:18 +00:00
|
|
|
inherits.push_back(id);
|
|
|
|
while (current->GetKind() == LexTokenKind::CommaSymbol) {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
if (!ParseIdentifier(id, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2021-01-02 16:41:53 +00:00
|
|
|
return false;
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-10-07 20:11:18 +00:00
|
|
|
inherits.push_back(id);
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
2020-10-10 18:02:47 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(OpenCurlyParenthesisSymbol, current);
|
2021-01-02 16:41:53 +00:00
|
|
|
return false;
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2020-11-01 12:40:44 +00:00
|
|
|
[[fallthrough]];
|
2020-10-07 20:11:18 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> statement = nullptr;
|
2020-10-31 18:23:15 +00:00
|
|
|
// TODO: Sort by complexity
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseVirtProp(statement, current, log) && !ParseFunc(statement, current, log) &&
|
2021-01-08 17:18:24 +00:00
|
|
|
!ParseVar(statement, current, log) && !ParseFuncDef(statement, current, log) &&
|
|
|
|
!ParseClass(statement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-10-31 18:23:15 +00:00
|
|
|
break;
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
body.push_back(statement.TakeOwnership());
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-01-06 12:32:06 +00:00
|
|
|
default:
|
|
|
|
logUnexpectedTokenWithAnyOf(current, LexTokenKind::SemicolonSymbol, LexTokenKind::ColonSymbol,
|
|
|
|
LexTokenKind::OpenCurlyParenthesisSymbol);
|
2020-10-07 20:11:18 +00:00
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedClassStatement(
|
|
|
|
ScriptTextSpan(start, current->GetSpan().GetEnd(), current->GetSpan().GetScriptName()), classAttr,
|
|
|
|
identifier, inherits, body);
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
2020-10-07 20:11:18 +00:00
|
|
|
return true;
|
2020-10-05 15:45:00 +00:00
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseTypeDef(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::TypedefKeyword) {
|
2020-10-08 17:53:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
auto start = current->GetSpan().GetStart();
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-08 17:53:02 +00:00
|
|
|
Identifier defineFrom;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParsePrimType(defineFrom, current, log) && !ParseIdentifier(defineFrom, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-10-08 17:53:02 +00:00
|
|
|
}
|
|
|
|
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-08 17:53:02 +00:00
|
|
|
Identifier defineTo;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (!ParseIdentifier(defineTo, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
EXPECT_TOKEN(current, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedTypeDefStatement(
|
|
|
|
ScriptTextSpan(start, current->GetSpan().GetEnd(), current->GetSpan().GetScriptName()), defineFrom,
|
|
|
|
defineTo);
|
2020-10-08 17:53:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseNamespace(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::NamespaceKeyword) {
|
2020-10-09 09:54:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
auto start = current->GetSpan().GetStart();
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-09 09:54:43 +00:00
|
|
|
Identifier identifier;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (!ParseIdentifier(identifier, current)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2021-01-05 18:21:06 +00:00
|
|
|
} else {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, OpenCurlyParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> script = nullptr;
|
|
|
|
if (!ParseScript(script, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
auto end = current->GetSpan().GetEnd();
|
2021-01-05 18:21:06 +00:00
|
|
|
EXPECT_TOKEN(current, CloseCurlyParenthesisSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedNamespaceStatement(ScriptTextSpan(start, end, current->GetSpan().GetScriptName()), identifier,
|
2021-01-05 18:21:06 +00:00
|
|
|
(const ParsedScriptStatement*)script.TakeOwnership());
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
2020-10-09 09:54:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseFunc(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
auto start = current->GetSpan().GetStart();
|
2020-10-10 12:29:37 +00:00
|
|
|
bool isShared = false;
|
|
|
|
bool isExternal = false;
|
|
|
|
bool modifiers = true;
|
|
|
|
while (modifiers) {
|
2020-11-01 17:43:35 +00:00
|
|
|
switch (current->GetKind()) {
|
2020-10-10 12:29:37 +00:00
|
|
|
case LexTokenKind::SharedKeyword:
|
|
|
|
isShared = true;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
continue;
|
|
|
|
case LexTokenKind::ExternalKeyword:
|
|
|
|
isExternal = true;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
continue;
|
|
|
|
default: modifiers = false; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AccessModifier accessModifier = AccessModifier::Public;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
|
2020-10-10 12:29:37 +00:00
|
|
|
accessModifier = AccessModifier::Private;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
|
2020-10-10 12:29:37 +00:00
|
|
|
accessModifier = AccessModifier::Protected;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2021-01-08 15:14:02 +00:00
|
|
|
ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
|
2020-10-10 12:29:37 +00:00
|
|
|
bool returnsReference = false;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::TildeSymbol) {
|
2020-10-10 12:29:37 +00:00
|
|
|
// TODO: Handle destructor
|
|
|
|
throw std::logic_error("not implemented");
|
2021-01-01 22:31:30 +00:00
|
|
|
} else if (ParseType(typeStatement, current, log)) {
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::AmpersandSymbol) {
|
2020-10-10 12:29:37 +00:00
|
|
|
returnsReference = true;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Identifier identifier;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (!ParseIdentifier(identifier, current)) {
|
2020-10-10 12:29:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> paramList = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseParamList(paramList, current, log)) {
|
2020-10-10 12:29:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool isConst = false;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
2020-10-10 12:29:37 +00:00
|
|
|
isConst = true;
|
2020-11-01 17:43:35 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2020-10-10 18:02:47 +00:00
|
|
|
FuncAttr funcAttr = FuncAttr::None;
|
2021-01-01 22:31:30 +00:00
|
|
|
ParseFuncAttr(funcAttr, current, log);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> statblock = nullptr;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatBlock(statblock, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-02 16:41:53 +00:00
|
|
|
return false;
|
2020-11-08 14:52:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedFuncStatement(
|
|
|
|
ScriptTextSpan(start, current->GetSpan().GetEnd(), current->GetSpan().GetScriptName()), isShared,
|
|
|
|
isExternal, accessModifier, typeStatement.TakeOwnership(), returnsReference, identifier,
|
|
|
|
paramList.TakeOwnership(), isConst, funcAttr, statblock.TakeOwnership());
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-08 15:14:02 +00:00
|
|
|
bool Parser::ParseType(ScopedPtr<const ParsedTypeStatement>& out, const LexToken*& currentToken,
|
|
|
|
const log_func& log) {
|
2021-01-06 12:32:06 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
auto start = current->GetSpan().GetStart();
|
2020-10-10 12:29:37 +00:00
|
|
|
bool isConst = false;
|
|
|
|
bool isArray = false;
|
|
|
|
bool isHandle = false;
|
2021-01-06 12:32:06 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
2020-10-10 12:29:37 +00:00
|
|
|
isConst = true;
|
2021-01-06 12:32:06 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
|
|
|
ScopedIdentifier scopedIdentifier;
|
2021-01-06 12:32:06 +00:00
|
|
|
ParseScope(scopedIdentifier.GetScope(), current, log);
|
|
|
|
if (!ParseDataType(scopedIdentifier.GetIdentifier(), current, log)) {
|
2020-10-10 12:29:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// TODO: Generics.
|
2021-01-06 12:32:06 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
if (current->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) {
|
|
|
|
logUnexpectedToken(CloseCurlyParenthesisSymbol, current);
|
2020-10-10 12:29:37 +00:00
|
|
|
} else {
|
2021-01-06 12:32:06 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
isArray = true;
|
|
|
|
}
|
2021-01-06 12:32:06 +00:00
|
|
|
} else if (current->GetKind() == LexTokenKind::AtSymbol) {
|
2020-10-10 12:29:37 +00:00
|
|
|
isHandle = true;
|
2021-01-06 12:32:06 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
2020-10-10 12:29:37 +00:00
|
|
|
isConst = true;
|
2021-01-06 12:32:06 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-06 12:32:06 +00:00
|
|
|
auto end = current->GetSpan().GetEnd();
|
|
|
|
currentToken = current;
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedTypeStatement(ScriptTextSpan(start, end, current->GetSpan().GetScriptName()), isConst, isArray,
|
|
|
|
isHandle, scopedIdentifier);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseScope(std::vector<Identifier>& scope, const LexToken*& currentToken, const log_func& log) {
|
2020-11-01 12:20:00 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() == LexTokenKind::ColonColonSymbol) {
|
2020-10-10 12:29:37 +00:00
|
|
|
scope.emplace_back();
|
2020-11-01 12:20:00 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Identifier identifier;
|
2020-11-01 12:20:00 +00:00
|
|
|
if (ParseIdentifier(identifier, current)) {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-10 12:29:37 +00:00
|
|
|
scope.push_back(identifier);
|
2020-11-01 12:50:35 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::ColonColonSymbol) {
|
2020-11-01 12:20:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-10-10 12:29:37 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-08 14:41:18 +00:00
|
|
|
while (current->GetKind() == LexTokenKind::ColonColonSymbol) {
|
2020-11-01 12:20:00 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
const auto* n = current;
|
2020-10-10 12:29:37 +00:00
|
|
|
if (ParseIdentifier(identifier, n)) {
|
|
|
|
PROGRESS_TOKEN(n);
|
|
|
|
if (n->GetKind() == LexTokenKind::ColonColonSymbol) {
|
2020-11-01 12:20:00 +00:00
|
|
|
current = n;
|
2020-10-10 12:29:37 +00:00
|
|
|
scope.push_back(identifier);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, current);
|
2020-10-10 12:29:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: Handle generics in script class name.
|
2020-11-01 12:20:00 +00:00
|
|
|
currentToken = current;
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) {
|
2020-10-31 18:23:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2020-11-01 12:25:38 +00:00
|
|
|
currentToken = current;
|
2020-10-31 18:23:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseParamList(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-10-10 12:29:37 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto start = currentToken->GetSpan().GetStart();
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
2020-10-10 18:02:47 +00:00
|
|
|
std::vector<const ParsedParamListStatement::ParsedParameter*> parameters;
|
|
|
|
|
2020-10-10 12:29:37 +00:00
|
|
|
if (currentToken->GetKind() == LexTokenKind::VoidKeyword) {
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
2021-01-05 12:20:34 +00:00
|
|
|
EXPECT_TOKEN(currentToken, CloseParenthesisSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedParamListStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()),
|
|
|
|
parameters);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
2020-10-31 18:23:15 +00:00
|
|
|
}
|
|
|
|
if (currentToken->GetKind() == LexTokenKind::CloseParenthesisSymbol) {
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedParamListStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()),
|
|
|
|
parameters);
|
2020-10-10 12:29:37 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
while (true) {
|
2021-01-08 15:14:02 +00:00
|
|
|
ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
|
2020-10-10 18:02:47 +00:00
|
|
|
TypeMod typeMod = TypeMod::None;
|
|
|
|
Identifier identifier;
|
2020-11-01 17:43:35 +00:00
|
|
|
const ParsedStatement* defaultExpression = nullptr;
|
2020-10-10 18:02:47 +00:00
|
|
|
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseType(typeStatement, currentToken, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(currentToken);
|
2020-10-10 12:29:37 +00:00
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
ParseTypeMod(typeMod, currentToken, log);
|
2021-01-02 16:41:53 +00:00
|
|
|
if (!ParseIdentifier(identifier, currentToken)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(Identifier, currentToken);
|
2021-01-05 12:20:34 +00:00
|
|
|
} else {
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
2021-01-02 16:41:53 +00:00
|
|
|
}
|
2020-10-10 18:02:47 +00:00
|
|
|
// TODO: Default expression
|
|
|
|
|
|
|
|
parameters.push_back(new ParsedParamListStatement::ParsedParameter(
|
2020-12-06 11:35:08 +00:00
|
|
|
dynamic_cast<const ParsedTypeStatement*>(typeStatement.TakeOwnership()), typeMod, identifier,
|
|
|
|
defaultExpression));
|
2020-10-10 18:02:47 +00:00
|
|
|
|
2020-10-10 12:29:37 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::CommaSymbol) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
}
|
2021-01-05 12:20:34 +00:00
|
|
|
EXPECT_TOKEN(currentToken, CloseParenthesisSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedParamListStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()),
|
|
|
|
parameters);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) {
|
2020-10-10 12:29:37 +00:00
|
|
|
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:
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParsePrimType(out, currentToken, log)) {
|
2020-10-10 12:29:37 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
bool Parser::ParseVirtProp(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-10-31 18:23:15 +00:00
|
|
|
const auto* current = currentToken;
|
2020-11-01 17:43:35 +00:00
|
|
|
AccessModifier access = AccessModifier::Public;
|
2020-10-31 18:23:15 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::PrivateKeyword) {
|
|
|
|
access = AccessModifier::Private;
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
} else if (current->GetKind() == LexTokenKind::ProtectedKeyword) {
|
|
|
|
access = AccessModifier::Protected;
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
2021-01-08 15:14:02 +00:00
|
|
|
ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseType(typeStatement, current, log)) {
|
2020-10-31 18:23:15 +00:00
|
|
|
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;
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> getStatement = nullptr;
|
2020-10-31 18:23:15 +00:00
|
|
|
bool hasSet = false;
|
|
|
|
bool setConst = false;
|
|
|
|
FuncAttr setAttr = FuncAttr::None;
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> setStatement = nullptr;
|
2020-10-31 18:23:15 +00:00
|
|
|
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);
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
ParseFuncAttr(getAttr, current, log);
|
2020-10-31 18:23:15 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatBlock(getStatement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
2020-11-08 14:41:18 +00:00
|
|
|
} else {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-31 18:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasGet) {
|
2021-01-09 12:20:56 +00:00
|
|
|
logError(DiagnosticType::DoubleProperty,
|
|
|
|
ScriptTextSpan(start, current->GetSpan().GetEnd(), current->GetSpan().GetScriptName()),
|
|
|
|
{});
|
2020-10-31 18:23:15 +00:00
|
|
|
}
|
|
|
|
hasGet = true;
|
|
|
|
} else if (current->GetKind() == LexTokenKind::SetKeyword) {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
if (current->GetKind() == LexTokenKind::ConstKeyword) {
|
|
|
|
setConst = true;
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
ParseFuncAttr(setAttr, current, log);
|
2020-10-31 18:23:15 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::SemicolonSymbol) {
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatBlock(setStatement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
2020-11-08 14:41:18 +00:00
|
|
|
} else {
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-10-31 18:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasSet) {
|
2021-01-09 12:20:56 +00:00
|
|
|
logError(DiagnosticType::DoubleProperty,
|
|
|
|
ScriptTextSpan(start, current->GetSpan().GetEnd(), current->GetSpan().GetScriptName()),
|
|
|
|
{});
|
2020-10-31 18:23:15 +00:00
|
|
|
}
|
|
|
|
hasSet = true;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-11-01 12:50:35 +00:00
|
|
|
if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(CloseCurlyParenthesisSymbol, current);
|
2020-11-01 12:50:35 +00:00
|
|
|
} else {
|
2020-10-31 18:23:15 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedVirtPropStatement(
|
|
|
|
ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
access, typeStatement.TakeOwnership(), ref, identifier, hasGet, getConst, getAttr,
|
|
|
|
getStatement.TakeOwnership(), hasSet, setConst, setAttr, setStatement.TakeOwnership());
|
2020-10-31 18:23:15 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseIfStatement([[maybe_unused]] ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::IfKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> condition = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseAssign(condition, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> body = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatement(body, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> elseStatement = nullptr;
|
2020-11-01 17:43:35 +00:00
|
|
|
if (current->GetKind() == LexTokenKind::ElseKeyword) {
|
|
|
|
PROGRESS_TOKEN(current);
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatement(elseStatement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedIfStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2020-12-06 11:35:08 +00:00
|
|
|
condition.TakeOwnership(), body.TakeOwnership(), elseStatement.TakeOwnership());
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2021-01-01 22:17:34 +00:00
|
|
|
// TODO: All the other statements. (switch | try );
|
2021-01-01 12:17:53 +00:00
|
|
|
switch (currentToken->GetKind()) {
|
2021-01-01 22:31:30 +00:00
|
|
|
case LexTokenKind::IfKeyword: return ParseIfStatement(out, currentToken, log);
|
|
|
|
case LexTokenKind::ForKeyword: return ParseForStatement(out, currentToken, log);
|
|
|
|
case LexTokenKind::WhileKeyword: return ParseWhileStatement(out, currentToken, log);
|
|
|
|
case LexTokenKind::ReturnKeyword: return ParseReturn(out, currentToken, log);
|
|
|
|
case LexTokenKind::BreakKeyword: return ParseBreak(out, currentToken, log);
|
|
|
|
case LexTokenKind::ContinueKeyword: return ParseContinue(out, currentToken, log);
|
|
|
|
case LexTokenKind::DoKeyword: return ParseDoWhileStatement(out, currentToken, log);
|
2021-01-02 10:54:16 +00:00
|
|
|
case LexTokenKind::TryKeyword: return ParseTryStatement(out, currentToken, log);
|
2021-01-02 11:38:50 +00:00
|
|
|
case LexTokenKind::SwitchKeyword: return ParseSwitchStatement(out, currentToken, log);
|
2021-01-01 22:31:30 +00:00
|
|
|
default: return ParseStatBlock(out, currentToken, log) || ParseExprStat(out, currentToken, log);
|
2021-01-01 12:17:53 +00:00
|
|
|
}
|
|
|
|
return false;
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseVar([[maybe_unused]] ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
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);
|
|
|
|
}
|
2021-01-08 15:14:02 +00:00
|
|
|
ScopedPtr<const ParsedTypeStatement> typeStatement = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseType(typeStatement, current, log)) {
|
2020-11-01 17:43:35 +00:00
|
|
|
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)
|
2020-11-08 14:41:18 +00:00
|
|
|
EXPECT_TOKEN(current, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedVarStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
access, typeStatement.TakeOwnership(), identifier);
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseStatBlock(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-11-08 14:41:18 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2020-11-01 17:43:35 +00:00
|
|
|
std::vector<const ParsedStatement*> statements;
|
|
|
|
while (true) {
|
|
|
|
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
|
|
|
break;
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> stat = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParseVar(stat, current, log) || ParseStatement(stat, current, log)) {
|
2020-12-06 11:35:08 +00:00
|
|
|
statements.push_back(stat.TakeOwnership());
|
2020-11-01 17:43:35 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
} else {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(CloseCurlyParenthesisSymbol, current);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out =
|
|
|
|
new ParsedStatBlockStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
statements);
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-06 11:35:08 +00:00
|
|
|
bool Parser::ParseFuncDef([[maybe_unused]] ScopedPtr<const ParsedStatement>& out,
|
2021-01-01 22:31:30 +00:00
|
|
|
[[maybe_unused]] const LexToken*& currentToken, [[maybe_unused]] const log_func& log) {
|
2021-01-01 22:17:34 +00:00
|
|
|
// TODO
|
2020-11-01 17:43:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParsePrimType(Identifier& out, const LexToken*& token, [[maybe_unused]] const log_func& log) {
|
2020-10-10 12:29:37 +00:00
|
|
|
switch (token->GetKind()) {
|
2020-10-08 17:53:02 +00:00
|
|
|
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;
|
2020-10-10 14:04:59 +00:00
|
|
|
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;
|
2020-10-08 17:53:02 +00:00
|
|
|
default: return false;
|
|
|
|
}
|
|
|
|
}
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) {
|
2020-10-10 14:20:56 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::AmpersandSymbol) {
|
2020-10-10 12:29:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-10-10 14:20:56 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
switch (currentToken->GetKind()) {
|
2020-10-10 12:29:37 +00:00
|
|
|
case LexTokenKind::InKeyword:
|
|
|
|
typeMod = TypeMod::RefIn;
|
2020-10-10 14:20:56 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
case LexTokenKind::OutKeyword:
|
|
|
|
typeMod = TypeMod::RefOut;
|
2020-10-10 14:20:56 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
case LexTokenKind::InoutKeyword:
|
|
|
|
typeMod = TypeMod::RefInOut;
|
2020-10-10 14:20:56 +00:00
|
|
|
PROGRESS_TOKEN(currentToken);
|
2020-10-10 12:29:37 +00:00
|
|
|
return true;
|
|
|
|
default: typeMod = TypeMod::RefInOut; return true;
|
|
|
|
}
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseAssign(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> leftHand = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseTernary(leftHand, current, log)) {
|
2020-11-01 17:43:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
AssignmentOperator op;
|
|
|
|
if (!ParseAssignOp(op, current)) {
|
2020-12-06 11:35:08 +00:00
|
|
|
out = leftHand.TakeOwnership();
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> rightHand = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseAssign(rightHand, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
out = leftHand.TakeOwnership();
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedBinaryStatement<AssignmentOperator>(ScriptTextSpan(currentToken->GetSpan().GetStart(),
|
|
|
|
current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
leftHand.TakeOwnership(), op, rightHand.TakeOwnership());
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseTernary(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
// TODO: implement ternary.
|
2021-01-01 22:31:30 +00:00
|
|
|
return ParseExpr(out, currentToken, log);
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|
|
|
|
|
2020-12-06 11:35:08 +00:00
|
|
|
#define EXPR_PARSER(operator, name, func) \
|
2021-01-01 22:41:37 +00:00
|
|
|
operator(name); \
|
2020-12-06 11:35:08 +00:00
|
|
|
if (func(name, current)) { \
|
|
|
|
PROGRESS_TOKEN(current); \
|
|
|
|
ScopedPtr<const ParsedStatement> rightHand = nullptr; \
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseExprTerm(rightHand, current, log)) { \
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current); \
|
2020-12-06 11:35:08 +00:00
|
|
|
out = leftHand.TakeOwnership(); \
|
|
|
|
currentToken = current; \
|
|
|
|
return true; \
|
|
|
|
} \
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedBinaryStatement < operator>(ScriptTextSpan(currentToken->GetSpan().GetStart(), \
|
|
|
|
current->GetSpan().GetEnd(), \
|
|
|
|
current->GetSpan().GetScriptName()), \
|
2020-12-06 11:35:08 +00:00
|
|
|
leftHand.TakeOwnership(), name, rightHand.TakeOwnership()); \
|
|
|
|
currentToken = current; \
|
|
|
|
return true; \
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:31:30 +00:00
|
|
|
bool Parser::ParseExpr(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken, const log_func& log) {
|
2020-11-01 17:43:35 +00:00
|
|
|
const auto* current = currentToken;
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> leftHand = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseExprTerm(leftHand, current, log)) {
|
2020-11-01 17:43:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
EXPR_PARSER(MathOperator, mathOp, ParseMathOp);
|
|
|
|
EXPR_PARSER(ComparisonOperator, compOp, ParseCompOp);
|
|
|
|
EXPR_PARSER(LogicOperator, logicOp, ParseLogicOp);
|
|
|
|
EXPR_PARSER(BitOperator, bitOp, ParseBitOp);
|
|
|
|
|
|
|
|
out = leftHand.TakeOwnership();
|
2020-11-01 17:43:35 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseExprTerm(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-08 14:41:18 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
// TODO ([type '='] initlist)
|
|
|
|
|
|
|
|
PreOperator preOperator;
|
2021-01-01 22:31:30 +00:00
|
|
|
bool hasPreOp = ParsePreOp(preOperator, currentToken, log);
|
2020-11-08 14:41:18 +00:00
|
|
|
if (hasPreOp) {
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> operand = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseExprValue(operand, current, log)) {
|
2020-11-08 14:41:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: remainder of
|
|
|
|
if (current->GetKind() == LexTokenKind::PlusPlusSymbol) {
|
2021-01-09 12:20:56 +00:00
|
|
|
operand =
|
|
|
|
new ParsedIncrementStatement(ScriptTextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
operand.TakeOwnership());
|
2020-11-08 14:41:18 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
} else if (current->GetKind() == LexTokenKind::MinusMinusSymbol) {
|
2021-01-09 12:20:56 +00:00
|
|
|
operand =
|
|
|
|
new ParsedDecrementStatement(ScriptTextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
|
|
|
operand.TakeOwnership());
|
2020-11-08 14:41:18 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasPreOp) {
|
|
|
|
// TODO: integrate pre operator
|
|
|
|
}
|
2020-12-06 11:35:08 +00:00
|
|
|
out = operand.TakeOwnership();
|
2020-11-08 14:41:18 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseExprValue(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-08 14:41:18 +00:00
|
|
|
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
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParseVarAccess(out, current, log)) {
|
2020-11-08 14:41:18 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// TODO: cast
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParseLiteral(out, current, log)) {
|
2020-11-08 14:41:18 +00:00
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (current->GetKind() == LexTokenKind::OpenParenthesisSymbol) {
|
|
|
|
PROGRESS_TOKEN(current);
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseAssign(out, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-11-08 14:41:18 +00:00
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
2021-01-05 12:20:34 +00:00
|
|
|
currentToken = current;
|
2020-11-08 14:41:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// TODO: lambda
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseLiteral(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
[[maybe_unused]] const log_func& log) {
|
2020-11-08 14:41:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseReturn(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-08 14:41:18 +00:00
|
|
|
auto start = currentToken->GetSpan().GetStart();
|
|
|
|
if (currentToken->GetKind() != LexTokenKind::ReturnKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
2020-12-06 11:35:08 +00:00
|
|
|
ScopedPtr<const ParsedStatement> returnBody;
|
2021-01-01 22:31:30 +00:00
|
|
|
ParseAssign(returnBody, currentToken, log);
|
2020-11-08 14:41:18 +00:00
|
|
|
EXPECT_TOKEN(currentToken, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedReturnStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()),
|
|
|
|
returnBody.TakeOwnership());
|
2020-11-08 14:41:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseExprStat(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
|
|
|
if (!ParseAssign(out, currentToken, log)) {
|
2020-11-08 14:41:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(currentToken, SemicolonSymbol);
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseVarAccess(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-11-08 14:41:18 +00:00
|
|
|
std::vector<Identifier> scope;
|
|
|
|
auto start = currentToken->GetSpan().GetStart();
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParseScope(scope, currentToken, log)) {
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedVarAccessStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()),
|
|
|
|
scope);
|
2020-11-08 14:41:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseContinue(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
[[maybe_unused]] const log_func& log) {
|
2020-12-06 11:35:08 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::ContinueKeyword) {
|
2020-11-15 09:21:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto start = currentToken->GetSpan().GetStart();
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
EXPECT_TOKEN(currentToken, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedContinueStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()));
|
2020-11-15 09:21:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseBreak(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
[[maybe_unused]] const log_func& log) {
|
2020-12-06 11:35:08 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::BreakKeyword) {
|
2020-11-15 09:21:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto start = currentToken->GetSpan().GetStart();
|
|
|
|
PROGRESS_TOKEN(currentToken);
|
|
|
|
EXPECT_TOKEN(currentToken, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedBreakStatement(
|
|
|
|
ScriptTextSpan(start, currentToken->GetSpan().GetEnd(), currentToken->GetSpan().GetScriptName()));
|
2020-11-15 09:21:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseForStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2020-12-06 11:35:08 +00:00
|
|
|
if (currentToken->GetKind() != LexTokenKind::ForKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto* current = currentToken;
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> init;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseVar(init, current, log) && !ParseExprStat(init, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ScopedPtr<const ParsedStatement> condition;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseExprStat(condition, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::vector<const ParsedStatement*> increment;
|
|
|
|
while (true) {
|
|
|
|
ScopedPtr<const ParsedStatement> element;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (ParseAssign(element, current, log)) {
|
2020-12-06 11:35:08 +00:00
|
|
|
increment.push_back(element.TakeOwnership());
|
|
|
|
}
|
|
|
|
if (current->GetKind() != LexTokenKind::CommaSymbol) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> statementBlock;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatement(statementBlock, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2020-12-06 11:35:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedForStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2020-12-06 11:35:08 +00:00
|
|
|
init.TakeOwnership(), condition.TakeOwnership(), increment,
|
|
|
|
statementBlock.TakeOwnership());
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 12:14:29 +00:00
|
|
|
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseWhileStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2021-01-01 12:14:29 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::WhileKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> condition = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseAssign(condition, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-01 12:14:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> body = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatement(body, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-01 12:14:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedWhileStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2021-01-01 12:14:29 +00:00
|
|
|
condition.TakeOwnership(), body.TakeOwnership());
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 22:17:34 +00:00
|
|
|
bool Parser::ParseDoWhileStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
2021-01-01 22:31:30 +00:00
|
|
|
const log_func& log) {
|
2021-01-01 12:21:59 +00:00
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::DoKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-01-02 10:53:16 +00:00
|
|
|
PROGRESS_TOKEN(current);
|
2021-01-01 12:21:59 +00:00
|
|
|
ScopedPtr<const ParsedStatement> body = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseStatement(body, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-01 12:21:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, WhileKeyword);
|
|
|
|
EXPECT_TOKEN(current, OpenParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> condition = nullptr;
|
2021-01-01 22:31:30 +00:00
|
|
|
if (!ParseAssign(condition, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-01 12:21:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CloseParenthesisSymbol);
|
|
|
|
EXPECT_TOKEN(current, SemicolonSymbol);
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedDoWhileStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2021-01-01 12:21:59 +00:00
|
|
|
condition.TakeOwnership(), body.TakeOwnership());
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-02 10:53:16 +00:00
|
|
|
bool Parser::ParseTryStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
|
|
|
const Parser::log_func& log) {
|
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::TryKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
|
|
|
|
ScopedPtr<const ParsedStatement> tryStatement = nullptr;
|
|
|
|
if (!ParseStatBlock(tryStatement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-02 10:53:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, CatchKeyword);
|
|
|
|
ScopedPtr<const ParsedStatement> catchStatement = nullptr;
|
|
|
|
if (!ParseStatBlock(catchStatement, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-02 10:53:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedTryStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2021-01-02 10:53:16 +00:00
|
|
|
tryStatement.TakeOwnership(), catchStatement.TakeOwnership());
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-02 11:38:50 +00:00
|
|
|
bool Parser::ParseSwitchStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
|
|
|
const Parser::log_func& log) {
|
|
|
|
const auto* current = currentToken;
|
|
|
|
if (current->GetKind() != LexTokenKind::SwitchKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
EXPECT_TOKEN(currentToken, OpenParenthesisSymbol);
|
|
|
|
ScopedPtr<const ParsedStatement> expression = nullptr;
|
|
|
|
if (!ParseExpr(expression, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-02 11:38:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(currentToken, CloseParenthesisSymbol);
|
|
|
|
EXPECT_TOKEN(currentToken, OpenCurlyParenthesisSymbol);
|
|
|
|
std::vector<const ParsedStatement*> caseStatements;
|
|
|
|
while (true) {
|
|
|
|
if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (current->GetKind() == LexTokenKind::CaseKeyword ||
|
|
|
|
currentToken->GetKind() == LexTokenKind::DefaultKeyword) {
|
|
|
|
ScopedPtr<const ParsedStatement> stat = nullptr;
|
|
|
|
if (!ParseCaseStatement(stat, current, log)) {
|
|
|
|
for (const auto* s : caseStatements) {
|
|
|
|
delete s;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
caseStatements.push_back(stat.TakeOwnership());
|
|
|
|
} else {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedToken(CaseKeyword, current);
|
2021-01-02 11:38:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Consume }
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedSwitchStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2021-01-02 11:38:50 +00:00
|
|
|
expression.TakeOwnership(), caseStatements);
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Parser::ParseCaseStatement(ScopedPtr<const ParsedStatement>& out, const LexToken*& currentToken,
|
|
|
|
const Parser::log_func& log) {
|
|
|
|
const auto* current = currentToken;
|
|
|
|
|
|
|
|
if (current->GetKind() != LexTokenKind::CaseKeyword && current->GetKind() != LexTokenKind::DefaultKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool isDefault = current->GetKind() == LexTokenKind::DefaultKeyword;
|
|
|
|
PROGRESS_TOKEN(current);
|
|
|
|
|
|
|
|
ScopedPtr<const ParsedStatement> expression = nullptr;
|
|
|
|
if (!isDefault) {
|
|
|
|
if (!ParseExpr(expression, current, log)) {
|
2021-01-06 12:32:06 +00:00
|
|
|
logUnexpectedTokenWithoutExpected(current);
|
2021-01-02 11:38:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPECT_TOKEN(current, ColonSymbol);
|
|
|
|
|
|
|
|
std::vector<const ParsedStatement*> statements;
|
|
|
|
while (true) {
|
|
|
|
// Minor optimization, if we encounter a case/default keyword we know the upcoming statement is another case
|
|
|
|
// so not part of the current case. Similarly, if we find a close curly parenthesis we know we're at the end
|
|
|
|
// of the current switch statement, so we don't need to continue parsing.
|
|
|
|
if (current->GetKind() == LexTokenKind::CaseKeyword || current->GetKind() == LexTokenKind::DefaultKeyword ||
|
|
|
|
current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopedPtr<const ParsedStatement> stat = nullptr;
|
|
|
|
if (ParseStatement(stat, current, log)) {
|
|
|
|
statements.push_back(stat.TakeOwnership());
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 12:20:56 +00:00
|
|
|
out = new ParsedCaseStatement(ScriptTextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd(),
|
|
|
|
current->GetSpan().GetScriptName()),
|
2021-01-02 11:38:50 +00:00
|
|
|
expression.TakeOwnership(), statements);
|
|
|
|
currentToken = current;
|
|
|
|
return true;
|
|
|
|
}
|
2020-11-01 17:43:35 +00:00
|
|
|
}
|