Select Git revision
test_ASTNodeIncDecExpressionBuilder.cpp
test_ASTNodeIncDecExpressionBuilder.cpp 13.55 KiB
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>
#include <language/ast/ASTBuilder.hpp>
#include <language/ast/ASTModulesImporter.hpp>
#include <language/ast/ASTNodeDataTypeBuilder.hpp>
#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
#include <language/ast/ASTNodeExpressionBuilder.hpp>
#include <language/ast/ASTNodeIncDecExpressionBuilder.hpp>
#include <language/ast/ASTNodeTypeCleaner.hpp>
#include <language/ast/ASTSymbolTableBuilder.hpp>
#include <language/utils/ASTPrinter.hpp>
#include <language/utils/OperatorRepository.hpp>
#include <utils/Demangle.hpp>
#include <pegtl/string_input.hpp>
#define CHECK_AST(data, expected_output) \
{ \
static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \
static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view> or \
std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \
\
TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
auto ast = ASTBuilder::build(input); \
\
ASTModulesImporter{*ast}; \
ASTNodeTypeCleaner<language::import_instruction>{*ast}; \
\
ASTSymbolTableBuilder{*ast}; \
ASTNodeDataTypeBuilder{*ast}; \
\
ASTNodeDeclarationToAffectationConverter{*ast}; \
ASTNodeTypeCleaner<language::var_declaration>{*ast}; \
\
ASTNodeExpressionBuilder{*ast}; \
\
std::stringstream ast_output; \
ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \
\
REQUIRE(ast_output.str() == expected_output); \
}
#define DISALLOWED_CHAINED_AST(data, expected_error) \
{ \
static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \
static_assert(std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view> or \
std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>); \
\
TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
auto ast = ASTBuilder::build(input); \
\
ASTModulesImporter{*ast}; \
ASTNodeTypeCleaner<language::import_instruction>{*ast}; \
\
ASTSymbolTableBuilder{*ast}; \
ASTNodeDataTypeBuilder{*ast}; \
\
ASTNodeDeclarationToAffectationConverter{*ast}; \
ASTNodeTypeCleaner<language::var_declaration>{*ast}; \
\
REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \
}
// clazy:excludeall=non-pod-global-static
TEST_CASE("ASTNodeIncDecExpressionBuilder", "[language]")
{
SECTION("Pre-increment")
{
SECTION("N")
{
std::string_view data = R"(
let i : N, i=0;
++i;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, unsigned long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
SECTION("Z")
{
std::string_view data = R"(
let i : Z, i=0;
++i;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::unary_plusplus:IncDecExpressionProcessor<language::unary_plusplus, long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
}
SECTION("Pre-decrement")
{
SECTION("N")
{
std::string_view data = R"(
let i : N, i=1;
--i;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:1:ValueProcessor)
`-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, unsigned long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
SECTION("Z")
{
std::string_view data = R"(
let i : Z, i=0;
--i;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::unary_minusminus:IncDecExpressionProcessor<language::unary_minusminus, long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
}
SECTION("Post-increment")
{
SECTION("N")
{
std::string_view data = R"(
let i : N, i=0;
i++;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, unsigned long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
SECTION("Z")
{
std::string_view data = R"(
let i : Z, i=0;
i++;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::post_plusplus:IncDecExpressionProcessor<language::post_plusplus, long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
}
SECTION("Post-decrement")
{
SECTION("N")
{
std::string_view data = R"(
let i : N, i=1;
i--;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:1:ValueProcessor)
`-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, unsigned long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
SECTION("Z")
{
std::string_view data = R"(
let i : Z, i=0;
i--;
)";
std::string_view result = R"(
(root:ASTNodeListProcessor)
+-(language::eq_op:AffectationProcessor<language::eq_op, long, long>)
| +-(language::name:i:NameProcessor)
| `-(language::integer:0:ValueProcessor)
`-(language::post_minusminus:IncDecExpressionProcessor<language::post_minusminus, long>)
`-(language::name:i:NameProcessor)
)";
CHECK_AST(data, result);
}
}
SECTION("Errors")
{
SECTION("Undefined operator")
{
auto& operator_repository = OperatorRepository::instance();
auto optional_value_type = operator_repository.getIncDecOperatorValueType("string ++");
REQUIRE(not optional_value_type.has_value());
}
SECTION("Invalid operand type")
{
auto ast = std::make_unique<ASTNode>();
ast->set_type<language::unary_plusplus>();
ast->m_data_type = ASTNodeDataType::build<ASTNodeDataType::undefined_t>();
ast->children.emplace_back(std::make_unique<ASTNode>());
REQUIRE_THROWS_WITH(ASTNodeIncDecExpressionBuilder{*ast}, "invalid operand type, expecting a variable");
}
SECTION("Invalid data type")
{
auto ast = std::make_unique<ASTNode>();
ast->set_type<language::unary_plusplus>();
ast->children.emplace_back(std::make_unique<ASTNode>());
ast->children[0]->set_type<language::name>();
REQUIRE_THROWS_WITH(ASTNodeIncDecExpressionBuilder{*ast}, "undefined affectation type: ++ undefined");
}
SECTION("Not allowed chained ++/--")
{
SECTION("++ ++ a")
{
std::string_view data = R"(
1 ++ ++;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("++ -- a")
{
std::string_view data = R"(
1 ++ --;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("-- ++ a")
{
std::string_view data = R"(
1 -- ++;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("-- -- a")
{
std::string_view data = R"(
1 -- --;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("a ++ ++")
{
std::string_view data = R"(
++ ++ 1;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("a ++ --")
{
std::string_view data = R"(
++ -- 1;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("a -- ++")
{
std::string_view data = R"(
-- ++ 1;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("a -- --")
{
std::string_view data = R"(
-- -- 1;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("++ (a ++)")
{
std::string_view data = R"(
++ (1 ++);
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("++ (a --)")
{
std::string_view data = R"(
++ (1 --);
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("-- (a ++)")
{
std::string_view data = R"(
-- (1 ++);
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("-- (a --)")
{
std::string_view data = R"(
-- (1 --);
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("(++ a) ++")
{
std::string_view data = R"(
(++ 1) ++;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("(++ a) --")
{
std::string_view data = R"(
(++ 1) --;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("(-- a) ++")
{
std::string_view data = R"(
(-- 1) ++;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
SECTION("(-- a) --")
{
std::string_view data = R"(
(-- 1) --;
)";
std::string error_message = R"(invalid operand type, expecting a variable)";
DISALLOWED_CHAINED_AST(data, error_message)
}
}
}
}