diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index 75842ad029795a579a213b2d50bed15bcfb68b30..efddefd1a2081ee30fe26cb77cb16e95eb33c8d1 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -78,6 +78,16 @@ parser(const std::string& filename)
 
     std::cout << ASTPrinter{*root_node} << '\n';
 
+    auto& function_table = root_node->m_symbol_table->functionTable();
+
+    for (size_t i_function = 0; i_function < function_table.size(); ++i_function) {
+      const auto& function_descriptor = function_table[i_function];
+      std::cout << "function " << rang::fgB::magenta << function_descriptor.name() << rang::style::reset << '\n';
+      std::cout << ASTPrinter(function_descriptor.domainMappingNode());
+      std::cout << ASTPrinter(function_descriptor.definitionNode());
+      std::cout << "--------\n";
+    }
+
     ExecutionPolicy exec_all;
     root_node->execute(exec_all);
     std::cout << *(root_node->m_symbol_table) << '\n';
diff --git a/src/language/ast/ASTNode.hpp b/src/language/ast/ASTNode.hpp
index b3dd41ca65faae6324d040aa7f4b66c078f45f6c..a3b9bd21569d490b1bc7f450eee546279b91a681 100644
--- a/src/language/ast/ASTNode.hpp
+++ b/src/language/ast/ASTNode.hpp
@@ -45,7 +45,7 @@ class ASTNode : public parse_tree::basic_node<ASTNode>
   std::shared_ptr<SymbolTable> m_symbol_table;
   std::unique_ptr<INodeProcessor> m_node_processor;
 
-  ASTNodeDataType m_data_type{ASTNodeDataType::undefined_t};
+  ASTNodeDataType m_data_type;
 
   [[nodiscard]] PUGS_INLINE std::string
   string() const
diff --git a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
index e27bd531d743b410ecb381e665bb4af145e4731f..66420138cd85f3fcf220ceec883f6c2b1b012759 100644
--- a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
@@ -405,18 +405,22 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
     };
 
     using OperatorT = std::decay_t<decltype(operator_v)>;
+
+    const ASTNodeDataType& target_data_type = n.children[0]->m_data_type;
+    const ASTNodeDataType& source_data_type = n.children[1]->m_data_type;
+
     // Special treatment dedicated to R^1 to be able to initialize them
-    if (((n.m_data_type != n.children[1]->m_data_type) and (n.m_data_type == ASTNodeDataType::vector_t) and
-         (n.m_data_type.dimension() == 1)) or
+    if (((target_data_type != source_data_type) and (target_data_type == ASTNodeDataType::vector_t) and
+         (target_data_type.dimension() == 1)) or
         // Special treatment for R^d vectors and operator *=
-        ((n.m_data_type == ASTNodeDataType::vector_t) and (n.children[1]->m_data_type != ASTNodeDataType::vector_t) and
+        ((target_data_type == ASTNodeDataType::vector_t) and (source_data_type != ASTNodeDataType::vector_t) and
          std::is_same_v<OperatorT, language::multiplyeq_op>)) {
-      ASTNodeNaturalConversionChecker{*n.children[1], ASTNodeDataType::double_t};
+      ASTNodeNaturalConversionChecker{*n.children[1], ASTNodeDataType::build<ASTNodeDataType::double_t>()};
     } else {
-      ASTNodeNaturalConversionChecker{*n.children[1], n.m_data_type};
+      ASTNodeNaturalConversionChecker{*n.children[1], target_data_type};
     }
 
-    set_affectation_processor_for_value(n.m_data_type);
+    set_affectation_processor_for_value(target_data_type);
   };
 
   if (n.is_type<language::eq_op>()) {
diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 6dc726f555219b855e2a125b0ab22b586dec2dad..6b1fe91ec1006600bf601c737719869497041e2b 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -281,10 +281,16 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
         return get_function_argument_to_tuple_converter(double{});
       }
       case ASTNodeDataType::vector_t: {
-        switch (parameter_type.dimension()) {
+        switch (parameter_type.contentType().dimension()) {
         case 1: {
           return get_function_argument_to_tuple_converter(TinyVector<1>{});
         }
+        case 2: {
+          return get_function_argument_to_tuple_converter(TinyVector<2>{});
+        }
+        case 3: {
+          return get_function_argument_to_tuple_converter(TinyVector<3>{});
+        }
         // LCOV_EXCL_START
         default: {
           throw ParseError("unexpected error: unexpected tuple content for function: '" + dataTypeName(parameter_type) +
@@ -316,7 +322,7 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
 
   if (parameter_type == ASTNodeDataType::vector_t and parameter_type.dimension() == 1) {
     if (not isNaturalConversion(argument_node_sub_data_type.m_data_type, parameter_type)) {
-      ASTNodeNaturalConversionChecker{argument_node_sub_data_type, ASTNodeDataType::double_t};
+      ASTNodeNaturalConversionChecker{argument_node_sub_data_type, ASTNodeDataType::build<ASTNodeDataType::double_t>()};
     }
   } else {
     ASTNodeNaturalConversionChecker{argument_node_sub_data_type, parameter_type};
diff --git a/src/language/ast/ASTNodeDataType.cpp b/src/language/ast/ASTNodeDataType.cpp
index c77659d983c58a571ac3dd8426437be6478ceddb..10ec58b451ead8402a328744cb977c29557dbbbf 100644
--- a/src/language/ast/ASTNodeDataType.cpp
+++ b/src/language/ast/ASTNodeDataType.cpp
@@ -16,7 +16,7 @@ getVectorDataType(const ASTNode& type_node)
     throw ParseError("unexpected non integer constant dimension", dimension_node.begin());
   }
   const size_t dimension = std::stol(dimension_node.string());
-  return ASTNodeDataType{ASTNodeDataType::vector_t, dimension};
+  return ASTNodeDataType::build<ASTNodeDataType::vector_t>(dimension);
 }
 
 std::string
@@ -45,14 +45,21 @@ dataTypeName(const ASTNodeDataType& data_type)
   case ASTNodeDataType::tuple_t:
     name = "tuple(" + dataTypeName(data_type.contentType()) + ')';
     break;
-  case ASTNodeDataType::list_t:
-    name = "list";
+  case ASTNodeDataType::list_t: {
+    std::ostringstream data_type_name_list;
+    const auto& data_type_list = data_type.contentTypeList();
+    data_type_name_list << dataTypeName(*data_type_list[0]);
+    for (size_t i = 1; i < data_type_list.size(); ++i) {
+      data_type_name_list << '*' << dataTypeName(*data_type_list[i]);
+    }
+    name = "list(" + data_type_name_list.str() + ")";
     break;
+  }
   case ASTNodeDataType::string_t:
     name = "string";
     break;
   case ASTNodeDataType::typename_t:
-    name = "typename";
+    name = std::string("typename(") + dataTypeName(data_type.contentType()) + ")";
     break;
   case ASTNodeDataType::type_name_id_t:
     name = "type_name_id";
@@ -88,7 +95,7 @@ dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& dat
              (data_type_2 == ASTNodeDataType::vector_t)) {
     return data_type_2;
   } else {
-    return ASTNodeDataType::undefined_t;
+    return ASTNodeDataType{};
   }
 }
 
diff --git a/src/language/ast/ASTNodeDataType.hpp b/src/language/ast/ASTNodeDataType.hpp
index 863a87dad0a3df9d3659b9c661336fbf5e384aca..98dfaecf8dc06da4b0b42090fe9ea9bd411ddc50 100644
--- a/src/language/ast/ASTNodeDataType.hpp
+++ b/src/language/ast/ASTNodeDataType.hpp
@@ -6,8 +6,19 @@
 #include <limits>
 #include <memory>
 #include <string>
+#include <variant>
+#include <vector>
 
 class ASTNode;
+class ASTNodeDataType;
+
+ASTNodeDataType getVectorDataType(const ASTNode& type_node);
+
+std::string dataTypeName(const ASTNodeDataType& data_type);
+
+ASTNodeDataType dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2);
+
+bool isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type);
 
 class ASTNodeDataType
 {
@@ -33,31 +44,46 @@ class ASTNodeDataType
 
  private:
   DataType m_data_type;
-  std::shared_ptr<ASTNodeDataType> m_content_type;
-  size_t m_dimension;
-  std::string m_name_of_type_id;
+
+  using DataTypeDetails = std::variant<std::monostate,
+                                       size_t,
+                                       std::string,
+                                       std::shared_ptr<const ASTNodeDataType>,
+                                       std::vector<std::shared_ptr<const ASTNodeDataType>>>;
+
+  DataTypeDetails m_details;
 
  public:
   PUGS_INLINE
   size_t
   dimension() const
   {
-    return m_dimension;
+    Assert(std::holds_alternative<size_t>(m_details));
+    return std::get<size_t>(m_details);
+  }
+
+  PUGS_INLINE
+  const std::string&
+  nameOfTypeId() const
+  {
+    Assert(std::holds_alternative<std::string>(m_details));
+    return std::get<std::string>(m_details);
   }
 
   PUGS_INLINE
   const ASTNodeDataType&
   contentType() const
   {
-    Assert(m_content_type);
-    return *m_content_type;
+    Assert(std::holds_alternative<std::shared_ptr<const ASTNodeDataType>>(m_details));
+    return *std::get<std::shared_ptr<const ASTNodeDataType>>(m_details);
   }
 
   PUGS_INLINE
-  const std::string&
-  nameOfTypeId() const
+  const std::vector<std::shared_ptr<const ASTNodeDataType>>&
+  contentTypeList() const
   {
-    return m_name_of_type_id;
+    Assert(std::holds_alternative<std::vector<std::shared_ptr<const ASTNodeDataType>>>(m_details));
+    return std::get<std::vector<std::shared_ptr<const ASTNodeDataType>>>(m_details);
   }
 
   PUGS_INLINE
@@ -69,38 +95,83 @@ class ASTNodeDataType
   ASTNodeDataType& operator=(const ASTNodeDataType&) = default;
   ASTNodeDataType& operator=(ASTNodeDataType&&) = default;
 
-  ASTNodeDataType(DataType data_type)
-    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_name_of_type_id{"unknown"}
-  {}
+  template <DataType data_type>
+  [[nodiscard]] static ASTNodeDataType
+  build()
+  {
+    static_assert(data_type != tuple_t, "tuple_t requires sub_type");
+    static_assert(data_type != typename_t, "typename_t requires sub_type");
+    static_assert(data_type != vector_t, "vector_t requires dimension");
+    static_assert(data_type != type_id_t, "type_id_t requires name");
+    static_assert(data_type != list_t, "list_t requires list of types");
 
-  ASTNodeDataType(DataType data_type, const ASTNodeDataType& content_type)
-    : m_data_type{data_type},
-      m_content_type{std::make_shared<ASTNodeDataType>(content_type)},
-      m_dimension{1},
-      m_name_of_type_id{"unknown"}
-  {}
+    return ASTNodeDataType{data_type};
+  }
 
-  ASTNodeDataType(DataType data_type, size_t dimension)
-    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{dimension}, m_name_of_type_id{"unknown"}
-  {}
+  template <DataType data_type>
+  [[nodiscard]] static ASTNodeDataType
+  build(const ASTNodeDataType& content_type)
+  {
+    static_assert((data_type == tuple_t) or (data_type == typename_t),
+                  "incorrect data_type construction: cannot have content");
+    Assert(content_type != ASTNodeDataType::undefined_t);
 
-  ASTNodeDataType(DataType data_type, const std::string& type_name)
-    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_name_of_type_id{type_name}
-  {}
+    return ASTNodeDataType{data_type, content_type};
+  }
+
+  template <DataType data_type>
+  [[nodiscard]] static ASTNodeDataType
+  build(const size_t dimension)
+  {
+    static_assert((data_type == vector_t), "incorrect data_type construction: cannot have dimension");
+    return ASTNodeDataType{data_type, dimension};
+  }
+
+  template <DataType data_type>
+  [[nodiscard]] static ASTNodeDataType
+  build(const std::string& type_name)
+  {
+    static_assert((data_type == type_id_t), "incorrect data_type construction: cannot provide name of type");
+    return ASTNodeDataType{data_type, type_name};
+  }
+
+  template <DataType data_type>
+  [[nodiscard]] static ASTNodeDataType
+  build(const std::vector<std::shared_ptr<const ASTNodeDataType>>& list_of_types)
+  {
+    static_assert((data_type == list_t), "incorrect data_type construction: cannot provide a list of data types");
+
+    for (auto i : list_of_types) {
+      Assert(i->m_data_type != ASTNodeDataType::undefined_t, "cannot build a type list containing undefined types");
+    }
+
+    return ASTNodeDataType{data_type, list_of_types};
+  }
+
+  ASTNodeDataType() : m_data_type{undefined_t} {}
 
   ASTNodeDataType(const ASTNodeDataType&) = default;
 
   ASTNodeDataType(ASTNodeDataType&&) = default;
 
   ~ASTNodeDataType() = default;
-};
 
-ASTNodeDataType getVectorDataType(const ASTNode& type_node);
+ private:
+  explicit ASTNodeDataType(DataType data_type) : m_data_type{data_type} {}
 
-std::string dataTypeName(const ASTNodeDataType& data_type);
+  explicit ASTNodeDataType(DataType data_type, const ASTNodeDataType& content_type)
+    : m_data_type{data_type}, m_details{std::make_shared<const ASTNodeDataType>(content_type)}
+  {}
 
-ASTNodeDataType dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2);
+  explicit ASTNodeDataType(DataType data_type, const std::vector<std::shared_ptr<const ASTNodeDataType>>& list_of_types)
+    : m_data_type{data_type}, m_details{list_of_types}
+  {}
 
-bool isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type);
+  explicit ASTNodeDataType(DataType data_type, const size_t dimension) : m_data_type{data_type}, m_details{dimension} {}
+
+  explicit ASTNodeDataType(DataType data_type, const std::string& type_name)
+    : m_data_type{data_type}, m_details{type_name}
+  {}
+};
 
 #endif   // AST_NODE_DATA_TYPE_HPP
diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp
index 7da94cc5f7d00132b226f8ba0e7e5d95d4097b35..4a56bdae9cc854582e7e8df435ebbaea8e01a582 100644
--- a/src/language/ast/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp
@@ -7,10 +7,10 @@
 #include <language/utils/SymbolTable.hpp>
 #include <utils/PugsAssert.hpp>
 
-ASTNodeDataType
+void
 ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const
 {
-  ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
+  ASTNodeDataType data_type;
   if (type_node.is_type<language::type_expression>()) {
     if (type_node.children.size() != name_node.children.size()) {
       std::ostringstream message;
@@ -21,21 +21,24 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
       throw ParseError(message.str(), name_node.begin());
     }
 
+    std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list;
+    sub_data_type_list.reserve(type_node.children.size());
     for (size_t i = 0; i < type_node.children.size(); ++i) {
       auto& sub_type_node = *type_node.children[i];
       auto& sub_name_node = *name_node.children[i];
       _buildDeclarationNodeDataTypes(sub_type_node, sub_name_node);
+      sub_data_type_list.push_back(std::make_shared<const ASTNodeDataType>(sub_type_node.m_data_type));
     }
-    data_type = ASTNodeDataType::typename_t;
+    data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list);
   } else {
     if (type_node.is_type<language::B_set>()) {
-      data_type = ASTNodeDataType::bool_t;
+      data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
     } else if (type_node.is_type<language::Z_set>()) {
-      data_type = ASTNodeDataType::int_t;
+      data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
     } else if (type_node.is_type<language::N_set>()) {
-      data_type = ASTNodeDataType::unsigned_int_t;
+      data_type = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
     } else if (type_node.is_type<language::R_set>()) {
-      data_type = ASTNodeDataType::double_t;
+      data_type = ASTNodeDataType::build<ASTNodeDataType::double_t>();
     } else if (type_node.is_type<language::vector_type>()) {
       data_type = getVectorDataType(type_node);
     } else if (type_node.is_type<language::tuple_type_specifier>()) {
@@ -56,28 +59,28 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
           throw ParseError(os.str(), std::vector{content_node->begin()});
         }
 
-        content_node->m_data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id};
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::type_id_t>(type_name_id);
       } else if (content_node->is_type<language::B_set>()) {
-        content_node->m_data_type = ASTNodeDataType::bool_t;
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
       } else if (content_node->is_type<language::Z_set>()) {
-        content_node->m_data_type = ASTNodeDataType::int_t;
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       } else if (content_node->is_type<language::N_set>()) {
-        content_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
       } else if (content_node->is_type<language::R_set>()) {
-        content_node->m_data_type = ASTNodeDataType::double_t;
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::double_t>();
       } else if (content_node->is_type<language::vector_type>()) {
         content_node->m_data_type = getVectorDataType(*type_node.children[0]);
       } else if (content_node->is_type<language::string_type>()) {
-        content_node->m_data_type = ASTNodeDataType::string_t;
+        content_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
       } else {
         // LCOV_EXCL_START
         throw UnexpectedError("unexpected content type in tuple");
         // LCOV_EXCL_STOP
       }
 
