diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp index 58d6d0cf1e59920fd5f382d61360e0692d726e43..4a56bdae9cc854582e7e8df435ebbaea8e01a582 100644 --- a/src/language/ast/ASTNodeDataTypeBuilder.cpp +++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp @@ -261,48 +261,9 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const } } - auto check_image_type = [&](const ASTNode& image_node) { - ASTNodeDataType value_type; - if (image_node.is_type<language::B_set>()) { - value_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>(); - } else if (image_node.is_type<language::Z_set>()) { - value_type = ASTNodeDataType::build<ASTNodeDataType::int_t>(); - } else if (image_node.is_type<language::N_set>()) { - value_type = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>(); - } else if (image_node.is_type<language::R_set>()) { - value_type = ASTNodeDataType::build<ASTNodeDataType::double_t>(); - } else if (image_node.is_type<language::vector_type>()) { - value_type = getVectorDataType(image_node); - } else if (image_node.is_type<language::string_type>()) { - value_type = ASTNodeDataType::build<ASTNodeDataType::string_t>(); - } - - // LCOV_EXCL_START - if (value_type == ASTNodeDataType::undefined_t) { - throw ParseError("invalid value type", image_node.begin()); - } - // LCOV_EXCL_STOP - }; - -#warning probably useless now - if (image_domain_node.is_type<language::type_expression>()) { - std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list; - sub_data_type_list.reserve(image_domain_node.children.size()); - - for (size_t i = 0; i < image_domain_node.children.size(); ++i) { - check_image_type(*image_domain_node.children[i]); - sub_data_type_list.push_back( - std::make_shared<const ASTNodeDataType>(image_domain_node.children[i]->m_data_type)); - } - image_domain_node.m_data_type = ASTNodeDataType::build<ASTNodeDataType::typename_t>( - ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list)); - } else { - check_image_type(image_domain_node); - } - this->_buildNodeDataTypes(image_expression_node); - ASTNodeNaturalConversionChecker(image_expression_node, image_domain_node.m_data_type); + ASTNodeNaturalConversionChecker<AllowRToR1Conversion>(image_expression_node, image_domain_node.m_data_type); n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>(); return; diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.cpp b/src/language/ast/ASTNodeNaturalConversionChecker.cpp index b740faa821c41d55fcd47e2590c21c3512fd71c1..cf1ccdabf1cffa0e2256ed17e13dca6717229fc9 100644 --- a/src/language/ast/ASTNodeNaturalConversionChecker.cpp +++ b/src/language/ast/ASTNodeNaturalConversionChecker.cpp @@ -4,12 +4,21 @@ #include <language/utils/ParseError.hpp> #include <utils/Exceptions.hpp> +template <typename RToR1Conversion> void -ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& node, - const ASTNodeDataType& data_type, - const ASTNodeDataType& target_data_type) const +ASTNodeNaturalConversionChecker<RToR1Conversion>::_checkIsNaturalTypeConversion( + const ASTNode& node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const { if (not isNaturalConversion(data_type, target_data_type)) { + if constexpr (std::is_same_v<RToR1ConversionStrategy, AllowRToR1Conversion>) { + if ((target_data_type == ASTNodeDataType::vector_t) and (target_data_type.dimension() == 1)) { + if (isNaturalConversion(data_type, ASTNodeDataType::build<ASTNodeDataType::double_t>())) { + return; + } + } + } std::ostringstream error_message; error_message << "invalid implicit conversion: "; error_message << rang::fgB::red << dataTypeName(data_type) << " -> " << dataTypeName(target_data_type) @@ -23,21 +32,29 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& no } } +template <typename RToR1Conversion> void -ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNode& node, - const ASTNodeDataType& data_type, - const ASTNodeDataType& target_data_type) const +ASTNodeNaturalConversionChecker<RToR1Conversion>::_checkIsNaturalExpressionConversion( + const ASTNode& node, + const ASTNodeDataType& data_type, + const ASTNodeDataType& target_data_type) const { if (target_data_type == ASTNodeDataType::typename_t) { this->_checkIsNaturalExpressionConversion(node, data_type, target_data_type.contentType()); } else if (target_data_type == ASTNodeDataType::vector_t) { - switch (node.m_data_type) { + switch (data_type) { case ASTNodeDataType::list_t: { - if (node.children.size() != target_data_type.dimension()) { + const auto& content_type_list = data_type.contentTypeList(); + if (content_type_list.size() != target_data_type.dimension()) { throw ParseError("incompatible dimensions in affectation", std::vector{node.begin()}); } - for (const auto& child : node.children) { - this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, + + Assert(content_type_list.size() == node.children.size()); + for (size_t i = 0; i < content_type_list.size(); ++i) { + const auto& child_type = *content_type_list[i]; + const auto& child_node = *node.children[i]; + Assert(child_type == child_node.m_data_type); + this->_checkIsNaturalExpressionConversion(child_node, child_type, ASTNodeDataType::build<ASTNodeDataType::double_t>()); } @@ -99,15 +116,22 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo } } -ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNode& data_node, - const ASTNodeDataType& target_data_type) +template <typename RToR1Conversion> +ASTNodeNaturalConversionChecker<RToR1Conversion>::ASTNodeNaturalConversionChecker( + const ASTNode& data_node, + const ASTNodeDataType& target_data_type) { this->_checkIsNaturalExpressionConversion(data_node, data_node.m_data_type, target_data_type); } -ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNodeSubDataType& data_node_sub_data_type, - const ASTNodeDataType& target_data_type) +template <typename RToR1Conversion> +ASTNodeNaturalConversionChecker<RToR1Conversion>::ASTNodeNaturalConversionChecker( + const ASTNodeSubDataType& data_node_sub_data_type, + const ASTNodeDataType& target_data_type) { this->_checkIsNaturalExpressionConversion(data_node_sub_data_type.m_parent_node, data_node_sub_data_type.m_data_type, target_data_type); } + +template class ASTNodeNaturalConversionChecker<AllowRToR1Conversion>; +template class ASTNodeNaturalConversionChecker<DisallowRToR1Conversion>; diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.hpp b/src/language/ast/ASTNodeNaturalConversionChecker.hpp index 9d89e3b4925b6aaebfbc06c92fe30164e9b061fd..ebf83d7ca3d750d33fe6d18a6d0388bdea4c627c 100644 --- a/src/language/ast/ASTNodeNaturalConversionChecker.hpp +++ b/src/language/ast/ASTNodeNaturalConversionChecker.hpp @@ -5,9 +5,20 @@ #include <language/ast/ASTNodeDataType.hpp> #include <language/ast/ASTNodeSubDataType.hpp> +struct AllowRToR1Conversion +{ +}; + +struct DisallowRToR1Conversion +{ +}; + +template <typename RToR1Conversion = DisallowRToR1Conversion> class ASTNodeNaturalConversionChecker { private: + using RToR1ConversionStrategy = RToR1Conversion; + void _checkIsNaturalTypeConversion(const ASTNode& ast_node, const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type) const; diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp index 3ce9d041604f5a10cbe9ea97f063c3d24a1fd04d..5a071366578271161d21a27d2ce0d5e883f9c7c3 100644 --- a/tests/test_ASTNodeFunctionExpressionBuilder.cpp +++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp @@ -53,10 +53,25 @@ \ ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ - REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, ParseError); \ + REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, ParseError); \ } -#define CHECK_AST_THROWS_WITH(data, error) \ +#define CHECK_TYPE_BUILDER_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); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error); \ + } + +#define CHECK_EXPRESSION_BUILDER_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>); \ @@ -656,60 +671,54 @@ sum(2); { std::string_view data = R"( let bad_conv : string -> R, s -> s; -bad_conv(2); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"}); } SECTION("R -> B") { std::string_view data = R"( let bad_B : R -> B, x -> x; -bad_B(2); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); } SECTION("R -> N") { std::string_view data = R"( let next : R -> N, x -> x; -next(6); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); } SECTION("R -> Z") { std::string_view data = R"( let prev : R -> Z, x -> x; -prev(-3); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); } SECTION("N -> B") { std::string_view data = R"( let bad_B : N -> B, n -> n; -bad_B(3); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); } SECTION("Z -> B") { std::string_view data = R"( let bad_B : Z -> B, n -> n; -bad_B(3); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); + CHECK_TYPE_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); } } @@ -723,7 +732,7 @@ let n : N, n = 2; negate(n); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); } SECTION("Z -> B") @@ -733,7 +742,7 @@ let negate : B -> B, b -> not b; negate(3-4); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); } SECTION("R -> B") @@ -743,7 +752,7 @@ let negate : B -> B, b -> not b; negate(3.24); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); } SECTION("R -> N") @@ -753,7 +762,7 @@ let next : N -> N, n -> n+1; next(3.24); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); } SECTION("R -> Z") @@ -763,7 +772,7 @@ let prev : Z -> Z, z -> z-1; prev(3 + .24); )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); } } @@ -776,7 +785,7 @@ let f : R^2 -> R, x->x[0]; f((1,2,3)); )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); } SECTION("tuple[2] -> R^3") @@ -786,7 +795,7 @@ let f : R^3 -> R, x->x[0]; f((1,2)); )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); } SECTION("compound tuple[3] -> R^2") @@ -796,7 +805,7 @@ let f : R*R^2 -> R, (t,x)->x[0]; f(1,(1,2,3)); )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); } SECTION("compound tuple[2] -> R^3") @@ -806,7 +815,7 @@ let f : R^3*R^2 -> R, (x,y)->x[0]*y[1]; f((1,2),(3,4)); )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"}); } SECTION("list instead of tuple -> R^3") @@ -816,7 +825,7 @@ let f : R^3 -> R, x -> x[0]*x[1]; f(1,2,3); )"; - CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments: expecting 1, provided 3"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"bad number of arguments: expecting 1, provided 3"}); } SECTION("list instead of tuple -> R^3*R^2") @@ -826,7 +835,7 @@ let f : R^3*R^2 -> R, (x,y) -> x[0]*x[1]-y[0]; f((1,2,3),2,3); )"; - CHECK_AST_THROWS_WITH(data, std::string{"bad number of arguments: expecting 2, provided 3"}); + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"bad number of arguments: expecting 2, provided 3"}); } } } diff --git a/tests/test_ASTNodeNaturalConversionChecker.cpp b/tests/test_ASTNodeNaturalConversionChecker.cpp index a9c187551f42d64860569a60b4f3584ac058b963..ed1e834c016ac9e7c6f3d796a7018ce290aa9324 100644 --- a/tests/test_ASTNodeNaturalConversionChecker.cpp +++ b/tests/test_ASTNodeNaturalConversionChecker.cpp @@ -95,7 +95,8 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") SECTION("list -> R^1") { - data_node->m_data_type = list_dt; + data_node->m_data_type = + ASTNodeDataType::build<ASTNodeDataType::list_t>({std::make_shared<const ASTNodeDataType>(double_dt)}); { std::unique_ptr list0_node = std::make_unique<ASTNode>(); list0_node->m_data_type = double_dt; @@ -140,7 +141,9 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") SECTION("list -> R^2") { - data_node->m_data_type = list_dt; + data_node->m_data_type = + ASTNodeDataType::build<ASTNodeDataType::list_t>({std::make_shared<const ASTNodeDataType>(double_dt), + std::make_shared<const ASTNodeDataType>(unsigned_int_dt)}); { std::unique_ptr list0_node = std::make_unique<ASTNode>(); list0_node->m_data_type = double_dt; @@ -163,7 +166,9 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") SECTION("list -> R^3") { - data_node->m_data_type = list_dt; + data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>( + {std::make_shared<const ASTNodeDataType>(double_dt), std::make_shared<const ASTNodeDataType>(unsigned_int_dt), + std::make_shared<const ASTNodeDataType>(int_dt)}); { std::unique_ptr list0_node = std::make_unique<ASTNode>(); list0_node->m_data_type = double_dt; @@ -765,7 +770,8 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") SECTION("list1 -> R^d") { - data_node->m_data_type = list_dt; + data_node->m_data_type = + ASTNodeDataType::build<ASTNodeDataType::list_t>({std::make_shared<const ASTNodeDataType>(double_dt)}); { std::unique_ptr list0_node = std::make_unique<ASTNode>(); list0_node->m_data_type = double_dt; @@ -817,7 +823,9 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]") SECTION("list3 -> R^d") { - data_node->m_data_type = list_dt; + data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>( + {std::make_shared<const ASTNodeDataType>(double_dt), std::make_shared<const ASTNodeDataType>(unsigned_int_dt), + std::make_shared<const ASTNodeDataType>(int_dt)}); { std::unique_ptr list0_node = std::make_unique<ASTNode>(); list0_node->m_data_type = double_dt;