diff --git a/src/language/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ASTNodeListAffectationExpressionBuilder.cpp index aa8e3804ccb697e09e3b9918530b361ab48e23f8..4cc62a54402f8eaaeee5283d3bf2c7c50831be00 100644 --- a/src/language/ASTNodeListAffectationExpressionBuilder.cpp +++ b/src/language/ASTNodeListAffectationExpressionBuilder.cpp @@ -95,8 +95,7 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor( break; } default: { - throw parse_error("unexpected error: undefined value type for tuple affectation", - std::vector{value_node.begin()}); + throw parse_error("undefined value type for tuple affectation", std::vector{value_node.begin()}); } } }; @@ -142,7 +141,6 @@ ASTNodeListAffectationExpressionBuilder::ASTNodeListAffectationExpressionBuilder throw parse_error("undefined affectation operator for tuples", std::vector{node.begin()}); } } else { - throw parse_error("unexpected error: invalid right hand side in tuple affectation", - std::vector{node.children[1]->begin()}); + throw parse_error("invalid right hand side in tuple affectation", std::vector{node.children[1]->begin()}); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ffa8ee7a33cd63eb39fcabfe255e68605c4e1b7c..c43aebe8c642bc16524f02ac075670cae5af7b85 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable (unit_tests test_ASTNodeFunctionExpressionBuilder.cpp test_ASTNodeIncDecExpressionBuilder.cpp test_ASTNodeJumpPlacementChecker.cpp + test_ASTNodeListAffectationExpressionBuilder.cpp test_ASTNodeListProcessor.cpp test_ASTNodeTypeCleaner.cpp test_ASTNodeUnaryOperatorExpressionBuilder.cpp diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2932203cee2cceeebdc487e175d04db381063b7a --- /dev/null +++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp @@ -0,0 +1,318 @@ +#include <catch2/catch.hpp> + +#include <ASTBuilder.hpp> +#include <ASTNodeDataTypeBuilder.hpp> + +#include <ASTNodeDeclarationToAffectationConverter.hpp> +#include <ASTNodeTypeCleaner.hpp> + +#include <ASTNodeExpressionBuilder.hpp> + +#include <ASTNodeListAffectationExpressionBuilder.hpp> + +#include <ASTSymbolTableBuilder.hpp> + +#include <ASTPrinter.hpp> + +#include <Demangle.hpp> + +#include <PEGGrammar.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>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::declaration>{*ast}; \ + ASTNodeTypeCleaner<language::let_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 CHECK_AST_THROWS_WITH(data, 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(error)>, std::string>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::declaration>{*ast}; \ + ASTNodeTypeCleaner<language::let_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ + } + +TEST_CASE("ASTNodeListAffectationExpressionBuilder", "[language]") +{ + const std::string demangled_stdstring = demangle(typeid(std::string{}).name()); + + SECTION("Declaration") + { + SECTION("without conversion R*R") + { + std::string_view data = R"( +R*R (x,y) = (2.3, 6.2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x:NameProcessor) + | `-(language::name:y:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:2.3:ValueProcessor) + `-(language::real:6.2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("without conversion B*Z*N") + { + std::string_view data = R"( +N n = 2; +B*Z*N (b,z,m) = (false, -2, n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::false_kw:ValueProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + | `-(language::integer:2:ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("with conversion R*B*Z*N") + { + std::string_view data = R"( +R*B*Z*N (r,b,z,m) = (3.2, 1, 6, 2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:6:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("with conversion R*R*R*R") + { + std::string_view data = R"( +R*R*R*R (r,b,z,m) = (3.2, 1, 6, 2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:z:NameProcessor) + | `-(language::name:m:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::integer:1:ValueProcessor) + +-(language::integer:6:ValueProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("from function") + { + std::string_view data = R"( +let f: R -> R*R, x -> (x*x, x+1); +R*R (x,y) = f(2); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:x:NameProcessor) + | `-(language::name:y:NameProcessor) + `-(language::function_evaluation:FunctionProcessor) + +-(language::name:f:NameProcessor) + `-(language::integer:2:ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string without conversion") + { + std::string_view data = R"( +string*string (s,r) = ("foo","bar"); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:s:NameProcessor) + | `-(language::name:r:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::literal:"foo":ValueProcessor) + `-(language::literal:"bar":ValueProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("string with conversion") + { + std::string_view data = R"( +N n =2; +string*string*string*string (r,s,t,u) = (3.2, -2, true, n); +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) + | +-(language::name:n:NameProcessor) + | `-(language::integer:2:ValueProcessor) + `-(language::eq_op:ListAffectationProcessor<language::eq_op>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:s:NameProcessor) + | +-(language::name:t:NameProcessor) + | `-(language::name:u:NameProcessor) + `-(language::expression_list:ASTNodeExpressionListProcessor) + +-(language::real:3.2:ValueProcessor) + +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + | `-(language::integer:2:ValueProcessor) + +-(language::true_kw:ValueProcessor) + `-(language::name:n:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("invalid affectation rhs") + { + std::string_view data = R"( +R x; +R i; +(x,i) = 3; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid right hand side in tuple affectation"}); + } + + SECTION("incompatible list sizes") + { + std::string_view data = R"( +R*R (x,y) = (3, 3, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes 2") + { + std::string_view data = R"( +R*R*R (x,y,z) = (1, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +let f: R -> R, x -> x*x; +R*R (x,y) = f(3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +R*R (x,y) = (2,3); +(x,y) += (1,4); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation operator for tuples"}); + } + + SECTION("invalid operand type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +R*R (x,y) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid operand type for affectation"}); + } + + SECTION("invalid operand type for string affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +string*N (s,n) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid operand type for string affectation"}); + } + + SECTION("invalid value type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +R x; + +(f,x) = (3,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"undefined value type for tuple affectation"}); + } + } +}