From dd076908a2afc59a935122ba2e9428c52717f8ab Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 7 Feb 2020 11:11:26 +0100
Subject: [PATCH] Allow '0' to initialize R^d in function arguments and return

For instance, the following code is now allowed
``
// '0' argument interpreted as 0 in R^d
let f0: R^3->R, x -> x[2];
R x0 = f0(0);

let f1: R^3*R->R, (x,t) -> x[2]*t;
R x1 = f1(0, 1);

// '0' returned and interpreted as 0 in R^d
let f2: R->R^3*R, x->(0, 2*x);
R^3*R (x2,t2) = f2(2);

let f3: R->R^3, x->0;
R^3 x3 = f3(2.3);
``
---
 .../ASTNodeAffectationExpressionBuilder.cpp   |  32 +----
 .../ASTNodeCFunctionExpressionBuilder.cpp     |   3 +-
 src/language/ASTNodeDataTypeBuilder.cpp       |  16 +--
 .../ASTNodeFunctionExpressionBuilder.cpp      | 128 ++++++++++++------
 .../ASTNodeFunctionExpressionBuilder.hpp      |   3 +-
 ...STNodeListAffectationExpressionBuilder.cpp |  35 +----
 .../ASTNodeNaturalConversionChecker.cpp       |  64 ++++++++-
 .../ASTNodeNaturalConversionChecker.hpp       |  15 +-
 .../node_processor/AffectationProcessor.hpp   |   2 +
 .../FunctionArgumentConverter.hpp             |   2 +
 .../node_processor/FunctionProcessor.hpp      |   2 +
 11 files changed, 181 insertions(+), 121 deletions(-)

diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
index 1e5f911ff..8c4357ce4 100644
--- a/src/language/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -219,37 +219,7 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
       }
     };
 
-    if (n.m_data_type == ASTNodeDataType::vector_t) {
-      // Only real data are considered
-      const ASTNode& data_node = *n.children[1];
-      switch (data_node.m_data_type) {
-      case ASTNodeDataType::list_t: {
-        if (data_node.children.size() != n.m_data_type.dimension()) {
-          throw parse_error("incompatible dimensions in affectation", std::vector{n.begin()});
-        }
-        for (const auto& child : data_node.children) {
-          ASTNodeNaturalConversionChecker{n, child->m_data_type, ASTNodeDataType::double_t};
-        }
-
-        break;
-      }
-      case ASTNodeDataType::vector_t: {
-        if (data_node.m_data_type.dimension() != n.m_data_type.dimension()) {
-          throw parse_error("incompatible dimensions in affectation", std::vector{n.begin()});
-        }
-        break;
-      }
-      case ASTNodeDataType::int_t: {
-        // Nothing to check by now since the special value 0 is allowed
-        break;
-      }
-      default: {
-        ASTNodeNaturalConversionChecker{n, data_node.m_data_type, n.m_data_type};
-      }
-      }
-    } else {
-      ASTNodeNaturalConversionChecker{n, n.children[1]->m_data_type, n.m_data_type};
-    }
+    ASTNodeNaturalConversionChecker{*n.children[1], n.m_data_type};
 
     set_affectation_processor_for_value(n.m_data_type);
   };
diff --git a/src/language/ASTNodeCFunctionExpressionBuilder.cpp b/src/language/ASTNodeCFunctionExpressionBuilder.cpp
index 6e93f998a..99a1c8ac0 100644
--- a/src/language/ASTNodeCFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeCFunctionExpressionBuilder.cpp
@@ -61,8 +61,7 @@ ASTNodeCFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeDataType&
     }
   };
 
-  ASTNodeNaturalConversionChecker{argument_node_sub_data_type.m_parent_node, argument_node_sub_data_type.m_data_type,
-                                  parameter_type};
+  ASTNodeNaturalConversionChecker{argument_node_sub_data_type, parameter_type};
 
   return get_function_argument_converter_for_argument_type();
 }
diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index f979a3768..d1400f8c3 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -74,7 +74,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       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};
+        ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t};
       }   // in the case of empty for_test (not simplified node), nothing to check!
     }
 
