diff --git a/src/language/node_processor/IncDecExpressionProcessor.hpp b/src/language/node_processor/IncDecExpressionProcessor.hpp index 9e50106e5c531e8f5cd3dcd546bf131570c499c6..199d3ebb834e7b89dfdc714b89977c6ae78c7b0c 100644 --- a/src/language/node_processor/IncDecExpressionProcessor.hpp +++ b/src/language/node_processor/IncDecExpressionProcessor.hpp @@ -16,6 +16,11 @@ struct IncDecOp<language::unary_minusminus> PUGS_INLINE A eval(A& a) { + if constexpr (std::is_same_v<A, uint64_t>) { + if (a == 0) { + throw std::domain_error("decrement would produce negative value"); + } + } return --a; } }; @@ -38,6 +43,11 @@ struct IncDecOp<language::post_minusminus> PUGS_INLINE A eval(A& a) { + if constexpr (std::is_same_v<A, uint64_t>) { + if (a == 0) { + throw std::domain_error("decrement would produce negative value"); + } + } return a--; } }; @@ -64,7 +74,12 @@ class IncDecExpressionProcessor final : public INodeProcessor DataVariant execute(ExecutionPolicy&) { - return IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value)); + try { + return IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value)); + } + catch (std::domain_error& e) { + throw ParseError(e.what(), m_node.children[0]->begin()); + } } IncDecExpressionProcessor(ASTNode& node) : m_node{node} diff --git a/tests/test_IncDecExpressionProcessor.cpp b/tests/test_IncDecExpressionProcessor.cpp index a69d9d951986d111bc2d2616c675e2ce93ce713f..ba04c7ab259797b49ca6a9ffd1eb57f5d1a72b38 100644 --- a/tests/test_IncDecExpressionProcessor.cpp +++ b/tests/test_IncDecExpressionProcessor.cpp @@ -58,6 +58,23 @@ REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast}, error_message); \ } +#define CHECK_INCDEC_THROWS_WITH(data, error_message) \ + { \ + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + \ + REQUIRE_THROWS_WITH(ast->execute(exec_policy), error_message); \ + } + // clazy:excludeall=non-pod-global-static TEST_CASE("IncDecExpressionProcessor", "[language]") @@ -124,6 +141,16 @@ TEST_CASE("IncDecExpressionProcessor", "[language]") SECTION("errors") { + SECTION("negative pre -- operator for N") + { + CHECK_INCDEC_THROWS_WITH(R"(let n:N, n=0;--n;)", "decrement would produce negative value"); + } + + SECTION("negative post -- operator for N") + { + CHECK_INCDEC_THROWS_WITH(R"(let n:N, n=0;n--;)", "decrement would produce negative value"); + } + SECTION("undefined pre -- operator") { auto error_message = [](std::string type_name) {