-      data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, content_node->m_data_type};
+      data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(content_node->m_data_type);
     } else if (type_node.is_type<language::string_type>()) {
-      data_type = ASTNodeDataType::string_t;
+      data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
     } else if (type_node.is_type<language::type_name_id>()) {
       const std::string& type_name_id = type_node.string();
 
@@ -93,7 +96,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
         throw ParseError(os.str(), std::vector{type_node.begin()});
       }
 
-      data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id};
+      data_type = ASTNodeDataType::build<ASTNodeDataType::type_id_t>(type_name_id);
     }
 
     if (name_node.is_type<language::name_list>()) {
@@ -113,7 +116,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
   }
 
   Assert(data_type != ASTNodeDataType::undefined_t);
-  return data_type;
+  type_node.m_data_type = ASTNodeDataType::build<ASTNodeDataType::typename_t>(data_type);
 }
 
 void
@@ -128,51 +131,51 @@ 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, ASTNodeDataType::bool_t};
+        ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
       }   // in the case of empty for_test (not simplified node), nothing to check!
     }
 
-    n.m_data_type = ASTNodeDataType::void_t;
+    n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
   } else {
     if (n.has_content()) {
       if (n.is_type<language::import_instruction>()) {
-        n.m_data_type = ASTNodeDataType::void_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
       } else if (n.is_type<language::module_name>()) {
-        n.m_data_type = ASTNodeDataType::string_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
       } else if (n.is_type<language::true_kw>() or n.is_type<language::false_kw>()) {
-        n.m_data_type = ASTNodeDataType::bool_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
       } else if (n.is_type<language::real>()) {
-        n.m_data_type = ASTNodeDataType::double_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::double_t>();
       } else if (n.is_type<language::integer>()) {
-        n.m_data_type = ASTNodeDataType::int_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       } else if (n.is_type<language::vector_type>()) {
         n.m_data_type = getVectorDataType(n);
 
-      } else if (n.is_type<language::tuple_expression>()) {
-        n.m_data_type = ASTNodeDataType::list_t;
-
       } else if (n.is_type<language::literal>()) {
-        n.m_data_type = ASTNodeDataType::string_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
       } else if (n.is_type<language::cout_kw>() or n.is_type<language::cerr_kw>() or n.is_type<language::clog_kw>()) {
-        n.m_data_type = ASTNodeDataType::void_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
       } else if (n.is_type<language::var_declaration>()) {
         auto& name_node = *(n.children[0]);
         auto& type_node = *(n.children[1]);
 
-        type_node.m_data_type = _buildDeclarationNodeDataTypes(type_node, name_node);
-        n.m_data_type         = type_node.m_data_type;
+        _buildDeclarationNodeDataTypes(type_node, name_node);
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
       } else if (n.is_type<language::fct_declaration>()) {
-        n.children[0]->m_data_type = ASTNodeDataType::function_t;
+        n.children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::function_t>();
 
         const std::string& symbol = n.children[0]->string();
-        auto [i_symbol, success]  = n.m_symbol_table->find(symbol, n.children[0]->begin());
+
+        auto [i_symbol, success] = n.m_symbol_table->find(symbol, n.children[0]->begin());
 
         auto& function_table = n.m_symbol_table->functionTable();
 
         uint64_t function_id                    = std::get<uint64_t>(i_symbol->attributes().value());
         FunctionDescriptor& function_descriptor = function_table[function_id];
 
+        this->_buildNodeDataTypes(function_descriptor.domainMappingNode());
+
         ASTNode& parameters_domain_node = *function_descriptor.domainMappingNode().children[0];
         ASTNode& parameters_name_node   = *function_descriptor.definitionNode().children[0];
 
@@ -202,28 +205,9 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
         auto simple_type_allocator = [&](const ASTNode& type_node, ASTNode& symbol_node) {
           Assert(symbol_node.is_type<language::name>());
-          ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
-          if (type_node.is_type<language::B_set>()) {
-            data_type = ASTNodeDataType::bool_t;
-          } else if (type_node.is_type<language::Z_set>()) {
-            data_type = ASTNodeDataType::int_t;
-          } else if (type_node.is_type<language::N_set>()) {
-            data_type = ASTNodeDataType::unsigned_int_t;
-          } else if (type_node.is_type<language::R_set>()) {
-            data_type = ASTNodeDataType::double_t;
-          } else if (type_node.is_type<language::vector_type>()) {
-            data_type = getVectorDataType(type_node);
-          } else if (type_node.is_type<language::string_type>()) {
-            data_type = ASTNodeDataType::string_t;
-          }
+          const ASTNodeDataType& data_type = type_node.m_data_type.contentType();
 
-          // LCOV_EXCL_START
-          if (data_type == ASTNodeDataType::undefined_t) {
-            throw ParseError("invalid parameter type", type_node.begin());
-          }
-          // LCOV_EXCL_STOP
-
-          symbol_node.m_data_type   = data_type;
+          symbol_node.m_data_type   = type_node.m_data_type.contentType();
           const std::string& symbol = symbol_node.string();
 
           std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
@@ -236,28 +220,22 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
         if (nb_parameter_domains == 1) {
           simple_type_allocator(parameters_domain_node, parameters_name_node);
         } else {
+          std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list;
+          sub_data_type_list.reserve(nb_parameter_domains);
+
           for (size_t i = 0; i < nb_parameter_domains; ++i) {
             simple_type_allocator(*parameters_domain_node.children[i], *parameters_name_node.children[i]);
+            sub_data_type_list.push_back(
+              std::make_shared<const ASTNodeDataType>(parameters_name_node.children[i]->m_data_type));
           }
-          parameters_name_node.m_data_type = ASTNodeDataType::list_t;
+          parameters_name_node.m_data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list);
         }
 
-        // build types for compound types
-        for (auto& child : parameters_domain_node.children) {
-          this->_buildNodeDataTypes(*child);
-        }
-        for (auto& child : parameters_name_node.children) {
-          this->_buildNodeDataTypes(*child);
-        }
+        this->_buildNodeDataTypes(function_descriptor.definitionNode());
 
         ASTNode& image_domain_node     = *function_descriptor.domainMappingNode().children[1];
         ASTNode& image_expression_node = *function_descriptor.definitionNode().children[1];
 
-        this->_buildNodeDataTypes(image_domain_node);
-        for (auto& child : image_domain_node.children) {
-          this->_buildNodeDataTypes(*child);
-        }
-
         const size_t nb_image_domains =
           (image_domain_node.is_type<language::type_expression>()) ? image_domain_node.children.size() : 1;
         const size_t nb_image_expressions =
@@ -283,39 +261,11 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
           }
         }
 
-        auto check_image_type = [&](const ASTNode& image_node) {
-          ASTNodeDataType value_type{ASTNodeDataType::undefined_t};
-          if (image_node.is_type<language::B_set>()) {
-            value_type = ASTNodeDataType::bool_t;
-          } else if (image_node.is_type<language::Z_set>()) {
-            value_type = ASTNodeDataType::int_t;
-          } else if (image_node.is_type<language::N_set>()) {
-            value_type = ASTNodeDataType::unsigned_int_t;
-          } else if (image_node.is_type<language::R_set>()) {
-            value_type = 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::string_t;
-          }
+        this->_buildNodeDataTypes(image_expression_node);
 
-          // LCOV_EXCL_START
-          if (value_type == ASTNodeDataType::undefined_t) {
-            throw ParseError("invalid value type", image_node.begin());
-          }
-          // LCOV_EXCL_STOP
-        };
+        ASTNodeNaturalConversionChecker<AllowRToR1Conversion>(image_expression_node, image_domain_node.m_data_type);
 
-        if (image_domain_node.is_type<language::type_expression>()) {
-          for (size_t i = 0; i < image_domain_node.children.size(); ++i) {
-            check_image_type(*image_domain_node.children[i]);
-          }
-          image_domain_node.m_data_type = ASTNodeDataType::typename_t;
-        } else {
-          check_image_type(image_domain_node);
-        }
-
-        n.m_data_type = ASTNodeDataType::void_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
         return;
       } else if (n.is_type<language::name>()) {
         std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
@@ -330,56 +280,103 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
     }
 
     if (n.is_type<language::break_kw>() or n.is_type<language::continue_kw>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
     } else if (n.is_type<language::eq_op>() or n.is_type<language::multiplyeq_op>() or
                n.is_type<language::divideeq_op>() or n.is_type<language::pluseq_op>() or
                n.is_type<language::minuseq_op>()) {
       n.m_data_type = n.children[0]->m_data_type;
+
+    } else if (n.is_type<language::tuple_expression>()) {
+      std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list;
+      sub_data_type_list.reserve(n.children.size());
+
+      for (size_t i = 0; i < n.children.size(); ++i) {
+        sub_data_type_list.push_back(std::make_shared<const ASTNodeDataType>(n.children[i]->m_data_type));
+      }
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list);
+
     } else if (n.is_type<language::type_mapping>() or n.is_type<language::function_definition>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
+      for (auto& child : n.children) {
+        this->_buildNodeDataTypes(*child);
+      }
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+    } else if (n.is_type<language::type_expression>()) {
+      std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list;
+      sub_data_type_list.reserve(n.children.size());
+
+      auto check_sub_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
+      };
+
+      for (size_t i = 0; i < n.children.size(); ++i) {
+        check_sub_type(*n.children[i]);
+        sub_data_type_list.push_back(std::make_shared<const ASTNodeDataType>(n.children[i]->m_data_type));
+      }
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::typename_t>(
+        ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list));
+
     } else if (n.is_type<language::for_post>() or n.is_type<language::for_init>() or
                n.is_type<language::for_statement_block>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
     } else if (n.is_type<language::for_test>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
     } else if (n.is_type<language::statement_block>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
+      n.m_data_type = ASTNodeDataType::build<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;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
 
       const ASTNode& test_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
 
     } else if (n.is_type<language::do_while_statement>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
 
       const ASTNode& test_node = *n.children[1];
-      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
 
     } else if (n.is_type<language::unary_not>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
 
       const ASTNode& operand_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{operand_node, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{operand_node, ASTNodeDataType::build<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
                n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
     } else if (n.is_type<language::and_op>() or n.is_type<language::or_op>() or n.is_type<language::xor_op>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
 
       const ASTNode& lhs_node = *n.children[0];
-      ASTNodeNaturalConversionChecker{lhs_node, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{lhs_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
 
       const ASTNode& rhs_node = *n.children[1];
-      ASTNodeNaturalConversionChecker{rhs_node, ASTNodeDataType::bool_t};
+      ASTNodeNaturalConversionChecker{rhs_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
 
     } else if (n.is_type<language::unary_minus>()) {
       n.m_data_type = n.children[0]->m_data_type;
       if ((n.children[0]->m_data_type == ASTNodeDataType::unsigned_int_t) or
           (n.children[0]->m_data_type == ASTNodeDataType::bool_t)) {
-        n.m_data_type = ASTNodeDataType::int_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       } else {
         n.m_data_type = n.children[0]->m_data_type;
       }
@@ -391,7 +388,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       const ASTNodeDataType type_0 = n.children[0]->m_data_type;
       const ASTNodeDataType type_1 = n.children[1]->m_data_type;
       if ((type_0 == ASTNodeDataType::bool_t) and (type_1 == ASTNodeDataType::bool_t)) {
-        n.m_data_type = ASTNodeDataType::int_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       } else {
         n.m_data_type = dataTypePromotion(type_0, type_1);
       }
@@ -404,7 +401,8 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       }
     } else if (n.is_type<language::function_evaluation>()) {
       if (n.children[0]->m_data_type == ASTNodeDataType::function_t) {
-        const std::string& function_name  = n.children[0]->string();
+        const std::string& function_name = n.children[0]->string();
+
         auto [i_function_symbol, success] = n.m_symbol_table->find(function_name, n.children[0]->begin());
 
         auto& function_table = n.m_symbol_table->functionTable();
@@ -414,28 +412,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
         ASTNode& image_domain_node = *function_descriptor.domainMappingNode().children[1];
 
-        ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
-        if (image_domain_node.is_type<language::type_expression>()) {
-          data_type = image_domain_node.m_data_type;
-        } else {
-          if (image_domain_node.is_type<language::B_set>()) {
-            data_type = ASTNodeDataType::bool_t;
-          } else if (image_domain_node.is_type<language::Z_set>()) {
-            data_type = ASTNodeDataType::int_t;
-          } else if (image_domain_node.is_type<language::N_set>()) {
-            data_type = ASTNodeDataType::unsigned_int_t;
-          } else if (image_domain_node.is_type<language::R_set>()) {
-            data_type = ASTNodeDataType::double_t;
-          } else if (image_domain_node.is_type<language::vector_type>()) {
-            data_type = getVectorDataType(image_domain_node);
-          } else if (image_domain_node.is_type<language::string_type>()) {
-            data_type = ASTNodeDataType::string_t;
-          }
-        }
-
-        Assert(data_type != ASTNodeDataType::undefined_t);   // LCOV_EXCL_LINE
-
-        n.m_data_type = data_type;
+        n.m_data_type = image_domain_node.m_data_type.contentType();
       } else if (n.children[0]->m_data_type == ASTNodeDataType::builtin_function_t) {
         const std::string builtin_function_name = n.children[0]->string();
         auto& symbol_table                      = *n.m_symbol_table;
@@ -460,7 +437,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       auto& array_expression = *n.children[0];
       auto& index_expression = *n.children[1];
 
-      ASTNodeNaturalConversionChecker{index_expression, ASTNodeDataType::int_t};
+      ASTNodeNaturalConversionChecker{index_expression, ASTNodeDataType::build<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)
@@ -469,15 +446,35 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
         throw ParseError(message.str(), n.begin());
       } else {
-        n.m_data_type = ASTNodeDataType::double_t;
+        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::double_t>();
       }
-    } else if (n.is_type<language::B_set>() or n.is_type<language::Z_set>() or n.is_type<language::N_set>() or
-               n.is_type<language::R_set>() or n.is_type<language::string_type>() or
-               n.is_type<language::vector_type>() or n.is_type<language::type_name_id>()) {
-      n.m_data_type = ASTNodeDataType::typename_t;
+    } else if (n.is_type<language::B_set>()) {
+      n.m_data_type =
+        ASTNodeDataType::build<ASTNodeDataType::typename_t>(ASTNodeDataType::build<ASTNodeDataType::bool_t>());
+    } else if (n.is_type<language::Z_set>()) {
+      n.m_data_type =
+        ASTNodeDataType::build<ASTNodeDataType::typename_t>(ASTNodeDataType::build<ASTNodeDataType::int_t>());
+    } else if (n.is_type<language::N_set>()) {
+      n.m_data_type =
+        ASTNodeDataType::build<ASTNodeDataType::typename_t>(ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>());
+    } else if (n.is_type<language::string_type>()) {
+      n.m_data_type =
+        ASTNodeDataType::build<ASTNodeDataType::typename_t>(ASTNodeDataType::build<ASTNodeDataType::string_t>());
+    } else if (n.is_type<language::R_set>()) {
+      n.m_data_type =
+        ASTNodeDataType::build<ASTNodeDataType::typename_t>(ASTNodeDataType::build<ASTNodeDataType::double_t>());
+    } else if (n.is_type<language::vector_type>()) {
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::typename_t>(getVectorDataType(n));
     } else if (n.is_type<language::name_list>() or n.is_type<language::lvalue_list>() or
                n.is_type<language::function_argument_list>() or n.is_type<language::expression_list>()) {
-      n.m_data_type = ASTNodeDataType::list_t;
+      std::vector<std::shared_ptr<const ASTNodeDataType>> sub_data_type_list;
+      sub_data_type_list.reserve(n.children.size());
+
+      for (size_t i = 0; i < n.children.size(); ++i) {
+        sub_data_type_list.push_back(std::make_shared<const ASTNodeDataType>(n.children[i]->m_data_type));
+      }
+
+      n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::list_t>(sub_data_type_list);
     }
   }
 }
@@ -485,17 +482,9 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 ASTNodeDataTypeBuilder::ASTNodeDataTypeBuilder(ASTNode& node)
 {
   Assert(node.is_root());
-  node.m_data_type = ASTNodeDataType::void_t;
+  node.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
 
   this->_buildNodeDataTypes(node);
 
-  FunctionTable& function_table = node.m_symbol_table->functionTable();
-  for (size_t function_id = 0; function_id < function_table.size(); ++function_id) {
-    FunctionDescriptor& function_descriptor = function_table[function_id];
-    ASTNode& function_expression            = function_descriptor.definitionNode();
-
-    this->_buildNodeDataTypes(function_expression);
-  }
-
   std::cout << " - build node data types\n";
 }
diff --git a/src/language/ast/ASTNodeDataTypeBuilder.hpp b/src/language/ast/ASTNodeDataTypeBuilder.hpp
index 93643c82d80c9c222cb12b482416a661ff20fb31..be2c35adfb2ab81479ef27d385be880b35b0538c 100644
--- a/src/language/ast/ASTNodeDataTypeBuilder.hpp
+++ b/src/language/ast/ASTNodeDataTypeBuilder.hpp
@@ -6,7 +6,7 @@
 class ASTNodeDataTypeBuilder
 {
  private:
-  ASTNodeDataType _buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const;
+  void _buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const;
 
   void _buildNodeDataTypes(ASTNode& node) const;
 
diff --git a/src/language/ast/ASTNodeDataTypeFlattener.cpp b/src/language/ast/ASTNodeDataTypeFlattener.cpp
index da2d064c6dd677e9eae4444cde59700c3a61ec2d..51d055836393b1ee680b7d983756bee39020d992 100644
--- a/src/language/ast/ASTNodeDataTypeFlattener.cpp
+++ b/src/language/ast/ASTNodeDataTypeFlattener.cpp
@@ -11,7 +11,7 @@ ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataT
       ASTNodeDataTypeFlattener{*child_node, flattened_datatype_list};
     }
   } else if (node.is_type<language::function_evaluation>()) {
-    if (node.m_data_type != ASTNodeDataType::typename_t) {
+    if (node.m_data_type != ASTNodeDataType::list_t) {
       flattened_datatype_list.push_back({node.m_data_type, node});
     } else {
       ASTNode& function_name_node = *node.children[0];
@@ -28,24 +28,8 @@ ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataT
         ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1];
 
         for (auto& image_sub_domain : function_image_domain.children) {
-          ASTNodeDataType data_type = ASTNodeDataType::undefined_t;
-
-          if (image_sub_domain->is_type<language::B_set>()) {
-            data_type = ASTNodeDataType::bool_t;
-          } else if (image_sub_domain->is_type<language::Z_set>()) {
-            data_type = ASTNodeDataType::int_t;
-          } else if (image_sub_domain->is_type<language::N_set>()) {
-            data_type = ASTNodeDataType::unsigned_int_t;
-          } else if (image_sub_domain->is_type<language::R_set>()) {
-            data_type = ASTNodeDataType::double_t;
-          } else if (image_sub_domain->is_type<language::vector_type>()) {
-            data_type = getVectorDataType(*image_sub_domain);
-          } else if (image_sub_domain->is_type<language::string_type>()) {
-            data_type = ASTNodeDataType::string_t;
-          }
-
-          Assert(data_type != ASTNodeDataType::undefined_t);
-          flattened_datatype_list.push_back({data_type, node});
+          Assert(image_sub_domain->m_data_type == ASTNodeDataType::typename_t);
+          flattened_datatype_list.push_back({image_sub_domain->m_data_type.contentType(), node});
         }
         break;
       }
diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
index 072a2af6015eed0dab37468c0c5e7211ec887eff..af8b1cbc0b4ca138f86601755493e90a089ff0c2 100644
--- a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
@@ -36,7 +36,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
       // LCOV_EXCL_START
     default: {
       throw ParseError("unexpected error: invalid argument type 0",
-                        std::vector{node_sub_data_type.m_parent_node.begin()});
+                       std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -52,7 +52,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
       } else {
         // LCOV_EXCL_START
         throw ParseError("unexpected error: invalid argument dimension",
-                          std::vector{node_sub_data_type.m_parent_node.begin()});
+                         std::vector{node_sub_data_type.m_parent_node.begin()});
         // LCOV_EXCL_STOP
       }
     }
