diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp index 68bb5a9203f71eb27d7e64a0eb17d0440e7edf9a..a320695ac7b95a29ffa22e4fc5d83f66d5d475c1 100644 --- a/src/language/ASTNodeDataTypeBuilder.cpp +++ b/src/language/ASTNodeDataTypeBuilder.cpp @@ -1,5 +1,7 @@ #include <ASTNodeDataTypeBuilder.hpp> +#include <ASTNodeNaturalConversionChecker.hpp> + #include <PEGGrammar.hpp> #include <PugsAssert.hpp> #include <SymbolTable.hpp> @@ -65,6 +67,15 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const for (auto& child : n.children) { this->_buildNodeDataTypes(*child); } + + if (n.is_type<language::for_statement>()) { + const ASTNode& test_node = *n.children[1]; + + if (not n.children[1]->is_type<language::for_test>()) { + ASTNodeNaturalConversionChecker{test_node, test_node.m_data_type, ASTNodeDataType::bool_t}; + } // in the case of empty for_test (not simplified node), nothing to check! + } + n.m_data_type = ASTNodeDataType::void_t; } else { if (n.has_content()) { @@ -255,26 +266,16 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const n.m_data_type = ASTNodeDataType::void_t; } else if (n.is_type<language::if_statement>() or n.is_type<language::while_statement>()) { n.m_data_type = ASTNodeDataType::void_t; - if ((n.children[0]->m_data_type > ASTNodeDataType::double_t) or - (n.children[0]->m_data_type < ASTNodeDataType::bool_t)) { - const ASTNodeDataType type_0 = n.children[0]->m_data_type; - std::ostringstream message; - message << "Cannot convert data type to boolean value\n" - << "note: incompatible operand '" << n.children[0]->string() << "' of type " << dataTypeName(type_0) - << std::ends; - throw parse_error(message.str(), n.children[0]->begin()); - } + + const ASTNode& test_node = *n.children[0]; + ASTNodeNaturalConversionChecker{test_node, test_node.m_data_type, ASTNodeDataType::bool_t}; + } else if (n.is_type<language::do_while_statement>()) { n.m_data_type = ASTNodeDataType::void_t; - if ((n.children[1]->m_data_type > ASTNodeDataType::double_t) or - (n.children[1]->m_data_type < ASTNodeDataType::bool_t)) { - const ASTNodeDataType type_0 = n.children[1]->m_data_type; - std::ostringstream message; - message << "Cannot convert data type to boolean value\n" - << "note: incompatible operand '" << n.children[1]->string() << "' of type " << dataTypeName(type_0) - << std::ends; - throw parse_error(message.str(), n.children[1]->begin()); - } + + const ASTNode& test_node = *n.children[1]; + ASTNodeNaturalConversionChecker{test_node, test_node.m_data_type, ASTNodeDataType::bool_t}; + } else if (n.is_type<language::unary_not>() or n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or n.is_type<language::eqeq_op>() or diff --git a/tests/test_DoWhileProcessor.cpp b/tests/test_DoWhileProcessor.cpp index 135c8d221dda475ca2552826e7f338fa80b3e8c2..d68b2f9e44b07a7c35fc2cb40b02a5667caa0f0b 100644 --- a/tests/test_DoWhileProcessor.cpp +++ b/tests/test_DoWhileProcessor.cpp @@ -48,6 +48,16 @@ REQUIRE(value == expected_value); \ } +#define CHECK_DO_WHILE_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + TEST_CASE("DoWhileProcessor", "[language]") { SECTION("simple loop") @@ -90,4 +100,17 @@ do { )"; CHECK_WHILE_PROCESSOR_RESULT(data, "i", 12ul); } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +do { +} while(1); +)"; + + CHECK_DO_WHILE_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: Z -> B"); + } + } } diff --git a/tests/test_ForProcessor.cpp b/tests/test_ForProcessor.cpp index 7b4faa85585e36290794a39ea5a5199f2487f3b8..51195d9b3fa75bb5569bef8151a653cc31b9db38 100644 --- a/tests/test_ForProcessor.cpp +++ b/tests/test_ForProcessor.cpp @@ -48,6 +48,16 @@ REQUIRE(value == expected_value); \ } +#define CHECK_FOR_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + TEST_CASE("ForProcessor", "[language]") { SECTION("simple for") @@ -84,4 +94,17 @@ for(N l=0; l<10; ++l) { )"; CHECK_FOR_PROCESSOR_RESULT(data, "i", 42ul); } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +for(N l=0; l; ++l) { +} +)"; + + CHECK_FOR_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: N -> B"); + } + } } diff --git a/tests/test_IfProcessor.cpp b/tests/test_IfProcessor.cpp index 9df57fc071bb385ce57b86ec484145682dd5ad59..492d9b7b308dc06d6c89795b313421eeb2657ffb 100644 --- a/tests/test_IfProcessor.cpp +++ b/tests/test_IfProcessor.cpp @@ -48,6 +48,16 @@ REQUIRE(value == expected_value); \ } +#define CHECK_IF_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + TEST_CASE("IfProcessor", "[language]") { SECTION("simple if(true)") @@ -97,4 +107,18 @@ if(false) { )"; CHECK_IF_PROCESSOR_RESULT(data, "i", 2ul); } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +if (1.2) { +} + +)"; + + CHECK_IF_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: R -> B"); + } + } } diff --git a/tests/test_WhileProcessor.cpp b/tests/test_WhileProcessor.cpp index d9200a1f5395a59de3edeb26297ba856869cf486..98e46e73ee06a3c0f352b823ab46494bcd5425ab 100644 --- a/tests/test_WhileProcessor.cpp +++ b/tests/test_WhileProcessor.cpp @@ -48,6 +48,16 @@ REQUIRE(value == expected_value); \ } +#define CHECK_WHILE_PROCESSOR_THROWS_WITH(data, error_message) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ + } + TEST_CASE("WhileProcessor", "[language]") { SECTION("simple loop") @@ -90,4 +100,17 @@ while(i<10) { )"; CHECK_WHILE_PROCESSOR_RESULT(data, "i", 12ul); } + + SECTION("errors") + { + SECTION("bad test type") + { + std::string_view data = R"( +while(1) { +} +)"; + + CHECK_WHILE_PROCESSOR_THROWS_WITH(data, "invalid implicit conversion: Z -> B"); + } + } }