diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85e610b0b3ec83e2efa9083af82bc13ee56032a8
--- /dev/null
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -0,0 +1,134 @@
+#include <ASTNodeDataTypeBuilder.hpp>
+
+#include <PEGGrammar.hpp>
+#include <PugsAssert.hpp>
+#include <SymbolTable.hpp>
+
+void
+ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
+{
+  if (n.is<language::bloc>() or n.is<language::for_statement>()) {
+    for (auto& child : n.children) {
+      this->_buildNodeDataTypes(*child);
+    }
+    n.m_data_type = ASTNodeDataType::void_t;
+  } else {
+    if (n.has_content()) {
+      if (n.is<language::true_kw>() or n.is<language::false_kw>()) {
+        n.m_data_type = ASTNodeDataType::bool_t;
+      } else if (n.is<language::real>()) {
+        n.m_data_type = ASTNodeDataType::double_t;
+      } else if (n.is<language::integer>()) {
+        n.m_data_type = ASTNodeDataType::int_t;
+      } else if (n.is<language::literal>()) {
+        n.m_data_type = ASTNodeDataType::string_t;
+      } else if (n.is<language::cout_kw>() or n.is<language::cerr_kw>() or n.is<language::clog_kw>()) {
+        n.m_data_type = ASTNodeDataType::void_t;
+      } else if (n.is<language::declaration>()) {
+        auto& type_node = *(n.children[0]);
+        ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
+        if (type_node.is<language::B_set>()) {
+          data_type = ASTNodeDataType::bool_t;
+        } else if (type_node.is<language::Z_set>()) {
+          data_type = ASTNodeDataType::int_t;
+        } else if (type_node.is<language::N_set>()) {
+          data_type = ASTNodeDataType::unsigned_int_t;
+        } else if (type_node.is<language::R_set>()) {
+          data_type = ASTNodeDataType::double_t;
+        } else if (type_node.is<language::string_type>()) {
+          data_type = ASTNodeDataType::string_t;
+        }
+        if (data_type == ASTNodeDataType::undefined_t) {
+          throw parse_error("unexpected error: invalid datatype", type_node.begin());
+        }
+        type_node.m_data_type      = ASTNodeDataType::void_t;
+        n.children[1]->m_data_type = data_type;
+        const std::string& symbol  = n.children[1]->string();
+
+        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
+
+        auto [i_symbol, found] = symbol_table->find(symbol);
+        Assert(found);
+        i_symbol->second.setDataType(data_type);
+        n.m_data_type = data_type;
+      } else if (n.is<language::name>()) {
+        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
+
+        auto [i_symbol, found] = symbol_table->find(n.string());
+        Assert(found);
+        n.m_data_type = i_symbol->second.dataType();
+      }
+    }
+    for (auto& child : n.children) {
+      this->_buildNodeDataTypes(*child);
+    }
+
+    if (n.is<language::break_kw>() or n.is<language::continue_kw>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+    } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or
+               n.is<language::pluseq_op>() or n.is<language::minuseq_op>() or n.is<language::bit_andeq_op>() or
+               n.is<language::bit_xoreq_op>() or n.is<language::bit_oreq_op>()) {
+      n.m_data_type = n.children[0]->m_data_type;
+    } else if (n.is<language::for_statement>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+    } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_bloc>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+    } else if (n.is<language::for_test>()) {
+      n.m_data_type = ASTNodeDataType::bool_t;
+    } else if (n.is<language::statement_bloc>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+    } else if (n.is<language::if_statement>() or n.is<language::while_statement>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+      if ((n.children[0]->m_data_type > ASTNodeDataType::double_t) or
+          (n.children[0]->m_data_type < ASTNodeDataType::bool_t)) {
+        const ASTNodeDataType type_0 = n.children[0]->m_data_type;
+        std::ostringstream message;
+        message << "Cannot convert data type to boolean value\n"
+                << "note: incompatible operand '" << n.children[0]->string() << "' of type " << dataTypeName(type_0)
+                << std::ends;
+        throw parse_error(message.str(), n.children[0]->begin());
+      }
+    } else if (n.is<language::do_while_statement>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
+      if ((n.children[1]->m_data_type > ASTNodeDataType::double_t) or
+          (n.children[1]->m_data_type < ASTNodeDataType::bool_t)) {
+        const ASTNodeDataType type_0 = n.children[1]->m_data_type;
+        std::ostringstream message;
+        message << "Cannot convert data type to boolean value\n"
+                << "note: incompatible operand '" << n.children[1]->string() << "' of type " << dataTypeName(type_0)
+                << std::ends;
+        throw parse_error(message.str(), n.children[1]->begin());
+      }
+    } else if (n.is<language::unary_not>() or n.is<language::lesser_op>() or n.is<language::lesser_or_eq_op>() or
+               n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::eqeq_op>() or
+               n.is<language::not_eq_op>() or n.is<language::and_op>() or n.is<language::or_op>() or
+               n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>()) {
+      n.m_data_type = ASTNodeDataType::bool_t;
+    } else if (n.is<language::unary_minus>() or n.is<language::unary_plus>() or n.is<language::unary_plusplus>() or
+               n.is<language::unary_minusminus>()) {
+      n.m_data_type = n.children[0]->m_data_type;
+    } else if (n.is<language::plus_op>() or n.is<language::minus_op>() or n.is<language::multiply_op>() or
+               n.is<language::divide_op>()) {
+      const ASTNodeDataType type_0 = n.children[0]->m_data_type;
+      const ASTNodeDataType type_1 = n.children[1]->m_data_type;
+
+      n.m_data_type = dataTypePromotion(type_0, type_1);
+      if (n.m_data_type == ASTNodeDataType::undefined_t) {
+        std::ostringstream message;
+        message << "undefined binary operator\n"
+                << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0)
+                << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends;
+        throw parse_error(message.str(), n.begin());
+      }
+    }
+  }
+}
+
+ASTNodeDataTypeBuilder::ASTNodeDataTypeBuilder(ASTNode& node)
+{
+  Assert(node.is_root());
+  node.m_data_type = ASTNodeDataType::void_t;
+
+  this->_buildNodeDataTypes(node);
+  std::cout << " - build node data types\n";
+}
diff --git a/src/language/ASTNodeDataTypeBuilder.hpp b/src/language/ASTNodeDataTypeBuilder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..126c8d44285a998599c14314a404ddfdab0d3591
--- /dev/null
+++ b/src/language/ASTNodeDataTypeBuilder.hpp
@@ -0,0 +1,15 @@
+#ifndef AST_NODE_DATA_TYPE_BUILDER_HPP
+#define AST_NODE_DATA_TYPE_BUILDER_HPP
+
+#include <ASTNode.hpp>
+
+class ASTNodeDataTypeBuilder
+{
+ private:
+  void _buildNodeDataTypes(ASTNode& node);
+
+ public:
+  ASTNodeDataTypeBuilder(ASTNode& root_node);
+};
+
+#endif   // AST_NODE_DATA_TYPE_BUILDER_HPP
diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt
index c99aa359270586271348d6e7b72a1392745baaf0..8216aeac94b8868a3dd73a2604e46e53de740ba0 100644
--- a/src/language/CMakeLists.txt
+++ b/src/language/CMakeLists.txt
@@ -8,6 +8,7 @@ add_library(
   ASTBuilder.cpp
   ASTDotPrinter.cpp
   ASTNodeDataType.cpp
+  ASTNodeDataTypeBuilder.cpp
   ASTNodeAffectationExpressionBuilder.cpp
   ASTNodeBinaryOperatorExpressionBuilder.cpp
   ASTNodeExpressionBuilder.cpp
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index 8f85044d192728a07edc34c2b8bded238ac38f2d..9f3483851420fa4e55550bc10ffbaff9e52b441c 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -19,6 +19,8 @@
 #include <PEGGrammar.hpp>
 #include <SymbolTable.hpp>
 
+#include <ASTNodeDataTypeBuilder.hpp>
+
 #include <EscapedString.hpp>
 
 #include <ASTNodeExpressionBuilder.hpp>
@@ -31,141 +33,6 @@
 
 namespace language
 {
-namespace internal
-{
-void
-build_node_data_types(ASTNode& n)
-{
-  if (n.is<language::bloc>() or n.is<for_statement>()) {
-    if (!n.children.empty()) {
-      for (auto& child : n.children) {
-        build_node_data_types(*child);
-      }
-    }
-    n.m_data_type = ASTNodeDataType::void_t;
-  } else {
-    if (n.has_content()) {
-      if (n.is<language::true_kw>() or n.is<language::false_kw>() or n.is<language::do_kw>()) {
-        n.m_data_type = ASTNodeDataType::bool_t;
-      } else if (n.is<language::real>()) {
-        n.m_data_type = ASTNodeDataType::double_t;
-      } else if (n.is<language::integer>()) {
-        n.m_data_type = ASTNodeDataType::int_t;
-      } else if (n.is<language::literal>()) {
-        n.m_data_type = ASTNodeDataType::string_t;
-      } else if (n.is<language::cout_kw>() or n.is<language::cerr_kw>() or n.is<language::clog_kw>()) {
-        n.m_data_type = ASTNodeDataType::void_t;
-      } else if (n.is<language::declaration>()) {
-        auto& type_node = *(n.children[0]);
-        ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
-        if (type_node.is<language::B_set>()) {
-          data_type = ASTNodeDataType::bool_t;
-        } else if (type_node.is<language::Z_set>()) {
-          data_type = ASTNodeDataType::int_t;
-        } else if (type_node.is<language::N_set>()) {
-          data_type = ASTNodeDataType::unsigned_int_t;
-        } else if (type_node.is<language::R_set>()) {
-          data_type = ASTNodeDataType::double_t;
-        } else if (type_node.is<language::string_type>()) {
-          data_type = ASTNodeDataType::string_t;
-        }
-        if (data_type == ASTNodeDataType::undefined_t) {
-          throw parse_error("unexpected error: invalid datatype", type_node.begin());
-        }
-        type_node.m_data_type      = ASTNodeDataType::void_t;
-        n.children[1]->m_data_type = data_type;
-        const std::string& symbol  = n.children[1]->string();
-
-        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
-
-        auto [i_symbol, found] = symbol_table->find(symbol);
-        Assert(found);
-        i_symbol->second.setDataType(data_type);
-        n.m_data_type = data_type;
-      } else if (n.is<language::name>()) {
-        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
-
-        auto [i_symbol, found] = symbol_table->find(n.string());
-        Assert(found);
-        n.m_data_type = i_symbol->second.dataType();
-      }
-    }
-    for (auto& child : n.children) {
-      build_node_data_types(*child);
-    }
-
-    if (n.is<language::break_kw>() or n.is<language::continue_kw>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-    } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or
-               n.is<language::pluseq_op>() or n.is<language::minuseq_op>() or n.is<language::bit_andeq_op>() or
-               n.is<language::bit_xoreq_op>() or n.is<language::bit_oreq_op>()) {
-      n.m_data_type = n.children[0]->m_data_type;
-    } else if (n.is<language::for_statement>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-    } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_bloc>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-    } else if (n.is<language::for_test>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
-    } else if (n.is<language::statement_bloc>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-    } else if (n.is<language::if_statement>() or n.is<language::while_statement>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-      if ((n.children[0]->m_data_type > ASTNodeDataType::double_t) or
-          (n.children[0]->m_data_type < ASTNodeDataType::bool_t)) {
-        const ASTNodeDataType type_0 = n.children[0]->m_data_type;
-        std::ostringstream message;
-        message << "Cannot convert data type to boolean value\n"
-                << "note: incompatible operand '" << n.children[0]->string() << " of type ' (" << dataTypeName(type_0)
-                << ')' << std::ends;
-        throw parse_error(message.str(), n.children[0]->begin());
-      }
-    } else if (n.is<language::do_while_statement>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-      if ((n.children[1]->m_data_type > ASTNodeDataType::double_t) or
-          (n.children[1]->m_data_type < ASTNodeDataType::bool_t)) {
-        const ASTNodeDataType type_0 = n.children[1]->m_data_type;
-        std::ostringstream message;
-        message << "Cannot convert data type to boolean value\n"
-                << "note: incompatible operand '" << n.children[1]->string() << " of type ' (" << dataTypeName(type_0)
-                << ')' << std::ends;
-        throw parse_error(message.str(), n.children[1]->begin());
-      }
-    } else if (n.is<language::unary_not>() or n.is<language::lesser_op>() or n.is<language::lesser_or_eq_op>() or
-               n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::eqeq_op>() or
-               n.is<language::not_eq_op>() or n.is<language::and_op>() or n.is<language::or_op>() or
-               n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>()) {
-      n.m_data_type = ASTNodeDataType::bool_t;
-    } else if (n.is<language::unary_minus>() or n.is<language::unary_plus>() or n.is<language::unary_plusplus>() or
-               n.is<language::unary_minusminus>()) {
-      n.m_data_type = n.children[0]->m_data_type;
-    } else if (n.is<language::plus_op>() or n.is<language::minus_op>() or n.is<language::multiply_op>() or
-               n.is<language::divide_op>()) {
-      const ASTNodeDataType type_0 = n.children[0]->m_data_type;
-      const ASTNodeDataType type_1 = n.children[1]->m_data_type;
-
-      n.m_data_type = dataTypePromotion(type_0, type_1);
-      if (n.m_data_type == ASTNodeDataType::undefined_t) {
-        std::ostringstream message;
-        message << "undefined binary operator\n"
-                << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0)
-                << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends;
-        throw parse_error(message.str(), n.begin());
-      }
-    }
-  }
-}
-}   // namespace internal
-
-void
-build_node_data_types(ASTNode& n)
-{
-  Assert(n.is_root());
-  n.m_data_type = ASTNodeDataType::void_t;
-
-  internal::build_node_data_types(n);
-  std::cout << " - build node data types\n";
-}
-
 namespace internal
 {
 void
@@ -332,7 +199,7 @@ parser(const std::string& filename)
       std::cout << "   AST dot file: " << dot_filename << '\n';
     }
 
-    language::build_node_data_types(*root_node);
+    ASTNodeDataTypeBuilder{*root_node};
 
     language::check_node_data_types(*root_node);
     language::build_node_values(*root_node);