@@ -62,7 +62,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
       } else {
         // LCOV_EXCL_START
         throw ParseError("unexpected error: invalid argument dimension",
-                          std::vector{node_sub_data_type.m_parent_node.begin()});
+                         std::vector{node_sub_data_type.m_parent_node.begin()});
         // LCOV_EXCL_STOP
       }
     }
@@ -77,7 +77,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
       // LCOV_EXCL_START
     default: {
       throw ParseError("unexpected error: invalid argument type",
-                        std::vector{node_sub_data_type.m_parent_node.begin()});
+                       std::vector{node_sub_data_type.m_parent_node.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -218,7 +218,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
       // LCOV_EXCL_START
     default: {
       throw ParseError("unexpected error: undefined expression value type for function",
-                        std::vector{node.children[1]->begin()});
+                       std::vector{node.children[1]->begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -233,7 +233,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
       } else {
         // LCOV_EXCL_START
         throw ParseError("unexpected error: invalid dimension for returned vector",
-                          std::vector{function_component_expression.begin()});
+                         std::vector{function_component_expression.begin()});
         // LCOV_EXCL_STOP
       }
     }
@@ -244,7 +244,7 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
       } else {
         // LCOV_EXCL_START
         throw ParseError("unexpected error: invalid dimension for returned vector",
-                          std::vector{function_component_expression.begin()});
+                         std::vector{function_component_expression.begin()});
         // LCOV_EXCL_STOP
       }
     }
@@ -256,13 +256,13 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& r
       }
       // LCOV_EXCL_START
       throw ParseError("unexpected error: undefined expression value type for function",
-                        std::vector{function_component_expression.begin()});
+                       std::vector{function_component_expression.begin()});
       // LCOV_EXCL_STOP
     }
     // LCOV_EXCL_START
     default: {
       throw ParseError("unexpected error: undefined expression value type for function",
-                        std::vector{function_component_expression.begin()});
+                       std::vector{function_component_expression.begin()});
     }
       // LCOV_EXCL_STOP
     }
@@ -330,29 +330,13 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
 
   std::unique_ptr function_processor = this->_buildArgumentConverter(function_descriptor, node);
 
-  auto add_component_expression = [&](ASTNode& expression_node, ASTNode& domain_node) {
-    ASTNodeDataType return_value_type = ASTNodeDataType::undefined_t;
+  auto add_component_expression = [&](ASTNode& expression_node, const ASTNode& image_domain_node) {
+    Assert(image_domain_node.m_data_type == ASTNodeDataType::typename_t);
 
-    ASTNode& image_domain_node = domain_node;
-
-    if (image_domain_node.is_type<language::B_set>()) {
-      return_value_type = ASTNodeDataType::bool_t;
-    } else if (image_domain_node.is_type<language::Z_set>()) {
-      return_value_type = ASTNodeDataType::int_t;
-    } else if (image_domain_node.is_type<language::N_set>()) {
-      return_value_type = ASTNodeDataType::unsigned_int_t;
-    } else if (image_domain_node.is_type<language::R_set>()) {
-      return_value_type = ASTNodeDataType::double_t;
-    } else if (image_domain_node.is_type<language::vector_type>()) {
-      return_value_type = getVectorDataType(image_domain_node);
-    } else if (image_domain_node.is_type<language::string_type>()) {
-      return_value_type = ASTNodeDataType::string_t;
-    }
-
-    Assert(return_value_type != ASTNodeDataType::undefined_t);
+    const ASTNodeDataType return_value_type = image_domain_node.m_data_type.contentType();
 
     if ((return_value_type == ASTNodeDataType::vector_t) and (return_value_type.dimension() == 1)) {
-      ASTNodeNaturalConversionChecker{expression_node, ASTNodeDataType::double_t};
+      ASTNodeNaturalConversionChecker{expression_node, ASTNodeDataType::build<ASTNodeDataType::double_t>()};
     } else {
       ASTNodeNaturalConversionChecker{expression_node, return_value_type};
     }
@@ -364,11 +348,14 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
   ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1];
   ASTNode& function_expression   = *function_descriptor.definitionNode().children[1];
 
+  Assert(function_image_domain.m_data_type == ASTNodeDataType::typename_t);
+  const ASTNodeDataType function_return_type = function_image_domain.m_data_type.contentType();
+
   if (function_image_domain.is_type<language::vector_type>()) {
     ASTNodeDataType vector_type = getVectorDataType(function_image_domain);
 
     if ((vector_type.dimension() == 1) and (function_expression.m_data_type != ASTNodeDataType::vector_t)) {
-      ASTNodeNaturalConversionChecker{function_expression, ASTNodeDataType::double_t};
+      ASTNodeNaturalConversionChecker{function_expression, ASTNodeDataType::build<ASTNodeDataType::double_t>()};
     } else {
       ASTNodeNaturalConversionChecker{function_expression, vector_type};
     }
@@ -377,7 +364,8 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
 
       for (size_t i = 0; i < vector_type.dimension(); ++i) {
         function_processor->addFunctionExpressionProcessor(
-          this->_getFunctionProcessor(ASTNodeDataType::double_t, node, *function_expression.children[i]));
+          this->_getFunctionProcessor(ASTNodeDataType::build<ASTNodeDataType::double_t>(), node,
+                                      *function_expression.children[i]));
       }
 
       switch (vector_type.dimension()) {
diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
index daa5a0bd371150ffd3d33a60993a3d4d10c48d96..9da8319fa5119fa22b3d6ce95e6e1e1084b401f2 100644
--- a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
@@ -190,7 +190,7 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
 
   if ((value_node.m_data_type != rhs_node_sub_data_type.m_data_type) and
       (value_node.m_data_type == ASTNodeDataType::vector_t) and (value_node.m_data_type.dimension() == 1)) {
-    ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, ASTNodeDataType::double_t};
+    ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, ASTNodeDataType::build<ASTNodeDataType::double_t>()};
   } else {
     ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, value_node.m_data_type};
   }
@@ -211,7 +211,7 @@ ASTNodeListAffectationExpressionBuilder::_buildListAffectationProcessor()
   ASTNode& name_list_node = *m_node.children[0];
 
   if (name_list_node.children.size() != flattened_rhs_data_type_list.size()) {
-    throw ParseError("incompatible list sizes in affectation", std::vector{m_node.begin()});
+    throw ParseError("incompatible list sizes in affectation", std::vector{m_node.children[0]->begin()});
   }
 
   using ListAffectationProcessorT = ListAffectationProcessor<OperatorT>;
diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.cpp b/src/language/ast/ASTNodeNaturalConversionChecker.cpp
index 0faabac4fa7d0cb197ba3b8f35ffcfadce3f162a..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,26 +32,41 @@ 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::vector_t) {
-    switch (node.m_data_type) {
+  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 (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, ASTNodeDataType::double_t);
+
+      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>());
       }
 
       break;
     }
     case ASTNodeDataType::vector_t: {
       if (data_type.dimension() != target_data_type.dimension()) {
-        throw ParseError("incompatible dimensions in affectation", std::vector{node.begin()});
+        std::ostringstream error_message;
+        error_message << "invalid implicit conversion: ";
+        error_message << rang::fgB::red << dataTypeName(data_type) << " -> " << dataTypeName(target_data_type)
+                      << rang::fg::reset;
+        throw ParseError(error_message.str(), std::vector{node.begin()});
       }
       break;
     }