@@ -100,7 +100,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
           this->_buildNodeDataTypes(*child);
         }
         for (auto&& child : n.children) {
-          ASTNodeNaturalConversionChecker{*child, child->m_data_type, ASTNodeDataType::double_t};
+          ASTNodeNaturalConversionChecker{*child, ASTNodeDataType::double_t};
         }
 
         if (n.children.size() <= 3) {
@@ -302,19 +302,19 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       n.m_data_type = ASTNodeDataType::void_t;
 
       const ASTNode& test_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{test_node, test_node.m_data_type, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t};
 
     } else if (n.is_type<language::do_while_statement>()) {
       n.m_data_type = ASTNodeDataType::void_t;
 
       const ASTNode& test_node = *n.children[1];
-      ASTNodeNaturalConversionChecker{test_node, test_node.m_data_type, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t};
 
     } else if (n.is_type<language::unary_not>()) {
       n.m_data_type = ASTNodeDataType::bool_t;
 
       const ASTNode& operand_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{operand_node, operand_node.m_data_type, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{operand_node, ASTNodeDataType::bool_t};
 
     } else if (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
@@ -324,10 +324,10 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       n.m_data_type = ASTNodeDataType::bool_t;
 
       const ASTNode& lhs_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{lhs_node, lhs_node.m_data_type, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{lhs_node, ASTNodeDataType::bool_t};
 
       const ASTNode& rhs_node = *n.children[1];
-      ASTNodeNaturalConversionChecker{rhs_node, rhs_node.m_data_type, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{rhs_node, ASTNodeDataType::bool_t};
 
     } else if (n.is_type<language::unary_minus>()) {
       n.m_data_type = n.children[0]->m_data_type;
@@ -414,7 +414,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       auto& array_expression = *n.children[0];
       auto& index_expression = *n.children[1];
 
-      ASTNodeNaturalConversionChecker{index_expression, index_expression.m_data_type, ASTNodeDataType::int_t};
+      ASTNodeNaturalConversionChecker{index_expression, ASTNodeDataType::int_t};
       if (array_expression.m_data_type != ASTNodeDataType::vector_t) {
         std::ostringstream message;
         message << "invalid types '" << rang::fgB::yellow << dataTypeName(array_expression.m_data_type)
diff --git a/src/language/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ASTNodeFunctionExpressionBuilder.cpp
index 69cdad7f1..414c7d9f7 100644
--- a/src/language/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeFunctionExpressionBuilder.cpp
@@ -17,8 +17,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
 {
   const size_t parameter_id = std::get<size_t>(parameter_symbol.attributes().value());
 
-  ASTNodeNaturalConversionChecker{node_sub_data_type.m_parent_node, node_sub_data_type.m_data_type,
-                                  parameter_symbol.attributes().dataType()};
+  ASTNodeNaturalConversionChecker{node_sub_data_type, parameter_symbol.attributes().dataType()};
 
   auto get_function_argument_converter_for =
     [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> {
@@ -56,10 +55,19 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
                             ", provided " + std::to_string(node_sub_data_type.m_data_type.dimension()) + ")",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
       }
+    }
+    case ASTNodeDataType::int_t: {
+      if (node_sub_data_type.m_parent_node.is_type<language::integer>()) {
+        if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) {
+          return std::make_unique<FunctionArgumentConverter<ParameterT, ZeroType>>(parameter_id);
+        }
+      }
+      [[fallthrough]];
     }
       // LCOV_EXCL_START
     default: {
-      throw parse_error("invalid argument type", std::vector{node_sub_data_type.m_parent_node.begin()});
+      throw parse_error("unexpected error: invalid argument type",
+                        std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -118,10 +126,8 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
       case 3: {
         return get_function_argument_converter_for_vector(TinyVector<3>{});
       }
-      default: {
-        throw parse_error("unexpected error: invalid parameter dimension", std::vector{m_node.begin()});
-      }
       }
+      [[fallthrough]];
     }
 
       // LCOV_EXCL_START
@@ -192,16 +198,15 @@ ASTNodeFunctionExpressionBuilder::_buildArgumentConverter(FunctionDescriptor& fu
 }
 
 std::unique_ptr<INodeProcessor>
-ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType expression_value_type,
-                                                        const ASTNodeDataType return_value_type,
+ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType return_value_type,
                                                         ASTNode& node,
                                                         ASTNode& function_component_expression)
 {
-  ASTNodeNaturalConversionChecker{function_component_expression, expression_value_type, return_value_type};
+  ASTNodeNaturalConversionChecker{function_component_expression, return_value_type};
 
   auto get_function_processor_for_expression_value = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
     using ReturnT = std::decay_t<decltype(return_v)>;
-    switch (expression_value_type) {
+    switch (function_component_expression.m_data_type) {
     case ASTNodeDataType::bool_t: {
       return std::make_unique<FunctionExpressionProcessor<ReturnT, bool>>(function_component_expression);
     }
@@ -234,18 +239,28 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType ex
 
   auto get_function_processor_for_expression_vector = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
     using ReturnT = std::decay_t<decltype(return_v)>;
-    switch (expression_value_type) {
+    switch (function_component_expression.m_data_type) {
     case ASTNodeDataType::vector_t: {
-      if (expression_value_type.dimension() == return_v.dimension()) {
+      if (function_component_expression.m_data_type.dimension() == return_v.dimension()) {
         return std::make_unique<FunctionExpressionProcessor<ReturnT, ReturnT>>(function_component_expression);
       } else {
         throw parse_error("invalid dimension for returned vector", std::vector{function_component_expression.begin()});
       }
     }
-      // LCOV_EXCL_START
+    case ASTNodeDataType::int_t: {
+      if (function_component_expression.is_type<language::integer>()) {
+        if (std::stoi(function_component_expression.string()) == 0) {
+          return std::make_unique<FunctionExpressionProcessor<ReturnT, ZeroType>>(function_component_expression);
+        }
+      }
+      throw parse_error("unexpected error: undefined expression value type for function",
+                        std::vector{function_component_expression.begin()});
+      break;
+    }
+    // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: undefined expression value type for function",
-                        std::vector{node.children[1]->begin()});
+                        std::vector{function_component_expression.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -329,8 +344,10 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
 
     Assert(return_value_type != ASTNodeDataType::undefined_t);
 
+    ASTNodeNaturalConversionChecker{expression_node, return_value_type};
+
     function_processor->addFunctionExpressionProcessor(
-      this->_getFunctionProcessor(expression_value_type, return_value_type, node, expression_node));
+      this->_getFunctionProcessor(return_value_type, node, expression_node));
   };
 
   ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1];
@@ -339,34 +356,67 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
   if (function_image_domain.is_type<language::vector_type>()) {
     ASTNodeDataType vector_type = getVectorDataType(function_image_domain);
 
-    Assert(vector_type.dimension() == function_expression.children.size());
+    ASTNodeNaturalConversionChecker{function_expression, vector_type};
+    if (function_expression.is_type<language::expression_list>()) {
+      Assert(vector_type.dimension() == function_expression.children.size());
+
+      for (size_t i = 0; i < vector_type.dimension(); ++i) {
+        function_processor->addFunctionExpressionProcessor(
+          this->_getFunctionProcessor(ASTNodeDataType::double_t, node, *function_expression.children[i]));
+      }
 
-    for (size_t i = 0; i < vector_type.dimension(); ++i) {
+      switch (vector_type.dimension()) {
+      case 1: {
+        node.m_node_processor =
+          std::make_unique<TupleToVectorProcessor<FunctionProcessor, 1>>(node, std::move(function_processor));
+        break;
+      }
+      case 2: {
+        node.m_node_processor =
+          std::make_unique<TupleToVectorProcessor<FunctionProcessor, 2>>(node, std::move(function_processor));
+        break;
+      }
+      case 3: {
+        node.m_node_processor =
+          std::make_unique<TupleToVectorProcessor<FunctionProcessor, 3>>(node, std::move(function_processor));
+        break;
+      }
+      default: {
+        throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
+      }
+      }
+    } else if (function_expression.is_type<language::integer>()) {
+      if (std::stoi(function_expression.string()) == 0) {
+        switch (vector_type.dimension()) {
+        case 1: {
+          node.m_node_processor =
+            std::make_unique<FunctionExpressionProcessor<TinyVector<1>, ZeroType>>(function_expression);
+          break;
+        }
+        case 2: {
+          node.m_node_processor =
+            std::make_unique<FunctionExpressionProcessor<TinyVector<2>, ZeroType>>(function_expression);
+          break;
+        }
+        case 3: {
+          node.m_node_processor =
+            std::make_unique<FunctionExpressionProcessor<TinyVector<3>, ZeroType>>(function_expression);
+          break;
+        }
+        default: {
+          throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
+        }
+        }
+      } else {
+        throw parse_error("unexpected error: expecting 0", std::vector{function_expression.begin()});
+      }
+    } else {
       function_processor->addFunctionExpressionProcessor(
-        this->_getFunctionProcessor(function_expression.children[i]->m_data_type, ASTNodeDataType::double_t, node,
-                                    *function_expression.children[i]));
-    }
+        this->_getFunctionProcessor(vector_type, node, function_expression));
 
-    switch (vector_type.dimension()) {
-    case 1: {
-      node.m_node_processor =
-        std::make_unique<TupleToVectorProcessor<FunctionProcessor, 1>>(node, std::move(function_processor));
-      break;
-    }
-    case 2: {
-      node.m_node_processor =
-        std::make_unique<TupleToVectorProcessor<FunctionProcessor, 2>>(node, std::move(function_processor));
-      break;
-    }
-    case 3: {
-      node.m_node_processor =
-        std::make_unique<TupleToVectorProcessor<FunctionProcessor, 3>>(node, std::move(function_processor));
-      break;
-    }
-    default: {
-      throw parse_error("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
-    }
+      node.m_node_processor = std::move(function_processor);
     }
+
   } else {
     if (function_expression.is_type<language::expression_list>()) {
       ASTNode& image_domain_node = function_image_domain;
diff --git a/src/language/ASTNodeFunctionExpressionBuilder.hpp b/src/language/ASTNodeFunctionExpressionBuilder.hpp
index 54c3297c6..798c78897 100644
--- a/src/language/ASTNodeFunctionExpressionBuilder.hpp
+++ b/src/language/ASTNodeFunctionExpressionBuilder.hpp
@@ -25,8 +25,7 @@ class ASTNodeFunctionExpressionBuilder
 
   std::unique_ptr<FunctionProcessor> _buildArgumentConverter(FunctionDescriptor& function_descriptor, ASTNode& node);
 
-  std::unique_ptr<INodeProcessor> _getFunctionProcessor(const ASTNodeDataType expression_value_type,
-                                                        const ASTNodeDataType return_value_type,
+  std::unique_ptr<INodeProcessor> _getFunctionProcessor(const ASTNodeDataType return_value_type,
                                                         ASTNode& node,
                                                         ASTNode& function_component_expression);
 
diff --git a/src/language/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ASTNodeListAffectationExpressionBuilder.cpp
index 3f88ad804..2c14148ec 100644
--- a/src/language/ASTNodeListAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeListAffectationExpressionBuilder.cpp
@@ -145,40 +145,7 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
     }
   };
 
-  if (value_node.m_data_type == ASTNodeDataType::vector_t) {
-    // Only real data are considered
-    const ASTNode& data_node = rhs_node_sub_data_type.m_parent_node;
-    switch (data_node.m_data_type) {
-    case ASTNodeDataType::list_t: {
-      if (data_node.children.size() != value_node.m_data_type.dimension()) {
-        throw parse_error("incompatible dimensions in affectation", std::vector{value_node.begin()});
-      }
-      for (const auto& child : data_node.children) {
-        ASTNodeNaturalConversionChecker{rhs_node_sub_data_type.m_parent_node, child->m_data_type,
-                                        ASTNodeDataType::double_t};
-      }
-
-      break;
-    }
-    case ASTNodeDataType::vector_t: {
-      if (data_node.m_data_type.dimension() != value_node.m_data_type.dimension()) {
-        throw parse_error("incompatible dimensions in affectation", std::vector{value_node.begin()});
-      }
-      break;
-    }
-    case ASTNodeDataType::int_t: {
-      // Nothing to check by now since the special value 0 is allowed
-      break;
-    }
-    default: {
-      ASTNodeNaturalConversionChecker{rhs_node_sub_data_type.m_parent_node, rhs_node_sub_data_type.m_data_type,
-                                      value_node.m_data_type};
-    }
-    }
-  } else {
-    ASTNodeNaturalConversionChecker{rhs_node_sub_data_type.m_parent_node, rhs_node_sub_data_type.m_data_type,
-                                    value_node.m_data_type};
-  }
+  ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, value_node.m_data_type};
 
   add_affectation_processor_for_value(value_node.m_data_type, rhs_node_sub_data_type);
 }
diff --git a/src/language/ASTNodeNaturalConversionChecker.cpp b/src/language/ASTNodeNaturalConversionChecker.cpp
index abf672e0d..f7c5fa95e 100644
--- a/src/language/ASTNodeNaturalConversionChecker.cpp
+++ b/src/language/ASTNodeNaturalConversionChecker.cpp
@@ -1,8 +1,11 @@
 #include <ASTNodeNaturalConversionChecker.hpp>
 
-ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNode& node,
-                                                                 const ASTNodeDataType& data_type,
-                                                                 const ASTNodeDataType& target_data_type)
+#include <PEGGrammar.hpp>
+
+void
+ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& node,
+                                                               const ASTNodeDataType& data_type,
+                                                               const ASTNodeDataType& target_data_type) const
 {
   if (not isNaturalConversion(data_type, target_data_type)) {
     std::ostringstream error_message;
@@ -12,3 +15,58 @@ ASTNodeNaturalConversionChecker::ASTNodeNaturalConversionChecker(const ASTNode&
     throw parse_error(error_message.str(), node.begin());
   }
 }
+
+void
+ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNode& node,
+                                                                     const ASTNodeDataType& data_type,
+                                                                     const ASTNodeDataType& target_data_type) const
+{
+  if (target_data_type == ASTNodeDataType::vector_t) {
+    // Only R^d data is considered
+    switch (node.m_data_type) {
+    case ASTNodeDataType::list_t: {
+      if (node.children.size() != target_data_type.dimension()) {
+        throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()});
+      }
+      for (const auto& child : node.children) {
+        this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, ASTNodeDataType::double_t);
+      }
+
+      break;
+    }
+    case ASTNodeDataType::vector_t: {
+      if (data_type.dimension() != target_data_type.dimension()) {
+        throw parse_error("incompatible dimensions in affectation", std::vector{node.begin()});
+      }
+      break;
+    }
+    case ASTNodeDataType::int_t: {
+      if (node.is_type<language::integer>()) {
+        if (std::stoi(node.string()) == 0) {
+          break;
+        }
+      }
+      this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
+      break;
+    }
+    default: {
+      this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
+    }
+    }
+  } else {
+    this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
+  }
+}
+
+ASTNodeNaturalConversionChecker::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)
+{
+  this->_checkIsNaturalExpressionConversion(data_node_sub_data_type.m_parent_node, data_node_sub_data_type.m_data_type,
+                                            target_data_type);
+}
diff --git a/src/language/ASTNodeNaturalConversionChecker.hpp b/src/language/ASTNodeNaturalConversionChecker.hpp
index fb2391895..bccd180b5 100644
--- a/src/language/ASTNodeNaturalConversionChecker.hpp
+++ b/src/language/ASTNodeNaturalConversionChecker.hpp
@@ -3,12 +3,23 @@
 
 #include <ASTNode.hpp>
 #include <ASTNodeDataType.hpp>
+#include <ASTNodeSubDataType.hpp>
 
 class ASTNodeNaturalConversionChecker
 {
+ private:
+  void _checkIsNaturalTypeConversion(const ASTNode& ast_node,
+                                     const ASTNodeDataType& data_type,
+                                     const ASTNodeDataType& target_data_type) const;
+
+  void _checkIsNaturalExpressionConversion(const ASTNode& ast_node,
+                                           const ASTNodeDataType& data_type,
+                                           const ASTNodeDataType& target_data_type) const;
+
  public:
-  ASTNodeNaturalConversionChecker(const ASTNode& ast_node,
-                                  const ASTNodeDataType& data_type,
+  ASTNodeNaturalConversionChecker(const ASTNode& data_node, const ASTNodeDataType& target_data_type);
+
+  ASTNodeNaturalConversionChecker(const ASTNodeSubDataType& data_node_sub_data_type,
                                   const ASTNodeDataType& target_data_type);
 };
 
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index c9e91663f..4449fd8ce 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -117,6 +117,8 @@ class AffectationExecutor final : public IAffectationExecutor
         }
       } else if (std::is_same_v<OperatorT, language::eq_op>) {
         m_lhs = ValueT{zero};
+      } else {
+        static_assert(std::is_same_v<OperatorT, language::eq_op>, "unexpected operator type");
       }
     }
   }
diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp
index 48455d0bd..fd05ca24b 100644
--- a/src/language/node_processor/FunctionArgumentConverter.hpp
+++ b/src/language/node_processor/FunctionArgumentConverter.hpp
@@ -26,6 +26,8 @@ class FunctionArgumentConverter final : public IFunctionArgumentConverter
       exec_policy.currentContext()[m_argument_id] = std::move(value);
     } else if constexpr (std::is_same_v<ExpectedValueType, std::string>) {
       exec_policy.currentContext()[m_argument_id] = std::move(std::to_string(std::get<ProvidedValueType>(value)));
+    } else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) {
+      exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero};
     } else {
       exec_policy.currentContext()[m_argument_id] =
         std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));
diff --git a/src/language/node_processor/FunctionProcessor.hpp b/src/language/node_processor/FunctionProcessor.hpp
index c45faaa39..a393117ba 100644
--- a/src/language/node_processor/FunctionProcessor.hpp
+++ b/src/language/node_processor/FunctionProcessor.hpp
@@ -26,6 +26,8 @@ class FunctionExpressionProcessor final : public INodeProcessor
       return m_function_expression.execute(exec_policy);
     } else if constexpr (std::is_same_v<ReturnType, std::string>) {
       return std::to_string(std::get<ExpressionValueType>(m_function_expression.execute(exec_policy)));
+    } else if constexpr (std::is_same_v<ExpressionValueType, ZeroType>) {
+      return ReturnType{ZeroType::zero};
     } else {
       return static_cast<ReturnType>(std::get<ExpressionValueType>(m_function_expression.execute(exec_policy)));
     }
-- 
GitLab