2020-10-10 12:29:37 +00:00
|
|
|
#include "../../extern/doctest.hpp"
|
|
|
|
#include "../../src/Parser/Parser.hpp"
|
|
|
|
|
|
|
|
using namespace MalachScript;
|
|
|
|
|
|
|
|
#define PARSER_TEST(name, tokens, asserts) \
|
|
|
|
TEST_CASE(name) { \
|
|
|
|
std::vector<Parser::LexToken*> vec = { \
|
|
|
|
tokens, \
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::EndOfFile>(TextSpan(0, 0)), \
|
|
|
|
}; \
|
|
|
|
for (size_t i = 0; i < vec.size() - 1; i++) { \
|
|
|
|
vec[i]->SetNext(vec[i + 1]); \
|
|
|
|
} \
|
|
|
|
Diagnostics::Diagnostics diags; \
|
|
|
|
auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags); \
|
|
|
|
auto* script = parser.Parse(); \
|
|
|
|
REQUIRE(diags.GetMessages().empty()); \
|
|
|
|
asserts; \
|
|
|
|
delete vec[0]; \
|
|
|
|
delete script; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PARSER_TEST_TOKENS(...) __VA_ARGS__
|
|
|
|
|
|
|
|
PARSER_TEST("Parse ``void foobar();``",
|
|
|
|
PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::VoidKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
|
|
|
|
{
|
|
|
|
REQUIRE(script->GetStatements().size() == 1);
|
|
|
|
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
|
2020-10-10 14:04:59 +00:00
|
|
|
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);
|
2020-10-10 12:29:37 +00:00
|
|
|
})
|
|
|
|
|
2020-10-10 14:04:59 +00:00
|
|
|
PARSER_TEST("Parse scoped function without body.",
|
2020-10-10 12:29:37 +00:00
|
|
|
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
|
|
|
|
{
|
|
|
|
REQUIRE(script->GetStatements().size() == 1);
|
|
|
|
REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Func);
|
2020-10-10 14:04:59 +00:00
|
|
|
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<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"par1"),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::BoolKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"par2"),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(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);
|
2020-10-10 12:29:37 +00:00
|
|
|
})
|
2020-10-10 14:20:56 +00:00
|
|
|
|
|
|
|
PARSER_TEST("Parse scoped function with reference parameters without body.",
|
|
|
|
PARSER_TEST_TOKENS(new Parser::IdentifierToken(TextSpan(0, 0), u8"foo"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"bar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::ColonColonSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"baz"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::OpenParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::IntKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::InKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"par1"),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CommaSymbol>(TextSpan(0, 0)),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::BoolKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::AmpersandSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::OutKeyword>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
|
|
|
|
new Parser::IdentifierToken(TextSpan(0, 0), u8"par2"),
|
|
|
|
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::CloseParenthesisSymbol>(TextSpan(0, 0)),
|
|
|
|
new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(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::RefIn);
|
|
|
|
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::RefOut);
|
|
|
|
CHECK(par2.GetIdentifier().GetString() == u8"par2");
|
|
|
|
CHECK(par2.GetDefaultExpression() == nullptr);
|
|
|
|
|
|
|
|
CHECK_FALSE(funcStat->IsConst());
|
|
|
|
CHECK(funcStat->GetFuncAttr() == MalachScript::FuncAttr::None);
|
|
|
|
CHECK(funcStat->GetStatBlock() == nullptr);
|
|
|
|
})
|