@@ -67,7 +91,8 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo
           (target_data_type.contentType().dimension() == 1)) {
         for (const auto& child : node.children) {
           if (not isNaturalConversion(child->m_data_type, target_data_type)) {
-            this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, ASTNodeDataType::double_t);
+            this->_checkIsNaturalExpressionConversion(*child, child->m_data_type,
+                                                      ASTNodeDataType::build<ASTNodeDataType::double_t>());
           }
         }
       } else {
@@ -79,7 +104,8 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo
       if ((target_data_type.contentType() == ASTNodeDataType::vector_t) and
           (target_data_type.contentType().dimension() == 1)) {
         if (not isNaturalConversion(data_type, target_data_type)) {
-          this->_checkIsNaturalExpressionConversion(node, data_type, ASTNodeDataType::double_t);
+          this->_checkIsNaturalExpressionConversion(node, data_type,
+                                                    ASTNodeDataType::build<ASTNodeDataType::double_t>());
         }
       } else {
         this->_checkIsNaturalExpressionConversion(node, data_type, target_content_type);
@@ -90,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/src/language/ast/ASTSymbolInitializationChecker.cpp b/src/language/ast/ASTSymbolInitializationChecker.cpp
index 3a8c846a3626a3acb815a401767d898b378f546c..0e4d441fe590fb16534987bc1683ee2aadf0e98e 100644
--- a/src/language/ast/ASTSymbolInitializationChecker.cpp
+++ b/src/language/ast/ASTSymbolInitializationChecker.cpp
@@ -37,9 +37,10 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
       if (node.children.size() == 4) {
         ASTNode& decl_name_list_node = *node.children[0];
         ASTNode& def_name_list_node  = *node.children[2];
-        Assert(def_name_list_node.is_type<language::name_list>());
-        ASTNode& expression_list_node = *node.children[3];
-        Assert(expression_list_node.is_type<language::expression_list>());
+
+        if (not def_name_list_node.is_type<language::name_list>()) {
+          throw ParseError("expecting a list of identifiers", std::vector{def_name_list_node.begin()});
+        }
 
         if (decl_name_list_node.children.size() != def_name_list_node.children.size()) {
           std::ostringstream os;
@@ -47,12 +48,8 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
              << " found " << def_name_list_node.children.size() << std::ends;
           throw ParseError(os.str(), std::vector{def_name_list_node.begin()});
         }
-        if (def_name_list_node.children.size() != expression_list_node.children.size()) {
-          std::ostringstream os;
-          os << "invalid number of definition expressions, expecting " << decl_name_list_node.children.size()
-             << " found " << expression_list_node.children.size() << std::ends;
-          throw ParseError(os.str(), std::vector{expression_list_node.begin()});
-        }
+
+        ASTNode& expression_list_node = *node.children[3];
 
         this->_checkSymbolInitialization(expression_list_node);
         for (size_t i = 0; i < decl_name_list_node.children.size(); ++i) {
diff --git a/src/language/modules/MeshModule.hpp b/src/language/modules/MeshModule.hpp
index f2c3d3d6360e5fd378d128d3b6b57e0de5a04509..ebb1383107ffd288001a48a5abced722ef37a4bd 100644
--- a/src/language/modules/MeshModule.hpp
+++ b/src/language/modules/MeshModule.hpp
@@ -8,7 +8,8 @@
 class IMesh;
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IMesh>> = {ASTNodeDataType::type_id_t, "mesh"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IMesh>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("mesh");
 
 class MeshModule : public BuiltinModule
 {
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index aa5c1fce3ee96c5318d930d75f2047df0d209735..497ba083ac2d9d2ca0359c5d73e85e094b1fed0e 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -63,11 +63,12 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab
     const IModule& populating_module = *i_module->second;
 
     this->_populateEmbedderTableT(module_name_node, populating_module.getNameBuiltinFunctionMap(),
-                                  ASTNodeDataType::builtin_function_t, symbol_table,
+                                  ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>(), symbol_table,
                                   symbol_table.builtinFunctionEmbedderTable());
 
-    this->_populateEmbedderTableT(module_name_node, populating_module.getNameTypeMap(), ASTNodeDataType::type_name_id_t,
-                                  symbol_table, symbol_table.typeEmbedderTable());
+    this->_populateEmbedderTableT(module_name_node, populating_module.getNameTypeMap(),
+                                  ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
+                                  symbol_table.typeEmbedderTable());
   } else {
     throw ParseError(std::string{"could not find module "} + module_name, std::vector{module_name_node.begin()});
   }
diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp
index 3c70be9a2db29d634b71ea96fb60fce38183c85d..96418b1693d377641f9bd096d263d5d17c6b929d 100644
--- a/src/language/modules/SchemeModule.hpp
+++ b/src/language/modules/SchemeModule.hpp
@@ -8,12 +8,12 @@
 class IBoundaryDescriptor;
 template <>
 inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>> =
-  {ASTNodeDataType::type_id_t, "boundary"};
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("boundary");
 
 class IBoundaryConditionDescriptor;
 template <>
 inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IBoundaryConditionDescriptor>> =
-  {ASTNodeDataType::type_id_t, "boundary_condition"};
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("boundary_condition");
 
 class SchemeModule : public BuiltinModule
 {
diff --git a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
index 7ed93683d1b6bcfd54e624385429bce4319976d5..713eda89aec0804efb4bcd323cb9a65c10b8967d 100644
--- a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
+++ b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
@@ -42,7 +42,7 @@ class ASTNodeExpressionListProcessor final : public INodeProcessor
 
     for (auto& child : m_node.children) {
       if (child->is_type<language::function_evaluation>()) {
-        if (child->m_data_type != ASTNodeDataType::typename_t) {
+        if (child->m_data_type != ASTNodeDataType::list_t) {
           ++number_of_values;
         } else {
           ASTNode& function_name_node = *child->children[0];
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index 6898bb2c2b25e4fe44a8f6e9ad271930086f0a81..e15d4aa692e9ddbc54ac086317b9ce8289c28b4c 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -488,9 +488,13 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor
                   child_value[j]);
               }
             } else if constexpr (std::is_same_v<T, int64_t>) {
-              // in this case a 0 is given
-              Assert(child_value == 0);
-              tuple_value[i] = ZeroType{};
+              if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+                tuple_value[i][0] = child_value;
+              } else {
+                // in this case a 0 is given
+                Assert(child_value == 0);
+                tuple_value[i] = ZeroType{};
+              }
             } else {
               // LCOV_EXCL_START
               throw ParseError("unexpected error: unexpected right hand side type in affectation",
diff --git a/src/language/utils/ASTNodeDataTypeTraits.hpp b/src/language/utils/ASTNodeDataTypeTraits.hpp
index 4ee3ba31bf60d3ca4f006fd0510fae0c1fc14056..946d63483dc8a61c33ade0b223c0619a66880fdd 100644
--- a/src/language/utils/ASTNodeDataTypeTraits.hpp
+++ b/src/language/utils/ASTNodeDataTypeTraits.hpp
@@ -8,27 +8,28 @@
 #include <vector>
 
 template <typename T>
-inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType::undefined_t;
+inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType{};
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<void> = ASTNodeDataType::void_t;
+inline ASTNodeDataType ast_node_data_type_from<void> = ASTNodeDataType::build<ASTNodeDataType::void_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::bool_t;
+inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::int_t;
+inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::unsigned_int_t;
+inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::double_t;
+inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::build<ASTNodeDataType::double_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::string_t;
+inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 template <>
-inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> = ASTNodeDataType::function_t;
+inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> =
+  ASTNodeDataType::build<ASTNodeDataType::function_t>();
 template <size_t N>
-inline ASTNodeDataType ast_node_data_type_from<TinyVector<N>> = {ASTNodeDataType::vector_t, N};
+inline ASTNodeDataType ast_node_data_type_from<TinyVector<N>> = ASTNodeDataType::build<ASTNodeDataType::vector_t>(N);
 
 template <typename T>
 inline ASTNodeDataType ast_node_data_type_from<std::vector<T>> =
-  ASTNodeDataType{ASTNodeDataType::tuple_t, ast_node_data_type_from<T>};
+  ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ast_node_data_type_from<T>);
 
 #endif   // AST_NODE_DATA_TYPE_TRAITS_H
diff --git a/src/language/utils/BuiltinFunctionEmbedder.hpp b/src/language/utils/BuiltinFunctionEmbedder.hpp
index 3974398e1803856585f91f09565b29da3d877533..d394aa20f9721a1dc12821960890d0c1f0b6db1c 100644
--- a/src/language/utils/BuiltinFunctionEmbedder.hpp
+++ b/src/language/utils/BuiltinFunctionEmbedder.hpp
@@ -126,14 +126,8 @@ class BuiltinFunctionEmbedder<FX(Args...)> : public IBuiltinFunctionEmbedder
   PUGS_INLINE ASTNodeDataType
   _getDataType() const
   {
-    if constexpr (is_data_variant_v<T>) {
-      return ast_node_data_type_from<T>;
-    } else if constexpr (std::is_same_v<void, T>) {
-      return ASTNodeDataType::void_t;
-    } else {
-      Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t);
-      return ast_node_data_type_from<T>;
-    }
+    Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t);
+    return ast_node_data_type_from<T>;
   }
 
   template <size_t I>
@@ -262,14 +256,8 @@ class BuiltinFunctionEmbedder<FX(void)> : public IBuiltinFunctionEmbedder
   PUGS_INLINE ASTNodeDataType
   _getDataType() const
   {
-    if constexpr (is_data_variant_v<T>) {
-      return ast_node_data_type_from<T>;
-    } else if constexpr (std::is_same_v<void, T>) {
-      return ASTNodeDataType::void_t;
-    } else {
-      Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t);
-      return ast_node_data_type_from<T>;
-    }
+    Assert(ast_node_data_type_from<T> != ASTNodeDataType::undefined_t);
+    return ast_node_data_type_from<T>;
   }
 
  public:
diff --git a/src/language/utils/PugsFunctionAdapter.hpp b/src/language/utils/PugsFunctionAdapter.hpp
index 660cae99e206b3320a9d28861fbc2ee0236d6022..4890664880c6e9bd3ce018f03db67c97b0587020 100644
--- a/src/language/utils/PugsFunctionAdapter.hpp
+++ b/src/language/utils/PugsFunctionAdapter.hpp
@@ -36,12 +36,14 @@ class PugsFunctionAdapter<OutputType(InputType...)>
 
   template <size_t I>
   [[nodiscard]] PUGS_INLINE static bool
-  _checkValidArgumentDataType(const ASTNode& arg_expression) noexcept
+  _checkValidArgumentDataType(const ASTNode& arg_expression) noexcept(NO_ASSERT)
   {
     using Arg = std::tuple_element_t<I, InputTuple>;
 
     constexpr const ASTNodeDataType& expected_input_data_type = ast_node_data_type_from<Arg>;
-    const ASTNodeDataType& arg_data_type                      = arg_expression.m_data_type;
+
+    Assert(arg_expression.m_data_type == ASTNodeDataType::typename_t);
+    const ASTNodeDataType& arg_data_type = arg_expression.m_data_type.contentType();
 
     return isNaturalConversion(expected_input_data_type, arg_data_type);
   }
@@ -55,53 +57,28 @@ class PugsFunctionAdapter<OutputType(InputType...)>
   }
 
   [[nodiscard]] PUGS_INLINE static bool
-  _checkValidInputDataType(const ASTNode& input_expression) noexcept
+  _checkValidInputDomain(const ASTNode& input_domain_expression) noexcept
   {
     if constexpr (NArgs == 1) {
-      return _checkValidArgumentDataType<0>(input_expression);
+      return _checkValidArgumentDataType<0>(input_domain_expression);
     } else {
-      if (input_expression.children.size() != NArgs) {
+      if ((input_domain_expression.m_data_type.contentType() != ASTNodeDataType::list_t) or
+          (input_domain_expression.children.size() != NArgs)) {
         return false;
       }
 
       using IndexSequence = std::make_index_sequence<NArgs>;
-      return _checkAllInputDataType(input_expression, IndexSequence{});
+      return _checkAllInputDataType(input_domain_expression, IndexSequence{});
     }
   }
 
   [[nodiscard]] PUGS_INLINE static bool
-  _checkValidOutputDataType(const ASTNode& return_expression) noexcept
+  _checkValidOutputDomain(const ASTNode& output_domain_expression) noexcept(NO_ASSERT)
   {
     constexpr const ASTNodeDataType& expected_return_data_type = ast_node_data_type_from<OutputType>;
-    const ASTNodeDataType& return_data_type                    = return_expression.m_data_type;
+    const ASTNodeDataType& return_data_type                    = output_domain_expression.m_data_type.contentType();
 
-    if (not isNaturalConversion(return_data_type, expected_return_data_type)) {
-      if (expected_return_data_type == ASTNodeDataType::vector_t) {
-        if (return_data_type == ASTNodeDataType::list_t) {
-          if (expected_return_data_type.dimension() != return_expression.children.size()) {
-            return false;
-          } else {
-            for (const auto& child : return_expression.children) {
-              const ASTNodeDataType& data_type = child->m_data_type;
-              if (not isNaturalConversion(data_type, ast_node_data_type_from<double>)) {
-                return false;
-              }
-            }
-          }
-        } else if ((expected_return_data_type.dimension() == 1) and
-                   isNaturalConversion(return_data_type, ast_node_data_type_from<double>)) {
-          return true;
-        } else if (return_data_type == ast_node_data_type_from<int64_t>) {
-          // 0 is the only valid value for vectors
-          return (return_expression.string() == "0");
-        } else {
-          return false;
-        }
-      } else {
-        return false;
-      }
-    }
-    return true;
+    return isNaturalConversion(return_data_type, expected_return_data_type);
   }
 
   template <typename Arg, typename... RemainingArgs>
@@ -124,10 +101,10 @@ class PugsFunctionAdapter<OutputType(InputType...)>
   PUGS_INLINE static void
   _checkFunction(const FunctionDescriptor& function)
   {
-    bool has_valid_input  = _checkValidInputDataType(*function.definitionNode().children[0]);
-    bool has_valid_output = _checkValidOutputDataType(*function.definitionNode().children[1]);
+    bool has_valid_input_domain = _checkValidInputDomain(*function.domainMappingNode().children[0]);
+    bool has_valid_output       = _checkValidOutputDomain(*function.domainMappingNode().children[1]);
 
-    if (not(has_valid_input and has_valid_output)) {
+    if (not(has_valid_input_domain and has_valid_output)) {
       std::ostringstream error_message;
       error_message << "invalid function type" << rang::style::reset << "\nnote: expecting " << rang::fgB::yellow
                     << _getInputDataTypeName() << " -> " << dataTypeName(ast_node_data_type_from<OutputType>)
diff --git a/src/language/utils/SymbolTable.hpp b/src/language/utils/SymbolTable.hpp
index 3eba77ec9c495a50183acda709abf030cbfc522b..6bcf267780884d1d8a1492b664ff492026ddd869 100644
--- a/src/language/utils/SymbolTable.hpp
+++ b/src/language/utils/SymbolTable.hpp
@@ -25,7 +25,7 @@ class SymbolTable
 
     bool m_is_initialized{false};
 
-    ASTNodeDataType m_data_type{ASTNodeDataType::undefined_t};
+    ASTNodeDataType m_data_type;
     DataVariant m_value;
 
    public:
diff --git a/tests/test_ASTNodeAffectationExpressionBuilder.cpp b/tests/test_ASTNodeAffectationExpressionBuilder.cpp
index 895fa860eafe2f6216066d422597e539c1a1cd65..64d60d9bfbed21703850f2d945092a9d5ae49fe0 100644
--- a/tests/test_ASTNodeAffectationExpressionBuilder.cpp
+++ b/tests/test_ASTNodeAffectationExpressionBuilder.cpp
@@ -40,8 +40,8 @@
   }
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t,
-                                                                                 "builtin_t"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t");
 const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>;
 
 #define CHECK_AST_WITH_BUILTIN(data, expected_output)                                                         \
@@ -59,7 +59,7 @@ const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const dou
       throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");        \
     }                                                                                                         \
                                                                                                               \
-    i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t);                                      \
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());            \
     i_symbol->attributes().setIsInitialized();                                                                \
     i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();                                 \
     symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \
@@ -124,7 +124,7 @@ const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const dou
       throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");        \
     }                                                                                                         \
                                                                                                               \
-    i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t);                                      \
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());            \
     i_symbol->attributes().setIsInitialized();                                                                \
     i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();                                 \
     symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \
@@ -1530,9 +1530,9 @@ let x : R, x=1; x/=2.3;
     {
       auto ast = std::make_unique<ASTNode>();
       ast->set_type<language::eq_op>();
-      ast->m_data_type = ASTNodeDataType::int_t;
 
       ast->children.emplace_back(std::make_unique<ASTNode>());
+      ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       ast->children.emplace_back(std::make_unique<ASTNode>());
       REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast},
                           "unexpected error: invalid implicit conversion: undefined -> Z");
@@ -1542,9 +1542,9 @@ let x : R, x=1; x/=2.3;
     {
       auto ast = std::make_unique<ASTNode>();
       ast->set_type<language::eq_op>();
-      ast->m_data_type = ASTNodeDataType::string_t;
 
       ast->children.emplace_back(std::make_unique<ASTNode>());
+      ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
       ast->children.emplace_back(std::make_unique<ASTNode>());
       REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast},
                           "unexpected error: invalid implicit conversion: undefined -> string");
@@ -1627,7 +1627,7 @@ let s : string, s="foo"; s*=2;
 let x : R^3; let y : R^1; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^1 -> R^3";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1638,7 +1638,7 @@ let x : R^3; let y : R^1; x = y;
 let x : R^3; let y : R^2; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^2 -> R^3";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1649,7 +1649,7 @@ let x : R^3; let y : R^2; x = y;
 let x : R^2; let y : R^1; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^1 -> R^2";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1660,7 +1660,7 @@ let x : R^2; let y : R^1; x = y;
 let x : R^2; let y : R^3; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^3 -> R^2";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1671,7 +1671,7 @@ let x : R^2; let y : R^3; x = y;
 let x : R^1; let y : R^2; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^2 -> R^1";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1679,10 +1679,10 @@ let x : R^1; let y : R^2; x = y;
       SECTION("R^1 <- R^3")
       {
         std::string_view data = R"(
-let x : R^1; let y : R^2; x = y;
+let x : R^1; let y : R^3; x = y;
 )";
 
-        std::string error_message = "incompatible dimensions in affectation";
+        std::string error_message = "invalid implicit conversion: R^3 -> R^1";
 
         CHECK_AST_THROWS_WITH(data, error_message);
       }
@@ -1799,20 +1799,6 @@ let (x,y,z):R*R*R, (x,y) = (2,3);
                           std::string{"invalid number of definition identifiers, expecting 3 found 2"});
     }
 
-    SECTION("incorrect identifier/expression number of symbols")
-    {
-      std::string_view data = R"(
-let (x,y,z):R*R*R, (x,y,z) = (2,3);
-)";
-
-      string_input input{data, "test.pgs"};
-      auto ast = ASTBuilder::build(input);
-
-      ASTSymbolTableBuilder{*ast};
-      REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast},
-                          std::string{"invalid number of definition expressions, expecting 3 found 2"});
-    }
-
     SECTION("incorrect identifier/expression number of symbols")
     {
       std::string_view data = R"(
diff --git a/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp b/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp
index 941df56ac9d28de2aa5a211c61964b8d9ce05ee6..45b1303c3db5c69457921d98f76f43403274d7ed 100644
--- a/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp
+++ b/tests/test_ASTNodeArraySubscriptExpressionBuilder.cpp
@@ -18,7 +18,7 @@ TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
     {
       {
         std::unique_ptr array_node = std::make_unique<ASTNode>();
-        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        array_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
         node->emplace_back(std::move(array_node));
       }
       REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
@@ -31,7 +31,7 @@ TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
     {
       {
         std::unique_ptr array_node = std::make_unique<ASTNode>();
-        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        array_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         node->emplace_back(std::move(array_node));
       }
       REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
@@ -44,7 +44,7 @@ TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
     {
       {
         std::unique_ptr array_node = std::make_unique<ASTNode>();
-        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        array_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
         node->emplace_back(std::move(array_node));
       }
       REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
@@ -62,7 +62,7 @@ TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
     {
       {
         std::unique_ptr array_node = std::make_unique<ASTNode>();
-        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 0};
+        array_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::vector_t>(0);
         node->emplace_back(std::move(array_node));
       }
       REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension");
@@ -71,7 +71,7 @@ TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
     {
       {
         std::unique_ptr array_node = std::make_unique<ASTNode>();
-        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 4};
+        array_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::vector_t>(4);
         node->emplace_back(std::move(array_node));
       }
       REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension");
diff --git a/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp b/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp
index 78a3f5f3b16bfdcb804421cc41e59a1c37abde4f..7226ec270bc72889cc13d37ebda069cbad7d3512 100644
--- a/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp
+++ b/tests/test_ASTNodeBinaryOperatorExpressionBuilder.cpp
@@ -1434,8 +1434,8 @@ x!=y;
         ast->set_type<language::multiply_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1446,8 +1446,8 @@ x!=y;
         ast->set_type<language::multiply_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1458,8 +1458,8 @@ x!=y;
         ast->set_type<language::multiply_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1470,8 +1470,8 @@ x!=y;
         ast->set_type<language::divide_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1482,8 +1482,8 @@ x!=y;
         ast->set_type<language::divide_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1494,8 +1494,8 @@ x!=y;
         ast->set_type<language::divide_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1506,8 +1506,8 @@ x!=y;
         ast->set_type<language::plus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1518,8 +1518,8 @@ x!=y;
         ast->set_type<language::plus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::void_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1530,8 +1530,8 @@ x!=y;
         ast->set_type<language::plus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1542,8 +1542,8 @@ x!=y;
         ast->set_type<language::minus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1554,8 +1554,8 @@ x!=y;
         ast->set_type<language::minus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1566,8 +1566,8 @@ x!=y;
         ast->set_type<language::minus_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1578,8 +1578,8 @@ x!=y;
         ast->set_type<language::or_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1590,8 +1590,8 @@ x!=y;
         ast->set_type<language::or_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1602,8 +1602,8 @@ x!=y;
         ast->set_type<language::or_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1614,8 +1614,8 @@ x!=y;
         ast->set_type<language::and_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1626,8 +1626,8 @@ x!=y;
         ast->set_type<language::and_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1638,8 +1638,8 @@ x!=y;
         ast->set_type<language::and_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1650,8 +1650,8 @@ x!=y;
         ast->set_type<language::xor_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1662,8 +1662,8 @@ x!=y;
         ast->set_type<language::xor_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1674,8 +1674,8 @@ x!=y;
         ast->set_type<language::xor_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1686,8 +1686,8 @@ x!=y;
         ast->set_type<language::greater_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1698,8 +1698,8 @@ x!=y;
         ast->set_type<language::greater_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1710,8 +1710,8 @@ x!=y;
         ast->set_type<language::greater_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1722,8 +1722,8 @@ x!=y;
         ast->set_type<language::lesser_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1734,8 +1734,8 @@ x!=y;
         ast->set_type<language::lesser_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1746,8 +1746,8 @@ x!=y;
         ast->set_type<language::lesser_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1758,8 +1758,8 @@ x!=y;
         ast->set_type<language::greater_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1770,8 +1770,8 @@ x!=y;
         ast->set_type<language::greater_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1782,8 +1782,8 @@ x!=y;
         ast->set_type<language::greater_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1794,8 +1794,8 @@ x!=y;
         ast->set_type<language::lesser_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1806,8 +1806,8 @@ x!=y;
         ast->set_type<language::lesser_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1818,8 +1818,8 @@ x!=y;
         ast->set_type<language::lesser_or_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1830,8 +1830,8 @@ x!=y;
         ast->set_type<language::eqeq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1842,8 +1842,8 @@ x!=y;
         ast->set_type<language::eqeq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1854,8 +1854,8 @@ x!=y;
         ast->set_type<language::eqeq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1866,8 +1866,8 @@ x!=y;
         ast->set_type<language::not_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::void_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1878,8 +1878,8 @@ x!=y;
         ast->set_type<language::not_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::string_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::int_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
@@ -1890,8 +1890,8 @@ x!=y;
         ast->set_type<language::not_eq_op>();
         ast->children.emplace_back(std::make_unique<ASTNode>());
         ast->children.emplace_back(std::make_unique<ASTNode>());
-        ast->children[0]->m_data_type = ASTNodeDataType::int_t;
-        ast->children[1]->m_data_type = ASTNodeDataType::string_t;
+        ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+        ast->children[1]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
 
         REQUIRE_THROWS_WITH(ASTNodeBinaryOperatorExpressionBuilder{*ast}, "undefined operand type for binary operator");
       }
diff --git a/tests/test_ASTNodeDataType.cpp b/tests/test_ASTNodeDataType.cpp
index 5a7b09eb32ace24066a3264d1acb055c33364dc7..21f5c08bfbe6399b8d5a27ea2c33b56e84f78232 100644
--- a/tests/test_ASTNodeDataType.cpp
+++ b/tests/test_ASTNodeDataType.cpp
@@ -15,66 +15,75 @@ struct vector_type;
 
 TEST_CASE("ASTNodeDataType", "[language]")
 {
+  const ASTNodeDataType undefined_dt        = ASTNodeDataType{};
+  const ASTNodeDataType bool_dt             = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
+  const ASTNodeDataType unsigned_int_dt     = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
+  const ASTNodeDataType int_dt              = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+  const ASTNodeDataType double_dt           = ASTNodeDataType::build<ASTNodeDataType::double_t>();
+  const ASTNodeDataType string_dt           = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+  const ASTNodeDataType void_dt             = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+  const ASTNodeDataType function_dt         = ASTNodeDataType::build<ASTNodeDataType::function_t>();
+  const ASTNodeDataType builtin_function_dt = ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>();
+
+  std::vector<std::shared_ptr<const ASTNodeDataType>> type_list;
+  type_list.push_back(std::make_shared<const ASTNodeDataType>(double_dt));
+  type_list.push_back(std::make_shared<const ASTNodeDataType>(int_dt));
+
+  const ASTNodeDataType list_dt = ASTNodeDataType::build<ASTNodeDataType::list_t>(type_list);
+
   SECTION("dataTypeName")
   {
-    REQUIRE(dataTypeName(ASTNodeDataType::undefined_t) == "undefined");
-    REQUIRE(dataTypeName(ASTNodeDataType::bool_t) == "B");
-    REQUIRE(dataTypeName(ASTNodeDataType::unsigned_int_t) == "N");
-    REQUIRE(dataTypeName(ASTNodeDataType::int_t) == "Z");
-    REQUIRE(dataTypeName(ASTNodeDataType::double_t) == "R");
-    REQUIRE(dataTypeName(ASTNodeDataType::string_t) == "string");
-    REQUIRE(dataTypeName(ASTNodeDataType::typename_t) == "typename");
-    REQUIRE(dataTypeName(ASTNodeDataType::void_t) == "void");
-    REQUIRE(dataTypeName(ASTNodeDataType::function_t) == "function");
-    REQUIRE(dataTypeName(ASTNodeDataType::builtin_function_t) == "builtin_function");
-    REQUIRE(dataTypeName(ASTNodeDataType::list_t) == "list");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}) ==
-            "tuple(B)");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}) ==
-            "tuple(N)");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}) ==
-            "tuple(Z)");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}) ==
-            "tuple(R)");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}) ==
-            "tuple(R)");
-
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::type_name_id_t, 1}) == "type_name_id");
-
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::type_id_t, "user_type"}) == "user_type");
-
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 1}) == "R^1");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 2}) == "R^2");
-    REQUIRE(dataTypeName(ASTNodeDataType{ASTNodeDataType::vector_t, 3}) == "R^3");
+    REQUIRE(dataTypeName(undefined_dt) == "undefined");
+    REQUIRE(dataTypeName(bool_dt) == "B");
+    REQUIRE(dataTypeName(unsigned_int_dt) == "N");
+    REQUIRE(dataTypeName(int_dt) == "Z");
+    REQUIRE(dataTypeName(double_dt) == "R");
+    REQUIRE(dataTypeName(string_dt) == "string");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::typename_t>(double_dt)) == "typename(R)");
+    REQUIRE(dataTypeName(void_dt) == "void");
+    REQUIRE(dataTypeName(function_dt) == "function");
+    REQUIRE(dataTypeName(builtin_function_dt) == "builtin_function");
+    REQUIRE(dataTypeName(list_dt) == "list(R*Z)");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt)) == "tuple(B)");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt)) == "tuple(N)");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)) == "tuple(Z)");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)) == "tuple(R)");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)) == "tuple(Z)");
+
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>()) == "type_name_id");
+
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::type_id_t>("user_type")) == "user_type");
+
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)) == "R^1");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)) == "R^2");
+    REQUIRE(dataTypeName(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)) == "R^3");
   }
 
   SECTION("promotion")
   {
-    REQUIRE(dataTypePromotion(ASTNodeDataType::undefined_t, ASTNodeDataType::undefined_t) ==
-            ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::void_t, ASTNodeDataType::double_t) == ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::undefined_t) == ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::bool_t) == ASTNodeDataType::double_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::unsigned_int_t) == ASTNodeDataType::double_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::int_t) == ASTNodeDataType::double_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::unsigned_int_t) ==
-            ASTNodeDataType::unsigned_int_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::bool_t) == ASTNodeDataType::int_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::bool_t) ==
-            ASTNodeDataType::unsigned_int_t);
-
-    REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::bool_t) == ASTNodeDataType::string_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::int_t) == ASTNodeDataType::string_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::unsigned_int_t) == ASTNodeDataType::string_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::string_t, ASTNodeDataType::double_t) == ASTNodeDataType::string_t);
-
-    REQUIRE(dataTypePromotion(ASTNodeDataType::bool_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::int_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::string_t) ==
-            ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::string_t) == ASTNodeDataType::undefined_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::bool_t, ASTNodeDataType::vector_t) == ASTNodeDataType::vector_t);
-    REQUIRE(dataTypePromotion(ASTNodeDataType::double_t, ASTNodeDataType::vector_t) == ASTNodeDataType::vector_t);
+    const ASTNodeDataType vector_dt = ASTNodeDataType::build<ASTNodeDataType::vector_t>(5);
+
+    REQUIRE(dataTypePromotion(undefined_dt, undefined_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(void_dt, double_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(int_dt, undefined_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(double_dt, bool_dt) == double_dt);
+    REQUIRE(dataTypePromotion(double_dt, unsigned_int_dt) == double_dt);
+    REQUIRE(dataTypePromotion(double_dt, int_dt) == double_dt);
+    REQUIRE(dataTypePromotion(int_dt, unsigned_int_dt) == unsigned_int_dt);
+    REQUIRE(dataTypePromotion(int_dt, bool_dt) == int_dt);
+    REQUIRE(dataTypePromotion(unsigned_int_dt, bool_dt) == unsigned_int_dt);
+
+    REQUIRE(dataTypePromotion(string_dt, bool_dt) == string_dt);
+    REQUIRE(dataTypePromotion(string_dt, int_dt) == string_dt);
+    REQUIRE(dataTypePromotion(string_dt, unsigned_int_dt) == string_dt);
+    REQUIRE(dataTypePromotion(string_dt, double_dt) == string_dt);
+
+    REQUIRE(dataTypePromotion(bool_dt, string_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(int_dt, string_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(unsigned_int_dt, string_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(double_dt, string_dt) == undefined_dt);
+    REQUIRE(dataTypePromotion(bool_dt, vector_dt) == vector_dt);
+    REQUIRE(dataTypePromotion(double_dt, vector_dt) == vector_dt);
   }
 
   SECTION("getVectorDataType")
@@ -96,7 +105,7 @@ TEST_CASE("ASTNodeDataType", "[language]")
 
     SECTION("good node")
     {
-      REQUIRE(getVectorDataType(*type_node) == ASTNodeDataType::vector_t);
+      REQUIRE(getVectorDataType(*type_node) == ASTNodeDataType::build<ASTNodeDataType::vector_t>(1));
       REQUIRE(getVectorDataType(*type_node).dimension() == 17);
     }
 
@@ -129,142 +138,133 @@ TEST_CASE("ASTNodeDataType", "[language]")
   {
     SECTION("-> B")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::bool_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::bool_t));
+      REQUIRE(isNaturalConversion(bool_dt, bool_dt));
+      REQUIRE(not isNaturalConversion(unsigned_int_dt, bool_dt));
+      REQUIRE(not isNaturalConversion(int_dt, bool_dt));
+      REQUIRE(not isNaturalConversion(double_dt, bool_dt));
+      REQUIRE(not isNaturalConversion(string_dt, bool_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt), bool_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1), bool_dt));
     }
 
     SECTION("-> N")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::unsigned_int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::unsigned_int_t));
