From a3a996d68a6f5f17ffec175558e551a74500a337 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 6 Dec 2020 12:35:08 +0100 Subject: [PATCH] Implements parsing for loop, cleanup of memory handling in parser. --- .clang-tidy | 4 +- src/Parser/Parser.cpp | 265 +++++++++--------- src/Parser/Parser.hpp | 49 ++-- src/Parser/Statements/ParsedStatement.hpp | 24 ++ src/Parser/Statements/ParsedStatementKind.hpp | 1 + src/Utils/ScopedPtr.hpp | 31 ++ 6 files changed, 216 insertions(+), 158 deletions(-) create mode 100644 src/Utils/ScopedPtr.hpp diff --git a/.clang-tidy b/.clang-tidy index 884002b..5edc8ce 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,5 @@ -Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*, -bugprone-*,modernize-*,-modernize-use-trailing-return-type' +Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*, +bugprone-*,modernize-*,-modernize-use-trailing-return-type,-readability-function-cognitive-complexity' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false CheckOptions: diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index db7ccfe..5a2d215 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -30,7 +30,7 @@ namespace MalachScript::Parser { if (currentToken->GetKind() == LexTokenKind::EndOfFile) { break; } - const ParsedStatement* statement; + ScopedPtr statement; auto result = ParseClass(statement, currentToken) || ParseFunc(statement, currentToken) || ParseNamespace(statement, currentToken); if (!result) { @@ -38,7 +38,7 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(currentToken); continue; } - statements.push_back(statement); + statements.push_back(statement.TakeOwnership()); current++; } statements.resize(current); @@ -48,7 +48,7 @@ namespace MalachScript::Parser { } return new ParsedScriptStatement(TextSpan(0, end), statements); } - bool Parser::ParseClass(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseClass(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool lookingForClass = true; @@ -107,14 +107,14 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); break; } - const ParsedStatement* statement = nullptr; + 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); + body.push_back(statement.TakeOwnership()); } break; } @@ -124,7 +124,7 @@ namespace MalachScript::Parser { currentToken = current; return true; } - bool Parser::ParseTypeDef(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::TypedefKeyword) { return false; @@ -143,10 +143,10 @@ namespace MalachScript::Parser { } PROGRESS_TOKEN(current); EXPECT_TOKEN(current, SemicolonSymbol); - out = new ParsedTypeDefStatement(TextSpan(start, current->GetSpan().GetEnd()), defineTo, defineFrom); + out = new ParsedTypeDefStatement(TextSpan(start, current->GetSpan().GetEnd()), defineFrom, defineTo); return true; } - bool Parser::ParseNamespace(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseNamespace(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::NamespaceKeyword) { return false; @@ -164,7 +164,7 @@ namespace MalachScript::Parser { currentToken = current; return true; } - bool Parser::ParseFunc(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseFunc(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; auto start = current->GetSpan().GetStart(); bool isShared = false; @@ -191,7 +191,7 @@ namespace MalachScript::Parser { accessModifier = AccessModifier::Protected; PROGRESS_TOKEN(current); } - const ParsedStatement* typeStatement = nullptr; + ScopedPtr typeStatement = nullptr; bool returnsReference = false; if (current->GetKind() == LexTokenKind::TildeSymbol) { // TODO: Handle destructor @@ -204,13 +204,11 @@ namespace MalachScript::Parser { } Identifier identifier; if (!ParseIdentifier(identifier, current)) { - delete typeStatement; return false; } PROGRESS_TOKEN(current); - const ParsedStatement* paramList = nullptr; + ScopedPtr paramList = nullptr; if (!ParseParamList(paramList, current)) { - delete typeStatement; return false; } bool isConst = false; @@ -220,7 +218,7 @@ namespace MalachScript::Parser { } FuncAttr funcAttr = FuncAttr::None; ParseFuncAttr(funcAttr, current); - const ParsedStatement* statblock = nullptr; + ScopedPtr statblock = nullptr; if (current->GetKind() != LexTokenKind::SemicolonSymbol) { if (!ParseStatBlock(statblock, current)) { LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); @@ -229,13 +227,13 @@ namespace MalachScript::Parser { PROGRESS_TOKEN(current); } out = new ParsedFuncStatement(TextSpan(start, current->GetSpan().GetEnd()), isShared, isExternal, - accessModifier, typeStatement, returnsReference, identifier, paramList, isConst, - funcAttr, statblock); + accessModifier, typeStatement.TakeOwnership(), returnsReference, identifier, + paramList.TakeOwnership(), isConst, funcAttr, statblock.TakeOwnership()); currentToken = current; return true; } - bool Parser::ParseType(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseType(ScopedPtr& out, const LexToken*& currentToken) { const auto* token = currentToken; auto start = token->GetSpan().GetStart(); bool isConst = false; @@ -339,7 +337,7 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseParamList(ScopedPtr& out, const LexToken*& currentToken) { if (currentToken->GetKind() != LexTokenKind::OpenParenthesisSymbol) { return false; } @@ -362,7 +360,7 @@ namespace MalachScript::Parser { return true; } while (true) { - const ParsedStatement* typeStatement = nullptr; + ScopedPtr typeStatement = nullptr; TypeMod typeMod = TypeMod::None; Identifier identifier; const ParsedStatement* defaultExpression = nullptr; @@ -376,7 +374,8 @@ namespace MalachScript::Parser { // TODO: Default expression parameters.push_back(new ParsedParamListStatement::ParsedParameter( - dynamic_cast(typeStatement), typeMod, identifier, defaultExpression)); + dynamic_cast(typeStatement.TakeOwnership()), typeMod, identifier, + defaultExpression)); if (currentToken->GetKind() != LexTokenKind::CommaSymbol) { break; @@ -419,7 +418,7 @@ namespace MalachScript::Parser { } } - bool Parser::ParseVirtProp([[maybe_unused]] const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseVirtProp([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; AccessModifier access = AccessModifier::Public; if (current->GetKind() == LexTokenKind::PrivateKeyword) { @@ -429,7 +428,7 @@ namespace MalachScript::Parser { access = AccessModifier::Protected; PROGRESS_TOKEN(current); } - const ParsedStatement* typeStatement = nullptr; + ScopedPtr typeStatement = nullptr; if (!ParseType(typeStatement, current)) { return false; } @@ -440,22 +439,20 @@ namespace MalachScript::Parser { } Identifier identifier; if (!ParseIdentifier(identifier, current)) { - delete typeStatement; return false; } PROGRESS_TOKEN(current); if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { - delete typeStatement; return false; } bool hasGet = false; bool getConst = false; FuncAttr getAttr = FuncAttr::None; - const ParsedStatement* getStatement = nullptr; + ScopedPtr getStatement = nullptr; bool hasSet = false; bool setConst = false; FuncAttr setAttr = FuncAttr::None; - const ParsedStatement* setStatement = nullptr; + ScopedPtr setStatement = nullptr; PROGRESS_TOKEN(current); while (true) { auto start = current->GetSpan().GetStart(); @@ -510,31 +507,33 @@ namespace MalachScript::Parser { } out = new ParsedVirtPropStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), - access, typeStatement, ref, identifier, hasGet, getConst, getAttr, - getStatement, hasSet, setConst, setAttr, setStatement); + access, typeStatement.TakeOwnership(), ref, identifier, hasGet, getConst, + getAttr, getStatement.TakeOwnership(), hasSet, setConst, setAttr, + setStatement.TakeOwnership()); currentToken = current; return true; } - bool Parser::ParseIfStatement([[maybe_unused]] const ParsedStatement*& out, const LexToken*& currentToken) { + 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); - const ParsedStatement* condition = nullptr; + ScopedPtr condition = nullptr; if (!ParseAssign(condition, current)) { LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } EXPECT_TOKEN(current, CloseParenthesisSymbol); - const ParsedStatement* body = nullptr; + ScopedPtr body = nullptr; if (!ParseStatement(body, current)) { LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); return false; } - const ParsedStatement* elseStatement = nullptr; + ScopedPtr elseStatement = nullptr; if (current->GetKind() == LexTokenKind::ElseKeyword) { PROGRESS_TOKEN(current); if (!ParseStatement(elseStatement, current)) { @@ -542,19 +541,20 @@ namespace MalachScript::Parser { } } out = new ParsedIfStatement(TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), - condition, body, elseStatement); + condition.TakeOwnership(), body.TakeOwnership(), elseStatement.TakeOwnership()); currentToken = current; return true; } - bool Parser::ParseStatement(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseStatement(ScopedPtr& out, const LexToken*& currentToken) { // TODO: All the other statements. - return ParseIfStatement(out, currentToken) || ParseReturn(out, currentToken) || - ParseStatBlock(out, currentToken) || ParseExprStat(out, currentToken); + 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]] const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseVar([[maybe_unused]] ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; AccessModifier access = AccessModifier::Public; if (current->GetKind() == LexTokenKind::PrivateKeyword) { @@ -564,13 +564,12 @@ namespace MalachScript::Parser { access = AccessModifier::Protected; PROGRESS_TOKEN(current); } - const ParsedStatement* typeStatement = nullptr; + ScopedPtr typeStatement = nullptr; if (!ParseType(typeStatement, current)) { return false; } Identifier identifier; if (!ParseIdentifier(identifier, current)) { - delete typeStatement; return false; } PROGRESS_TOKEN(current); @@ -578,12 +577,12 @@ namespace MalachScript::Parser { // 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, identifier); + typeStatement.TakeOwnership(), identifier); currentToken = current; return true; } - bool Parser::ParseStatBlock(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; if (current->GetKind() != LexTokenKind::OpenCurlyParenthesisSymbol) { return false; @@ -594,9 +593,9 @@ namespace MalachScript::Parser { if (current->GetKind() == LexTokenKind::CloseCurlyParenthesisSymbol) { break; } - const ParsedStatement* stat = nullptr; + ScopedPtr stat = nullptr; if (ParseVar(stat, current) || ParseStatement(stat, current)) { - statements.push_back(stat); + statements.push_back(stat.TakeOwnership()); } else { break; } @@ -613,7 +612,7 @@ namespace MalachScript::Parser { return true; } - bool Parser::ParseFuncDef([[maybe_unused]] const ParsedStatement*& out, + bool Parser::ParseFuncDef([[maybe_unused]] ScopedPtr& out, [[maybe_unused]] const LexToken*& currentToken) { return false; } @@ -657,111 +656,73 @@ namespace MalachScript::Parser { default: typeMod = TypeMod::RefInOut; return true; } } - bool Parser::ParseAssign(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseAssign(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; - const ParsedStatement* leftHand = nullptr; + ScopedPtr leftHand = nullptr; if (!ParseTernary(leftHand, current)) { return false; } AssignmentOperator op; if (!ParseAssignOp(op, current)) { - out = leftHand; + out = leftHand.TakeOwnership(); currentToken = current; return true; } PROGRESS_TOKEN(current); - const ParsedStatement* rightHand = nullptr; + ScopedPtr rightHand = nullptr; if (!ParseAssign(rightHand, current)) { LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); - out = leftHand; + out = leftHand.TakeOwnership(); currentToken = current; return true; } out = new ParsedBinaryStatement( - TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand, op, rightHand); + TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand.TakeOwnership(), op, + rightHand.TakeOwnership()); currentToken = current; return true; } - bool Parser::ParseTernary(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseTernary(ScopedPtr& out, const LexToken*& currentToken) { // TODO: implement ternary. return ParseExpr(out, currentToken); } - bool Parser::ParseExpr(const ParsedStatement*& out, const LexToken*& 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; - const ParsedStatement* leftHand = nullptr; + ScopedPtr leftHand = nullptr; if (!ParseExprTerm(leftHand, current)) { return false; } - MathOperator mathOp; - if (ParseMathOp(mathOp, current)) { - PROGRESS_TOKEN(current); - const ParsedStatement* rightHand = nullptr; - if (!ParseExprTerm(rightHand, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); - out = leftHand; - currentToken = current; - return true; - } - out = new ParsedBinaryStatement( - TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand, mathOp, rightHand); - currentToken = current; - return true; - } - ComparisonOperator compOp; - if (ParseCompOp(compOp, current)) { - PROGRESS_TOKEN(current); - const ParsedStatement* rightHand = nullptr; - if (!ParseExprTerm(rightHand, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); - out = leftHand; - currentToken = current; - return true; - } - out = new ParsedBinaryStatement( - TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand, compOp, rightHand); - currentToken = current; - return true; - } - LogicOperator logicOp; - if (ParseLogicOp(logicOp, current)) { - PROGRESS_TOKEN(current); - const ParsedStatement* rightHand = nullptr; - if (!ParseExprTerm(rightHand, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); - out = leftHand; - currentToken = current; - return true; - } - out = new ParsedBinaryStatement( - TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand, logicOp, - rightHand); - currentToken = current; - return true; - } - BitOperator bitOp; - if (ParseBitOp(bitOp, current)) { - PROGRESS_TOKEN(current); - const ParsedStatement* rightHand = nullptr; - if (!ParseExprTerm(rightHand, current)) { - LogError(Diagnostics::DiagnosticType::UnexpectedToken, current->GetSpan()); - out = leftHand; - currentToken = current; - return true; - } - out = new ParsedBinaryStatement( - TextSpan(currentToken->GetSpan().GetStart(), current->GetSpan().GetEnd()), leftHand, bitOp, rightHand); - currentToken = current; - return true; - } - out = leftHand; + 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([[maybe_unused]] const ParsedStatement*& out, - [[maybe_unused]] const LexToken*& currentToken) { + bool Parser::ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; // TODO ([type '='] initlist) @@ -770,7 +731,7 @@ namespace MalachScript::Parser { if (hasPreOp) { PROGRESS_TOKEN(current); } - const ParsedStatement* operand = nullptr; + ScopedPtr operand = nullptr; if (!ParseExprValue(operand, current)) { return false; } @@ -778,22 +739,22 @@ namespace MalachScript::Parser { // TODO: remainder of if (current->GetKind() == LexTokenKind::PlusPlusSymbol) { operand = new ParsedIncrementStatement(TextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd()), - operand); + operand.TakeOwnership()); PROGRESS_TOKEN(current); } else if (current->GetKind() == LexTokenKind::MinusMinusSymbol) { operand = new ParsedDecrementStatement(TextSpan(operand->GetSpan().GetStart(), current->GetSpan().GetEnd()), - operand); + operand.TakeOwnership()); PROGRESS_TOKEN(current); } if (hasPreOp) { // TODO: integrate pre operator } - out = operand; + out = operand.TakeOwnership(); currentToken = current; return true; } - bool Parser::ParseExprValue(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseExprValue(ScopedPtr& out, const LexToken*& currentToken) { const auto* current = currentToken; if (current->GetKind() == LexTokenKind::VoidKeyword) { PROGRESS_TOKEN(current); @@ -825,7 +786,7 @@ namespace MalachScript::Parser { return false; } - bool Parser::ParseLiteral(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseLiteral(ScopedPtr& out, const LexToken*& currentToken) { switch (currentToken->GetKind()) { case LexTokenKind::IntegerLiteral: out = new ParsedLiteralStatement( @@ -857,26 +818,26 @@ namespace MalachScript::Parser { default: return false; } } - bool Parser::ParseReturn(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseReturn(ScopedPtr& out, const LexToken*& currentToken) { auto start = currentToken->GetSpan().GetStart(); if (currentToken->GetKind() != LexTokenKind::ReturnKeyword) { return false; } PROGRESS_TOKEN(currentToken); - const ParsedStatement* returnBody = nullptr; + ScopedPtr returnBody; ParseAssign(returnBody, currentToken); EXPECT_TOKEN(currentToken, SemicolonSymbol); - out = new ParsedReturnStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), returnBody); + out = new ParsedReturnStatement(TextSpan(start, currentToken->GetSpan().GetEnd()), returnBody.TakeOwnership()); return true; } - bool Parser::ParseExprStat(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseExprStat(ScopedPtr& out, const LexToken*& currentToken) { if (!ParseAssign(out, currentToken)) { return false; } EXPECT_TOKEN(currentToken, SemicolonSymbol); return true; } - bool Parser::ParseVarAccess(const ParsedStatement*& out, const LexToken*& currentToken) { + bool Parser::ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken) { std::vector scope; auto start = currentToken->GetSpan().GetStart(); if (ParseScope(scope, currentToken)) { @@ -893,8 +854,8 @@ namespace MalachScript::Parser { } return false; } - bool Parser::ParseContinue(const ParsedStatement*& out, const LexToken*& currentToken) { - if (currentToken->GetKind() == LexTokenKind::ContinueKeyword) { + bool Parser::ParseContinue(ScopedPtr& out, const LexToken*& currentToken) { + if (currentToken->GetKind() != LexTokenKind::ContinueKeyword) { return false; } auto start = currentToken->GetSpan().GetStart(); @@ -903,8 +864,8 @@ namespace MalachScript::Parser { out = new ParsedContinueStatement(TextSpan(start, currentToken->GetSpan().GetEnd())); return true; } - bool Parser::ParseBreak(const ParsedStatement*& out, const LexToken*& currentToken) { - if (currentToken->GetKind() == LexTokenKind::BreakKeyword) { + bool Parser::ParseBreak(ScopedPtr& out, const LexToken*& currentToken) { + if (currentToken->GetKind() != LexTokenKind::BreakKeyword) { return false; } auto start = currentToken->GetSpan().GetStart(); @@ -913,4 +874,44 @@ namespace MalachScript::Parser { 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; + } } \ No newline at end of file diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 9b3862a..a7f913c 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -3,6 +3,7 @@ #include "../CoreData/Operators.hpp" #include "../Diagnostics/Diagnostics.hpp" +#include "../Utils/ScopedPtr.hpp" #include "Lexer/LexToken.hpp" #include "Statements/ParsedStatement.hpp" @@ -114,8 +115,8 @@ 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(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseAssign(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseType(ScopedPtr& out, const LexToken*& currentToken); + bool ParseAssign(ScopedPtr& out, const LexToken*& currentToken); // InitList inline static bool ParsePreOp(PreOperator& op, const LexToken*& token) { switch (token->GetKind()) { @@ -132,51 +133,51 @@ namespace MalachScript::Parser { // ArgList // FuncCall // ConstructCall - bool ParseVarAccess(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseVarAccess(ScopedPtr& out, const LexToken*& currentToken); // Cast - bool ParseLiteral(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseLiteral(ScopedPtr& out, const LexToken*& currentToken); bool ParseTypeMod(TypeMod& typeMod, const LexToken*& currentToken); // Lambda - bool ParseExprValue(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseExprValue(ScopedPtr& out, const LexToken*& currentToken); // ExprPostOp - bool ParseExprTerm(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseExpr(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseTernary(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseExprTerm(ScopedPtr& out, const LexToken*& currentToken); + bool ParseExpr(ScopedPtr& out, const LexToken*& currentToken); + bool ParseTernary(ScopedPtr& out, const LexToken*& currentToken); - bool ParseReturn(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseExprStat(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseContinue(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseBreak(const ParsedStatement*& out, const LexToken*& currentToken); + 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); - bool ParseIfStatement(const ParsedStatement*& out, const LexToken*& currentToken); - // For + bool ParseIfStatement(ScopedPtr& out, const LexToken*& currentToken); + bool ParseForStatement(ScopedPtr& out, const LexToken*& currentToken); // While // DoWhile // Try // Case // Switch - bool ParseStatement(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseVar(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseStatBlock(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseStatement(ScopedPtr& out, const LexToken*& currentToken); + bool ParseVar(ScopedPtr& out, const LexToken*& currentToken); + bool ParseStatBlock(ScopedPtr& out, const LexToken*& currentToken); bool ParseFuncAttr(FuncAttr& out, const LexToken*& currentToken); - bool ParseParamList(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseParamList(ScopedPtr& out, const LexToken*& currentToken); - bool ParseVirtProp(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseFunc(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseFuncDef(const ParsedStatement*& out, const LexToken*& currentToken); - bool ParseClass(const ParsedStatement*& out, const LexToken*& currentToken); + 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); // Mixin // Enum // Import - bool ParseTypeDef(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseTypeDef(ScopedPtr& out, const LexToken*& currentToken); // InterfaceMethod // Interface - bool ParseNamespace(const ParsedStatement*& out, const LexToken*& currentToken); + bool ParseNamespace(ScopedPtr& out, const LexToken*& currentToken); const ParsedScriptStatement* ParseScript(); }; } diff --git a/src/Parser/Statements/ParsedStatement.hpp b/src/Parser/Statements/ParsedStatement.hpp index eeafe5b..7fad350 100644 --- a/src/Parser/Statements/ParsedStatement.hpp +++ b/src/Parser/Statements/ParsedStatement.hpp @@ -370,6 +370,30 @@ namespace MalachScript::Parser { ParsedBreakStatement(const TextSpan& span) : ParsedStatementImpl(span) {} }; + class ParsedForStatement : public ParsedStatementImpl { + public: + ParsedForStatement(const TextSpan& span, const ParsedStatement* init, const ParsedStatement* condition, + std::vector increment, const ParsedStatement* body) + : ParsedStatementImpl(span), _init(init), _condition(condition), _increment(increment.size()), _body(body) { + for (size_t i = 0; i < increment.size(); i++) { + _increment[i] = std::unique_ptr(increment[i]); + } + } + + inline const std::unique_ptr& GetInit() const noexcept { return _init; } + inline const std::unique_ptr& GetCondition() const noexcept { return _condition; } + inline const std::vector>& GetIncrement() const noexcept { + return _increment; + } + inline const std::unique_ptr& GetBody() const noexcept { return _body; } + + private: + std::unique_ptr _init; + std::unique_ptr _condition; + std::vector> _increment; + std::unique_ptr _body; + }; + } #endif // MALACHSCRIPT_PARSEDSTATEMENT_HPP diff --git a/src/Parser/Statements/ParsedStatementKind.hpp b/src/Parser/Statements/ParsedStatementKind.hpp index 0de3c34..3574778 100644 --- a/src/Parser/Statements/ParsedStatementKind.hpp +++ b/src/Parser/Statements/ParsedStatementKind.hpp @@ -24,6 +24,7 @@ namespace MalachScript::Parser { Decrement, Continue, Break, + For, }; } diff --git a/src/Utils/ScopedPtr.hpp b/src/Utils/ScopedPtr.hpp new file mode 100644 index 0000000..151a171 --- /dev/null +++ b/src/Utils/ScopedPtr.hpp @@ -0,0 +1,31 @@ +#ifndef MALACHSCRIPT_SCOPEDPTR_HPP +#define MALACHSCRIPT_SCOPEDPTR_HPP + +template class ScopedPtr { + T* _raw; + +public: + inline ScopedPtr() { _raw = nullptr; } + + inline ScopedPtr(T* ptr) { _raw = ptr; } + + inline ScopedPtr& operator=(T* b) { + _raw = b; + return *this; + } + + ScopedPtr(const ScopedPtr& b) = delete; + ScopedPtr& operator=(ScopedPtr const&) = delete; + + inline ~ScopedPtr() { delete _raw; } + + inline T* TakeOwnership() noexcept { + auto b = _raw; + _raw = nullptr; + return b; + } + + inline T* operator->() { return _raw; } +}; + +#endif // MALACHSCRIPT_SCOPEDPTR_HPP