From f5baed48a96d96dc07318f660145bc4f597c28de Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 10 Oct 2020 16:04:59 +0200 Subject: [PATCH] Lots more tests for function statements, fixes several bugs. --- src/Parser/Parser.cpp | 21 ++--- src/Parser/Statements/ParsedStatement.hpp | 4 +- tests/ParserTests/FunctionTests.cpp | 105 +++++++++++++++++++++- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 1186559..912604a 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -300,8 +300,8 @@ namespace MalachScript::Parser { } while (currentToken != nullptr && currentToken->GetKind() == LexTokenKind::ColonColonSymbol) { + PROGRESS_TOKEN(currentToken); const auto* n = currentToken; - PROGRESS_TOKEN(n); if (ParseIdentifier(identifier, n)) { PROGRESS_TOKEN(n); if (n->GetKind() == LexTokenKind::ColonColonSymbol) { @@ -341,12 +341,13 @@ namespace MalachScript::Parser { } while (true) { parameters.emplace_back(); - auto parameter = parameters.at(parameters.size() - 1); + auto& parameter = parameters.at(parameters.size() - 1); if (!ParseType((const ParsedStatement*&)parameter.GetTypeStatement(), currentToken)) { LogError(Diagnostics::DiagnosticType::UnexpectedToken, currentToken->GetSpan()); } ParseTypeMod(parameter.GetTypeMod()); ParseIdentifier(parameter.GetIdentifier(), currentToken); + PROGRESS_TOKEN(currentToken); if (currentToken->GetKind() != LexTokenKind::CommaSymbol) { break; } @@ -390,14 +391,14 @@ namespace MalachScript::Parser { 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: PrimitiveTypes::UintName(); return true; - case LexTokenKind::Uint8Keyword: PrimitiveTypes::Uint8Name(); return true; - case LexTokenKind::Uint16Keyword: PrimitiveTypes::Uint16Name(); return true; - case LexTokenKind::Uint32Keyword: PrimitiveTypes::Uint32Name(); return true; - case LexTokenKind::Uint64Keyword: PrimitiveTypes::Uint64Name(); return true; - case LexTokenKind::FloatKeyword: PrimitiveTypes::FloatName(); return true; - case LexTokenKind::DoubleKeyword: PrimitiveTypes::DoubleName(); return true; - case LexTokenKind::BoolKeyword: PrimitiveTypes::BoolName(); 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; } } diff --git a/src/Parser/Statements/ParsedStatement.hpp b/src/Parser/Statements/ParsedStatement.hpp index a4394a0..15b874d 100644 --- a/src/Parser/Statements/ParsedStatement.hpp +++ b/src/Parser/Statements/ParsedStatement.hpp @@ -106,7 +106,7 @@ namespace MalachScript::Parser { class ParsedParameter { private: const ParsedTypeStatement* _typeStatement = nullptr; - TypeMod _typeMod; + TypeMod _typeMod = TypeMod::None; Identifier _identifier; const ParsedExpression* _defaultExpression = nullptr; @@ -132,6 +132,8 @@ namespace MalachScript::Parser { public: ParsedParamListStatement(TextSpan span, std::vector parameters) : ParsedStatementImpl(span), _parameters(std::move(parameters)){}; + + [[nodiscard]] const std::vector& GetParameters() const noexcept { return _parameters; } }; class ParsedFuncStatement : public ParsedStatementImpl { diff --git a/tests/ParserTests/FunctionTests.cpp b/tests/ParserTests/FunctionTests.cpp index 743c734..42cff1c 100644 --- a/tests/ParserTests/FunctionTests.cpp +++ b/tests/ParserTests/FunctionTests.cpp @@ -33,9 +33,26 @@ PARSER_TEST("Parse ``void foobar();``", { REQUIRE(script->GetStatements().size() == 1); REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func); + auto funcStat = (const MalachScript::Parser::ParsedFuncStatement*)script->GetStatements()[0].get(); + CHECK_FALSE(funcStat->IsShared()); + CHECK_FALSE(funcStat->IsExternal()); + CHECK(funcStat->GetAccess() == MalachScript::AccessModifier::Public); + auto type = (const MalachScript::Parser::ParsedTypeStatement*)funcStat->GetTypeStatement().get(); + CHECK_FALSE(type->IsConst()); + CHECK_FALSE(type->IsArray()); + CHECK_FALSE(type->IsHandle()); + auto& id = type->GetScopedIdentifier(); + CHECK(id.GetIdentifier().GetString() == u8"void"); + CHECK_FALSE(funcStat->ReturnsReference()); + CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); + auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); + CHECK(paramList->GetParameters().empty()); + CHECK_FALSE(funcStat->IsConst()); + CHECK(funcStat->GetFuncAttr() == MalachScript::FuncAttr::None); + CHECK(funcStat->GetStatBlock() == nullptr); }) -PARSER_TEST("Parse ``foo::bar::baz foobar();``", +PARSER_TEST("Parse scoped function without body.", PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), new Parser::LexTokenImpl(TextSpan(0, 0)), new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"), @@ -49,4 +66,90 @@ PARSER_TEST("Parse ``foo::bar::baz foobar();``", { REQUIRE(script->GetStatements().size() == 1); REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func); + auto funcStat = (const MalachScript::Parser::ParsedFuncStatement*)script->GetStatements()[0].get(); + CHECK_FALSE(funcStat->IsShared()); + CHECK_FALSE(funcStat->IsExternal()); + CHECK(funcStat->GetAccess() == MalachScript::AccessModifier::Public); + auto type = (const MalachScript::Parser::ParsedTypeStatement*)funcStat->GetTypeStatement().get(); + CHECK_FALSE(type->IsConst()); + CHECK_FALSE(type->IsArray()); + CHECK_FALSE(type->IsHandle()); + auto& id = type->GetScopedIdentifier(); + CHECK(id.GetIdentifier().GetString() == u8"baz"); + CHECK(id.GetScope()[1].GetString() == u8"bar"); + CHECK(id.GetScope()[0].GetString() == u8"foo"); + CHECK_FALSE(funcStat->ReturnsReference()); + CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); + auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); + CHECK(paramList->GetParameters().empty()); + CHECK_FALSE(funcStat->IsConst()); + CHECK(funcStat->GetFuncAttr() == MalachScript::FuncAttr::None); + CHECK(funcStat->GetStatBlock() == nullptr); + }) + +PARSER_TEST("Parse scoped function with parameters without body.", + PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"), + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"), + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"), + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"), + new Parser::LexTokenImpl(TextSpan(0, 0)), + + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::IdentifierToken(TextSpan(0, 0), u8"par1"), + + new Parser::LexTokenImpl(TextSpan(0, 0)), + + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::IdentifierToken(TextSpan(0, 0), u8"par2"), + + new Parser::LexTokenImpl(TextSpan(0, 0)), + new Parser::LexTokenImpl(TextSpan(0, 0))), + { + REQUIRE(script->GetStatements().size() == 1); + REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func); + auto funcStat = (const MalachScript::Parser::ParsedFuncStatement*)script->GetStatements()[0].get(); + CHECK_FALSE(funcStat->IsShared()); + CHECK_FALSE(funcStat->IsExternal()); + CHECK(funcStat->GetAccess() == MalachScript::AccessModifier::Public); + auto type = (const MalachScript::Parser::ParsedTypeStatement*)funcStat->GetTypeStatement().get(); + CHECK_FALSE(type->IsConst()); + CHECK_FALSE(type->IsArray()); + CHECK_FALSE(type->IsHandle()); + auto& id = type->GetScopedIdentifier(); + CHECK(id.GetIdentifier().GetString() == u8"baz"); + CHECK(id.GetScope()[1].GetString() == u8"bar"); + CHECK(id.GetScope()[0].GetString() == u8"foo"); + CHECK_FALSE(funcStat->ReturnsReference()); + CHECK(funcStat->GetIdentifier().GetString() == u8"foobar"); + auto paramList = (const MalachScript::Parser::ParsedParamListStatement*)funcStat->GetParamList().get(); + CHECK(paramList->GetParameters().size() == 2); + + auto& par1 = paramList->GetParameters()[0]; + CHECK_FALSE(par1.GetTypeStatement()->IsConst()); + CHECK_FALSE(par1.GetTypeStatement()->IsArray()); + CHECK_FALSE(par1.GetTypeStatement()->IsHandle()); + auto& par1TypeId = par1.GetTypeStatement()->GetScopedIdentifier(); + CHECK(par1TypeId.GetIdentifier().GetString() == u8"int"); + CHECK(par1.GetTypeMod() == TypeMod::None); + CHECK(par1.GetIdentifier().GetString() == u8"par1"); + CHECK(par1.GetDefaultExpression() == nullptr); + + auto& par2 = paramList->GetParameters()[1]; + CHECK_FALSE(par2.GetTypeStatement()->IsConst()); + CHECK_FALSE(par2.GetTypeStatement()->IsArray()); + CHECK_FALSE(par2.GetTypeStatement()->IsHandle()); + auto& par2TypeId = par2.GetTypeStatement()->GetScopedIdentifier(); + CHECK(par2TypeId.GetIdentifier().GetString() == u8"bool"); + CHECK(par2.GetTypeMod() == TypeMod::None); + CHECK(par2.GetIdentifier().GetString() == u8"par2"); + CHECK(par2.GetDefaultExpression() == nullptr); + + CHECK_FALSE(funcStat->IsConst()); + CHECK(funcStat->GetFuncAttr() == MalachScript::FuncAttr::None); + CHECK(funcStat->GetStatBlock() == nullptr); })