diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index f88dbdc..fd2bc52 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -10,19 +10,27 @@ #define EXPECT_TOKEN(token, kind) \ if (token->GetKind() != LexTokenKind::kind) { \ - LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan()); \ + logError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan()); \ } else { \ PROGRESS_TOKEN(token); \ } namespace MalachScript::Parser { - const ParsedScriptStatement* Parser::Parse() { return ParseScript(); } + const ParsedScriptStatement* Parser::Parse(const LexToken* firstToken, std::u8string_view scriptName, + Diagnostics::Diagnostics* diagnostics) { + const error_log_func& errorLog = [diagnostics, scriptName](Diagnostics::DiagnosticType type, + const TextSpan& span) { + diagnostics->LogError(type, scriptName, span); + }; - const ParsedScriptStatement* Parser::ParseScript() { + return ParseScript(firstToken, errorLog); + } + + const ParsedScriptStatement* Parser::ParseScript(const LexToken* firstToken, const error_log_func& logError) { std::vector statements; statements.reserve(32); size_t current = 0; - const auto* currentToken = _firstToken; + const auto* currentToken = firstToken; while (true) { while (currentToken->GetKind() == LexTokenKind::Whitespace) { currentToken = currentToken->GetNext().get(); @@ -31,8 +39,9 @@ namespace MalachScript::Parser { break; } ScopedPtr statement; - auto result = ParseClass(statement, currentToken) || ParseFunc(statement, currentToken) || - ParseNamespace(statement, currentToken); + auto result = ParseClass(statement, currentToken, logError) || + ParseFunc(statement, currentToken, logError) || + ParseNamespace(statement, currentToken, logError); if (!result) { // TODO: Log error PROGRESS_TOKEN(currentToken); @@ -48,7 +57,8 @@ namespace MalachScript::Parser { } return new ParsedScriptStatement(TextSpan(0, end), statements); } - bool Parser::ParseClass(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseClass(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool lookingForClass = true; @@ -66,7 +76,7 @@ namespace MalachScript::Parser { // 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()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } PROGRESS_TOKEN(current); std::vector inherits; @@ -82,19 +92,19 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); Identifier id; if (!ParseIdentifier(id, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + 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()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } inherits.push_back(id); PROGRESS_TOKEN(current); } if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } [[fallthrough]]; // Intentionally don't break so we continue into the inner body statement. @@ -109,9 +119,9 @@ namespace MalachScript::Parser { } 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()); + if (!ParseVirtProp(statement, current, logError) && !ParseFunc(statement, current, logError) && + !ParseVar(statement, current, logError) && !ParseFuncDef(statement, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); break; } body.push_back(statement.TakeOwnership()); @@ -124,7 +134,8 @@ namespace MalachScript::Parser { currentToken = current; return true; } - bool Parser::ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::TypedefKeyword) { return false; @@ -132,21 +143,22 @@ namespace MalachScript::Parser { auto start = current->GetSpan().GetStart(); PROGRESS_TOKEN(current); Identifier defineFrom; - if (!ParsePrimType(defineFrom, current) && !ParseIdentifier(defineFrom, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParsePrimType(defineFrom, current, logError) && !ParseIdentifier(defineFrom, current)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } PROGRESS_TOKEN(current); Identifier defineTo; if (!ParseIdentifier(defineTo, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + 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) { + bool Parser::ParseNamespace(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::NamespaceKeyword) { return false; @@ -155,16 +167,17 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); Identifier identifier; if (!ParseIdentifier(identifier, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } - const auto* script = ParseScript(); + const auto* script = ParseScript(current, logError); 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) { + bool Parser::ParseFunc(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool isShared = false; @@ -196,7 +209,7 @@ namespace MalachScript::Parser { if (current->GetKind() == LexTokenKind::TildeSymbol) { // TODO: Handle destructor throw std::logic_error("not implemented"); - } else if (ParseType(typeStatement, current)) { + } else if (ParseType(typeStatement, current, logError)) { if (current->GetKind() == LexTokenKind::AmpersandSymbol) { returnsReference = true; PROGRESS_TOKEN(current); @@ -208,7 +221,7 @@ namespace MalachScript::Parser { } PROGRESS_TOKEN(current); ScopedPtr paramList = nullptr; - if (!ParseParamList(paramList, current)) { + if (!ParseParamList(paramList, current, logError)) { return false; } bool isConst = false; @@ -217,11 +230,11 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); } FuncAttr funcAttr = FuncAttr::None; - ParseFuncAttr(funcAttr, current); + ParseFuncAttr(funcAttr, current, logError); ScopedPtr statblock = nullptr; if (current->GetKind() != LexTokenKind::SemicolonSymbol) { - if (!ParseStatBlock(statblock, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseStatBlock(statblock, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } } else { PROGRESS_TOKEN(current); @@ -233,7 +246,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseType(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseType(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* token = currentToken; auto start = token->GetSpan().GetStart(); bool isConst = false; @@ -244,15 +258,15 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(token); } ScopedIdentifier scopedIdentifier; - ParseScope(scopedIdentifier.GetScope(), token); - if (!ParseDataType(scopedIdentifier.GetIdentifier(), token)) { + ParseScope(scopedIdentifier.GetScope(), token, logError); + if (!ParseDataType(scopedIdentifier.GetIdentifier(), token, logError)) { return false; } // TODO: Generics. if (token->GetKind() == LexTokenKind::OpenBlockParenthesisSymbol) { PROGRESS_TOKEN(token); if (token->GetKind() != LexTokenKind::CloseBlockParenthesisSymbol) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, token->GetSpan()); } else { PROGRESS_TOKEN(token); isArray = true; @@ -270,7 +284,8 @@ namespace MalachScript::Parser { out = new ParsedTypeStatement(TextSpan(start, end), isConst, isArray, isHandle, scopedIdentifier); return true; } - bool Parser::ParseScope(std::vector& scope, const LexToken*& currentToken) { + bool Parser::ParseScope(std::vector& scope, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() == LexTokenKind::ColonColonSymbol) { scope.emplace_back(); @@ -300,7 +315,7 @@ namespace MalachScript::Parser { break; } } else { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); break; } } @@ -309,7 +324,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken) { + bool Parser::ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { bool lookingForFuncAttr = true; const auto* current = currentToken; while (lookingForFuncAttr) { @@ -337,7 +353,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseParamList(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseParamList(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) { return false; } @@ -348,7 +365,7 @@ namespace MalachScript::Parser { if (currentToken->GetKind() == LexTokenKind::VoidKeyword) { PROGRESS_TOKEN(currentToken); if (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); } PROGRESS_TOKEN(currentToken); out = new ParsedParamListStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), parameters); @@ -365,10 +382,10 @@ namespace MalachScript::Parser { Identifier identifier; const ParsedStatement* defaultExpression = nullptr; - if (!ParseType(typeStatement, currentToken)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); + if (!ParseType(typeStatement, currentToken, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); } - ParseTypeMod(typeMod, currentToken); + ParseTypeMod(typeMod, currentToken, logError); ParseIdentifier(identifier, currentToken); PROGRESS_TOKEN(currentToken); // TODO: Default expression @@ -383,7 +400,7 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(currentToken); } while (currentToken->GetKind() != LexTokenKind::CloseParenthesisSymbol) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); if (currentToken->GetKind() == LexTokenKind::EndOfFile) { break; } @@ -399,7 +416,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken) { + bool Parser::ParseDataType(Identifier& out, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { switch (currentToken->GetKind()) { case LexTokenKind::Identifier: out = static_cast(currentToken)->GetValue(); @@ -410,7 +428,7 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(currentToken); return true; default: - if (ParsePrimType(out, currentToken)) { + if (ParsePrimType(out, currentToken, logError)) { PROGRESS_TOKEN(currentToken); return true; } @@ -418,7 +436,8 @@ namespace MalachScript::Parser { } } - bool Parser::ParseVirtProp([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseVirtProp([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; AccessModifier access = AccessModifier::Public; if (current->GetKind() == LexTokenKind::PrivateKeyword) { @@ -429,7 +448,7 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); } ScopedPtr typeStatement = nullptr; - if (!ParseType(typeStatement, current)) { + if (!ParseType(typeStatement, current, logError)) { return false; } bool ref = false; @@ -462,18 +481,17 @@ namespace MalachScript::Parser { getConst = true; PROGRESS_TOKEN(current); } - ParseFuncAttr(getAttr, current); + ParseFuncAttr(getAttr, current, logError); if (current->GetKind() != LexTokenKind::SemicolonSymbol) { - if (!ParseStatBlock(getStatement, current)) { - this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseStatBlock(getStatement, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } } else { PROGRESS_TOKEN(current); } if (hasGet) { - this->LogError(Diagnostics::DiagnosticType::DoubleProperty, - TextSpan(start, current->GetSpan().GetEnd())); + logError(Diagnostics::DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd())); } hasGet = true; } else if (current->GetKind() == LexTokenKind::SetKeyword) { @@ -482,18 +500,17 @@ namespace MalachScript::Parser { setConst = true; PROGRESS_TOKEN(current); } - ParseFuncAttr(setAttr, current); + ParseFuncAttr(setAttr, current, logError); if (current->GetKind() != LexTokenKind::SemicolonSymbol) { - if (!ParseStatBlock(setStatement, current)) { - this->LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseStatBlock(setStatement, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } } else { PROGRESS_TOKEN(current); } if (hasSet) { - this->LogError(Diagnostics::DiagnosticType::DoubleProperty, - TextSpan(start, current->GetSpan().GetEnd())); + logError(Diagnostics::DiagnosticType::DoubleProperty, TextSpan(start, current->GetSpan().GetEnd())); } hasSet = true; } else { @@ -501,7 +518,7 @@ namespace MalachScript::Parser { } } if (current->GetKind() != LexTokenKind::CloseCurlyParenthesisSymbol) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } else { PROGRESS_TOKEN(current); } @@ -514,8 +531,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseIfStatement([[maybe_unused]] ScopedPtr& out, - const LexToken*& currentToken) { + bool Parser::ParseIfStatement([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::IfKeyword) { return false; @@ -523,21 +540,21 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; - if (!ParseAssign(condition, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseAssign(condition, current, logError)) { + 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()); + if (!ParseStatement(body, current, logError)) { + 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()); + if (!ParseStatement(elseStatement, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } } out = new ParsedIfStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), @@ -546,22 +563,24 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseStatement(ScopedPtr& out, const LexToken*& currentToken) { - // TODO: All the other statements. (dowhile | switch | try ); + bool Parser::ParseStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { + // TODO: All the other statements. (switch | try ); switch (currentToken->GetKind()) { - case LexTokenKind::IfKeyword: return ParseIfStatement(out, currentToken); - case LexTokenKind::ForKeyword: return ParseForStatement(out, currentToken); - case LexTokenKind::WhileKeyword: return ParseWhileStatement(out, currentToken); - case LexTokenKind::ReturnKeyword: return ParseReturn(out, currentToken); - case LexTokenKind::BreakKeyword: return ParseBreak(out, currentToken); - case LexTokenKind::ContinueKeyword: return ParseContinue(out, currentToken); - case LexTokenKind::DoKeyword: return ParseDoWhileStatement(out, currentToken); - default: return ParseStatBlock(out, currentToken) || ParseExprStat(out, currentToken); + case LexTokenKind::IfKeyword: return ParseIfStatement(out, currentToken, logError); + case LexTokenKind::ForKeyword: return ParseForStatement(out, currentToken, logError); + case LexTokenKind::WhileKeyword: return ParseWhileStatement(out, currentToken, logError); + case LexTokenKind::ReturnKeyword: return ParseReturn(out, currentToken, logError); + case LexTokenKind::BreakKeyword: return ParseBreak(out, currentToken, logError); + case LexTokenKind::ContinueKeyword: return ParseContinue(out, currentToken, logError); + case LexTokenKind::DoKeyword: return ParseDoWhileStatement(out, currentToken, logError); + default: return ParseStatBlock(out, currentToken, logError) || ParseExprStat(out, currentToken, logError); } return false; } - bool Parser::ParseVar([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseVar([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; AccessModifier access = AccessModifier::Public; if (current->GetKind() == LexTokenKind::PrivateKeyword) { @@ -572,7 +591,7 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); } ScopedPtr typeStatement = nullptr; - if (!ParseType(typeStatement, current)) { + if (!ParseType(typeStatement, current, logError)) { return false; } Identifier identifier; @@ -589,7 +608,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { return false; @@ -601,7 +621,7 @@ namespace MalachScript::Parser { break; } ScopedPtr stat = nullptr; - if (ParseVar(stat, current) || ParseStatement(stat, current)) { + if (ParseVar(stat, current, logError) || ParseStatement(stat, current, logError)) { statements.push_back(stat.TakeOwnership()); } else { break; @@ -610,7 +630,7 @@ namespace MalachScript::Parser { if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { PROGRESS_TOKEN(current); } else { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } out = new ParsedStatBlockStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), @@ -620,10 +640,13 @@ namespace MalachScript::Parser { } bool Parser::ParseFuncDef([[maybe_unused]] ScopedPtr& out, - [[maybe_unused]] const LexToken*& currentToken) { + [[maybe_unused]] const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { + // TODO return false; } - bool Parser::ParsePrimType(Identifier& out, const LexToken*& token) { + bool Parser::ParsePrimType(Identifier& out, const LexToken*& token, + [[maybe_unused]] const error_log_func& logError) { switch (token->GetKind()) { case LexTokenKind::VoidKeyword: out = PrimitiveTypes::VoidName(); return true; case LexTokenKind::IntKeyword: out = PrimitiveTypes::IntName(); return true; @@ -642,7 +665,8 @@ namespace MalachScript::Parser { default: return false; } } - bool Parser::ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken) { + bool Parser::ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { if (currentToken->GetKind() != LexTokenKind::AmpersandSymbol) { return false; } @@ -663,10 +687,11 @@ namespace MalachScript::Parser { default: typeMod = TypeMod::RefInOut; return true; } } - bool Parser::ParseAssign(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseAssign(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; ScopedPtr leftHand = nullptr; - if (!ParseTernary(leftHand, current)) { + if (!ParseTernary(leftHand, current, logError)) { return false; } AssignmentOperator op; @@ -677,8 +702,8 @@ namespace MalachScript::Parser { } PROGRESS_TOKEN(current); ScopedPtr rightHand = nullptr; - if (!ParseAssign(rightHand, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseAssign(rightHand, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); out = leftHand.TakeOwnership(); currentToken = current; return true; @@ -690,9 +715,10 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseTernary(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseTernary(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { // TODO: implement ternary. - return ParseExpr(out, currentToken); + return ParseExpr(out, currentToken, logError); } #define EXPR_PARSER(operator, name, func) \ @@ -700,8 +726,8 @@ namespace MalachScript::Parser { if (func(name, current)) { \ PROGRESS_TOKEN(current); \ ScopedPtr rightHand = nullptr; \ - if (!ParseExprTerm(rightHand, current)) { \ - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); \ + if (!ParseExprTerm(rightHand, current, logError)) { \ + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); \ out = leftHand.TakeOwnership(); \ currentToken = current; \ return true; \ @@ -713,10 +739,11 @@ namespace MalachScript::Parser { return true; \ } - bool Parser::ParseExpr(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseExpr(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; ScopedPtr leftHand = nullptr; - if (!ParseExprTerm(leftHand, current)) { + if (!ParseExprTerm(leftHand, current, logError)) { return false; } EXPR_PARSER(MathOperator, mathOp, ParseMathOp); @@ -729,17 +756,18 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; // TODO ([type '='] initlist) PreOperator preOperator; - bool hasPreOp = ParsePreOp(preOperator, currentToken); + bool hasPreOp = ParsePreOp(preOperator, currentToken, logError); if (hasPreOp) { PROGRESS_TOKEN(current); } ScopedPtr operand = nullptr; - if (!ParseExprValue(operand, current)) { + if (!ParseExprValue(operand, current, logError)) { return false; } @@ -761,7 +789,8 @@ namespace MalachScript::Parser { currentToken = current; return true; } - bool Parser::ParseExprValue(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseExprValue(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() == LexTokenKind::VoidKeyword) { PROGRESS_TOKEN(current); @@ -772,19 +801,19 @@ namespace MalachScript::Parser { } // TODO: constructcall // TODO: funccall - if (ParseVarAccess(out, current)) { + if (ParseVarAccess(out, current, logError)) { currentToken = current; return true; } // TODO: cast - if (ParseLiteral(out, current)) { + if (ParseLiteral(out, current, logError)) { currentToken = current; return true; } if (current->GetKind() == LexTokenKind::OpenParenthesisSymbol) { PROGRESS_TOKEN(current); - if (!ParseAssign(out, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseAssign(out, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); } EXPECT_TOKEN(current, CloseParenthesisSymbol); return true; @@ -793,7 +822,8 @@ namespace MalachScript::Parser { return false; } - bool Parser::ParseLiteral(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseLiteral(ScopedPtr& out, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { switch (currentToken->GetKind()) { case LexTokenKind::IntegerLiteral: out = new ParsedLiteralStatement( @@ -825,29 +855,32 @@ namespace MalachScript::Parser { default: return false; } } - bool Parser::ParseReturn(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseReturn(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { auto start = currentToken->GetSpan().GetStart(); if (currentToken->GetKind() != LexTokenKind::ReturnKeyword) { return false; } PROGRESS_TOKEN(currentToken); ScopedPtr returnBody; - ParseAssign(returnBody, currentToken); + ParseAssign(returnBody, currentToken, logError); 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)) { + bool Parser::ParseExprStat(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { + if (!ParseAssign(out, currentToken, logError)) { return false; } EXPECT_TOKEN(currentToken, SemicolonSymbol); return true; } - bool Parser::ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { std::vector scope; auto start = currentToken->GetSpan().GetStart(); - if (ParseScope(scope, currentToken)) { + if (ParseScope(scope, currentToken, logError)) { out = new ParsedVarAccessStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), scope); return true; } @@ -861,7 +894,8 @@ namespace MalachScript::Parser { } return false; } - bool Parser::ParseContinue(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseContinue(ScopedPtr& out, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { if (currentToken->GetKind() != LexTokenKind::ContinueKeyword) { return false; } @@ -871,7 +905,8 @@ namespace MalachScript::Parser { out = new ParsedContinueStatement(TextSpan(start, currentToken->GetSpan().GetEnd())); return true; } - bool Parser::ParseBreak(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseBreak(ScopedPtr& out, const LexToken*& currentToken, + [[maybe_unused]] const error_log_func& logError) { if (currentToken->GetKind() != LexTokenKind::BreakKeyword) { return false; } @@ -881,7 +916,8 @@ namespace MalachScript::Parser { out = new ParsedBreakStatement(TextSpan(start, currentToken->GetSpan().GetEnd())); return true; } - bool Parser::ParseForStatement(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseForStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { if (currentToken->GetKind() != LexTokenKind::ForKeyword) { return false; } @@ -889,19 +925,19 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr init; - if (!ParseVar(init, current) && !ParseExprStat(init, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseVar(init, current, logError) && !ParseExprStat(init, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } ScopedPtr condition; - if (!ParseExprStat(condition, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseExprStat(condition, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } std::vector increment; while (true) { ScopedPtr element; - if (ParseAssign(element, current)) { + if (ParseAssign(element, current, logError)) { increment.push_back(element.TakeOwnership()); } if (current->GetKind() != LexTokenKind::CommaSymbol) { @@ -910,8 +946,8 @@ namespace MalachScript::Parser { } EXPECT_TOKEN(current, CloseParenthesisSymbol); ScopedPtr statementBlock; - if (!ParseStatement(statementBlock, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseStatement(statementBlock, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } @@ -922,7 +958,8 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseWhileStatement(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseWhileStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::WhileKeyword) { return false; @@ -930,14 +967,14 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; - if (!ParseAssign(condition, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseAssign(condition, current, logError)) { + 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()); + if (!ParseStatement(body, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } out = new ParsedWhileStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), @@ -945,21 +982,22 @@ namespace MalachScript::Parser { currentToken = current; return true; } - bool Parser::ParseDoWhileStatement(ScopedPtr& out, const LexToken*& currentToken) { + bool Parser::ParseDoWhileStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func& logError) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::DoKeyword) { return false; } ScopedPtr body = nullptr; - if (!ParseStatement(body, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseStatement(body, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } EXPECT_TOKEN(current, WhileKeyword); EXPECT_TOKEN(current, OpenParenthesisSymbol); ScopedPtr condition = nullptr; - if (!ParseAssign(condition, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); + if (!ParseAssign(condition, current, logError)) { + logError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } EXPECT_TOKEN(current, CloseParenthesisSymbol); diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 27c8f27..a855034 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -1,6 +1,7 @@ #ifndef MALACHSCRIPT_PARSER_HPP #define MALACHSCRIPT_PARSER_HPP +#include #include "../CoreData/Operators.hpp" #include "../Diagnostics/Diagnostics.hpp" #include "../Utils/ScopedPtr.hpp" @@ -10,18 +11,11 @@ namespace MalachScript::Parser { class Parser { public: - Parser(std::u8string_view scriptName, const LexToken* firstToken, Diagnostics::Diagnostics* diagnostics) - : _scriptName(scriptName), _diagnostics(diagnostics), _firstToken(firstToken) {} - const ParsedScriptStatement* Parse(); + static const ParsedScriptStatement* Parse(const LexToken* firstToken, std::u8string_view scriptName, + Diagnostics::Diagnostics* diagnostics); private: - std::u8string_view _scriptName; - Diagnostics::Diagnostics* _diagnostics; - const LexToken* _firstToken; - - inline void LogError(Diagnostics::DiagnosticType type, const TextSpan& span) { - _diagnostics->LogError(type, _scriptName, span); - } + typedef const std::function error_log_func; ///////////////////////////////////////////////////////////////////////////////////////// // Underlying functions are laid out in the order they are defined in the grammar.ebnf // @@ -112,13 +106,15 @@ namespace MalachScript::Parser { } } - bool ParsePrimType(Identifier& out, const LexToken*& currentToken); - bool ParseDataType(Identifier& out, const LexToken*& currentToken); - bool ParseScope(std::vector& out, const LexToken*& currentToken); - bool ParseType(ScopedPtr& out, const LexToken*& currentToken); - bool ParseAssign(ScopedPtr& out, const LexToken*& currentToken); + static bool ParsePrimType(Identifier& out, const LexToken*& currentToken, const error_log_func&); + static bool ParseDataType(Identifier& out, const LexToken*& currentToken, const error_log_func&); + static bool ParseScope(std::vector& out, const LexToken*& currentToken, const error_log_func&); + static bool ParseType(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseAssign(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // InitList - inline static bool ParsePreOp(PreOperator& op, const LexToken*& token) { + inline static bool ParsePreOp(PreOperator& op, const LexToken*& token, const error_log_func&) { switch (token->GetKind()) { case LexTokenKind::MinusSymbol: op = PreOperator::Negation; return true; case LexTokenKind::PlusSymbol: op = PreOperator::Identity; return true; @@ -133,52 +129,76 @@ namespace MalachScript::Parser { // ArgList // FuncCall // ConstructCall - bool ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // Cast - bool ParseLiteral(ScopedPtr& out, const LexToken*& currentToken); - bool ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken); + static bool ParseLiteral(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken, const error_log_func&); // Lambda - bool ParseExprValue(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseExprValue(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // ExprPostOp - bool ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken); - bool ParseExpr(ScopedPtr& out, const LexToken*& currentToken); - bool ParseTernary(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseExpr(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseTernary(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); - bool ParseReturn(ScopedPtr& out, const LexToken*& currentToken); - bool ParseExprStat(ScopedPtr& out, const LexToken*& currentToken); - bool ParseContinue(ScopedPtr& out, const LexToken*& currentToken); - bool ParseBreak(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseReturn(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseExprStat(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseContinue(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseBreak(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); - bool ParseIfStatement(ScopedPtr& out, const LexToken*& currentToken); - bool ParseForStatement(ScopedPtr& out, const LexToken*& currentToken); - bool ParseWhileStatement(ScopedPtr& out, const LexToken*& currentToken); - bool ParseDoWhileStatement(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseIfStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseForStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseWhileStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseDoWhileStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // Try // Case // Switch - bool ParseStatement(ScopedPtr& out, const LexToken*& currentToken); - bool ParseVar(ScopedPtr& out, const LexToken*& currentToken); - bool ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseStatement(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseVar(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); - bool ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken); - bool ParseParamList(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken, const error_log_func&); + static bool ParseParamList(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); - bool ParseVirtProp(ScopedPtr& out, const LexToken*& currentToken); - bool ParseFunc(ScopedPtr& out, const LexToken*& currentToken); - bool ParseFuncDef(ScopedPtr& out, const LexToken*& currentToken); - bool ParseClass(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseVirtProp(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseFunc(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseFuncDef(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static bool ParseClass(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // Mixin // Enum // Import - bool ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken); + static bool ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); // InterfaceMethod // Interface - bool ParseNamespace(ScopedPtr& out, const LexToken*& currentToken); - const ParsedScriptStatement* ParseScript(); + static bool ParseNamespace(ScopedPtr& out, const LexToken*& currentToken, + const error_log_func&); + static const ParsedScriptStatement* ParseScript(const LexToken* firstToken, const error_log_func&); }; } diff --git a/tests/ParserTests/ClassTests.cpp b/tests/ParserTests/ClassTests.cpp index c861929..72c20a7 100644 --- a/tests/ParserTests/ClassTests.cpp +++ b/tests/ParserTests/ClassTests.cpp @@ -13,8 +13,7 @@ using namespace MalachScript; vec[i]->SetNext(vec[i + 1]); \ } \ Diagnostics::Diagnostics diags; \ - auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags); \ - auto* script = parser.Parse(); \ + auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ REQUIRE(diags.GetMessages().empty()); \ asserts; \ delete vec[0]; \ diff --git a/tests/ParserTests/FunctionTests.cpp b/tests/ParserTests/FunctionTests.cpp index f29e06a..46b2624 100644 --- a/tests/ParserTests/FunctionTests.cpp +++ b/tests/ParserTests/FunctionTests.cpp @@ -13,8 +13,7 @@ using namespace MalachScript; vec[i]->SetNext(vec[i + 1]); \ } \ Diagnostics::Diagnostics diags; \ - auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags); \ - auto* script = parser.Parse(); \ + auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ REQUIRE(diags.GetMessages().empty()); \ asserts; \ delete vec[0]; \ diff --git a/tests/ParserTests/ParserIntegrationTests.cpp b/tests/ParserTests/ParserIntegrationTests.cpp index 547edd3..7137a95 100644 --- a/tests/ParserTests/ParserIntegrationTests.cpp +++ b/tests/ParserTests/ParserIntegrationTests.cpp @@ -9,8 +9,7 @@ using namespace MalachScript; Diagnostics::Diagnostics diags; \ auto lexer = Parser::Lexer(u8##name, u8##scriptText, &diags); \ auto token = lexer.Lex(); \ - auto parser = Parser::Parser(u8##name, token, &diags); \ - auto script = parser.Parse(); \ + auto script = Parser::Parser::Parse(token, u8##name, &diags); \ asserts; \ delete script; \ } diff --git a/tests/ParserTests/VirtPropTests.cpp b/tests/ParserTests/VirtPropTests.cpp index 81463e5..df3f9a0 100644 --- a/tests/ParserTests/VirtPropTests.cpp +++ b/tests/ParserTests/VirtPropTests.cpp @@ -13,8 +13,7 @@ using namespace MalachScript; vec[i]->SetNext(vec[i + 1]); \ } \ Diagnostics::Diagnostics diags; \ - auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags); \ - auto* script = parser.Parse(); \ + auto* script = Parser::Parser::Parse(vec.front(), u8"scriptname", &diags); \ REQUIRE(diags.GetMessages().empty()); \ asserts; \ delete vec[0]; \