From 888ae4e303ea6670f3f1cccfec409d92333ce7a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Fri, 3 Jun 2022 18:24:25 +0200
Subject: [PATCH] Check that natural integer cannot become negative on
 decrement

---
 .../IncDecExpressionProcessor.hpp             | 17 +++++++++++-
 tests/test_IncDecExpressionProcessor.cpp      | 27 +++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/src/language/node_processor/IncDecExpressionProcessor.hpp b/src/language/node_processor/IncDecExpressionProcessor.hpp
index 9e50106e5..199d3ebb8 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 a69d9d951..ba04c7ab2 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) {
-- 
GitLab