+      REQUIRE(isNaturalConversion(bool_dt, unsigned_int_dt));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, unsigned_int_dt));
+      REQUIRE(isNaturalConversion(int_dt, unsigned_int_dt));
+      REQUIRE(not isNaturalConversion(double_dt, unsigned_int_dt));
+      REQUIRE(not isNaturalConversion(string_dt, unsigned_int_dt));
+      REQUIRE(
+        not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt), unsigned_int_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1), unsigned_int_dt));
     }
 
     SECTION("-> Z")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::int_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::int_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::int_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::int_t));
+      REQUIRE(isNaturalConversion(bool_dt, int_dt));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, int_dt));
+      REQUIRE(isNaturalConversion(int_dt, int_dt));
+      REQUIRE(not isNaturalConversion(double_dt, int_dt));
+      REQUIRE(not isNaturalConversion(string_dt, int_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt), int_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1), int_dt));
     }
 
     SECTION("-> R")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::double_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::double_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::double_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::double_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::double_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::double_t));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::double_t));
+      REQUIRE(isNaturalConversion(bool_dt, double_dt));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, double_dt));
+      REQUIRE(isNaturalConversion(int_dt, double_dt));
+      REQUIRE(isNaturalConversion(double_dt, double_dt));
+      REQUIRE(not isNaturalConversion(string_dt, double_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt), double_dt));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1), double_dt));
     }
 
     SECTION("-> string")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType::string_t));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType::string_t));
+      REQUIRE(isNaturalConversion(bool_dt, string_dt));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, string_dt));
+      REQUIRE(isNaturalConversion(int_dt, string_dt));
+      REQUIRE(isNaturalConversion(double_dt, string_dt));
+      REQUIRE(isNaturalConversion(string_dt, string_dt));
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt), string_dt));
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1), string_dt));
     }
 
     SECTION("-> tuple")
     {
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t,
-                                  ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::bool_t,
-                                  ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                  ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}));
-      REQUIRE(
-        not isNaturalConversion(ASTNodeDataType::int_t,
-                                ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}}));
-
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t,
-                                  ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                  ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::unsigned_int_t,
-                                  ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t,
-                                      ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                      ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}));
-
-      REQUIRE(
-        isNaturalConversion(ASTNodeDataType::bool_t,
-                            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}));
-      REQUIRE(isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                          ASTNodeDataType{ASTNodeDataType::double_t}}));
-      REQUIRE(
-        isNaturalConversion(ASTNodeDataType::unsigned_int_t,
-                            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}));
-      REQUIRE(
-        isNaturalConversion(ASTNodeDataType::double_t,
-                            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}));
-      REQUIRE(
-        not isNaturalConversion(ASTNodeDataType::string_t,
-                                ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}}));
+      REQUIRE(isNaturalConversion(bool_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt)));
+      REQUIRE(isNaturalConversion(bool_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt)));
+      REQUIRE(not isNaturalConversion(int_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt)));
+
+      REQUIRE(isNaturalConversion(unsigned_int_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt)));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)));
+      REQUIRE(not isNaturalConversion(double_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt)));
+
+      REQUIRE(isNaturalConversion(bool_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)));
+      REQUIRE(isNaturalConversion(int_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)));
+      REQUIRE(isNaturalConversion(unsigned_int_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)));
+      REQUIRE(isNaturalConversion(double_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)));
+      REQUIRE(not isNaturalConversion(string_dt, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)));
     }
 
     SECTION("-> vector")
     {
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}));
-
-      REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1},
-                                  ASTNodeDataType{ASTNodeDataType::vector_t, 1}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 1}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 1}));
-
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 2}));
-      REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2},
-                                  ASTNodeDataType{ASTNodeDataType::vector_t, 2}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 2}));
-
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 1},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 3}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 2},
-                                      ASTNodeDataType{ASTNodeDataType::vector_t, 3}));
-      REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::vector_t, 3},
-                                  ASTNodeDataType{ASTNodeDataType::vector_t, 3}));
+      REQUIRE(not isNaturalConversion(bool_dt, ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)));
+      REQUIRE(not isNaturalConversion(unsigned_int_dt, ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)));
+      REQUIRE(not isNaturalConversion(int_dt, ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)));
+      REQUIRE(not isNaturalConversion(double_dt, ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)));
+      REQUIRE(not isNaturalConversion(string_dt, ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)));
+
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1),
+                                  ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)));
+
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)));
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2),
+                                  ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)));
+
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2),
+                                      ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)));
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3),
+                                  ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)));
     }
 
     SECTION("-> type_id")
     {
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::bool_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(
-        not isNaturalConversion(ASTNodeDataType::unsigned_int_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::int_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::double_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::string_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::vector_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-      REQUIRE(not isNaturalConversion(ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-
-      REQUIRE(isNaturalConversion(ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"},
-                                  ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"}));
-
-      REQUIRE(not isNaturalConversion(ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"},
-                                      ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"}));
+      REQUIRE(not isNaturalConversion(bool_dt, ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(unsigned_int_dt, ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(int_dt, ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(double_dt, ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(string_dt, ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1),
+                                      ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt),
+                                      ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+
+      REQUIRE(isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo"),
+                                  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo")));
+
+      REQUIRE(not isNaturalConversion(ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo"),
+                                      ASTNodeDataType::build<ASTNodeDataType::type_id_t>("bar")));
     }
   }
+
+#ifndef NDEBUG
+  SECTION("errors")
+  {
+    REQUIRE_THROWS_AS(ASTNodeDataType::build<ASTNodeDataType::tuple_t>(undefined_dt), AssertError);
+  }
+#endif   // NDEBUG
 }
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index c5c691a28db39749f1910521b875eca0af0e8271..dd206297d82c52bbbf7dda7e304d6b3966524d4f 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -29,8 +29,8 @@
   }
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t,
-                                                                                 "builtin_t"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t");
 const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>;
 
 #define CHECK_AST_WITH_BUILTIN(data, expected_output)                                                         \
@@ -47,7 +47,7 @@ const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const dou
       throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");        \
     }                                                                                                         \
                                                                                                               \
-    i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t);                                      \
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());            \
     i_symbol->attributes().setIsInitialized();                                                                \
     i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();                                 \
     symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \
@@ -277,17 +277,17 @@ let (x,b,n,s) : R*B*N*string;
 
       std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:typename)
-     +-(language::name_list:list)
+ `-(language::var_declaration:void)
+     +-(language::name_list:list(R*B*N*string))
      |   +-(language::name:x:R)
      |   +-(language::name:b:B)
      |   +-(language::name:n:N)
      |   `-(language::name:s:string)
-     `-(language::type_expression:typename)
-         +-(language::R_set:typename)
-         +-(language::B_set:typename)
-         +-(language::N_set:typename)
-         `-(language::string_type:typename)
+     `-(language::type_expression:typename(list(typename(R)*typename(B)*typename(N)*typename(string))))
+         +-(language::R_set:typename(R))
+         +-(language::B_set:typename(B))
+         +-(language::N_set:typename(N))
+         `-(language::string_type:typename(string))
 )";
 
       CHECK_AST(data, result);
@@ -377,12 +377,12 @@ let t : (B), t = (true, false);
 
         std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:tuple(B))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(B))
-     +-(language::tuple_type_specifier:tuple(B))
-     |   `-(language::B_set:typename)
+     +-(language::tuple_type_specifier:typename(tuple(B)))
+     |   `-(language::B_set:typename(B))
      +-(language::name:t:tuple(B))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(B*B))
          +-(language::true_kw:B)
          `-(language::false_kw:B)
 )";
@@ -398,12 +398,12 @@ let t : (N), t = (1, 2, 3, 5);
 
         std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:tuple(N))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(N))
-     +-(language::tuple_type_specifier:tuple(N))
-     |   `-(language::N_set:typename)
+     +-(language::tuple_type_specifier:typename(tuple(N)))
+     |   `-(language::N_set:typename(N))
      +-(language::name:t:tuple(N))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(Z*Z*Z*Z))
          +-(language::integer:1:Z)
          +-(language::integer:2:Z)
          +-(language::integer:3:Z)
@@ -422,17 +422,17 @@ let t : (Z), t = (2, n, true);
 
         std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:N)
+ +-(language::var_declaration:void)
  |   +-(language::name:n:N)
- |   +-(language::N_set:typename)
+ |   +-(language::N_set:typename(N))
  |   +-(language::name:n:N)
  |   `-(language::integer:3:Z)
- `-(language::var_declaration:tuple(Z))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(Z))
-     +-(language::tuple_type_specifier:tuple(Z))
-     |   `-(language::Z_set:typename)
+     +-(language::tuple_type_specifier:typename(tuple(Z)))
+     |   `-(language::Z_set:typename(Z))
      +-(language::name:t:tuple(Z))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(Z*N*B))
          +-(language::integer:2:Z)
          +-(language::name:n:N)
          `-(language::true_kw:B)
@@ -449,12 +449,12 @@ let t : (R), t = (2, 3.1, 5);
 
         std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:tuple(R))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(R))
-     +-(language::tuple_type_specifier:tuple(R))
-     |   `-(language::R_set:typename)
+     +-(language::tuple_type_specifier:typename(tuple(R)))
+     |   `-(language::R_set:typename(R))
      +-(language::name:t:tuple(R))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(Z*R*Z))
          +-(language::integer:2:Z)
          +-(language::real:3.1:R)
          `-(language::integer:5:Z)
@@ -473,36 +473,36 @@ let t2 : (R^3), t2 = (0, 0);
 
         std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:R^2)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:R^2)
- |   +-(language::vector_type:typename)
- |   |   +-(language::R_set:typename)
+ |   +-(language::vector_type:typename(R^2))
+ |   |   +-(language::R_set:typename(R))
  |   |   `-(language::integer:2:Z)
  |   +-(language::name:a:R^2)
- |   `-(language::expression_list:list)
+ |   `-(language::expression_list:list(Z*R))
  |       +-(language::integer:2:Z)
  |       `-(language::real:3.1:R)
- +-(language::var_declaration:tuple(R^2))
+ +-(language::var_declaration:void)
  |   +-(language::name:t1:tuple(R^2))
- |   +-(language::tuple_type_specifier:tuple(R^2))
- |   |   `-(language::vector_type:typename)
- |   |       +-(language::R_set:typename)
+ |   +-(language::tuple_type_specifier:typename(tuple(R^2)))
+ |   |   `-(language::vector_type:typename(R^2))
+ |   |       +-(language::R_set:typename(R))
  |   |       `-(language::integer:2:Z)
  |   +-(language::name:t1:tuple(R^2))
- |   `-(language::expression_list:list)
+ |   `-(language::expression_list:list(R^2*list(Z*Z)*Z))
  |       +-(language::name:a:R^2)
- |       +-(language::tuple_expression:list)
+ |       +-(language::tuple_expression:list(Z*Z))
  |       |   +-(language::integer:1:Z)
  |       |   `-(language::integer:2:Z)
  |       `-(language::integer:0:Z)
- `-(language::var_declaration:tuple(R^3))
+ `-(language::var_declaration:void)
      +-(language::name:t2:tuple(R^3))
-     +-(language::tuple_type_specifier:tuple(R^3))
-     |   `-(language::vector_type:typename)
-     |       +-(language::R_set:typename)
+     +-(language::tuple_type_specifier:typename(tuple(R^3)))
+     |   `-(language::vector_type:typename(R^3))
+     |       +-(language::R_set:typename(R))
      |       `-(language::integer:3:Z)
      +-(language::name:t2:tuple(R^3))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(Z*Z))
          +-(language::integer:0:Z)
          `-(language::integer:0:Z)
 )";
@@ -518,12 +518,12 @@ let t : (string), t = ("foo", "bar");
 
         std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:tuple(string))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(string))
