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