#include "Parser.hpp" #include #include "../CoreData/PrimitiveTypes.hpp" #include "../Diagnostics/DiagnosticTypeEN_US.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) { \ logUnexpectedToken(kind, token); \ if ((token)->GetNext() != nullptr && (token)->GetNext()->GetNext() != nullptr && \ (token)->GetNext()->GetKind() == LexTokenKind::kind) { \ (token) = (token)->GetNext()->GetNext().get(); \ } \ } else { \ PROGRESS_TOKEN(token); \ } #define logError(type, span, formats) log(DiagnosticLevel::Error, type, span, formats) #define logUnexpectedToken(expected, found) \ log(DiagnosticLevel::Error, DiagnosticType::UnexpectedToken, (found)->GetSpan(), \ {LexTokenKindHelper::ToString(LexTokenKind::expected), (found)->ToString()}); #define logUnexpectedTokenWithAnyOf(found, ...) \ std::vector vars = {__VA_ARGS__}; \ auto expectedTokens = std::vector(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()}); namespace MalachScript::Parser { using namespace Diagnostics; const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, std::u8string_view scriptName, Logger* diagnostics) { const log_func& log = [diagnostics, scriptName](DiagnosticLevel level, DiagnosticType type, const TextSpan& span, const std::vector& formats) { diagnostics->Log(level, type, scriptName, span, formats); }; ScopedPtr s = nullptr; ParseScript(s, firstToken, log); return dynamic_cast(s.TakeOwnership()); } bool Parser::ParseScript(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { std::vector statements; const size_t reservedScriptSize = 32; statements.reserve(reservedScriptSize); size_t currentAmount = 0; const auto* current = currentToken; while (true) { while (current->GetKind() == LexTokenKind::Whitespace) { current = current->GetNext().get(); } if (current->GetKind() == LexTokenKind::EndOfFile) { break; } if (current->GetKind() == LexTokenKind::SemicolonSymbol) { PROGRESS_TOKEN(current); continue; } // Deal with namespace if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { break; } ScopedPtr statement; // TODO: Sort by performance auto result = ParseTypeDef(statement, current, log) || ParseClass(statement, current, log) || ParseFunc(statement, current, log) || ParseNamespace(statement, current, log); if (!result) { logUnexpectedTokenWithoutExpected(current); PROGRESS_TOKEN(current); continue; } statements.push_back(statement.TakeOwnership()); currentAmount++; } statements.resize(currentAmount); auto end = 0; if (currentAmount > 0) { end = statements.back()->GetSpan().GetEnd(); } out = new ParsedScriptStatement(TextSpan(0, end), statements); currentToken = current; return true; } bool Parser::ParseClass(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool lookingForClass = true; ClassAttr classAttr = ClassAttr::None; while (lookingForClass) { switch (current->GetKind()) { 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; 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)) { logUnexpectedToken(Identifier, current); return false; } PROGRESS_TOKEN(current); std::vector inherits; std::vector body; switch (current->GetKind()) { case LexTokenKind::SemicolonSymbol: { PROGRESS_TOKEN(current); break; } case LexTokenKind::ColonSymbol: { PROGRESS_TOKEN(current); Identifier id; if (!ParseIdentifier(id, current)) { logUnexpectedToken(Identifier, current); return false; } inherits.push_back(id); while (current->GetKind() == LexTokenKind::CommaSymbol) { PROGRESS_TOKEN(current); if (!ParseIdentifier(id, current)) { logUnexpectedToken(Identifier, current); return false; } inherits.push_back(id); PROGRESS_TOKEN(current); } if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { logUnexpectedToken(OpenCurlyParenthesisSymbol, current); return false; } [[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 statement = nullptr; // TODO: Sort by complexity if (!ParseVirtProp(statement, current, log) && !ParseFunc(statement, current, log) && !ParseVar(statement, current, log) && !ParseFuncDef(statement, current, log)) { logUnexpectedTokenWithoutExpected(current); break; } body.push_back(statement.TakeOwnership()); } break; } default: logUnexpectedTokenWithAnyOf(current, LexTokenKind::SemicolonSymbol, LexTokenKind::ColonSymbol, LexTokenKind::OpenCurlyParenthesisSymbol); } out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), classAttr, identifier, inherits, body); currentToken = current; return true; } bool Parser::ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { 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, log) && !ParseIdentifier(defineFrom, current)) { logUnexpectedTokenWithoutExpected(current); } PROGRESS_TOKEN(current); Identifier defineTo; if (!ParseIdentifier(defineTo, current)) { logUnexpectedToken(Identifier, current); } PROGRESS_TOKEN(current); EXPECT_TOKEN(current, SemicolonSymbol); out = new ParsedTypeDefStatement(TextSpan(start, current->GetSpan().GetEnd()), defineFrom, defineTo); return true; } bool Parser::ParseNamespace(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { 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)) { logUnexpectedToken(Identifier, current); } else { PROGRESS_TOKEN(current); } EXPECT_TOKEN(current, OpenCurlyParenthesisSymbol); ScopedPtr script = nullptr; if (!ParseScript(script, current, log)) { logUnexpectedTokenWithoutExpected(current); } auto end = current->GetSpan().GetEnd(); EXPECT_TOKEN(current, CloseCurlyParenthesisSymbol); out = new ParsedNamespaceStatement(TextSpan(start, end), identifier, (const ParsedScriptStatement*)script.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseFunc(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { 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 typeStatement = nullptr; bool returnsReference = false; if (current->GetKind() == LexTokenKind::TildeSymbol) { // TODO: Handle destructor throw std::logic_error("not implemented"); } else if (ParseType(typeStatement, current, log)) { if (current->GetKind() == LexTokenKind::AmpersandSymbol) { returnsReference = true; PROGRESS_TOKEN(current); } } Identifier identifier; if (!ParseIdentifier(identifier, current)) { return false; } PROGRESS_TOKEN(current); ScopedPtr paramList = nullptr; if (!ParseParamList(paramList, current, log)) { return false; } bool isConst = false; if (current->GetKind() == LexTokenKind::ConstKeyword) { isConst = true; PROGRESS_TOKEN(current); } FuncAttr funcAttr = FuncAttr::None; ParseFuncAttr(funcAttr, current, log); ScopedPtr statblock = nullptr; if (current->GetKind() != LexTokenKind::SemicolonSymbol) { if (!ParseStatBlock(statblock, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } } 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool isConst = false; bool isArray = false; bool isHandle = false; if (current->GetKind() == LexTokenKind::ConstKeyword) { isConst = true; PROGRESS_TOKEN(current); } ScopedIdentifier scopedIdentifier; ParseScope(scopedIdentifier.GetScope(), current, log); if (!ParseDataType(scopedIdentifier.GetIdentifier(), current, log)) { return false; } // TODO: Generics. if (current->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) { PROGRESS_TOKEN(current); if (current->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) { logUnexpectedToken(CloseCurlyParenthesisSymbol, current); } else { PROGRESS_TOKEN(current); isArray = true; } } else if (current->GetKind() == LexTokenKind::AtSymbol) { isHandle = true; PROGRESS_TOKEN(current); if (current->GetKind() == LexTokenKind::ConstKeyword) { isConst = true; PROGRESS_TOKEN(current); } } auto end = current->GetSpan().GetEnd(); currentToken = current; out = new ParsedTypeStatement(TextSpan(start, end), isConst, isArray, isHandle, scopedIdentifier); return true; } bool Parser::ParseScope(std::vector& scope, const LexToken*& currentToken, const log_func& log) { 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 { logUnexpectedToken(Identifier, current); break; } } // TODO: Handle generics in script class name. currentToken = current; return true; } bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { 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& out, const LexToken*& currentToken, const log_func& log) { if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) { return false; } auto start = currentToken->GetSpan().GetStart(); PROGRESS_TOKEN(currentToken); std::vector parameters; if (currentToken->GetKind() == LexTokenKind::VoidKeyword) { PROGRESS_TOKEN(currentToken); EXPECT_TOKEN(currentToken, CloseParenthesisSymbol); 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 typeStatement = nullptr; TypeMod typeMod = TypeMod::None; Identifier identifier; const ParsedStatement* defaultExpression = nullptr; if (!ParseType(typeStatement, currentToken, log)) { logUnexpectedTokenWithoutExpected(currentToken); } ParseTypeMod(typeMod, currentToken, log); if (!ParseIdentifier(identifier, currentToken)) { logUnexpectedToken(Identifier, currentToken); } else { PROGRESS_TOKEN(currentToken); } // TODO: Default expression parameters.push_back(new ParsedParamListStatement::ParsedParameter( dynamic_cast(typeStatement.TakeOwnership()), typeMod, identifier, defaultExpression)); if (currentToken->GetKind() != LexTokenKind::CommaSymbol) { break; } PROGRESS_TOKEN(currentToken); } EXPECT_TOKEN(currentToken, CloseParenthesisSymbol); out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters); return true; } bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { switch (currentToken->GetKind()) { case LexTokenKind::Identifier: out = static_cast(currentToken)->GetValue(); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::AutoKeyword: out = PrimitiveTypes::AutoName(); PROGRESS_TOKEN(currentToken); return true; default: if (ParsePrimType(out, currentToken, log)) { PROGRESS_TOKEN(currentToken); return true; } return false; } } bool Parser::ParseVirtProp([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { 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 typeStatement = nullptr; if (!ParseType(typeStatement, current, log)) { 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 getStatement = nullptr; bool hasSet = false; bool setConst = false; FuncAttr setAttr = FuncAttr::None; ScopedPtr 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, log); if (current->GetKind() != LexTokenKind::SemicolonSymbol) { if (!ParseStatBlock(getStatement, current, log)) { logUnexpectedTokenWithoutExpected(current); } } else { PROGRESS_TOKEN(current); } if (hasGet) { logError(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, log); if (current->GetKind() != LexTokenKind::SemicolonSymbol) { if (!ParseStatBlock(setStatement, current, log)) { logUnexpectedTokenWithoutExpected(current); } } else { PROGRESS_TOKEN(current); } if (hasSet) { logError(DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd()), {}); } hasSet = true; } else { break; } } if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol) { logUnexpectedToken(CloseCurlyParenthesisSymbol, current); } 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::IfKeyword) { return false; } PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; if (!ParseAssign(condition, current, log)) { logUnexpectedTokenWithoutExpected(current); } EXPECT_TOKEN(current, CloseParenthesisSymbol); ScopedPtr body = nullptr; if (!ParseStatement(body, current, log)) { logUnexpectedTokenWithoutExpected(current); } ScopedPtr elseStatement = nullptr; if (current->GetKind() == LexTokenKind::ElseKeyword) { PROGRESS_TOKEN(current); if (!ParseStatement(elseStatement, current, log)) { logUnexpectedTokenWithoutExpected(current); } } out = new ParsedIfStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), condition.TakeOwnership(), body.TakeOwnership(), elseStatement.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseStatement(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { // TODO: All the other statements. (switch | try ); switch (currentToken->GetKind()) { 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); case LexTokenKind::TryKeyword: return ParseTryStatement(out, currentToken, log); case LexTokenKind::SwitchKeyword: return ParseSwitchStatement(out, currentToken, log); default: return ParseStatBlock(out, currentToken, log) || ParseExprStat(out, currentToken, log); } return false; } bool Parser::ParseVar([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { 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 typeStatement = nullptr; if (!ParseType(typeStatement, current, log)) { 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { return false; } PROGRESS_TOKEN(current); std::vector statements; while (true) { if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { break; } ScopedPtr stat = nullptr; if (ParseVar(stat, current, log) || ParseStatement(stat, current, log)) { statements.push_back(stat.TakeOwnership()); } else { break; } } if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { PROGRESS_TOKEN(current); } else { logUnexpectedToken(CloseCurlyParenthesisSymbol, current); } out = new ParsedStatBlockStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), statements); currentToken = current; return true; } bool Parser::ParseFuncDef([[maybe_unused]] ScopedPtr& out, [[maybe_unused]] const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { // TODO return false; } bool Parser::ParsePrimType(Identifier& out, const LexToken*& token, [[maybe_unused]] const log_func& log) { 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, [[maybe_unused]] const log_func& log) { 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; ScopedPtr leftHand = nullptr; if (!ParseTernary(leftHand, current, log)) { return false; } AssignmentOperator op; if (!ParseAssignOp(op, current)) { out = leftHand.TakeOwnership(); currentToken = current; return true; } PROGRESS_TOKEN(current); ScopedPtr rightHand = nullptr; if (!ParseAssign(rightHand, current, log)) { logUnexpectedTokenWithoutExpected(current); out = leftHand.TakeOwnership(); currentToken = current; return true; } out = new ParsedBinaryStatement( TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand.TakeOwnership(), op, rightHand.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseTernary(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { // TODO: implement ternary. return ParseExpr(out, currentToken, log); } #define EXPR_PARSER(operator, name, func) \ operator(name); \ if (func(name, current)) { \ PROGRESS_TOKEN(current); \ ScopedPtr rightHand = nullptr; \ if (!ParseExprTerm(rightHand, current, log)) { \ logUnexpectedTokenWithoutExpected(current); \ 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; ScopedPtr leftHand = nullptr; if (!ParseExprTerm(leftHand, current, log)) { 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& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; // TODO ([type '='] initlist) PreOperator preOperator; bool hasPreOp = ParsePreOp(preOperator, currentToken, log); if (hasPreOp) { PROGRESS_TOKEN(current); } ScopedPtr operand = nullptr; if (!ParseExprValue(operand, current, log)) { 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& out, const LexToken*& currentToken, const log_func& log) { 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, log)) { currentToken = current; return true; } // TODO: cast if (ParseLiteral(out, current, log)) { currentToken = current; return true; } if (current->GetKind() == LexTokenKind::OpenParenthesisSymbol) { PROGRESS_TOKEN(current); if (!ParseAssign(out, current, log)) { logUnexpectedTokenWithoutExpected(current); } EXPECT_TOKEN(current, CloseParenthesisSymbol); currentToken = current; return true; } // TODO: lambda return false; } bool Parser::ParseLiteral(ScopedPtr& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { switch (currentToken->GetKind()) { case LexTokenKind::IntegerLiteral: out = new ParsedLiteralStatement( currentToken->GetSpan(), static_cast(currentToken)->GetValue()); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::FloatLiteral: out = new ParsedLiteralStatement( currentToken->GetSpan(), static_cast(currentToken)->GetValue()); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::StringLiteral: out = new ParsedLiteralStatement( currentToken->GetSpan(), static_cast(currentToken)->GetValue()); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::TrueKeyword: out = new ParsedLiteralStatement(currentToken->GetSpan(), true); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::FalseKeyword: out = new ParsedLiteralStatement(currentToken->GetSpan(), false); PROGRESS_TOKEN(currentToken); return true; case LexTokenKind::NullKeyword: out = new ParsedLiteralStatement(currentToken->GetSpan(), nullptr); PROGRESS_TOKEN(currentToken); return true; default: return false; } } bool Parser::ParseReturn(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { auto start = currentToken->GetSpan().GetStart(); if (currentToken->GetKind() != LexTokenKind::ReturnKeyword) { return false; } PROGRESS_TOKEN(currentToken); ScopedPtr returnBody; ParseAssign(returnBody, currentToken, log); EXPECT_TOKEN(currentToken, SemicolonSymbol); out = new ParsedReturnStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), returnBody.TakeOwnership()); return true; } bool Parser::ParseExprStat(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { if (!ParseAssign(out, currentToken, log)) { return false; } EXPECT_TOKEN(currentToken, SemicolonSymbol); return true; } bool Parser::ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { std::vector scope; auto start = currentToken->GetSpan().GetStart(); if (ParseScope(scope, currentToken, log)) { 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& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { 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& out, const LexToken*& currentToken, [[maybe_unused]] const log_func& log) { 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& out, const LexToken*& currentToken, const log_func& log) { if (currentToken->GetKind() != LexTokenKind::ForKeyword) { return false; } const auto* current = currentToken; PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr init; if (!ParseVar(init, current, log) && !ParseExprStat(init, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } ScopedPtr condition; if (!ParseExprStat(condition, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } std::vector increment; while (true) { ScopedPtr element; if (ParseAssign(element, current, log)) { increment.push_back(element.TakeOwnership()); } if (current->GetKind() != LexTokenKind::CommaSymbol) { break; } } EXPECT_TOKEN(current, CloseParenthesisSymbol); ScopedPtr statementBlock; if (!ParseStatement(statementBlock, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } out = new ParsedForStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), init.TakeOwnership(), condition.TakeOwnership(), increment, statementBlock.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseWhileStatement(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::WhileKeyword) { return false; } PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; if (!ParseAssign(condition, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } EXPECT_TOKEN(current, CloseParenthesisSymbol); ScopedPtr body = nullptr; if (!ParseStatement(body, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } out = new ParsedWhileStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), condition.TakeOwnership(), body.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseDoWhileStatement(ScopedPtr& out, const LexToken*& currentToken, const log_func& log) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::DoKeyword) { return false; } PROGRESS_TOKEN(current); ScopedPtr body = nullptr; if (!ParseStatement(body, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } EXPECT_TOKEN(current, WhileKeyword); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; if (!ParseAssign(condition, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } EXPECT_TOKEN(current, CloseParenthesisSymbol); EXPECT_TOKEN(current, SemicolonSymbol); out = new ParsedDoWhileStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), condition.TakeOwnership(), body.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseTryStatement(ScopedPtr& out, const LexToken*& currentToken, const Parser::log_func& log) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::TryKeyword) { return false; } PROGRESS_TOKEN(current); ScopedPtr tryStatement = nullptr; if (!ParseStatBlock(tryStatement, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } EXPECT_TOKEN(current, CatchKeyword); ScopedPtr catchStatement = nullptr; if (!ParseStatBlock(catchStatement, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } out = new ParsedTryStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), tryStatement.TakeOwnership(), catchStatement.TakeOwnership()); currentToken = current; return true; } bool Parser::ParseSwitchStatement(ScopedPtr& 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 expression = nullptr; if (!ParseExpr(expression, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } EXPECT_TOKEN(currentToken, CloseParenthesisSymbol); EXPECT_TOKEN(currentToken, OpenCurlyParenthesisSymbol); std::vector caseStatements; while (true) { if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { break; } if (current->GetKind() == LexTokenKind::CaseKeyword || currentToken->GetKind() == LexTokenKind::DefaultKeyword) { ScopedPtr stat = nullptr; if (!ParseCaseStatement(stat, current, log)) { for (const auto* s : caseStatements) { delete s; } return false; } caseStatements.push_back(stat.TakeOwnership()); } else { logUnexpectedToken(CaseKeyword, current); return false; } } // Consume } PROGRESS_TOKEN(current); out = new ParsedSwitchStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), expression.TakeOwnership(), caseStatements); currentToken = current; return true; } bool Parser::ParseCaseStatement(ScopedPtr& 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 expression = nullptr; if (!isDefault) { if (!ParseExpr(expression, current, log)) { logUnexpectedTokenWithoutExpected(current); return false; } } EXPECT_TOKEN(current, ColonSymbol); std::vector 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 stat = nullptr; if (ParseStatement(stat, current, log)) { statements.push_back(stat.TakeOwnership()); } else { break; } } out = new ParsedCaseStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), expression.TakeOwnership(), statements); currentToken = current; return true; } }