-     +-(language::tuple_type_specifier:tuple(string))
-     |   `-(language::string_type:typename)
+     +-(language::tuple_type_specifier:typename(tuple(string)))
+     |   `-(language::string_type:typename(string))
      +-(language::name:t:tuple(string))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(string*string))
          +-(language::literal:"foo":string)
          `-(language::literal:"bar":string)
 )";
@@ -540,12 +540,12 @@ let t : (builtin_t), t= (1,2,3);
 
         std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:tuple(builtin_t))
+ `-(language::var_declaration:void)
      +-(language::name:t:tuple(builtin_t))
-     +-(language::tuple_type_specifier:tuple(builtin_t))
-     |   `-(language::type_name_id:typename)
+     +-(language::tuple_type_specifier:typename(tuple(builtin_t)))
+     |   `-(language::type_name_id:builtin_t)
      +-(language::name:t:tuple(builtin_t))
-     `-(language::expression_list:list)
+     `-(language::expression_list:list(Z*Z*Z))
          +-(language::integer:1:Z)
          +-(language::integer:2:Z)
          `-(language::integer:3:Z)
@@ -885,13 +885,13 @@ x = f(x);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:f:function)
- +-(language::var_declaration:R^2)
+ +-(language::var_declaration:void)
  |   +-(language::name:x:R^2)
- |   +-(language::vector_type:typename)
- |   |   +-(language::R_set:typename)
+ |   +-(language::vector_type:typename(R^2))
+ |   |   +-(language::R_set:typename(R))
  |   |   `-(language::integer:2:Z)
  |   +-(language::name:x:R^2)
- |   `-(language::expression_list:list)
+ |   `-(language::expression_list:list(Z*Z))
  |       +-(language::integer:1:Z)
  |       `-(language::integer:2:Z)
  `-(language::eq_op:R^2)
@@ -918,9 +918,9 @@ let x : R, x = incr(3);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:incr:function)
- `-(language::var_declaration:R)
+ `-(language::var_declaration:void)
      +-(language::name:x:R)
-     +-(language::R_set:typename)
+     +-(language::R_set:typename(R))
      +-(language::name:x:R)
      `-(language::function_evaluation:R)
          +-(language::name:incr:function)
@@ -941,13 +941,13 @@ let  diff : R, diff = substract(3,2);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:substract:function)
- `-(language::var_declaration:R)
+ `-(language::var_declaration:void)
      +-(language::name:diff:R)
-     +-(language::R_set:typename)
+     +-(language::R_set:typename(R))
      +-(language::name:diff:R)
      `-(language::function_evaluation:R)
          +-(language::name:substract:function)
-         `-(language::function_argument_list:list)
+         `-(language::function_argument_list:list(Z*Z))
              +-(language::integer:3:Z)
              `-(language::integer:2:Z)
 )";
@@ -967,9 +967,9 @@ let z : Z, z = incr(3);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:incr:function)
- `-(language::var_declaration:Z)
+ `-(language::var_declaration:void)
      +-(language::name:z:Z)
-     +-(language::Z_set:typename)
+     +-(language::Z_set:typename(Z))
      +-(language::name:z:Z)
      `-(language::function_evaluation:Z)
          +-(language::name:incr:function)
@@ -990,9 +990,9 @@ let n : N, n = double(3);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:double:function)
- `-(language::var_declaration:N)
+ `-(language::var_declaration:void)
      +-(language::name:n:N)
-     +-(language::N_set:typename)
+     +-(language::N_set:typename(N))
      +-(language::name:n:N)
      `-(language::function_evaluation:N)
          +-(language::name:double:function)
@@ -1013,9 +1013,9 @@ let b : B, b = greater_than_2(3);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:greater_than_2:function)
- `-(language::var_declaration:B)
+ `-(language::var_declaration:void)
      +-(language::name:b:B)
-     +-(language::B_set:typename)
+     +-(language::B_set:typename(B))
      +-(language::name:b:B)
      `-(language::function_evaluation:B)
          +-(language::name:greater_than_2:function)
@@ -1036,13 +1036,13 @@ let s : string, s = cat("foo", "bar");
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:cat:function)
- `-(language::var_declaration:string)
+ `-(language::var_declaration:void)
      +-(language::name:s:string)
-     +-(language::string_type:typename)
+     +-(language::string_type:typename(string))
      +-(language::name:s:string)
      `-(language::function_evaluation:string)
          +-(language::name:cat:function)
-         `-(language::function_argument_list:list)
+         `-(language::function_argument_list:list(string*string))
              +-(language::literal:"foo":string)
              `-(language::literal:"bar":string)
 )";
@@ -1061,17 +1061,17 @@ let (x,x2) : R*R, (x,x2) = x_x2(3);
 (root:void)
  +-(language::fct_declaration:void)
  |   `-(language::name:x_x2:function)
- `-(language::var_declaration:typename)
-     +-(language::name_list:list)
+ `-(language::var_declaration:void)
+     +-(language::name_list:list(R*R))
      |   +-(language::name:x:R)
      |   `-(language::name:x2:R)
-     +-(language::type_expression:typename)
-     |   +-(language::R_set:typename)
-     |   `-(language::R_set:typename)
-     +-(language::name_list:list)
+     +-(language::type_expression:typename(list(typename(R)*typename(R))))
+     |   +-(language::R_set:typename(R))
+     |   `-(language::R_set:typename(R))
+     +-(language::name_list:list(R*R))
      |   +-(language::name:x:R)
      |   `-(language::name:x2:R)
-     `-(language::function_evaluation:typename)
+     `-(language::function_evaluation:list(typename(R)*typename(R)))
          +-(language::name:x_x2:function)
          `-(language::integer:3:Z)
 )";
@@ -1128,9 +1128,9 @@ for (let i : N, i=0; i<3; ++i){
     std::string_view result = R"(
 (root:void)
  `-(language::for_statement:void)
-     +-(language::var_declaration:N)
+     +-(language::var_declaration:void)
      |   +-(language::name:i:N)
-     |   +-(language::N_set:typename)
+     |   +-(language::N_set:typename(N))
      |   +-(language::name:i:N)
      |   `-(language::integer:0:Z)
      +-(language::lesser_op:B)
@@ -1154,9 +1154,9 @@ let b:B;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:B)
+ `-(language::var_declaration:void)
      +-(language::name:b:B)
-     `-(language::B_set:typename)
+     `-(language::B_set:typename(B))
 )";
 
     CHECK_AST(data, result);
@@ -1170,9 +1170,9 @@ let n :N;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:N)
+ `-(language::var_declaration:void)
      +-(language::name:n:N)
-     `-(language::N_set:typename)
+     `-(language::N_set:typename(N))
 )";
 
     CHECK_AST(data, result);
@@ -1186,9 +1186,9 @@ let z:Z;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:Z)
+ `-(language::var_declaration:void)
      +-(language::name:z:Z)
-     `-(language::Z_set:typename)
+     `-(language::Z_set:typename(Z))
 )";
 
     CHECK_AST(data, result);
@@ -1202,9 +1202,9 @@ let r:R;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:R)
+ `-(language::var_declaration:void)
      +-(language::name:r:R)
-     `-(language::R_set:typename)
+     `-(language::R_set:typename(R))
 )";
 
     CHECK_AST(data, result);
@@ -1218,9 +1218,9 @@ let s: string;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:string)
+ `-(language::var_declaration:void)
      +-(language::name:s:string)
-     `-(language::string_type:typename)
+     `-(language::string_type:typename(string))
 )";
 
     CHECK_AST(data, result);
@@ -1235,9 +1235,9 @@ let t : builtin_t, t= 1;
 
     std::string_view result = R"(
 (root:void)
- `-(language::var_declaration:builtin_t)
+ `-(language::var_declaration:void)
      +-(language::name:t:builtin_t)
-     +-(language::type_name_id:typename)
+     +-(language::type_name_id:typename(builtin_t))
      +-(language::name:t:builtin_t)
      `-(language::integer:1:Z)
 )";
@@ -1282,9 +1282,9 @@ a = 1;
 
     std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:N)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:N)
- |   `-(language::N_set:typename)
+ |   `-(language::N_set:typename(N))
  `-(language::eq_op:N)
      +-(language::name:a:N)
      `-(language::integer:1:Z)
@@ -1302,9 +1302,9 @@ a *= 1.2;
 
     std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:N)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:N)
- |   +-(language::N_set:typename)
+ |   +-(language::N_set:typename(N))
  |   +-(language::name:a:N)
  |   `-(language::integer:1:Z)
  `-(language::multiplyeq_op:N)
@@ -1324,9 +1324,9 @@ a /= 2;
 
     std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:R)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:R)
- |   +-(language::R_set:typename)
+ |   +-(language::R_set:typename(R))
  |   +-(language::name:a:R)
  |   `-(language::integer:3:Z)
  `-(language::divideeq_op:R)
@@ -1346,9 +1346,9 @@ a += 2;
 
     std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:Z)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:Z)
- |   +-(language::Z_set:typename)
+ |   +-(language::Z_set:typename(Z))
  |   +-(language::name:a:Z)
  |   `-(language::integer:3:Z)
  `-(language::pluseq_op:Z)
@@ -1368,9 +1368,9 @@ a -= 2;
 
     std::string_view result = R"(
 (root:void)
- +-(language::var_declaration:Z)
+ +-(language::var_declaration:void)
  |   +-(language::name:a:Z)
- |   +-(language::Z_set:typename)
+ |   +-(language::Z_set:typename(Z))
  |   +-(language::name:a:Z)
  |   `-(language::integer:1:Z)
  `-(language::minuseq_op:Z)
@@ -1408,9 +1408,9 @@ for (let i:Z, i=0; i<3; i += 1) { i += 2; }
     std::string_view result = R"(
 (root:void)
  `-(language::for_statement:void)
-     +-(language::var_declaration:Z)
+     +-(language::var_declaration:void)
      |   +-(language::name:i:Z)
-     |   +-(language::Z_set:typename)
+     |   +-(language::Z_set:typename(Z))
      |   +-(language::name:i:Z)
      |   `-(language::integer:0:Z)
      +-(language::lesser_op:B)
diff --git a/tests/test_ASTNodeDataTypeChecker.cpp b/tests/test_ASTNodeDataTypeChecker.cpp
index e016e1087281b3175eba0076cb21aaab7234c89b..60dfc787a65b6af66f3463fe0871bb0b0a79116d 100644
--- a/tests/test_ASTNodeDataTypeChecker.cpp
+++ b/tests/test_ASTNodeDataTypeChecker.cpp
@@ -45,7 +45,7 @@ for(let i:Z, i=0; i<10; ++i) {
     ASTSymbolTableBuilder{*ast};
     ASTNodeDataTypeBuilder{*ast};
 
-    ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
+    ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::undefined_t>();
 
     REQUIRE_THROWS_AS(ASTNodeDataTypeChecker{*ast}, ParseError);
   }
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_ASTNodeIncDecExpressionBuilder.cpp b/tests/test_ASTNodeIncDecExpressionBuilder.cpp
index 60ce2489fd8b1b93996cd2904b8bf9852b8a1c79..627d6f96606a13a97907d01d314339f846049892 100644
--- a/tests/test_ASTNodeIncDecExpressionBuilder.cpp
+++ b/tests/test_ASTNodeIncDecExpressionBuilder.cpp
@@ -310,7 +310,7 @@ x--;
     {
       auto ast = std::make_unique<ASTNode>();
       ast->set_type<language::unary_plusplus>();
-      ast->m_data_type = ASTNodeDataType::undefined_t;
+      ast->m_data_type = ASTNodeDataType::build<ASTNodeDataType::undefined_t>();
 
       ast->children.emplace_back(std::make_unique<ASTNode>());
 
diff --git a/tests/test_ASTNodeJumpPlacementChecker.cpp b/tests/test_ASTNodeJumpPlacementChecker.cpp
index 631b172775f381405bbc8ff830d19aad92b9c8e5..040c2db1c3d7b0ee3be8c663a5c701827e230fb2 100644
--- a/tests/test_ASTNodeJumpPlacementChecker.cpp
+++ b/tests/test_ASTNodeJumpPlacementChecker.cpp
@@ -75,7 +75,7 @@ do {
       ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
-      ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
+      ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::undefined_t>();
 
       REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, ParseError);
     }
