From dbd7dfdd7356e922c26cb2d58b1ca7fc4d8964b6 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 26 May 2019 14:20:40 +0200 Subject: [PATCH] Implements assignment parsing --- .../ParsedStatements/ParsedStatement.hpp | 50 +++++++++++++++++-- src/Parser/Parser.cpp | 48 ++++++++++++++---- src/Parser/Parser.hpp | 3 ++ tests/parser/ParserTests.cpp | 37 ++++++++++++++ 4 files changed, 125 insertions(+), 13 deletions(-) diff --git a/src/Parser/ParsedStatements/ParsedStatement.hpp b/src/Parser/ParsedStatements/ParsedStatement.hpp index 389e727..015d9c3 100644 --- a/src/Parser/ParsedStatements/ParsedStatement.hpp +++ b/src/Parser/ParsedStatements/ParsedStatement.hpp @@ -1,30 +1,32 @@ -#include - -#include #ifndef PORYGONLANG_PARSEDSTATEMENT_HPP #define PORYGONLANG_PARSEDSTATEMENT_HPP +#include #include +#include + #include "../ParsedExpressions/ParsedExpression.hpp" enum class ParsedStatementKind{ + Bad, Script, Block, Expression, + Assignment }; class ParsedStatement { unsigned int _start; unsigned int _length; public: - virtual ParsedStatementKind GetKind() = 0; ParsedStatement(unsigned int start, unsigned int length){ _start = start; _length = length; } virtual ~ParsedStatement() = default; + virtual ParsedStatementKind GetKind() = 0; unsigned int GetStartPosition(){ return _start; @@ -35,6 +37,14 @@ public: } }; +class ParsedBadStatement : public ParsedStatement{ +public: + ParsedBadStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length){}; + ParsedStatementKind GetKind() final{ + return ParsedStatementKind ::Bad; + } +}; + class ParsedBlockStatement : public ParsedStatement{ std::vector _statements; public: @@ -86,4 +96,36 @@ public: } }; +class ParsedAssignmentStatement : public ParsedStatement{ + bool _local; + std::string _identifier; + ParsedExpression* _expression; +public: + ParsedAssignmentStatement(bool local, std::string identifier, ParsedExpression* expression, unsigned int start, unsigned int length) + : ParsedStatement(start, length){ + _local = local; + _identifier = std::move(identifier); + _expression = expression; + } + ~ParsedAssignmentStatement() final{ + delete _expression; + } + + ParsedStatementKind GetKind() final{ + return ParsedStatementKind ::Assignment; + } + + bool IsLocal(){ + return _local; + } + + std::string GetIdentifier(){ + return _identifier; + } + + ParsedExpression* GetExpression(){ + return _expression; + } +}; + #endif //PORYGONLANG_PARSEDSTATEMENT_HPP diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 37d3dfa..e2f2faa 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -19,15 +19,53 @@ ParsedScriptStatement* Parser::Parse() { return new ParsedScriptStatement(statements); } +IToken *Parser::Peek() { + return this -> _tokens[_position]; +} + +IToken *Parser::Next() { + this -> _position++; + return this -> _tokens[_position - 1]; +} + ParsedStatement* Parser::ParseStatement(IToken* current){ + if (current->GetKind() == TokenKind::LocalKeyword){ + return ParseAssignment(current); + } else if (this->Peek()->GetKind() == TokenKind::AssignmentToken){ + return ParseAssignment(current); + } return new ParsedExpressionStatement(this -> ParseExpression(current)); } +ParsedStatement *Parser::ParseAssignment(IToken *current) { + bool isLocal = false; + IToken* identifier; + if (current -> GetKind() == TokenKind::LocalKeyword){ + isLocal = true; + identifier = this -> Next(); + } else{ + identifier = current; + } + auto assignmentToken = this->Next(); + auto expression = this -> ParseExpression(this -> Next()); + + if (identifier -> GetKind() != TokenKind::Identifier){ + this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength()); + return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength()); + } + if (assignmentToken -> GetKind() != TokenKind::AssignmentToken){ + this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength()); + return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength()); + } + + auto start = current -> GetStartPosition(); + return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> Value, expression, start, expression->GetEndPosition() - start); +} + ParsedExpression* Parser::ParseExpression(IToken* current){ return this -> ParseBinaryExpression(current, OperatorPrecedence::No); } - OperatorPrecedence GetUnaryPrecedence(TokenKind kind){ switch (kind){ case TokenKind::PlusToken: @@ -135,12 +173,4 @@ ParsedExpression *Parser::ParseParenthesizedExpression(IToken *current) { } -IToken *Parser::Peek() { - return this -> _tokens[_position]; -} - -IToken *Parser::Next() { - this -> _position++; - return this -> _tokens[_position - 1]; -} diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 282a71e..227be4b 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -24,7 +24,10 @@ class Parser { IToken* Peek(); IToken* Next(); + ParsedStatement* ParseStatement(IToken* current); + ParsedStatement* ParseAssignment(IToken *current); + ParsedExpression* ParseExpression(IToken* current); ParsedExpression* ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence); ParsedExpression* ParsePrimaryExpression(IToken* current); diff --git a/tests/parser/ParserTests.cpp b/tests/parser/ParserTests.cpp index c44bf7a..1f9ce70 100644 --- a/tests/parser/ParserTests.cpp +++ b/tests/parser/ParserTests.cpp @@ -154,5 +154,42 @@ TEST_CASE( "Parse String Tokens", "[parser]" ) { REQUIRE(boolean->GetValue() == "foo bar"); } +TEST_CASE( "Parse Global Assignment", "[parser]" ) { + vector v { + new IdentifierToken("foo",0,0), + new SimpleToken(TokenKind::AssignmentToken,0,0), + new SimpleToken(TokenKind::TrueKeyword,0,0), + new SimpleToken(TokenKind::EndOfFile,0,0) + }; + Parser parser = Parser(v, nullptr); + auto parsedStatements = parser.Parse() -> GetStatements(); + REQUIRE(parsedStatements.size() == 1); + auto firstStatement = parsedStatements[0]; + REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); + auto assignment = (ParsedAssignmentStatement*)firstStatement; + REQUIRE(!assignment -> IsLocal()); + REQUIRE(assignment->GetIdentifier() == "foo"); + REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); +} + +TEST_CASE( "Parse local Assignment", "[parser]" ) { + vector v { + new SimpleToken(TokenKind::LocalKeyword,0,0), + new IdentifierToken("foo",0,0), + new SimpleToken(TokenKind::AssignmentToken,0,0), + new SimpleToken(TokenKind::TrueKeyword,0,0), + new SimpleToken(TokenKind::EndOfFile,0,0) + }; + Parser parser = Parser(v, nullptr); + auto parsedStatements = parser.Parse() -> GetStatements(); + REQUIRE(parsedStatements.size() == 1); + auto firstStatement = parsedStatements[0]; + REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); + auto assignment = (ParsedAssignmentStatement*)firstStatement; + REQUIRE(assignment -> IsLocal()); + REQUIRE(assignment->GetIdentifier() == "foo"); + REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); +} + #endif \ No newline at end of file