From c407ba2f50976e36bffe03e74f5de121a82a4f2b Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 31 May 2019 15:00:14 +0200 Subject: [PATCH] Implements parsing function declarations --- src/Parser/Lexer.cpp | 2 + .../ParsedStatements/ParsedStatement.hpp | 43 +++++++-- src/Parser/Parser.cpp | 93 +++++++++++++++++-- src/Parser/Parser.hpp | 4 +- src/Parser/TokenKind.hpp | 1 + src/Parser/TypedVariableIdentifier.hpp | 25 +++++ src/Utilities/HashedString.hpp | 7 ++ tests/parser/ParserTests.cpp | 31 +++++++ 8 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 src/Parser/TypedVariableIdentifier.hpp diff --git a/src/Parser/Lexer.cpp b/src/Parser/Lexer.cpp index 595b276..882e0c3 100644 --- a/src/Parser/Lexer.cpp +++ b/src/Parser/Lexer.cpp @@ -56,6 +56,8 @@ IToken* Lexer::LexNext(char c){ return new SimpleToken(TokenKind::OpenParenthesis, this -> Position - 1, 1); case ')': return new SimpleToken(TokenKind::CloseParenthesis, this -> Position - 1, 1); + case ',': + return new SimpleToken(TokenKind::CommaToken, this -> Position - 1, 1); case '=': if (Lexer::Peek() == '='){ Lexer::Next(); diff --git a/src/Parser/ParsedStatements/ParsedStatement.hpp b/src/Parser/ParsedStatements/ParsedStatement.hpp index a69e4d0..2093a1e 100644 --- a/src/Parser/ParsedStatements/ParsedStatement.hpp +++ b/src/Parser/ParsedStatements/ParsedStatement.hpp @@ -1,9 +1,3 @@ -#include - -#include - - - #ifndef PORYGONLANG_PARSEDSTATEMENT_HPP #define PORYGONLANG_PARSEDSTATEMENT_HPP @@ -13,13 +7,15 @@ #include "../ParsedExpressions/ParsedExpression.hpp" #include "../../Utilities/HashedString.hpp" +#include "../TypedVariableIdentifier.hpp" enum class ParsedStatementKind{ Bad, Script, Block, Expression, - Assignment + Assignment, + FunctionDeclaration }; class ParsedStatement { @@ -105,6 +101,39 @@ public: } }; +class ParsedFunctionDeclarationStatement : public ParsedStatement{ + HashedString _identifier; + vector _parameters; + ParsedBlockStatement* _block; +public: + ParsedFunctionDeclarationStatement(HashedString identifier, vector parameters, ParsedBlockStatement* block, + unsigned int start, unsigned int length) + : ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)), _block(block){}; + + ~ParsedFunctionDeclarationStatement() override { + for (auto v : _parameters){ + delete v; + } + delete _block; + } + + ParsedStatementKind GetKind() final{ + return ParsedStatementKind ::FunctionDeclaration; + } + + HashedString GetIdentifier(){ + return _identifier; + } + + vector GetParameters(){ + return _parameters; + } + + ParsedBlockStatement* GetBlock(){ + return _block; + } +}; + class ParsedAssignmentStatement : public ParsedStatement{ bool _local; HashedString _identifier; diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index ad445a2..e241f75 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -2,6 +2,7 @@ #include "Parser.hpp" #include "UnaryOperatorKind.hpp" #include "BinaryOperatorKind.hpp" +#include "TypedVariableIdentifier.hpp" ParsedScriptStatement* Parser::Parse() { @@ -11,9 +12,6 @@ ParsedScriptStatement* Parser::Parse() { if (next->GetKind() == TokenKind::EndOfFile){ break; } - if (next->GetKind() == TokenKind::WhiteSpace){ - continue; - } statements.push_back(this -> ParseStatement(next)); } return new ParsedScriptStatement(statements); @@ -29,9 +27,13 @@ IToken *Parser::Next() { } ParsedStatement* Parser::ParseStatement(IToken* current){ - if (current->GetKind() == TokenKind::LocalKeyword){ - return ParseAssignment(current); - } else if (this->Peek()->GetKind() == TokenKind::AssignmentToken){ + auto currentKind = current->GetKind(); + switch (currentKind){ + case TokenKind ::LocalKeyword: return this -> ParseAssignment(current); + case TokenKind ::FunctionKeyword: return this -> ParseFunctionDeclaration(current); + default: break; + } + if (this->Peek()->GetKind() == TokenKind::AssignmentToken){ return ParseAssignment(current); } return new ParsedExpressionStatement(this -> ParseExpression(current)); @@ -62,8 +64,83 @@ ParsedStatement *Parser::ParseAssignment(IToken *current) { return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> Value, expression, start, expression->GetEndPosition() - start); } +ParsedStatement *Parser::ParseBlock(vector endTokens) { + vector statements; + while (true){ + auto next = this -> Next(); + auto nextKind = next->GetKind(); + if (std::find(endTokens.begin(), endTokens.end(), nextKind) != endTokens.end()){ + break; + } + if (nextKind == TokenKind::EndOfFile){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength()); + break; + } + statements.push_back(this -> ParseStatement(next)); + } + return new ParsedBlockStatement(statements); +} + +ParsedStatement *Parser::ParseFunctionDeclaration(IToken *current) { + auto functionIdentifierToken = this->Next(); + auto openParenthesis = this->Next(); + vector parameters; + bool hasErrors = false; + if (functionIdentifierToken->GetKind() != TokenKind::Identifier){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, functionIdentifierToken->GetStartPosition(), functionIdentifierToken->GetLength()); + hasErrors = true; + } + if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, openParenthesis->GetStartPosition(), openParenthesis->GetLength()); + hasErrors = true; + } + + while (true){ + auto type = this->Next(); + auto identifier = this->Next(); + auto next = this->Next(); + if (type->GetKind() != TokenKind::Identifier &&!hasErrors){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength()); + hasErrors = true; + continue; + } + if (identifier->GetKind() != TokenKind::Identifier &&!hasErrors){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength()); + hasErrors = true; + continue; + } + auto typeToken = (IdentifierToken*)type; + auto identifierToken = (IdentifierToken*)identifier; + parameters.push_back(new TypedVariableIdentifier(HashedString(typeToken->Value), HashedString(identifierToken->Value))); + + auto nextKind = next->GetKind(); + if (nextKind == TokenKind::CloseParenthesis || nextKind == TokenKind::EndOfFile){ + break; + } else if (nextKind != TokenKind::CommaToken && !hasErrors){ + this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength()); + hasErrors = true; + } + } + auto block = this -> ParseBlock({TokenKind ::EndKeyword}); + + auto start = current->GetStartPosition(); + if (hasErrors){ + return new ParsedBadStatement(start, block->GetEndPosition() - start); + } + if (block->GetKind() == ParsedStatementKind::Bad){ + return new ParsedBadStatement(start, block->GetEndPosition() - start); + } + auto functionIdentifier = ((IdentifierToken*) functionIdentifierToken)->Value; + return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters, (ParsedBlockStatement*)block, start, block->GetEndPosition() - start); + +} + ParsedExpression* Parser::ParseExpression(IToken* current){ - return this -> ParseBinaryExpression(current, OperatorPrecedence::No); + auto expression = this -> ParseBinaryExpression(current, OperatorPrecedence::No); + if (this -> Peek() -> GetKind() == TokenKind::OpenParenthesis){ + //TODO: Function Evaluation + } + return expression; } OperatorPrecedence GetUnaryPrecedence(TokenKind kind){ @@ -175,3 +252,5 @@ ParsedExpression *Parser::ParseParenthesizedExpression(IToken *current) { + + diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 227be4b..2c497ab 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -26,7 +26,9 @@ class Parser { IToken* Next(); ParsedStatement* ParseStatement(IToken* current); - ParsedStatement* ParseAssignment(IToken *current); + ParsedStatement* ParseAssignment(IToken* current); + ParsedStatement *ParseBlock(vector endTokens); + ParsedStatement* ParseFunctionDeclaration(IToken* current); ParsedExpression* ParseExpression(IToken* current); ParsedExpression* ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence); diff --git a/src/Parser/TokenKind.hpp b/src/Parser/TokenKind.hpp index 5a688e3..4286370 100644 --- a/src/Parser/TokenKind.hpp +++ b/src/Parser/TokenKind.hpp @@ -15,6 +15,7 @@ enum class TokenKind{ InequalityToken, OpenParenthesis, CloseParenthesis, + CommaToken, Identifier, diff --git a/src/Parser/TypedVariableIdentifier.hpp b/src/Parser/TypedVariableIdentifier.hpp new file mode 100644 index 0000000..c289e79 --- /dev/null +++ b/src/Parser/TypedVariableIdentifier.hpp @@ -0,0 +1,25 @@ + +#ifndef PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP +#define PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP + +#include "../Utilities/HashedString.hpp" + +class TypedVariableIdentifier{ + HashedString _type; + HashedString _identifier; +public: + TypedVariableIdentifier(HashedString type, HashedString identifier) + : _type(type), _identifier(identifier) + { + } + + HashedString GetType(){ + return _type; + } + + HashedString GetIdentifier(){ + return _identifier; + } +}; + +#endif //PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP diff --git a/src/Utilities/HashedString.hpp b/src/Utilities/HashedString.hpp index b276f55..58517a9 100644 --- a/src/Utilities/HashedString.hpp +++ b/src/Utilities/HashedString.hpp @@ -19,6 +19,13 @@ public: const int GetHash(){ return _hash; } + + bool operator==(const HashedString& b) const{ + return _hash == b._hash; + } + bool operator!=(const HashedString& b) const{ + return _hash != b._hash; + } }; #endif //PORYGONLANG_HASHEDSTRING_HPP diff --git a/tests/parser/ParserTests.cpp b/tests/parser/ParserTests.cpp index 4455fe3..72550f3 100644 --- a/tests/parser/ParserTests.cpp +++ b/tests/parser/ParserTests.cpp @@ -191,5 +191,36 @@ TEST_CASE( "Parse local Assignment", "[parser]" ) { REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); } +TEST_CASE( "Parse function declaration", "[parser]" ){ + vector v { + new SimpleToken(TokenKind::FunctionKeyword,0,0), + new IdentifierToken("foo",0,0), + new SimpleToken(TokenKind::OpenParenthesis,0,0), + new IdentifierToken("number",0,0), + new IdentifierToken("bar",0,0), + new SimpleToken(TokenKind::CommaToken,0,0), + new IdentifierToken("number",0,0), + new IdentifierToken("par",0,0), + new SimpleToken(TokenKind::CloseParenthesis,0,0), + new IdentifierToken("bar",0,0), + new SimpleToken(TokenKind::PlusToken,0,0), + new IdentifierToken("par",0,0), + new SimpleToken(TokenKind::EndKeyword,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::FunctionDeclaration); + auto functionDeclaration = (ParsedFunctionDeclarationStatement*)firstStatement; + REQUIRE(functionDeclaration->GetIdentifier() == HashedString("foo")); + auto parameters = functionDeclaration->GetParameters(); + CHECK(parameters[0]->GetType() == HashedString("number")); + CHECK(parameters[0]->GetIdentifier() == HashedString("bar")); + CHECK(parameters[1]->GetType() == HashedString("number")); + CHECK(parameters[1]->GetIdentifier() == HashedString("par")); +} + #endif \ No newline at end of file