@@ -144,7 +144,7 @@ do {
       ASTSymbolTableBuilder{*ast};
       ASTNodeDataTypeBuilder{*ast};
 
-      ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
+      ast->children[0]->m_data_type = ASTNodeDataType::build<ASTNodeDataType::undefined_t>();
 
       REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, ParseError);
     }
diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
index 333b98bd998124e676c885025ef1d646ba517829..c15be1db66c0bbbe9a5e9eee4c895f21f3bb30d7 100644
--- a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
+++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
@@ -385,7 +385,7 @@ let x:R^2, x = (1,2);
 let y:R^3, y = x;
 )";
 
-      CHECK_AST_THROWS_WITH(data, std::string{"incompatible dimensions in affectation"});
+      CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^3"});
     }
 
     SECTION("invalid Z -> R^d conversion (non-zero)")
diff --git a/tests/test_ASTNodeNaturalConversionChecker.cpp b/tests/test_ASTNodeNaturalConversionChecker.cpp
index fe29cf9d0148d7a4d0a31bd71b97d84820e63299..ed1e834c016ac9e7c6f3d796a7018ce290aa9324 100644
--- a/tests/test_ASTNodeNaturalConversionChecker.cpp
+++ b/tests/test_ASTNodeNaturalConversionChecker.cpp
@@ -13,6 +13,22 @@ struct integer;
 
 TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 {
+  const ASTNodeDataType undefined_dt        = ASTNodeDataType{};
+  const ASTNodeDataType bool_dt             = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
+  const ASTNodeDataType unsigned_int_dt     = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
+  const ASTNodeDataType int_dt              = ASTNodeDataType::build<ASTNodeDataType::int_t>();
+  const ASTNodeDataType double_dt           = ASTNodeDataType::build<ASTNodeDataType::double_t>();
+  const ASTNodeDataType string_dt           = ASTNodeDataType::build<ASTNodeDataType::string_t>();
+  const ASTNodeDataType void_dt             = ASTNodeDataType::build<ASTNodeDataType::void_t>();
+  const ASTNodeDataType function_dt         = ASTNodeDataType::build<ASTNodeDataType::function_t>();
+  const ASTNodeDataType builtin_function_dt = ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>();
+
+  std::vector<std::shared_ptr<const ASTNodeDataType>> type_list;
+  type_list.push_back(std::make_shared<const ASTNodeDataType>(double_dt));
+  type_list.push_back(std::make_shared<const ASTNodeDataType>(int_dt));
+
+  const ASTNodeDataType list_dt = ASTNodeDataType::build<ASTNodeDataType::list_t>(type_list);
+
   SECTION("Valid conversions")
   {
     std::unique_ptr data_node = std::make_unique<ASTNode>();
@@ -21,50 +37,50 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("string -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = string_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("R^d -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::vector_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(5);
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("R -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = double_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("Z -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("N -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("B -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("list -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = list_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
 
       SECTION("tuple -> string")
       {
-        data_node->m_data_type = ASTNodeDataType::tuple_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, string_dt});
       }
     }
 
@@ -72,24 +88,27 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("R^1 -> R^1")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}});
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)});
       }
 
       SECTION("list -> R^1")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        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    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
         }
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)});
       }
 
       SECTION("'0' -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::int_t, 1};
+        data_node->m_data_type = int_dt;
         data_node->set_type<language::integer>();
         data_node->source  = "0";
         auto& source       = data_node->source;
@@ -98,62 +117,73 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("d = 1")
         {
-          REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 1}});
+          REQUIRE_NOTHROW(
+            ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)});
         }
         SECTION("d = 2")
         {
-          REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}});
+          REQUIRE_NOTHROW(
+            ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)});
         }
         SECTION("d = 3")
         {
-          REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}});
+          REQUIRE_NOTHROW(
+            ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)});
         }
       }
 
       SECTION("R^2 -> R^2")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}});
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)});
       }
 
       SECTION("list -> R^2")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        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    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
         }
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 2}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)});
       }
 
       SECTION("R^3 -> R^3")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}});
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)});
       }
 
       SECTION("list -> R^3")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        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    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::vector_t, 3}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)});
       }
     }
 
@@ -161,26 +191,26 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("R -> R")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t});
+        data_node->m_data_type = double_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, double_dt});
       }
 
       SECTION("Z -> R")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t});
+        data_node->m_data_type = int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, double_dt});
       }
 
       SECTION("N -> R")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t});
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, double_dt});
       }
 
       SECTION("B -> R")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, double_dt});
       }
     }
 
@@ -188,20 +218,20 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("Z -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t});
+        data_node->m_data_type = int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, int_dt});
       }
 
       SECTION("N -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t});
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, int_dt});
       }
 
       SECTION("B -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, int_dt});
       }
     }
 
@@ -209,20 +239,20 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("Z -> N")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t});
+        data_node->m_data_type = int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt});
       }
 
       SECTION("N -> N")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t});
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt});
       }
 
       SECTION("B -> N")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt});
       }
     }
 
@@ -230,8 +260,8 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("B -> B")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, bool_dt});
       }
     }
 
@@ -239,216 +269,204 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("B -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
+        data_node->m_data_type = bool_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::bool_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt)});
       }
 
       SECTION("B -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
-        REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node,
-                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+        data_node->m_data_type = bool_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                                      unsigned_int_dt)});
       }
 
       SECTION("N -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node,
-                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                                      unsigned_int_dt)});
       }
 
       SECTION("Z -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node,
-                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+        data_node->m_data_type = int_dt;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                                      unsigned_int_dt)});
       }
 
       SECTION("B -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
+        data_node->m_data_type = bool_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)});
       }
 
       SECTION("N -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        data_node->m_data_type = unsigned_int_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)});
       }
 
       SECTION("Z -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
+        data_node->m_data_type = int_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt)});
       }
 
       SECTION("B -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
+        data_node->m_data_type = bool_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)});
       }
 
       SECTION("N -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        data_node->m_data_type = unsigned_int_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)});
       }
 
       SECTION("Z -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
+        data_node->m_data_type = int_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)});
       }
 
       SECTION("R -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
+        data_node->m_data_type = double_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt)});
       }
 
       SECTION("R^1 -> tuple(R^1)")
       {
-        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        auto R1                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
         data_node->m_data_type = R1;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R1}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R1)});
       }
 
       SECTION("R^2 -> tuple(R^2)")
       {
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         data_node->m_data_type = R2;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R2}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2)});
       }
 
       SECTION("R^3 -> tuple(R^3)")
       {
-        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        auto R3                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
         data_node->m_data_type = R3;
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R3}});
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R3)});
       }
 
       SECTION("string -> tuple(string)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::string_t};
+        data_node->m_data_type = string_dt;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                      ASTNodeDataType{ASTNodeDataType::string_t}}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt)});
       }
 
       SECTION("type_id_t -> tuple(type_id_t)")
       {
-        auto type_id           = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
+        auto type_id           = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
         data_node->m_data_type = type_id;
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id)});
       }
 
       SECTION("(B, B, B) -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          list0_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::bool_t;
+          list1_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::bool_t;
+          list2_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(B, N, Z) -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          list0_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(B, N, Z) -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          list0_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(R, N, Z) -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(R^1, R^1) -> tuple(R^1)")
       {
-        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        auto R1                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
           list0_node->m_data_type    = R1;
@@ -458,14 +476,14 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
           list1_node->m_data_type    = R1;
           data_node->emplace_back(std::move(list1_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R1};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R1);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(R^2, R^2, R^2) -> tuple(R^2)")
       {
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
           list0_node->m_data_type    = R2;
@@ -479,14 +497,14 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
           list2_node->m_data_type    = R2;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R2};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(R^3, R^3) -> tuple(R^3)")
       {
-        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        auto R3                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
           list0_node->m_data_type    = R3;
@@ -496,14 +514,14 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
           list1_node->m_data_type    = R3;
           data_node->emplace_back(std::move(list1_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R3};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R3);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(string, string) -> tuple(string)")
       {
-        auto str_t             = ASTNodeDataType{ASTNodeDataType::string_t};
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        auto str_t             = string_dt;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
           list0_node->m_data_type    = str_t;
@@ -513,14 +531,14 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
           list1_node->m_data_type    = str_t;
           data_node->emplace_back(std::move(list1_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, str_t};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(str_t);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("(type_id_t, type_id_t) -> tuple(type_id_t)")
       {
-        auto type_id           = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        auto type_id           = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
           list0_node->m_data_type    = type_id;
@@ -530,169 +548,168 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
           list1_node->m_data_type    = type_id;
           data_node->emplace_back(std::move(list1_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id);
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(B) -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(B) -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(Z) -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(N) -> tuple(N)")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(B) -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(N) -> tuple(Z)")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(Z) -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(B) -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(Z) -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(N) -> tuple(R)")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(R) -> tuple(R)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(B) -> tuple(string)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(Z) -> tuple(string)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(N) -> tuple(string)")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(R) -> tuple(string)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(string) -> tuple(string)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
-        auto tuple_t           = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
+        auto tuple_t           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
 
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
       }
 
       SECTION("tuple(R^1) -> tuple(R^1)")
       {
-        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R1};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R1}});
+        auto R1                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R1);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R1)});
       }
 
       SECTION("tuple(R^2) -> tuple(R^2)")
       {
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R2};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R2}});
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2)});
       }
 
       SECTION("tuple(R^3) -> tuple(R^3)")
       {
-        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, R3};
-        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R3}});
+        auto R3                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R3);
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R3)});
       }
 
       SECTION("tuple(type_id_t) -> tuple(type_id_t)")
       {
-        auto type_id           = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id};
+        auto type_id           = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id);
         REQUIRE_NOTHROW(
-          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, type_id}});
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id)});
       }
     }
   }
@@ -705,132 +722,135 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("R^2 -> R^1")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
+                            "invalid implicit conversion: R^2 -> R^1");
       }
 
       SECTION("R^3 -> R^1")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
+                            "invalid implicit conversion: R^3 -> R^1");
       }
 
       SECTION("R^1 -> R^2")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
+                            "invalid implicit conversion: R^1 -> R^2");
       }
 
       SECTION("R^3 -> R^2")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
+                            "invalid implicit conversion: R^3 -> R^2");
       }
 
       SECTION("R^1 -> R^3")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
+                            "invalid implicit conversion: R^1 -> R^3");
       }
 
       SECTION("R^2 -> R^3")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
+                            "invalid implicit conversion: R^2 -> R^3");
       }
 
       SECTION("list1 -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        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    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "incompatible dimensions in affectation");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "incompatible dimensions in affectation");
         }
       }
 
       SECTION("list2 -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
         }
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "incompatible dimensions in affectation");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "incompatible dimensions in affectation");
         }
       }
 
       SECTION("list3 -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        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    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "incompatible dimensions in affectation");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "incompatible dimensions in affectation");
         }
       }
@@ -839,60 +859,58 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
       {
         SECTION("tuple(N) -> R^1")
         {
-          data_node->m_data_type =
-            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: tuple(N) -> R^1");
         }
 
         SECTION("tuple(R) -> R^1")
         {
-          data_node->m_data_type =
-            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: tuple(R) -> R^1");
         }
 
         SECTION("tuple(R) -> R^2")
         {
-          data_node->m_data_type =
-            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: tuple(R) -> R^2");
         }
 
         SECTION("tuple(B) -> R^2")
         {
-          data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: tuple(B) -> R^2");
         }
 
         SECTION("tuple(Z) -> R^3")
         {
-          data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: tuple(Z) -> R^3");
         }
 
         SECTION("tuple(R) -> R^3")
         {
-          data_node->m_data_type =
-            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: tuple(R) -> R^3");
         }
 
         SECTION("tuple(R^1) -> tuple(R^3)")
         {
-          auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}};
-          auto tuple_R3 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}};
+          auto tuple_R1 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1));
+          auto tuple_R3 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3));
           data_node->m_data_type = tuple_R1;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R3}),
                               "invalid implicit conversion: R^1 -> R^3");
@@ -900,8 +918,10 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(R^2) -> tuple(R^3)")
         {
-          auto tuple_R2 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}};
-          auto tuple_R3 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 3}};
+          auto tuple_R2 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2));
+          auto tuple_R3 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(3));
           data_node->m_data_type = tuple_R2;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R3}),
                               "invalid implicit conversion: R^2 -> R^3");
@@ -909,8 +929,10 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(R^2) -> tuple(R^1)")
         {
-          auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}};
-          auto tuple_R2 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 2}};
+          auto tuple_R1 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1));
+          auto tuple_R2 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(2));
           data_node->m_data_type = tuple_R2;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R1}),
                               "invalid implicit conversion: R^2 -> R^1");
@@ -918,8 +940,8 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(R) -> tuple(Z)")
         {
-          auto tuple_R = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
-          auto tuple_Z = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+          auto tuple_R           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+          auto tuple_Z           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
           data_node->m_data_type = tuple_R;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_Z}),
                               "invalid implicit conversion: R -> Z");
@@ -927,8 +949,9 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(R) -> tuple(R^1)")
         {
-          auto tuple_R  = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
-          auto tuple_R1 = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::vector_t, 1}};
+          auto tuple_R = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+          auto tuple_R1 =
+            ASTNodeDataType::build<ASTNodeDataType::tuple_t>(ASTNodeDataType::build<ASTNodeDataType::vector_t>(1));
           data_node->m_data_type = tuple_R;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R1}),
                               "invalid implicit conversion: R -> R^1");
@@ -936,8 +959,8 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(string) -> tuple(R)")
         {
-          auto tuple_string = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::string_t}};
-          auto tuple_R      = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          auto tuple_string      = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(string_dt);
+          auto tuple_R           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
           data_node->m_data_type = tuple_string;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R}),
                               "invalid implicit conversion: string -> R");
@@ -945,10 +968,10 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(type_id) -> tuple(R)")
         {
-          auto type_id = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
+          auto type_id = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
 
-          auto tuple_type_id = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id};
-          auto tuple_R       = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          auto tuple_type_id     = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id);
+          auto tuple_R           = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
           data_node->m_data_type = tuple_type_id;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_R}),
                               "invalid implicit conversion: foo -> R");
@@ -956,11 +979,11 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
         SECTION("tuple(type_id) -> tuple(R)")
         {
-          auto type_id0 = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
-          auto type_id1 = ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"};
+          auto type_id0 = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
+          auto type_id1 = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("bar");
 
-          auto tuple_type_id0    = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id0};
-          auto tuple_type_id1    = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id1};
+          auto tuple_type_id0    = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id0);
+          auto tuple_type_id1    = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id1);
           data_node->m_data_type = tuple_type_id0;
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_type_id1}),
                               "invalid implicit conversion: foo -> bar");
@@ -969,33 +992,33 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
       SECTION("R -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
+        data_node->m_data_type = double_dt;
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: R -> R^1");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: R -> R^2");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: R -> R^3");
         }
       }
 
       SECTION("Z -> R^d (non-zero)")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
+        data_node->m_data_type = int_dt;
         data_node->set_type<language::integer>();
         data_node->source  = "1";
         auto& source       = data_node->source;
@@ -1005,99 +1028,99 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: Z -> R^1");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: Z -> R^2");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: Z -> R^3");
         }
       }
 
       SECTION("N -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        data_node->m_data_type = unsigned_int_dt;
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: N -> R^1");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: N -> R^2");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: N -> R^3");
         }
       }
 
       SECTION("B -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::bool_t;
+        data_node->m_data_type = bool_dt;
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: B -> R^1");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: B -> R^2");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: B -> R^3");
         }
       }
 
       SECTION("string -> R^d")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
+        data_node->m_data_type = string_dt;
 
         SECTION("d=1")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(1)}),
                               "invalid implicit conversion: string -> R^1");
         }
 
         SECTION("d=2")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)}),
                               "invalid implicit conversion: string -> R^2");
         }
 
         SECTION("d=3")
         {
           REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                                                               ASTNodeDataType::build<ASTNodeDataType::vector_t>(3)}),
                               "invalid implicit conversion: string -> R^3");
         }
       }
@@ -1107,44 +1130,43 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("string -> R")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = string_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: string -> R");
       }
 
       SECTION("R^1 -> R")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: R^1 -> R");
       }
 
       SECTION("R^2 -> R")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: R^2 -> R");
       }
 
       SECTION("R^3 -> R")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: R^3 -> R");
       }
 
       SECTION("tuple(N) -> R")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: tuple(N) -> R");
       }
 
       SECTION("tuple(R) -> R")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(double_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, double_dt}),
                             "invalid implicit conversion: tuple(R) -> R");
       }
     }
@@ -1153,51 +1175,50 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("string -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = string_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: string -> Z");
       }
 
       SECTION("R^1 -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: R^1 -> Z");
       }
 
       SECTION("R^2 -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: R^2 -> Z");
       }
 
       SECTION("R^3 -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: R^3 -> Z");
       }
 
       SECTION("R -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = double_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: R -> Z");
       }
 
       SECTION("tuple(N) -> Z")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: tuple(N) -> Z");
       }
 
       SECTION("tuple(Z) -> Z")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, int_dt}),
                             "invalid implicit conversion: tuple(Z) -> Z");
       }
     }
@@ -1206,51 +1227,50 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("string -> N")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = string_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: string -> N");
       }
 
       SECTION("R^1 -> N")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: R^1 -> N");
       }
 
       SECTION("R^2 -> N")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: R^2 -> N");
       }
 
       SECTION("R^3 -> N")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: R^3 -> N");
       }
 
       SECTION("R -> N")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = double_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: R -> N");
       }
 
       SECTION("tuple(Z) -> N")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: tuple(Z) -> N");
       }
 
       SECTION("tuple(N) -> N")
       {
-        data_node->m_data_type =
-          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, unsigned_int_dt}),
                             "invalid implicit conversion: tuple(N) -> N");
       }
     }
@@ -1259,64 +1279,64 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("string -> B")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = string_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: string -> B");
       }
 
       SECTION("R^1 -> B")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: R^1 -> B");
       }
 
       SECTION("R^2 -> B")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: R^2 -> B");
       }
 
       SECTION("R^3 -> B")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: R^3 -> B");
       }
 
       SECTION("R -> B")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = double_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: R -> B");
       }
 
       SECTION("Z -> B")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = int_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: Z -> B");
       }
 
       SECTION("N -> B")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: N -> B");
       }
 
       SECTION("tuple(Z) -> B")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: tuple(Z) -> B");
       }
 
       SECTION("tuple(B) -> B")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(bool_dt);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, bool_dt}),
                             "invalid implicit conversion: tuple(B) -> B");
       }
     }
@@ -1325,166 +1345,165 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
     {
       SECTION("N -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = unsigned_int_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: N -> B");
       }
 
       SECTION("Z -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::int_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = int_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: Z -> B");
       }
 
       SECTION("R -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = double_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: R -> B");
       }
 
       SECTION("string -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType::string_t;
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = string_dt;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: string -> B");
       }
 
       SECTION("R^1 -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: R^1 -> B");
       }
 
       SECTION("R^2 -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: R^2 -> B");
       }
 
       SECTION("R^3 -> tuple(B)")
       {
-        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                                         ASTNodeDataType{
-                                                                                           ASTNodeDataType::bool_t}}}),
+        data_node->m_data_type = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               bool_dt)}),
                             "invalid implicit conversion: R^3 -> B");
       }
 
       SECTION("R -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::double_t;
+        data_node->m_data_type = double_dt;
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::tuple_t,
-                                                                             ASTNodeDataType{
-                                                                               ASTNodeDataType::unsigned_int_t}}}),
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(
+                                                               unsigned_int_dt)}),
                             "invalid implicit conversion: R -> N");
       }
 
       SECTION("R^1 -> tuple(R^2)")
       {
-        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        auto R1                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(1);
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         data_node->m_data_type = R1;
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2)}),
+                            "invalid implicit conversion: R^1 -> R^2");
       }
 
       SECTION("R^2 -> tuple(R^3)")
       {
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
-        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
+        auto R3                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
         data_node->m_data_type = R2;
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R3}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R3)}),
+                            "invalid implicit conversion: R^2 -> R^3");
       }
 
       SECTION("R^3 -> tuple(R^2)")
       {
-        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
-        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        auto R3                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(3);
+        auto R2                = ASTNodeDataType::build<ASTNodeDataType::vector_t>(2);
         data_node->m_data_type = R3;
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
-                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}),
-                            "incompatible dimensions in affectation");
+                                                             ASTNodeDataType::build<ASTNodeDataType::tuple_t>(R2)}),
+                            "invalid implicit conversion: R^3 -> R^2");
       }
 
       SECTION("(B, R, Z) -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          list0_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::double_t;
+          list1_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
                             "invalid implicit conversion: R -> N");
       }
 
       SECTION("(R, N, Z) -> tuple(Z)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::double_t;
+          list0_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          list2_node->m_data_type    = int_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(int_dt);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
                             "invalid implicit conversion: R -> Z");
       }
 
       SECTION("(B, N, R) -> tuple(N)")
       {
-        data_node->m_data_type = ASTNodeDataType::list_t;
+        data_node->m_data_type = list_dt;
         {
           std::unique_ptr list0_node = std::make_unique<ASTNode>();
-          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          list0_node->m_data_type    = bool_dt;
           data_node->emplace_back(std::move(list0_node));
 
           std::unique_ptr list1_node = std::make_unique<ASTNode>();
-          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          list1_node->m_data_type    = unsigned_int_dt;
           data_node->emplace_back(std::move(list1_node));
 
           std::unique_ptr list2_node = std::make_unique<ASTNode>();
-          list2_node->m_data_type    = ASTNodeDataType::double_t;
+          list2_node->m_data_type    = double_dt;
           data_node->emplace_back(std::move(list2_node));
         }
-        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(unsigned_int_dt);
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
                             "invalid implicit conversion: R -> N");
       }
@@ -1492,9 +1511,9 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
 
     SECTION("(type_id_t, type_id_t) -> tuple(type_id_t)")
     {
-      auto type_id1          = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
-      auto type_id2          = ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"};
-      data_node->m_data_type = ASTNodeDataType::list_t;
+      auto type_id1          = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("foo");
+      auto type_id2          = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("bar");
+      data_node->m_data_type = list_dt;
       {
         std::unique_ptr list0_node = std::make_unique<ASTNode>();
         list0_node->m_data_type    = type_id1;
@@ -1504,7 +1523,7 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         list1_node->m_data_type    = type_id2;
         data_node->emplace_back(std::move(list1_node));
       }
-      auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id2};
+      auto tuple_t = ASTNodeDataType::build<ASTNodeDataType::tuple_t>(type_id2);
       REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
                           "invalid implicit conversion: foo -> bar");
     }
diff --git a/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp b/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp
index 6c30d3f0a9e8470f7156fe6aa8239002f065aee5..cc31b56706d9bdf952bcfdb5b4ab6e209e2be1df 100644
--- a/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp
+++ b/tests/test_ASTNodeUnaryOperatorExpressionBuilder.cpp
@@ -235,7 +235,7 @@ not b;
     {
       auto ast = std::make_unique<ASTNode>();
       ast->set_type<language::unary_minus>();
-      ast->m_data_type = ASTNodeDataType::int_t;
+      ast->m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
       ast->children.emplace_back(std::make_unique<ASTNode>());
 
       REQUIRE_THROWS_WITH(ASTNodeUnaryOperatorExpressionBuilder{*ast},
diff --git a/tests/test_AffectationProcessor.cpp b/tests/test_AffectationProcessor.cpp
index c94ecdb7d9a1d320dce9f00a7bd70755fd425749..75ba801b59cc8d06b213fd56b2dc18dbb74b7c45 100644
--- a/tests/test_AffectationProcessor.cpp
+++ b/tests/test_AffectationProcessor.cpp
@@ -395,19 +395,19 @@ TEST_CASE("AffectationProcessor", "[language]")
         CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 3;", "invalid implicit conversion: Z -> R^3");
 
         CHECK_AFFECTATION_THROWS_WITH("let x : R^1, x = 0; let y : R^2, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^1 -> R^2");
         CHECK_AFFECTATION_THROWS_WITH("let x : R^1, x = 0; let y : R^3, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^1 -> R^3");
 
         CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 0; let y : R^1, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^2 -> R^1");
         CHECK_AFFECTATION_THROWS_WITH("let x : R^2, x = 0; let y : R^3, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^2 -> R^3");
 
         CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 0; let y : R^1, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^3 -> R^1");
         CHECK_AFFECTATION_THROWS_WITH("let x : R^3, x = 0; let y : R^2, y = x;",
-                                      "incompatible dimensions in affectation");
+                                      "invalid implicit conversion: R^3 -> R^2");
       }
     }
   }
diff --git a/tests/test_BuiltinFunctionEmbedder.cpp b/tests/test_BuiltinFunctionEmbedder.cpp
index bf0445d6aadf5cfdbefed9134dafe0e89dd8d290..00f757fa68d935cdffbff876205e4ba5a16d1e68 100644
--- a/tests/test_BuiltinFunctionEmbedder.cpp
+++ b/tests/test_BuiltinFunctionEmbedder.cpp
@@ -5,15 +5,16 @@
 // clazy:excludeall=non-pod-global-static
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t,
-                                                                                 "shared_const_double"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_const_double");
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<double>> = {ASTNodeDataType::type_id_t, "shared_double"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_double");
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<uint64_t>> = {ASTNodeDataType::type_id_t,
-                                                                             "shared_uint64_t"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<uint64_t>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_uint64_t");
 
 TEST_CASE("BuiltinFunctionEmbedder", "[language]")
 {
diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp
index 1583f1df99d7eddefc3337529611a5d5720912a0..c1c1eb29b74fb9c5e6f8a170f76c7b4b2157c7b7 100644
--- a/tests/test_BuiltinFunctionRegister.hpp
+++ b/tests/test_BuiltinFunctionRegister.hpp
@@ -7,8 +7,8 @@
 #include <utils/Exceptions.hpp>
 
 template <>
-inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = {ASTNodeDataType::type_id_t,
-                                                                                 "builtin_t"};
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t");
 const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>;
 
 namespace test_only
@@ -127,7 +127,7 @@ class test_BuiltinFunctionRegister
       throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");
     }
 
-    i_symbol->attributes().setDataType(ASTNodeDataType::type_name_id_t);
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());
     i_symbol->attributes().setIsInitialized();
     i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();
     symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId()));
@@ -165,7 +165,7 @@ class test_BuiltinFunctionRegister
         throw ParseError(error_message.str(), root_node.begin());
       }
 
-      i_symbol->attributes().setDataType(ASTNodeDataType::builtin_function_t);
+      i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>());
       i_symbol->attributes().setIsInitialized();
       i_symbol->attributes().value() = builtin_function_embedder_table.size();
 
diff --git a/tests/test_FunctionTable.cpp b/tests/test_FunctionTable.cpp
index c6ae9ab2f856457aaff70aaf2e35146661fde1b0..eae87ca79ac45e18da301fef72e1bd2fd35f90cf 100644
--- a/tests/test_FunctionTable.cpp
+++ b/tests/test_FunctionTable.cpp
@@ -11,14 +11,14 @@ TEST_CASE("FunctionTable", "[language]")
   SECTION("FunctionDescriptor")
   {
     std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>();
-    domain_mapping_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+    domain_mapping_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
 
     std::unique_ptr definition_node = std::make_unique<ASTNode>();
-    definition_node->m_data_type    = ASTNodeDataType::double_t;
+    definition_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::double_t>();
     FunctionDescriptor f{"f", std::move(domain_mapping_node), std::move(definition_node)};
 
-    REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
-    REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t);
+    REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>());
+    REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::double_t>());
 
     REQUIRE(domain_mapping_node == nullptr);
     REQUIRE(definition_node == nullptr);
@@ -28,10 +28,10 @@ TEST_CASE("FunctionTable", "[language]")
   SECTION("uninitialized FunctionDescriptor")
   {
     std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>();
-    domain_mapping_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+    domain_mapping_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
 
     std::unique_ptr definition_node = std::make_unique<ASTNode>();
-    definition_node->m_data_type    = ASTNodeDataType::double_t;
+    definition_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::double_t>();
 
     SECTION("nothing initialized")
     {
@@ -44,7 +44,7 @@ TEST_CASE("FunctionTable", "[language]")
     {
       FunctionDescriptor f{"function", nullptr, std::move(definition_node)};
       REQUIRE_THROWS_AS(f.domainMappingNode(), AssertError);
-      REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t);
+      REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::double_t>());
       REQUIRE(definition_node == nullptr);
     }
 
@@ -52,7 +52,7 @@ TEST_CASE("FunctionTable", "[language]")
     {
       FunctionDescriptor f{"function", std::move(domain_mapping_node), nullptr};
       REQUIRE_THROWS_AS(f.definitionNode(), AssertError);
-      REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>());
       REQUIRE(domain_mapping_node == nullptr);
     }
   }
@@ -63,10 +63,10 @@ TEST_CASE("FunctionTable", "[language]")
   REQUIRE(table.size() == 0);
 
   std::unique_ptr domain_mapping_node = std::make_unique<ASTNode>();
-  domain_mapping_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+  domain_mapping_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>();
 
   std::unique_ptr definition_node = std::make_unique<ASTNode>();
-  definition_node->m_data_type    = ASTNodeDataType::double_t;
+  definition_node->m_data_type    = ASTNodeDataType::build<ASTNodeDataType::double_t>();
 
   size_t function_id =
     table.add(FunctionDescriptor{"function", std::move(domain_mapping_node), std::move(definition_node)});
@@ -82,8 +82,8 @@ TEST_CASE("FunctionTable", "[language]")
 
   auto& f = table[function_id];
   REQUIRE(f.name() == "function");
-  REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
-  REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t);
+  REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::unsigned_int_t>());
+  REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::build<ASTNodeDataType::double_t>());
 
   const auto& const_f = const_table[function_id];
   REQUIRE(const_f.name() == "function");
diff --git a/tests/test_PugsFunctionAdapter.cpp b/tests/test_PugsFunctionAdapter.cpp
index 45229f8b599a1517fcd4c2182de563601643250d..3a7ca2813845fa72b0db312b6d259195c162c09d 100644
--- a/tests/test_PugsFunctionAdapter.cpp
+++ b/tests/test_PugsFunctionAdapter.cpp
@@ -275,7 +275,7 @@ let R3toR3zero: R^3 -> R^3, x -> 0;
   {
     std::string_view data = R"(
 let R1toR1: R^1 -> R^1, x -> x;
-let R3toR3: R^3 -> R^3, x -> 1;
+let R3toR3: R^3 -> R^3, x -> 0;
 let RRRtoR3: R*R*R -> R^3, (x,y,z) -> (x,y,z);
 let R3toR2: R^3 -> R^2, x -> (x[0],x[1]+x[2]);
 let RtoNS: R -> N*string, x -> (1, "foo");
@@ -322,9 +322,9 @@ let RtoR: R -> R, x -> 2*x;
       const TinyVector<3> x{2, 1, 3};
       FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table);
 
-      REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<3>(TinyVector<3>)>::one_arg(function_symbol_id, x),
+      REQUIRE_THROWS_WITH(tests_adapter::TestBinary<TinyVector<2>(TinyVector<3>)>::one_arg(function_symbol_id, x),
                           "error: invalid function type\n"
-                          "note: expecting R^3 -> R^3\n"
+                          "note: expecting R^3 -> R^2\n"
                           "note: provided function R3toR3: R^3 -> R^3");
     }
 
diff --git a/tests/test_SymbolTable.cpp b/tests/test_SymbolTable.cpp
index bb80c4999781e59f3585f1ff64eba3ac3b71bcac..fed694f752f4b87ce79a88ae97547800bb4d35c2 100644
--- a/tests/test_SymbolTable.cpp
+++ b/tests/test_SymbolTable.cpp
@@ -67,8 +67,8 @@ TEST_CASE("SymbolTable", "[language]")
       attributes_a.setIsInitialized();
       REQUIRE(attributes_a.isInitialized());
 
-      attributes_a.setDataType(ASTNodeDataType::double_t);
-      REQUIRE(attributes_a.dataType() == ASTNodeDataType::double_t);
+      attributes_a.setDataType(ASTNodeDataType::build<ASTNodeDataType::double_t>());
+      REQUIRE(attributes_a.dataType() == ASTNodeDataType::build<ASTNodeDataType::double_t>());
 
       attributes_a.value() = 2.3;
 
@@ -166,8 +166,8 @@ TEST_CASE("SymbolTable", "[language]")
     attributes_a.setIsInitialized();
     REQUIRE(attributes_a.isInitialized());
 
-    attributes_a.setDataType(ASTNodeDataType::function_t);
-    REQUIRE(attributes_a.dataType() == ASTNodeDataType::function_t);
+    attributes_a.setDataType(ASTNodeDataType::build<ASTNodeDataType::function_t>());
+    REQUIRE(attributes_a.dataType() == ASTNodeDataType::build<ASTNodeDataType::function_t>());
 
     attributes_a.value() = static_cast<uint64_t>(2);