From 2e34cc59062ae51b1005f755bff7f418eab84b69 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 21 Jun 2019 18:56:06 +0200
Subject: [PATCH] Begin reorganization of AST construction to reduce
 compilation time

Code is quite crappy and will require lots of clean-up
---
 src/language/ASTBuilder.cpp                   |  267 +++
 src/language/ASTBuilder.hpp                   |   10 +
 src/language/ASTNode.hpp                      |   88 +
 .../ASTNodeAffectationExpressionBuilder.cpp   |  228 ++
 .../ASTNodeAffectationExpressionBuilder.hpp   |   11 +
 ...ASTNodeBinaryOperatorExpressionBuilder.cpp |  357 +++
 ...ASTNodeBinaryOperatorExpressionBuilder.hpp |   11 +
 src/language/ASTNodeDataType.cpp              |   48 +
 src/language/ASTNodeDataType.hpp              |   28 +
 src/language/ASTNodeExpressionBuilder.cpp     |  613 +++++
 src/language/ASTNodeExpressionBuilder.hpp     |   11 +
 src/language/CMakeLists.txt                   |    5 +
 src/language/PEGGrammar.hpp                   |  331 +++
 src/language/PugsParser.cpp                   | 1977 +----------------
 src/language/SymbolTable.hpp                  |  126 ++
 15 files changed, 2143 insertions(+), 1968 deletions(-)
 create mode 100644 src/language/ASTBuilder.cpp
 create mode 100644 src/language/ASTBuilder.hpp
 create mode 100644 src/language/ASTNode.hpp
 create mode 100644 src/language/ASTNodeAffectationExpressionBuilder.cpp
 create mode 100644 src/language/ASTNodeAffectationExpressionBuilder.hpp
 create mode 100644 src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
 create mode 100644 src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp
 create mode 100644 src/language/ASTNodeDataType.cpp
 create mode 100644 src/language/ASTNodeDataType.hpp
 create mode 100644 src/language/ASTNodeExpressionBuilder.cpp
 create mode 100644 src/language/ASTNodeExpressionBuilder.hpp
 create mode 100644 src/language/PEGGrammar.hpp
 create mode 100644 src/language/SymbolTable.hpp

diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp
new file mode 100644
index 000000000..5f8eb02e7
--- /dev/null
+++ b/src/language/ASTBuilder.cpp
@@ -0,0 +1,267 @@
+#include <ASTBuilder.hpp>
+
+using namespace TAO_PEGTL_NAMESPACE;
+
+#include <ASTNode.hpp>
+#include <PEGGrammar.hpp>
+
+#include <pegtl/contrib/parse_tree.hpp>
+
+namespace language
+{
+struct rearrange : parse_tree::apply<rearrange>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&... st)
+  {
+    if (n->children.size() == 1) {
+      n = std::move(n->children.back());
+    } else {
+      // First we rearrange tree
+      {
+        n->remove_content();
+        auto& children = n->children;
+        auto rhs       = std::move(children.back());
+        children.pop_back();
+        auto op = std::move(children.back());
+        children.pop_back();
+        op->children.emplace_back(std::move(n));
+        op->children.emplace_back(std::move(rhs));
+        n = std::move(op);
+        transform(n->children.front(), st...);
+      }
+      // Then we eventually simplify operations
+      {
+        if (n->is<language::minus_op>()) {
+          Assert(n->children.size() == 2);
+          auto& rhs = n->children[1];
+          if (rhs->is<language::unary_minus>()) {
+            rhs->remove_content();
+            n->id = typeid(language::plus_op);
+            rhs   = std::move(rhs->children[0]);
+          }
+        } else if (n->is<language::plus_op>()) {
+          Assert(n->children.size() == 2);
+          auto& rhs = n->children[1];
+          if (rhs->is<language::unary_minus>()) {
+            rhs->remove_content();
+            n->id = typeid(language::minus_op);
+            rhs   = std::move(rhs->children[0]);
+          }
+        }
+      }
+    }
+  }
+};
+
+struct simplify_unary : parse_tree::apply<simplify_unary>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&... st)
+  {
+    if (n->children.size() == 1) {
+      if (n->is<unary_expression>()) {
+        n->remove_content();
+        n = std::move(n->children.back());
+        transform(n, st...);
+      } else if (n->is<unary_minus>()) {
+        auto& child = n->children[0];
+        if (child->is<unary_minus>()) {
+          n->remove_content();
+          child->remove_content();
+          n = std::move(child->children[0]);
+          transform(n, st...);
+        }
+      } else if (n->is<unary_not>()) {
+        auto& child = n->children[0];
+        if (child->is<unary_not>()) {
+          n->remove_content();
+          child->remove_content();
+          n = std::move(child->children[0]);
+          transform(n, st...);
+        }
+      }
+    } else if (n->children.size() == 2) {
+      if (n->children[0]->is<language::unary_plus>()) {
+        n->remove_content();
+        n = std::move(n->children[1]);
+        transform(n, st...);
+      } else if (n->children[0]->is<language::unary_minus>() or n->children[0]->is<language::unary_not>() or
+                 n->children[0]->is<language::unary_minusminus>() or n->children[0]->is<language::unary_plusplus>()) {
+        n->remove_content();
+        auto expression     = std::move(n->children[1]);
+        auto unary_operator = std::move(n->children[0]);
+        unary_operator->children.emplace_back(std::move(expression));
+        n = std::move(unary_operator);
+        n->remove_content();
+        transform(n, st...);
+      } else if (n->children[1]->is<language::post_minusminus>() or n->children[1]->is<language::post_plusplus>()) {
+        n->remove_content();
+        auto expression     = std::move(n->children[0]);
+        auto unary_operator = std::move(n->children[1]);
+        unary_operator->children.emplace_back(std::move(expression));
+        n = std::move(unary_operator);
+        n->remove_content();
+        transform(n, st...);
+      }
+    }
+  }
+};
+
+struct simplify_statement_bloc : parse_tree::apply<simplify_statement_bloc>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&... st)
+  {
+    if (n->children.size() == 1) {
+      if (not n->children[0]->is<language::declaration>()) {
+        n->remove_content();
+        n = std::move(n->children.back());
+        transform(n, st...);
+      } else {
+        n->id = typeid(language::bloc);
+      }
+    }
+  }
+};
+
+struct simplify_for_statement_bloc : parse_tree::apply<simplify_for_statement_bloc>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&... st)
+  {
+    if (n->children.size() == 1) {
+      n->remove_content();
+      n = std::move(n->children.back());
+      transform(n, st...);
+    }
+  }
+};
+
+struct simplify_for_init : parse_tree::apply<simplify_for_init>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&...)
+  {
+    Assert(n->children.size() <= 1);
+    if (n->children.size() == 1) {
+      n->remove_content();
+      n = std::move(n->children.back());
+    }
+  }
+};
+
+struct simplify_for_test : parse_tree::apply<simplify_for_test>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&...)
+  {
+    Assert(n->children.size() <= 1);
+    if (n->children.size() == 1) {
+      n->remove_content();
+      n = std::move(n->children.back());
+    }
+  }
+};
+
+struct simplify_for_post : parse_tree::apply<simplify_for_post>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&...)
+  {
+    Assert(n->children.size() <= 1);
+    if (n->children.size() == 1) {
+      n->remove_content();
+      n = std::move(n->children.back());
+    }
+  }
+};
+
+struct simplify_stream_statement : parse_tree::apply<simplify_stream_statement>
+{
+  template <typename... States>
+  static void
+  transform(std::unique_ptr<Node>& n, States&&...)
+  {
+    for (size_t i = 1; i < n->children.size(); ++i) {
+      n->children[0]->children.emplace_back(std::move(n->children[i]));
+    }
+    n->remove_content();
+    n = std::move(n->children[0]);
+  }
+};
+
+template <typename Rule>
+using selector = parse_tree::selector<Rule,
+                                      parse_tree::store_content::on<true_kw,
+                                                                    false_kw,
+                                                                    integer,
+                                                                    real,
+                                                                    name,
+                                                                    B_set,
+                                                                    N_set,
+                                                                    Z_set,
+                                                                    R_set,
+                                                                    cout_kw,
+                                                                    cerr_kw,
+                                                                    clog_kw,
+                                                                    declaration,
+                                                                    if_statement,
+                                                                    do_while_statement,
+                                                                    while_statement,
+                                                                    for_statement,
+                                                                    break_kw,
+                                                                    continue_kw>,
+                                      rearrange::on<product, affectation, expression>,
+                                      simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>,
+                                      parse_tree::remove_content::on<plus_op,
+                                                                     minus_op,
+                                                                     multiply_op,
+                                                                     divide_op,
+                                                                     lesser_op,
+                                                                     lesser_or_eq_op,
+                                                                     greater_op,
+                                                                     greater_or_eq_op,
+                                                                     eqeq_op,
+                                                                     not_eq_op,
+                                                                     and_op,
+                                                                     or_op,
+                                                                     xor_op,
+                                                                     bitand_op,
+                                                                     bitor_op,
+                                                                     eq_op,
+                                                                     multiplyeq_op,
+                                                                     divideeq_op,
+                                                                     pluseq_op,
+                                                                     minuseq_op,
+                                                                     // shift_left_op,
+                                                                     // shift_right_op,
+                                                                     bit_andeq_op,
+                                                                     bit_xoreq_op,
+                                                                     bit_oreq_op,
+                                                                     unary_plusplus,
+                                                                     unary_minusminus,
+                                                                     post_minusminus,
+                                                                     post_plusplus>,
+                                      simplify_for_statement_bloc::on<for_statement_bloc>,
+                                      parse_tree::discard_empty::on<ignored, semicol, bloc>,
+                                      simplify_statement_bloc::on<statement_bloc>,
+                                      simplify_for_init::on<for_init>,
+                                      simplify_for_test::on<for_test>,
+                                      simplify_for_post::on<for_post>,
+                                      simplify_stream_statement::on<ostream_statement>>;
+
+}   // namespace language
+
+std::unique_ptr<language::Node>
+buildAST(read_input<>& input)
+{
+  return parse_tree::parse<language::grammar, language::Node, language::selector, nothing, language::errors>(input);
+}
diff --git a/src/language/ASTBuilder.hpp b/src/language/ASTBuilder.hpp
new file mode 100644
index 000000000..d6ccc2c8b
--- /dev/null
+++ b/src/language/ASTBuilder.hpp
@@ -0,0 +1,10 @@
+#ifndef AST_BUILDER_HPP
+#define AST_BUILDER_HPP
+
+#include <pegtl.hpp>
+
+#include <ASTNode.hpp>
+
+std::unique_ptr<language::Node> buildAST(read_input<>& input);
+
+#endif   // AST_BUILDER_HPP
diff --git a/src/language/ASTNode.hpp b/src/language/ASTNode.hpp
new file mode 100644
index 000000000..f237cdab0
--- /dev/null
+++ b/src/language/ASTNode.hpp
@@ -0,0 +1,88 @@
+#ifndef AST_NODE_HPP
+#define AST_NODE_HPP
+
+#include <PugsAssert.hpp>
+#include <PugsMacros.hpp>
+
+#include <ASTNodeDataType.hpp>
+
+#include <pegtl/contrib/parse_tree.hpp>
+
+using namespace TAO_PEGTL_NAMESPACE;
+
+namespace language
+{
+struct ExecUntilBreakOrContinue
+{
+  enum class JumpType
+  {
+    no_jump,
+    break_jump,
+    continue_jump
+  };
+
+ private:
+  JumpType m_jump_type{JumpType::no_jump};
+  bool m_exec{true};
+
+ public:
+  PUGS_INLINE
+  bool
+  exec() const
+  {
+    return m_exec;
+  }
+
+  PUGS_INLINE
+  JumpType
+  jumpType() const
+  {
+    return m_jump_type;
+  }
+
+  ExecUntilBreakOrContinue& operator=(const ExecUntilBreakOrContinue&) = delete;
+  ExecUntilBreakOrContinue& operator=(ExecUntilBreakOrContinue&&) = default;
+
+  ExecUntilBreakOrContinue() = default;
+
+  constexpr ExecUntilBreakOrContinue(const JumpType& jump_type)
+    : m_jump_type(jump_type), m_exec((jump_type == JumpType::no_jump))
+  {
+    ;
+  }
+};
+
+class SymbolTable;
+class INodeProcessor
+{
+ public:
+  virtual void execute(ExecUntilBreakOrContinue& exec_policy) = 0;
+
+  INodeProcessor(const INodeProcessor& node) = delete;
+
+  INodeProcessor() {}
+
+  virtual ~INodeProcessor() {}
+};
+
+struct Node : public parse_tree::basic_node<Node>
+{
+  std::shared_ptr<SymbolTable> m_symbol_table;
+  std::unique_ptr<INodeProcessor> m_node_processor;
+
+  PUGS_INLINE
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    Assert(static_cast<bool>(m_node_processor));
+    if (exec_policy.exec()) {
+      m_node_processor->execute(exec_policy);
+    }
+  }
+
+  DataType m_data_type{DataType::undefined_t};
+  DataVariant m_value;
+};
+}   // namespace language
+
+#endif   // AST_NODE_HPP
diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
new file mode 100644
index 000000000..afc79af35
--- /dev/null
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -0,0 +1,228 @@
+#include <ASTNodeAffectationExpressionBuilder.hpp>
+#include <PEGGrammar.hpp>
+#include <SymbolTable.hpp>
+
+namespace language
+{
+template <typename Op>
+struct AffOp;
+
+template <>
+struct AffOp<language::eq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a = b;
+  }
+};
+
+template <>
+struct AffOp<language::multiplyeq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a *= b;
+  }
+};
+
+template <>
+struct AffOp<language::divideeq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a /= b;
+  }
+};
+
+template <>
+struct AffOp<language::pluseq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a += b;
+  }
+};
+
+template <>
+struct AffOp<language::minuseq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a -= b;
+  }
+};
+
+template <>
+struct AffOp<language::bit_andeq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a &= b;
+  }
+};
+
+template <>
+struct AffOp<language::bit_xoreq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a ^= b;
+  }
+};
+
+template <>
+struct AffOp<language::bit_oreq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE void
+  eval(A& a, const B& b)
+  {
+    a |= b;
+  }
+};
+
+template <typename OperatorT, typename ValueT, typename DataT>
+class AffectationProcessor final : public INodeProcessor
+{
+ private:
+  Node& m_node;
+  DataVariant* p_value{nullptr};
+
+  static inline const bool _is_defined{[] {
+    if constexpr (std::is_same_v<OperatorT, language::bit_andeq_op> or
+                  std::is_same_v<OperatorT, language::bit_xoreq_op> or
+                  std::is_same_v<OperatorT, language::bit_oreq_op>) {
+      return std::is_same_v<std::decay_t<ValueT>, std::decay_t<DataT>> and std::is_integral_v<std::decay_t<ValueT>>;
+    } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) {
+      if constexpr (not std::is_same_v<OperatorT, language::eq_op>) {
+        return false;
+      }
+    }
+    return true;
+  }()};
+
+ public:
+  AffectationProcessor(Node& node) : m_node{node}
+  {
+    if constexpr (_is_defined) {
+      const std::string& symbol = m_node.children[0]->string();
+      auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
+      Assert(found);
+      p_value = &i_symbol->second.value();
+    } else {
+      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
+    }
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    if constexpr (_is_defined) {
+      m_node.children[1]->execute(exec_policy);
+
+      if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
+        if constexpr (std::is_same_v<ValueT, DataT>) {
+          *p_value = m_node.children[1]->m_value;
+        } else {
+          *p_value = static_cast<ValueT>(std::get<DataT>(m_node.children[1]->m_value));
+        }
+      } else {
+        AffOp<OperatorT>().eval(std::get<ValueT>(*p_value), std::get<DataT>(m_node.children[1]->m_value));
+      }
+    }
+  }
+};
+
+void
+set_affectation_processor(Node& n)
+{
+  auto set_affectation_processor = [](Node& n, const auto& operator_v) {
+    auto set_affectation_processor_for_data = [&](const auto& value, const DataType& data_type) {
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      using ValueT    = std::decay_t<decltype(value)>;
+      switch (data_type) {
+      case DataType::bool_t: {
+        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n);
+        break;
+      }
+      case DataType::int_t: {
+        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n);
+        break;
+      }
+      case DataType::double_t: {
+        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n);
+        break;
+      }
+      default: {
+        throw parse_error("undefined operand type for affectation", std::vector{n.children[0]->begin()});
+      }
+      }
+    };
+
+    auto set_affectation_processor_for_value = [&](const DataType& value_type) {
+      const DataType data_type = n.children[1]->m_data_type;
+      switch (value_type) {
+      case DataType::bool_t: {
+        set_affectation_processor_for_data(bool{}, data_type);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        set_affectation_processor_for_data(uint64_t{}, data_type);
+        break;
+      }
+      case DataType::int_t: {
+        set_affectation_processor_for_data(int64_t{}, data_type);
+        break;
+      }
+      case DataType::double_t: {
+        set_affectation_processor_for_data(double{}, data_type);
+        break;
+      }
+      default: {
+        throw parse_error("undefined value type for affectation", std::vector{n.begin()});
+      }
+      }
+    };
+
+    set_affectation_processor_for_value(n.m_data_type);
+  };
+
+  if (n.is<language::eq_op>()) {
+    set_affectation_processor(n, language::eq_op{});
+  } else if (n.is<language::multiplyeq_op>()) {
+    set_affectation_processor(n, language::multiplyeq_op{});
+  } else if (n.is<language::divideeq_op>()) {
+    set_affectation_processor(n, language::divideeq_op{});
+  } else if (n.is<language::pluseq_op>()) {
+    set_affectation_processor(n, language::pluseq_op{});
+  } else if (n.is<language::minuseq_op>()) {
+    set_affectation_processor(n, language::minuseq_op{});
+  } else if (n.is<language::bit_andeq_op>()) {
+    set_affectation_processor(n, language::bit_andeq_op{});
+  } else if (n.is<language::bit_xoreq_op>()) {
+    set_affectation_processor(n, language::bit_xoreq_op{});
+  } else if (n.is<language::bit_oreq_op>()) {
+    set_affectation_processor(n, language::bit_oreq_op{});
+  } else {
+    throw parse_error("unexpected error: undefined affectation operator", std::vector{n.begin()});
+  }
+}
+}   // namespace language
diff --git a/src/language/ASTNodeAffectationExpressionBuilder.hpp b/src/language/ASTNodeAffectationExpressionBuilder.hpp
new file mode 100644
index 000000000..eb80e6c8a
--- /dev/null
+++ b/src/language/ASTNodeAffectationExpressionBuilder.hpp
@@ -0,0 +1,11 @@
+#ifndef AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP
+#define AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP
+
+#include <ASTNode.hpp>
+
+namespace language
+{
+void set_affectation_processor(Node& node);
+}   // namespace language
+
+#endif   // AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP
diff --git a/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
new file mode 100644
index 000000000..8af0d4d5e
--- /dev/null
+++ b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
@@ -0,0 +1,357 @@
+#include <ASTNodeBinaryOperatorExpressionBuilder.hpp>
+#include <PEGGrammar.hpp>
+#include <SymbolTable.hpp>
+
+namespace language
+{
+template <typename Op>
+struct BinOp;
+
+template <>
+struct BinOp<language::and_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a and b)
+  {
+    return a and b;
+  }
+};
+
+template <>
+struct BinOp<language::or_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a or b)
+  {
+    return a or b;
+  }
+};
+
+template <>
+struct BinOp<language::xor_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a xor b)
+  {
+    return a xor b;
+  }
+};
+
+template <>
+struct BinOp<language::bitand_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a & b)
+  {
+    return a & b;
+  }
+};
+
+template <>
+struct BinOp<language::bitor_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a | b)
+  {
+    return a | b;
+  }
+};
+
+template <>
+struct BinOp<language::eqeq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a == b)
+  {
+    return a == b;
+  }
+};
+
+template <>
+struct BinOp<language::not_eq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a != b)
+  {
+    return a != b;
+  }
+};
+
+template <>
+struct BinOp<language::lesser_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a < b)
+  {
+    return a < b;
+  }
+};
+
+template <>
+struct BinOp<language::lesser_or_eq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a <= b)
+  {
+    return a <= b;
+  }
+};
+
+template <>
+struct BinOp<language::greater_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a > b)
+  {
+    return a > b;
+  }
+};
+
+template <>
+struct BinOp<language::greater_or_eq_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a >= b)
+  {
+    return a >= b;
+  }
+};
+
+template <>
+struct BinOp<language::plus_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a + b)
+  {
+    return a + b;
+  }
+};
+
+template <>
+struct BinOp<language::minus_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a - b)
+  {
+    return a - b;
+  }
+};
+
+template <>
+struct BinOp<language::multiply_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a * b)
+  {
+    return a * b;
+  }
+};
+
+template <>
+struct BinOp<language::divide_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a / b)
+  {
+    return a / b;
+  }
+};
+
+template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
+class BinaryExpressionProcessor final : public INodeProcessor
+{
+  Node& m_node;
+
+  PUGS_INLINE ValueT
+  eval(const DataVariant& a, const DataVariant& b)
+  {
+    // Add 'signed' when necessary to avoid signed/unsigned comparison warnings
+    if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and
+                  (std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or
+                   std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::bitand_op> or
+                   std::is_same_v<BinaryOpT, language::bitor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or
+                   std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or
+                   std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or
+                   std::is_same_v<BinaryOpT, language::greater_op> or
+                   std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and
+                  (std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) {
+      if constexpr (std::is_unsigned_v<A_DataT>) {
+        using signed_A_DataT          = std::make_signed_t<A_DataT>;
+        const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a));
+        return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b));
+      } else {
+        using signed_B_DataT          = std::make_signed_t<B_DataT>;
+        const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b));
+        return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
+      }
+    } else {
+      return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b));
+    }
+  }
+
+  static inline const bool _is_defined{[] {
+    if constexpr (std::is_same_v<BinaryOpT, language::bitand_op> or std::is_same_v<BinaryOpT, language::xor_op> or
+                  std::is_same_v<BinaryOpT, language::bitor_op>) {
+      return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>;
+    }
+    return true;
+  }()};
+
+ public:
+  BinaryExpressionProcessor(Node& node) : m_node{node}
+  {
+    if constexpr (not _is_defined) {
+      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
+    }
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    if constexpr (_is_defined) {
+      m_node.children[0]->execute(exec_policy);
+      m_node.children[1]->execute(exec_policy);
+
+      m_node.m_value = eval(m_node.children[0]->m_value, m_node.children[1]->m_value);
+    }
+  }
+};
+
+void
+set_binary_operator_processor(Node& n)
+{
+  auto set_binary_operator_processor = [](Node& n, const auto& operator_v) {
+    auto set_binary_operator_processor_for_data_b = [&](const auto value, const auto data_a,
+                                                        const DataType& data_type_b) {
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      using ValueT    = std::decay_t<decltype(value)>;
+      using DataTA    = std::decay_t<decltype(data_a)>;
+      switch (data_type_b) {
+      case DataType::bool_t: {
+        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, bool>>(n);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, uint64_t>>(n);
+        break;
+      }
+      case DataType::int_t: {
+        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, int64_t>>(n);
+        break;
+      }
+      case DataType::double_t: {
+        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, double>>(n);
+        break;
+      }
+      default: {
+        throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
+      }
+      }
+    };
+
+    auto set_binary_operator_processor_for_data_a = [&](const auto value, const DataType& data_type_a) {
+      const DataType data_type_b = n.children[1]->m_data_type;
+      switch (data_type_a) {
+      case DataType::bool_t: {
+        set_binary_operator_processor_for_data_b(value, bool{}, data_type_b);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        set_binary_operator_processor_for_data_b(value, uint64_t{}, data_type_b);
+        break;
+      }
+      case DataType::int_t: {
+        set_binary_operator_processor_for_data_b(value, int64_t{}, data_type_b);
+        break;
+      }
+      case DataType::double_t: {
+        set_binary_operator_processor_for_data_b(value, double{}, data_type_b);
+        break;
+      }
+      default: {
+        throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()});
+      }
+      }
+    };
+
+    auto set_binary_operator_processor_for_value = [&](const DataType& value_type) {
+      const DataType data_type_a = n.children[0]->m_data_type;
+      switch (value_type) {
+      case DataType::bool_t: {
+        set_binary_operator_processor_for_data_a(bool{}, data_type_a);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        set_binary_operator_processor_for_data_a(uint64_t{}, data_type_a);
+        break;
+      }
+      case DataType::int_t: {
+        set_binary_operator_processor_for_data_a(int64_t{}, data_type_a);
+        break;
+      }
+      case DataType::double_t: {
+        set_binary_operator_processor_for_data_a(double{}, data_type_a);
+        break;
+      }
+      default: {
+        throw parse_error("undefined value type for binary operator", std::vector{n.begin()});
+      }
+      }
+    };
+
+    set_binary_operator_processor_for_value(n.m_data_type);
+  };
+
+  if (n.is<language::multiply_op>()) {
+    set_binary_operator_processor(n, language::multiply_op{});
+  } else if (n.is<language::divide_op>()) {
+    set_binary_operator_processor(n, language::divide_op{});
+  } else if (n.is<language::plus_op>()) {
+    set_binary_operator_processor(n, language::plus_op{});
+  } else if (n.is<language::minus_op>()) {
+    set_binary_operator_processor(n, language::minus_op{});
+  } else if (n.is<language::or_op>()) {
+    set_binary_operator_processor(n, language::or_op{});
+  } else if (n.is<language::and_op>()) {
+    set_binary_operator_processor(n, language::and_op{});
+
+  } else if (n.is<language::xor_op>()) {
+    set_binary_operator_processor(n, language::xor_op{});
+  } else if (n.is<language::bitand_op>()) {
+    set_binary_operator_processor(n, language::bitand_op{});
+  } else if (n.is<language::bitor_op>()) {
+    set_binary_operator_processor(n, language::bitor_op{});
+
+  } else if (n.is<language::greater_op>()) {
+    set_binary_operator_processor(n, language::greater_op{});
+  } else if (n.is<language::greater_or_eq_op>()) {
+    set_binary_operator_processor(n, language::greater_or_eq_op{});
+  } else if (n.is<language::lesser_op>()) {
+    set_binary_operator_processor(n, language::lesser_op{});
+  } else if (n.is<language::lesser_or_eq_op>()) {
+    set_binary_operator_processor(n, language::lesser_or_eq_op{});
+  } else if (n.is<language::eqeq_op>()) {
+    set_binary_operator_processor(n, language::eqeq_op{});
+  } else if (n.is<language::not_eq_op>()) {
+    set_binary_operator_processor(n, language::not_eq_op{});
+  } else {
+    throw parse_error("unexpected error: undefined binary operator", std::vector{n.begin()});
+  }
+}
+
+}   // namespace language
diff --git a/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp b/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp
new file mode 100644
index 000000000..ac1ceae20
--- /dev/null
+++ b/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp
@@ -0,0 +1,11 @@
+#ifndef AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP
+#define AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP
+
+#include <ASTNode.hpp>
+
+namespace language
+{
+void set_binary_operator_processor(Node& node);
+}   // namespace language
+
+#endif   // AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP
diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
new file mode 100644
index 000000000..33d809c33
--- /dev/null
+++ b/src/language/ASTNodeDataType.cpp
@@ -0,0 +1,48 @@
+#include <ASTNodeDataType.hpp>
+
+namespace language
+{
+std::string
+dataTypeName(const DataType& data_type)
+{
+  std::string name;
+  switch (data_type) {
+  case DataType::undefined_t:
+    name = "undefined";
+    break;
+  case DataType::bool_t:
+    name = "B";
+    break;
+  case DataType::unsigned_int_t:
+    name = "N";
+    break;
+  case DataType::int_t:
+    name = "Z";
+    break;
+  case DataType::double_t:
+    name = "R";
+    break;
+  case DataType::typename_t:
+    name = "typename";
+    break;
+  case DataType::void_t:
+    name = "void";
+    break;
+  }
+  return name;
+}
+
+DataType
+dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2)
+{
+  if (data_type_1 == data_type_2) {
+    return data_type_1;
+  } else if ((std::max(data_type_1, data_type_2) <= DataType::double_t) and
+             (std::min(data_type_1, data_type_2) >= DataType::bool_t)) {
+    return std::max(data_type_1, data_type_2);
+  } else {
+    return DataType::undefined_t;
+  }
+}
+
+}   // namespace language
diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp
new file mode 100644
index 000000000..51a668184
--- /dev/null
+++ b/src/language/ASTNodeDataType.hpp
@@ -0,0 +1,28 @@
+#ifndef AST_NODE_DATATYPE_HPP
+#define AST_NODE_DATATYPE_HPP
+
+#include <string>
+#include <variant>
+
+namespace language
+{
+enum class DataType
+{
+  undefined_t    = -1,
+  bool_t         = 0,
+  unsigned_int_t = 1,
+  int_t          = 2,
+  double_t       = 3,
+  typename_t     = 10,
+  void_t         = 9999
+};
+
+std::string dataTypeName(const DataType& data_type);
+
+DataType dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2);
+
+using DataVariant = std::variant<std::monostate, bool, uint64_t, int64_t, double>;
+
+}   // namespace language
+
+#endif   // AST_NODE_DATATYPE_HPP
diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp
new file mode 100644
index 000000000..6101a778c
--- /dev/null
+++ b/src/language/ASTNodeExpressionBuilder.cpp
@@ -0,0 +1,613 @@
+#include <ASTNodeExpressionBuilder.hpp>
+
+#include <ASTNodeAffectationExpressionBuilder.hpp>
+#include <ASTNodeBinaryOperatorExpressionBuilder.hpp>
+
+#include <PEGGrammar.hpp>
+#include <SymbolTable.hpp>
+
+namespace language
+{
+class NodeList final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  NodeList(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    for (auto& child : m_node.children) {
+      child->execute(exec_policy);
+    }
+  }
+};
+
+class NoProcess final : public INodeProcessor
+{
+ public:
+  NoProcess() {}
+
+  PUGS_INLINE
+  void
+  execute(ExecUntilBreakOrContinue&)
+  {
+    ;
+  }
+};
+
+template <typename Op>
+struct UnaryOp;
+
+template <>
+struct UnaryOp<language::unary_minus>
+{
+  template <typename A>
+  PUGS_INLINE A
+  eval(const A& a)
+  {
+    return -a;
+  }
+};
+
+template <>
+struct UnaryOp<language::unary_not>
+{
+  template <typename A>
+  PUGS_INLINE bool
+  eval(const A& a)
+  {
+    return not a;
+  }
+};
+
+template <typename UnaryOpT, typename ValueT, typename DataT>
+class UnaryExpressionProcessor final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  PUGS_INLINE ValueT
+  eval(const DataVariant& a)
+  {
+    return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a));
+  }
+
+ public:
+  UnaryExpressionProcessor(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    m_node.children[0]->execute(exec_policy);
+    m_node.m_value = eval(m_node.children[0]->m_value);
+  }
+};
+
+template <typename Op>
+struct IncDecOp;
+
+template <>
+struct IncDecOp<language::unary_minusminus>
+{
+  template <typename A>
+  PUGS_INLINE A
+  eval(A& a)
+  {
+    return --a;
+  }
+};
+
+template <>
+struct IncDecOp<language::unary_plusplus>
+{
+  template <typename A>
+  PUGS_INLINE A
+  eval(A& a)
+  {
+    return ++a;
+  }
+};
+
+template <>
+struct IncDecOp<language::post_minusminus>
+{
+  template <typename A>
+  PUGS_INLINE A
+  eval(A& a)
+  {
+    return a--;
+  }
+};
+
+template <>
+struct IncDecOp<language::post_plusplus>
+{
+  template <typename A>
+  PUGS_INLINE A
+  eval(A& a)
+  {
+    return a++;
+  }
+};
+
+template <typename IncDecOpT, typename ValueT, typename DataT>
+class IncDecExpressionProcessor final : public INodeProcessor
+{
+  Node& m_node;
+  DataVariant* p_value{nullptr};
+
+  static inline const bool _is_defined{[] {
+    if constexpr (std::is_same_v<IncDecOpT, language::unary_minusminus> or
+                  std::is_same_v<IncDecOpT, language::unary_plusplus> or
+                  std::is_same_v<IncDecOpT, language::post_minusminus> or
+                  std::is_same_v<IncDecOpT, language::post_plusplus>) {
+      return not std::is_same_v<std::decay_t<DataT>, bool>;
+    }
+    return true;
+  }()};
+
+ public:
+  IncDecExpressionProcessor(Node& node) : m_node{node}
+  {
+    if constexpr (_is_defined) {
+      Assert(m_node.children[0]->is<language::name>());
+      // It is sure at this point that children 0 is a variable name
+      const std::string& symbol = m_node.children[0]->string();
+      auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
+      Assert(found);
+      p_value = &i_symbol->second.value();
+    } else {
+      throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()});
+    }
+  }
+  void
+  execute(ExecUntilBreakOrContinue&)
+  {
+    if constexpr (_is_defined) {
+      m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value));
+    }
+  }
+};
+
+class IfStatement final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  IfStatement(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    m_node.children[0]->execute(exec_policy);
+    const bool is_true = static_cast<bool>(std::visit(
+      [](const auto& value) -> bool {
+        using T = std::decay_t<decltype(value)>;
+        if constexpr (std::is_same_v<T, std::monostate>) {
+          return false;
+        } else {
+          return value;
+        }
+      },
+      m_node.children[0]->m_value));
+    if (is_true) {
+      Assert(m_node.children[1] != nullptr);
+      m_node.children[1]->execute(exec_policy);
+    } else {
+      if (m_node.children.size() == 3) {
+        // else statement
+        Assert(m_node.children[2] != nullptr);
+        m_node.children[2]->execute(exec_policy);
+      }
+    }
+  }
+};
+
+class DoWhileStatement final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  DoWhileStatement(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    bool continuation_test = true;
+    ExecUntilBreakOrContinue exec_until_jump;
+    do {
+      m_node.children[0]->execute(exec_until_jump);
+      if (not exec_until_jump.exec()) {
+        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
+          break;
+        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
+          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
+        }
+      }
+      m_node.children[1]->execute(exec_policy);
+      continuation_test = static_cast<bool>(std::visit(
+        [](const auto& value) -> bool {
+          using T = std::decay_t<decltype(value)>;
+          if constexpr (std::is_same_v<T, std::monostate>) {
+            return false;
+          } else {
+            return value;
+          }
+        },
+        m_node.children[1]->m_value));
+    } while (continuation_test);
+  }
+};
+
+class WhileStatement final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  WhileStatement(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    ExecUntilBreakOrContinue exec_until_jump;
+    while ([&]() {
+      m_node.children[0]->execute(exec_policy);
+      return static_cast<bool>(std::visit(
+        [](const auto& value) -> bool {
+          using T = std::decay_t<decltype(value)>;
+          if constexpr (std::is_same_v<T, std::monostate>) {
+            return false;
+          } else {
+            return value;
+          }
+        },
+        m_node.children[0]->m_value));
+    }()) {
+      m_node.children[1]->execute(exec_until_jump);
+      if (not exec_until_jump.exec()) {
+        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
+          break;
+        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
+          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
+        }
+      }
+    }
+  }
+};
+
+class ForStatement final : public INodeProcessor
+{
+  Node& m_node;
+
+ public:
+  ForStatement(Node& node) : m_node{node} {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    ExecUntilBreakOrContinue exec_until_jump;
+    m_node.children[0]->execute(exec_policy);
+    while ([&]() {
+      m_node.children[1]->execute(exec_policy);
+      return static_cast<bool>(std::visit(
+        [](const auto& value) -> bool {
+          using T = std::decay_t<decltype(value)>;
+          if constexpr (std::is_same_v<T, std::monostate>) {
+            return false;
+          } else {
+            return value;
+          }
+        },
+        m_node.children[1]->m_value));
+    }()) {
+      m_node.children[3]->execute(exec_until_jump);
+      if (not exec_until_jump.exec()) {
+        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
+          break;
+        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
+          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
+        }
+      }
+
+      m_node.children[2]->execute(exec_policy);
+    }
+  }
+};
+
+class NameExpression final : public INodeProcessor
+{
+  Node& m_node;
+  DataVariant* p_value{nullptr};
+
+ public:
+  NameExpression(Node& node) : m_node{node}
+  {
+    const std::string& symbol = m_node.string();
+    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
+    Assert(found);
+    p_value = &(i_symbol->second.value());
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue&)
+  {
+    m_node.m_value = *p_value;
+  }
+};
+
+class BreakExpression final : public INodeProcessor
+{
+ public:
+  BreakExpression() {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::break_jump);
+  }
+};
+
+class ContinueExpression final : public INodeProcessor
+{
+ public:
+  ContinueExpression() {}
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::continue_jump);
+  }
+};
+
+class OStreamObject final : public INodeProcessor
+{
+  Node& m_node;
+  std::ostream& m_os;
+
+ public:
+  OStreamObject(Node& node, std::ostream& os) : m_node{node}, m_os(os)
+  {
+    ;
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    for (size_t i = 0; i < m_node.children.size(); ++i) {
+      m_node.children[i]->execute(exec_policy);
+      std::visit(
+        [&](auto&& value) {
+          using ValueT = std::decay_t<decltype(value)>;
+          if constexpr (not std::is_same_v<std::monostate, ValueT>) {
+            if constexpr (std::is_same_v<bool, ValueT>) {
+              m_os << std::boolalpha << value;
+            } else {
+              m_os << value;
+            }
+          }
+        },
+        m_node.children[i]->m_value);
+    }
+  }
+};
+
+namespace internal
+{
+void
+build_node_type(Node& n)
+{
+  auto set_unary_operator_processor = [](Node& n, const auto& operator_v) {
+    auto set_unary_operator_processor_for_data = [&](const auto& value, const DataType& data_type) {
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      using ValueT    = std::decay_t<decltype(value)>;
+      switch (data_type) {
+      case DataType::bool_t: {
+        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, bool>>(n);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, uint64_t>>(n);
+        break;
+      }
+      case DataType::int_t: {
+        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, int64_t>>(n);
+        break;
+      }
+      case DataType::double_t: {
+        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, double>>(n);
+        break;
+      }
+      default: {
+        throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()});
+      }
+      }
+    };
+
+    auto set_unary_operator_processor_for_value = [&](const DataType& value_type) {
+      const DataType data_type = n.children[0]->m_data_type;
+      switch (value_type) {
+      case DataType::bool_t: {
+        set_unary_operator_processor_for_data(bool{}, data_type);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        set_unary_operator_processor_for_data(uint64_t{}, data_type);
+        break;
+      }
+      case DataType::int_t: {
+        set_unary_operator_processor_for_data(int64_t{}, data_type);
+        break;
+      }
+      case DataType::double_t: {
+        set_unary_operator_processor_for_data(double{}, data_type);
+        break;
+      }
+      default: {
+        throw parse_error("undefined value type for unary operator", std::vector{n.begin()});
+      }
+      }
+    };
+
+    set_unary_operator_processor_for_value(n.m_data_type);
+  };
+
+  auto set_inc_dec_operator_processor = [](Node& n, const auto& operator_v) {
+    auto set_inc_dec_operator_processor_for_data = [&](const auto& value, const DataType& data_type) {
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      using ValueT    = std::decay_t<decltype(value)>;
+      switch (data_type) {
+      case DataType::bool_t: {
+        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, bool>>(n);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, uint64_t>>(n);
+        break;
+      }
+      case DataType::int_t: {
+        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, int64_t>>(n);
+        break;
+      }
+      case DataType::double_t: {
+        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, double>>(n);
+        break;
+      }
+      default: {
+        throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()});
+      }
+      }
+    };
+
+    auto set_inc_dec_processor_for_value = [&](const DataType& value_type) {
+      const DataType data_type = n.children[0]->m_data_type;
+      switch (value_type) {
+      case DataType::bool_t: {
+        set_inc_dec_operator_processor_for_data(bool{}, data_type);
+        break;
+      }
+      case DataType::unsigned_int_t: {
+        set_inc_dec_operator_processor_for_data(uint64_t{}, data_type);
+        break;
+      }
+      case DataType::int_t: {
+        set_inc_dec_operator_processor_for_data(int64_t{}, data_type);
+        break;
+      }
+      case DataType::double_t: {
+        set_inc_dec_operator_processor_for_data(double{}, data_type);
+        break;
+      }
+      default: {
+        throw parse_error("undefined value type for unary operator", std::vector{n.begin()});
+      }
+      }
+    };
+
+    if (not n.children[0]->is<language::name>()) {
+      throw parse_error("invalid operand type for unary operator", std::vector{n.begin()});
+    }
+
+    set_inc_dec_processor_for_value(n.m_data_type);
+  };
+
+  if (n.is_root() or n.is<language::bloc>()) {
+    n.m_node_processor = std::make_unique<NodeList>(n);
+  } else if (n.is<language::declaration>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+
+  } 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>())) {
+    set_affectation_processor(n);
+
+  } else if (n.is<language::real>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else if (n.is<language::integer>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+
+  } else if (n.is<language::name>()) {
+    n.m_node_processor = std::make_unique<NameExpression>(n);
+
+  } else if (n.is<language::unary_minus>()) {
+    set_unary_operator_processor(n, language::unary_minus{});
+  } else if (n.is<language::unary_not>()) {
+    set_unary_operator_processor(n, language::unary_not{});
+
+  } else if (n.is<language::unary_minusminus>()) {
+    set_inc_dec_operator_processor(n, language::unary_minusminus{});
+  } else if (n.is<language::unary_plusplus>()) {
+    set_inc_dec_operator_processor(n, language::unary_plusplus{});
+  } else if (n.is<language::post_minusminus>()) {
+    set_inc_dec_operator_processor(n, language::post_minusminus{});
+  } else if (n.is<language::post_plusplus>()) {
+    set_inc_dec_operator_processor(n, language::post_plusplus{});
+
+  } else if (n.is<language::multiply_op>() or n.is<language::divide_op>() or n.is<language::plus_op>() or
+             n.is<language::minus_op>() or n.is<language::or_op>() or n.is<language::and_op>() or
+             n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>() or
+             n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::lesser_op>() or
+             n.is<language::lesser_or_eq_op>() or n.is<language::eqeq_op>() or n.is<language::not_eq_op>()) {
+    set_binary_operator_processor(n);
+
+  } else if (n.is<language::B_set>()) {
+  } else if (n.is<language::N_set>()) {
+  } else if (n.is<language::Z_set>()) {
+  } else if (n.is<language::cout_kw>()) {
+    n.m_node_processor = std::make_unique<OStreamObject>(n, std::cout);
+  } else if (n.is<language::cerr_kw>()) {
+    n.m_node_processor = std::make_unique<OStreamObject>(n, std::cerr);
+  } else if (n.is<language::clog_kw>()) {
+    n.m_node_processor = std::make_unique<OStreamObject>(n, std::clog);
+  } else if (n.is<language::R_set>()) {
+  } else if (n.is<language::if_statement>()) {
+    n.m_node_processor = std::make_unique<IfStatement>(n);
+  } else if (n.is<language::statement_bloc>()) {
+    n.m_node_processor = std::make_unique<NodeList>(n);
+  } else if (n.is<language::do_while_statement>()) {
+    n.m_node_processor = std::make_unique<DoWhileStatement>(n);
+  } else if (n.is<language::while_statement>()) {
+    n.m_node_processor = std::make_unique<WhileStatement>(n);
+  } else if (n.is<language::for_statement>()) {
+    n.m_node_processor = std::make_unique<ForStatement>(n);
+  } else if (n.is<language::for_statement_bloc>()) {
+    n.m_node_processor = std::make_unique<NodeList>(n);
+  } else if (n.is<language::for_init>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else if (n.is<language::for_post>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else if (n.is<language::for_test>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else if (n.is<language::break_kw>()) {
+    n.m_node_processor = std::make_unique<BreakExpression>();
+  } else if (n.is<language::continue_kw>()) {
+    n.m_node_processor = std::make_unique<ContinueExpression>();
+  } else if (n.is<language::true_kw>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else if (n.is<language::false_kw>()) {
+    n.m_node_processor = std::make_unique<NoProcess>();
+  } else {
+    std::ostringstream error_message;
+    error_message << "undefined node type '" << rang::fgB::red << n.name() << rang::fg::reset << "'";
+    throw parse_error{error_message.str(), std::vector{n.begin()}};
+  }
+
+  for (auto& child : n.children) {
+    internal::build_node_type(*child);
+  }
+}
+}   // namespace internal
+
+void
+build_node_type(Node& n)
+{
+  Assert(n.is_root());
+  Assert(n.is<void>());
+  n.m_node_processor = std::make_unique<NodeList>(n);
+  for (auto& child : n.children) {
+    internal::build_node_type(*child);
+  }
+  std::cout << " - build node types\n";
+}
+}   // namespace language
diff --git a/src/language/ASTNodeExpressionBuilder.hpp b/src/language/ASTNodeExpressionBuilder.hpp
new file mode 100644
index 000000000..4dc02c93b
--- /dev/null
+++ b/src/language/ASTNodeExpressionBuilder.hpp
@@ -0,0 +1,11 @@
+#ifndef AST_NODE_EXPRESSION_BUILDER_HPP
+#define AST_NODE_EXPRESSION_BUILDER_HPP
+
+#include <ASTNode.hpp>
+
+namespace language
+{
+void build_node_type(Node& n);
+}
+
+#endif   // AST_NODE_EXPRESSION_BUILDER_HPP
diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt
index 2a9e7547f..8436a645f 100644
--- a/src/language/CMakeLists.txt
+++ b/src/language/CMakeLists.txt
@@ -5,6 +5,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 add_library(
   PugsLanguage
+  ASTBuilder.cpp
+  ASTNodeDataType.cpp
+  ASTNodeAffectationExpressionBuilder.cpp
+  ASTNodeBinaryOperatorExpressionBuilder.cpp
+  ASTNodeExpressionBuilder.cpp
   PugsParser.cpp)
 
 #include_directories(${PUGS_SOURCE_DIR}/utils)
diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
new file mode 100644
index 000000000..e4c8a55af
--- /dev/null
+++ b/src/language/PEGGrammar.hpp
@@ -0,0 +1,331 @@
+#ifndef PEG_GRAMMAR_HPP
+#define PEG_GRAMMAR_HPP
+
+#include <pegtl.hpp>
+
+using namespace TAO_PEGTL_NAMESPACE;
+
+namespace language
+{
+// clang-format off
+
+struct slashslash : TAO_PEGTL_STRING("//") {};
+struct slashstar  : TAO_PEGTL_STRING("/*") {};
+struct starslash  : TAO_PEGTL_STRING("*/") {};
+
+struct comment
+    : sor< if_must< slashslash, until< eolf > >,
+           try_catch< slashstar, until< starslash> >,
+           // error management
+           if_must<at<slashstar>,raise<slashstar>, until< eof> > > {};
+
+struct ignored : star< sor< space, comment>  >{};
+
+struct integer
+    :  plus< digit > {};
+struct INTEGER : seq< integer, ignored >{};
+
+struct real
+    : seq< sor< seq<
+                  plus< digit >,
+                  one < '.' >,
+                  star< digit >
+                  >,
+                seq<
+                  one < '.' >,
+                  plus< digit >
+                  >
+                >,
+           opt<
+             seq<
+               one< 'E',
+                    'e' >,
+               opt< one< '+',
+                         '-' >
+                    >,
+               plus<digit>
+               >
+             >
+           >{};
+
+struct semicol : one< ';' >{};
+
+struct REAL : seq< real, ignored >{};
+
+struct B_set : one< 'B' >{};
+struct N_set : one< 'N' >{};
+struct Z_set : one< 'Z' >{};
+struct R_set : one< 'R' >{};
+
+struct basic_type : sor < B_set, R_set, Z_set, N_set > {};
+
+struct TYPESPECIFIER : seq< basic_type, ignored> {};
+
+struct and_kw :  TAO_PEGTL_KEYWORD("and") {};
+struct or_kw :  TAO_PEGTL_KEYWORD("or") {};
+
+struct xor_kw :  TAO_PEGTL_KEYWORD("xor") {};
+struct bitand_kw :  TAO_PEGTL_KEYWORD("bitand") {};
+struct bitor_kw :  TAO_PEGTL_KEYWORD("bitor") {};
+
+struct and_eq_kw :  TAO_PEGTL_KEYWORD("and_eq") {};
+struct xor_eq_kw :  TAO_PEGTL_KEYWORD("xor_eq") {};
+struct or_eq_kw :  TAO_PEGTL_KEYWORD("or_eq") {};
+
+struct not_kw :  TAO_PEGTL_KEYWORD("not") {};
+struct true_kw :  TAO_PEGTL_KEYWORD("true") {};
+struct false_kw :  TAO_PEGTL_KEYWORD("false") {};
+
+struct BOOL : seq< sor<true_kw, false_kw>, ignored > {};
+
+struct do_kw : TAO_PEGTL_KEYWORD("do") {};
+struct DO : seq < do_kw, ignored > {};
+
+struct while_kw : TAO_PEGTL_KEYWORD("while") {};
+struct WHILE : seq < while_kw, ignored > {};
+
+struct for_kw : TAO_PEGTL_KEYWORD("for") {};
+struct FOR : seq < for_kw, ignored > {};
+
+struct if_kw : TAO_PEGTL_KEYWORD("if") {};
+struct IF : seq < if_kw, ignored > {};
+
+struct else_kw : TAO_PEGTL_KEYWORD("else") {};
+struct ELSE : seq < else_kw, ignored > {};
+
+struct break_kw : TAO_PEGTL_KEYWORD("break") {};
+struct BREAK : seq < break_kw, ignored > {};
+
+struct continue_kw : TAO_PEGTL_KEYWORD("continue") {};
+struct CONTINUE : seq < continue_kw, ignored > {};
+
+struct cout_kw : TAO_PEGTL_KEYWORD("cout") {};
+struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {};
+struct clog_kw : TAO_PEGTL_KEYWORD("clog") {};
+
+struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw,  bitand_kw, bitor_kw, and_eq_kw, xor_eq_kw, or_eq_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {};
+
+struct name : minus< identifier, keywork >  {};
+struct NAME : seq < name, ignored > {};
+
+struct SEMICOL : seq< semicol , ignored > {};
+
+struct open_parent : seq< one< '(' >, ignored > {};
+struct close_parent : seq< one< ')' >, ignored > {};
+
+struct expression;
+struct parented_expression : if_must< open_parent, expression, close_parent > {};
+
+struct primary_expression : sor< BOOL, REAL, INTEGER , NAME, parented_expression > {};
+
+struct unary_plusplus : TAO_PEGTL_STRING("++") {};
+struct unary_minusminus : TAO_PEGTL_STRING("--") {};
+
+struct unary_plus :  one< '+' > {};
+struct unary_minus : one< '-' > {};
+
+struct unary_not : sor< one< '!'> , not_kw > {};
+
+struct unary_operator : seq< sor< unary_plusplus, unary_minusminus, unary_plus, unary_minus, unary_not>, ignored > {};
+
+struct post_plusplus : TAO_PEGTL_STRING("++") {};
+struct post_minusminus : TAO_PEGTL_STRING("--") {};
+
+struct postfix_operator : seq< sor< post_plusplus, post_minusminus>, ignored > {};
+
+struct postfix_expression : seq< primary_expression, star<postfix_operator> > {};
+
+struct unary_expression : sor< seq< unary_operator, unary_expression >,
+                               postfix_expression > {};
+
+struct and_op : seq< sor<TAO_PEGTL_STRING("&&"), and_kw>, ignored > {};
+struct or_op : seq< sor<TAO_PEGTL_STRING("||"), or_kw>, ignored > {};
+
+struct xor_op : seq< sor< one< '^' >, xor_kw>, ignored >{};
+struct bitand_op : seq< sor< seq< one< '&' >, not_at< one< '&' > > >, bitand_kw>, ignored >{};
+struct bitor_op : seq< sor< seq< one< '|' >, not_at< one< '|' > > >, bitor_kw>, ignored >{};
+
+struct eqeq_op : seq< TAO_PEGTL_STRING("=="), ignored > {};
+struct not_eq_op : seq< TAO_PEGTL_STRING("!="), ignored > {};
+
+struct lesser_op : seq< one< '<' >, not_at< one< '<' > >, ignored > {};
+struct lesser_or_eq_op : seq< TAO_PEGTL_STRING("<="), ignored > {};
+struct greater_op : seq< one< '>' >, not_at< one< '>' > >, ignored > {};
+struct greater_or_eq_op : seq< TAO_PEGTL_STRING(">="), ignored > {};
+
+struct shift_left_op : seq< TAO_PEGTL_STRING("<<"), ignored > {};
+struct shift_right_op : seq< TAO_PEGTL_STRING(">>"), ignored > {};
+
+struct plus_op : seq< one< '+' >, not_at< one< '+' > >, ignored > {};
+struct minus_op : seq< one< '-' >, not_at< one< '-' > >, ignored > {};
+struct multiply_op : seq< one< '*' >, ignored > {};
+struct divide_op : seq< one< '/' >, ignored > {};
+
+struct eq_op : seq< one<'='>, not_at< one< '=' > >, ignored > {};
+struct multiplyeq_op : seq< TAO_PEGTL_STRING("*="), ignored > {};
+struct divideeq_op : seq< TAO_PEGTL_STRING("/="), ignored > {};
+struct pluseq_op : seq< TAO_PEGTL_STRING("+="), ignored > {};
+struct minuseq_op : seq< TAO_PEGTL_STRING("-="), ignored > {};
+
+struct bit_andeq_op : seq< sor< TAO_PEGTL_STRING("&="), and_eq_kw >, ignored > {};
+struct bit_xoreq_op : seq< sor< TAO_PEGTL_STRING("^="), xor_eq_kw >, ignored > {};
+struct bit_oreq_op : seq< sor< TAO_PEGTL_STRING("|="), or_eq_kw >, ignored > {};
+
+struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {};
+
+struct sum : list_must< product, sor< plus_op, minus_op > > {};
+
+struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{};
+
+struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{};
+
+struct bitwise_and : list_must < equality, bitand_op >{};
+
+struct bitwise_xor : list_must< bitwise_and, xor_op >{};
+
+struct bitwise_or : list_must< bitwise_xor, bitor_op >{};
+
+struct logical_and : list_must< bitwise_or, and_op >{};
+
+struct logical_or : list_must< logical_and, or_op >{};
+
+struct expression : logical_or {};
+
+struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op,  bit_andeq_op,
+                        bit_xoreq_op, bit_oreq_op > {};
+
+struct affectation : seq< NAME , if_must< affect_op, expression > >{};
+
+struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{};
+
+struct open_brace : seq< one< '{' >, ignored >{};
+struct close_brace : seq< one< '}' >, ignored >{};
+
+struct instruction_list;
+
+struct braced_instruction_list
+    :  sor<try_catch< open_brace, instruction_list, close_brace >,
+           // non matching braces management
+           if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{};
+
+struct bloc : braced_instruction_list {};
+
+struct statement_bloc;
+
+struct if_statement : if_must< IF, parented_expression,  statement_bloc, opt< if_must<ELSE, statement_bloc > > >{};
+
+struct do_while_statement : if_must< DO, statement_bloc, WHILE, parented_expression >{};
+
+struct while_statement : if_must< WHILE, parented_expression, statement_bloc >{};
+
+struct for_init : opt< sor< declaration, affectation, expression > >{};
+struct for_test : opt< sor< affectation, expression > >{};
+struct for_post : opt< sor< affectation, expression > >{};
+
+struct for_statement_bloc;
+
+struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_bloc >{};
+
+struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{};
+struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{};
+
+struct instruction
+    : sor<if_must< declaration, semicol >,
+          if_must< affectation, semicol >,
+          if_statement,
+          if_must<do_while_statement, semicol>,
+          while_statement,
+          for_statement,
+          if_must< ostream_statement, semicol >,
+          if_must< BREAK, semicol >,
+          if_must< CONTINUE, semicol >,
+          if_must< expression, semicol >,
+          bloc,
+          semicol>
+{};
+
+struct INSTRUCTION : seq<instruction, ignored> {};
+struct statement_bloc : seq< sor< bloc, instruction >, ignored >{};
+
+struct for_statement_bloc : seq< sor< braced_instruction_list,
+                                      instruction >,
+                                 ignored >{};
+
+struct instruction_list : star< INSTRUCTION >{};
+struct grammar : must<ignored, instruction_list, eof>{};
+
+template <typename Rule>
+struct errors : public normal<Rule>
+{
+  static const std::string error_message;
+
+  template <typename Input, typename... States>
+  static void
+  raise(const Input& in, States&&... /*unused*/)
+  {
+    throw parse_error(error_message, std::vector{in.position()});
+  }
+};
+
+template <typename Rule>
+inline const std::string errors<Rule>::error_message = "parse error matching "+ internal::demangle< Rule >();
+
+template <>
+inline const std::string errors<language::semicol>::error_message = "parse error, missing ';'";
+template <>
+inline const std::string errors<language::SEMICOL>::error_message = "parse error, missing ';'";
+
+template <>
+inline const std::string errors<language::name>::error_message = "parse error, missing identifier";
+template <>
+inline const std::string errors<language::NAME>::error_message = "parse error, missing identifier";
+
+template <>
+inline const std::string errors<language::expression>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::product>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::sum>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::compare>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::equality>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::bitwise_and>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::bitwise_xor>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::bitwise_or>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::logical_and>::error_message = "parse error, missing expression";
+template <>
+inline const std::string errors<language::logical_or>::error_message = "parse error, missing expression";
+
+template <>
+inline const std::string errors<language::parented_expression>::error_message = "parse error, missing parented expression";
+
+template <>
+inline const std::string errors<language::statement_bloc>::error_message = "parse error, missing instruction";
+
+template <>
+inline const std::string errors<language::WHILE>::error_message = "parse error, missing 'while' statement";
+template <>
+inline const std::string errors<language::while_kw>::error_message = "parse error, missing 'while' statement";
+
+template <>
+inline const std::string errors<language::open_parent>::error_message = "parse error, missing open parent '('";
+
+template <>
+inline const std::string errors<language::for_statement_bloc>::error_message = "parse error, missing for-loop body";
+
+template <>
+inline const std::string errors<language::slashstar>::error_message = "bloc comment was never terminated, missing '*/'";
+
+template <>
+inline const std::string errors<language::open_brace>::error_message = "open brace was never closed, missing '}'";
+
+// clang-format on
+
+}   // namespace language
+
+#endif   // PEG_GRAMMAR_HPP
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index ff0c37f6d..092ff2bd0 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -9,1979 +9,20 @@
 
 #include <rang.hpp>
 
-#include <pegtl.hpp>
 #include <pegtl/analyze.hpp>
 #include <pegtl/contrib/parse_tree.hpp>
 #include <pegtl/contrib/parse_tree_to_dot.hpp>
 
-using namespace TAO_PEGTL_NAMESPACE;
+#include <ASTNode.hpp>
 
-namespace language
-{
-// clang-format off
-
-struct slashslash : TAO_PEGTL_STRING("//") {};
-struct slashstar  : TAO_PEGTL_STRING("/*") {};
-struct starslash  : TAO_PEGTL_STRING("*/") {};
-
-struct comment
-    : sor< if_must< slashslash, until< eolf > >,
-           try_catch< slashstar, until< starslash> >,
-           // error management
-           if_must<at<slashstar>,raise<slashstar>, until< eof> > > {};
-
-struct ignored : star< sor< space, comment>  >{};
-
-struct integer
-    :  plus< digit > {};
-struct INTEGER : seq< integer, ignored >{};
-
-struct real
-    : seq< sor< seq<
-                  plus< digit >,
-                  one < '.' >,
-                  star< digit >
-                  >,
-                seq<
-                  one < '.' >,
-                  plus< digit >
-                  >
-                >,
-           opt<
-             seq<
-               one< 'E',
-                    'e' >,
-               opt< one< '+',
-                         '-' >
-                    >,
-               plus<digit>
-               >
-             >
-           >{};
-
-struct semicol : one< ';' >{};
-
-struct REAL : seq< real, ignored >{};
-
-struct B_set : one< 'B' >{};
-struct N_set : one< 'N' >{};
-struct Z_set : one< 'Z' >{};
-struct R_set : one< 'R' >{};
-
-struct basic_type : sor < B_set, R_set, Z_set, N_set > {};
-
-struct TYPESPECIFIER : seq< basic_type, ignored> {};
-
-struct and_kw :  TAO_PEGTL_KEYWORD("and") {};
-struct or_kw :  TAO_PEGTL_KEYWORD("or") {};
-
-struct xor_kw :  TAO_PEGTL_KEYWORD("xor") {};
-struct bitand_kw :  TAO_PEGTL_KEYWORD("bitand") {};
-struct bitor_kw :  TAO_PEGTL_KEYWORD("bitor") {};
-
-struct and_eq_kw :  TAO_PEGTL_KEYWORD("and_eq") {};
-struct xor_eq_kw :  TAO_PEGTL_KEYWORD("xor_eq") {};
-struct or_eq_kw :  TAO_PEGTL_KEYWORD("or_eq") {};
-
-struct not_kw :  TAO_PEGTL_KEYWORD("not") {};
-struct true_kw :  TAO_PEGTL_KEYWORD("true") {};
-struct false_kw :  TAO_PEGTL_KEYWORD("false") {};
-
-struct BOOL : seq< sor<true_kw, false_kw>, ignored > {};
-
-struct do_kw : TAO_PEGTL_KEYWORD("do") {};
-struct DO : seq < do_kw, ignored > {};
-
-struct while_kw : TAO_PEGTL_KEYWORD("while") {};
-struct WHILE : seq < while_kw, ignored > {};
-
-struct for_kw : TAO_PEGTL_KEYWORD("for") {};
-struct FOR : seq < for_kw, ignored > {};
-
-struct if_kw : TAO_PEGTL_KEYWORD("if") {};
-struct IF : seq < if_kw, ignored > {};
-
-struct else_kw : TAO_PEGTL_KEYWORD("else") {};
-struct ELSE : seq < else_kw, ignored > {};
-
-struct break_kw : TAO_PEGTL_KEYWORD("break") {};
-struct BREAK : seq < break_kw, ignored > {};
-
-struct continue_kw : TAO_PEGTL_KEYWORD("continue") {};
-struct CONTINUE : seq < continue_kw, ignored > {};
-
-struct cout_kw : TAO_PEGTL_KEYWORD("cout") {};
-struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {};
-struct clog_kw : TAO_PEGTL_KEYWORD("clog") {};
-
-struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw,  bitand_kw, bitor_kw, and_eq_kw, xor_eq_kw, or_eq_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {};
-
-struct name : minus< identifier, keywork >  {};
-struct NAME : seq < name, ignored > {};
-
-struct SEMICOL : seq< semicol , ignored > {};
-
-struct open_parent : seq< one< '(' >, ignored > {};
-struct close_parent : seq< one< ')' >, ignored > {};
-
-struct expression;
-struct parented_expression : if_must< open_parent, expression, close_parent > {};
-
-struct primary_expression : sor< BOOL, REAL, INTEGER , NAME, parented_expression > {};
-
-struct unary_plusplus : TAO_PEGTL_STRING("++") {};
-struct unary_minusminus : TAO_PEGTL_STRING("--") {};
-
-struct unary_plus :  one< '+' > {};
-struct unary_minus : one< '-' > {};
-
-struct unary_not : sor< one< '!'> , not_kw > {};
-
-struct unary_operator : seq< sor< unary_plusplus, unary_minusminus, unary_plus, unary_minus, unary_not>, ignored > {};
-
-struct post_plusplus : TAO_PEGTL_STRING("++") {};
-struct post_minusminus : TAO_PEGTL_STRING("--") {};
-
-struct postfix_operator : seq< sor< post_plusplus, post_minusminus>, ignored > {};
-
-struct postfix_expression : seq< primary_expression, star<postfix_operator> > {};
-
-struct unary_expression : sor< seq< unary_operator, unary_expression >,
-                               postfix_expression > {};
-
-struct and_op : seq< sor<TAO_PEGTL_STRING("&&"), and_kw>, ignored > {};
-struct or_op : seq< sor<TAO_PEGTL_STRING("||"), or_kw>, ignored > {};
-
-struct xor_op : seq< sor< one< '^' >, xor_kw>, ignored >{};
-struct bitand_op : seq< sor< seq< one< '&' >, not_at< one< '&' > > >, bitand_kw>, ignored >{};
-struct bitor_op : seq< sor< seq< one< '|' >, not_at< one< '|' > > >, bitor_kw>, ignored >{};
-
-struct eqeq_op : seq< TAO_PEGTL_STRING("=="), ignored > {};
-struct not_eq_op : seq< TAO_PEGTL_STRING("!="), ignored > {};
-
-struct lesser_op : seq< one< '<' >, not_at< one< '<' > >, ignored > {};
-struct lesser_or_eq_op : seq< TAO_PEGTL_STRING("<="), ignored > {};
-struct greater_op : seq< one< '>' >, not_at< one< '>' > >, ignored > {};
-struct greater_or_eq_op : seq< TAO_PEGTL_STRING(">="), ignored > {};
-
-struct shift_left_op : seq< TAO_PEGTL_STRING("<<"), ignored > {};
-struct shift_right_op : seq< TAO_PEGTL_STRING(">>"), ignored > {};
-
-struct plus_op : seq< one< '+' >, not_at< one< '+' > >, ignored > {};
-struct minus_op : seq< one< '-' >, not_at< one< '-' > >, ignored > {};
-struct multiply_op : seq< one< '*' >, ignored > {};
-struct divide_op : seq< one< '/' >, ignored > {};
-
-struct eq_op : seq< one<'='>, not_at< one< '=' > >, ignored > {};
-struct multiplyeq_op : seq< TAO_PEGTL_STRING("*="), ignored > {};
-struct divideeq_op : seq< TAO_PEGTL_STRING("/="), ignored > {};
-struct pluseq_op : seq< TAO_PEGTL_STRING("+="), ignored > {};
-struct minuseq_op : seq< TAO_PEGTL_STRING("-="), ignored > {};
-
-struct bit_andeq_op : seq< sor< TAO_PEGTL_STRING("&="), and_eq_kw >, ignored > {};
-struct bit_xoreq_op : seq< sor< TAO_PEGTL_STRING("^="), xor_eq_kw >, ignored > {};
-struct bit_oreq_op : seq< sor< TAO_PEGTL_STRING("|="), or_eq_kw >, ignored > {};
-
-struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {};
-
-struct sum : list_must< product, sor< plus_op, minus_op > > {};
-
-struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{};
-
-struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{};
-
-struct bitwise_and : list_must < equality, bitand_op >{};
-
-struct bitwise_xor : list_must< bitwise_and, xor_op >{};
-
-struct bitwise_or : list_must< bitwise_xor, bitor_op >{};
-
-struct logical_and : list_must< bitwise_or, and_op >{};
-
-struct logical_or : list_must< logical_and, or_op >{};
-
-struct expression : logical_or {};
-
-struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op,  bit_andeq_op,
-                        bit_xoreq_op, bit_oreq_op > {};
-
-struct affectation : seq< NAME , if_must< affect_op, expression > >{};
-
-struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{};
-
-struct open_brace : seq< one< '{' >, ignored >{};
-struct close_brace : seq< one< '}' >, ignored >{};
-
-struct instruction_list;
-
-struct braced_instruction_list
-    :  sor<try_catch< open_brace, instruction_list, close_brace >,
-           // non matching braces management
-           if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{};
-
-struct bloc : braced_instruction_list {};
-
-struct statement_bloc;
-
-struct if_statement : if_must< IF, parented_expression,  statement_bloc, opt< if_must<ELSE, statement_bloc > > >{};
-
-struct do_while_statement : if_must< DO, statement_bloc, WHILE, parented_expression >{};
-
-struct while_statement : if_must< WHILE, parented_expression, statement_bloc >{};
-
-struct for_init : opt< sor< declaration, affectation, expression > >{};
-struct for_test : opt< sor< affectation, expression > >{};
-struct for_post : opt< sor< affectation, expression > >{};
-
-struct for_statement_bloc;
-
-struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_bloc >{};
-
-struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{};
-struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{};
-
-struct instruction
-    : sor<if_must< declaration, semicol >,
-          if_must< affectation, semicol >,
-          if_statement,
-          if_must<do_while_statement, semicol>,
-          while_statement,
-          for_statement,
-          if_must< ostream_statement, semicol >,
-          if_must< BREAK, semicol >,
-          if_must< CONTINUE, semicol >,
-          if_must< expression, semicol >,
-          bloc,
-          semicol>
-{};
-
-struct INSTRUCTION : seq<instruction, ignored> {};
-struct statement_bloc : seq< sor< bloc, instruction >, ignored >{};
-
-struct for_statement_bloc : seq< sor< braced_instruction_list,
-                                      instruction >,
-                                 ignored >{};
-
-struct instruction_list : star< INSTRUCTION >{};
-struct grammar : must<ignored, instruction_list, eof>{};
-
-template <typename Rule>
-struct errors : public normal<Rule>
-{
-  static const std::string error_message;
-
-  template <typename Input, typename... States>
-  static void
-  raise(const Input& in, States&&... /*unused*/)
-  {
-    throw parse_error(error_message, std::vector{in.position()});
-  }
-};
-
-template <typename Rule>
-inline const std::string errors<Rule>::error_message = "parse error matching "+ internal::demangle< Rule >();
-
-template <>
-inline const std::string errors<language::semicol>::error_message = "parse error, missing ';'";
-template <>
-inline const std::string errors<language::SEMICOL>::error_message = "parse error, missing ';'";
-
-template <>
-inline const std::string errors<language::name>::error_message = "parse error, missing identifier";
-template <>
-inline const std::string errors<language::NAME>::error_message = "parse error, missing identifier";
-
-template <>
-inline const std::string errors<language::expression>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::product>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::sum>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::compare>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::equality>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::bitwise_and>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::bitwise_xor>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::bitwise_or>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::logical_and>::error_message = "parse error, missing expression";
-template <>
-inline const std::string errors<language::logical_or>::error_message = "parse error, missing expression";
-
-template <>
-inline const std::string errors<language::parented_expression>::error_message = "parse error, missing parented expression";
-
-template <>
-inline const std::string errors<language::statement_bloc>::error_message = "parse error, missing instruction";
-
-template <>
-inline const std::string errors<language::WHILE>::error_message = "parse error, missing 'while' statement";
-template <>
-inline const std::string errors<language::while_kw>::error_message = "parse error, missing 'while' statement";
-
-template <>
-inline const std::string errors<language::open_parent>::error_message = "parse error, missing open parent '('";
-
-template <>
-inline const std::string errors<language::for_statement_bloc>::error_message = "parse error, missing for-loop body";
-
-template <>
-inline const std::string errors<language::slashstar>::error_message = "bloc comment was never terminated, missing '*/'";
-
-template <>
-inline const std::string errors<language::open_brace>::error_message = "open brace was never closed, missing '}'";
-
-// clang-format on
-
-enum class DataType
-{
-  undefined_t    = -1,
-  bool_t         = 0,
-  unsigned_int_t = 1,
-  int_t          = 2,
-  double_t       = 3,
-  typename_t     = 10,
-  void_t         = 9999
-};
-
-std::string
-dataTypeName(const DataType& data_type)
-{
-  std::string name;
-  switch (data_type) {
-  case DataType::undefined_t:
-    name = "undefined";
-    break;
-  case DataType::bool_t:
-    name = "B";
-    break;
-  case DataType::unsigned_int_t:
-    name = "N";
-    break;
-  case DataType::int_t:
-    name = "Z";
-    break;
-  case DataType::double_t:
-    name = "R";
-    break;
-  case DataType::typename_t:
-    name = "typename";
-    break;
-  case DataType::void_t:
-    name = "void";
-    break;
-  }
-  return name;
-}
-
-DataType
-dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2)
-{
-  if (data_type_1 == data_type_2) {
-    return data_type_1;
-  } else if ((std::max(data_type_1, data_type_2) <= DataType::double_t) and
-             (std::min(data_type_1, data_type_2) >= DataType::bool_t)) {
-    return std::max(data_type_1, data_type_2);
-  } else {
-    return DataType::undefined_t;
-  }
-}
-
-using DataVariant = std::variant<std::monostate, bool, uint64_t, int64_t, double>;
-
-struct ExecUntilBreakOrContinue
-{
-  enum class JumpType
-  {
-    no_jump,
-    break_jump,
-    continue_jump
-  };
-
- private:
-  JumpType m_jump_type{JumpType::no_jump};
-  bool m_exec{true};
-
- public:
-  PUGS_INLINE
-  bool
-  exec() const
-  {
-    return m_exec;
-  }
-
-  PUGS_INLINE
-  JumpType
-  jumpType() const
-  {
-    return m_jump_type;
-  }
-
-  ExecUntilBreakOrContinue& operator=(const ExecUntilBreakOrContinue&) = delete;
-  ExecUntilBreakOrContinue& operator=(ExecUntilBreakOrContinue&&) = default;
-
-  ExecUntilBreakOrContinue() = default;
-
-  constexpr ExecUntilBreakOrContinue(const JumpType& jump_type)
-    : m_jump_type(jump_type), m_exec((jump_type == JumpType::no_jump))
-  {
-    ;
-  }
-};
-
-class SymbolTable;
-class INodeProcessor
-{
- public:
-  virtual void execute(ExecUntilBreakOrContinue& exec_policy) = 0;
-
-  INodeProcessor(const INodeProcessor& node) = delete;
-
-  INodeProcessor() {}
-
-  virtual ~INodeProcessor() {}
-};
-
-struct Node : public parse_tree::basic_node<Node>
-{
-  std::shared_ptr<SymbolTable> m_symbol_table;
-  std::unique_ptr<INodeProcessor> m_node_processor;
-
-  PUGS_INLINE
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    Assert(static_cast<bool>(m_node_processor));
-    if (exec_policy.exec()) {
-      m_node_processor->execute(exec_policy);
-    }
-  }
-
-  DataType m_data_type{DataType::undefined_t};
-  DataVariant m_value;
-};
-
-struct rearrange : parse_tree::apply<rearrange>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&... st)
-  {
-    if (n->children.size() == 1) {
-      n = std::move(n->children.back());
-    } else {
-      // First we rearrange tree
-      {
-        n->remove_content();
-        auto& children = n->children;
-        auto rhs       = std::move(children.back());
-        children.pop_back();
-        auto op = std::move(children.back());
-        children.pop_back();
-        op->children.emplace_back(std::move(n));
-        op->children.emplace_back(std::move(rhs));
-        n = std::move(op);
-        transform(n->children.front(), st...);
-      }
-      // Then we eventually simplify operations
-      {
-        if (n->is<language::minus_op>()) {
-          Assert(n->children.size() == 2);
-          auto& rhs = n->children[1];
-          if (rhs->is<language::unary_minus>()) {
-            rhs->remove_content();
-            n->id = typeid(language::plus_op);
-            rhs   = std::move(rhs->children[0]);
-          }
-        } else if (n->is<language::plus_op>()) {
-          Assert(n->children.size() == 2);
-          auto& rhs = n->children[1];
-          if (rhs->is<language::unary_minus>()) {
-            rhs->remove_content();
-            n->id = typeid(language::minus_op);
-            rhs   = std::move(rhs->children[0]);
-          }
-        }
-      }
-    }
-  }
-};
-
-struct simplify_unary : parse_tree::apply<simplify_unary>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&... st)
-  {
-    if (n->children.size() == 1) {
-      if (n->is<unary_expression>()) {
-        n->remove_content();
-        n = std::move(n->children.back());
-        transform(n, st...);
-      } else if (n->is<unary_minus>()) {
-        auto& child = n->children[0];
-        if (child->is<unary_minus>()) {
-          n->remove_content();
-          child->remove_content();
-          n = std::move(child->children[0]);
-          transform(n, st...);
-        }
-      } else if (n->is<unary_not>()) {
-        auto& child = n->children[0];
-        if (child->is<unary_not>()) {
-          n->remove_content();
-          child->remove_content();
-          n = std::move(child->children[0]);
-          transform(n, st...);
-        }
-      }
-    } else if (n->children.size() == 2) {
-      if (n->children[0]->is<language::unary_plus>()) {
-        n->remove_content();
-        n = std::move(n->children[1]);
-        transform(n, st...);
-      } else if (n->children[0]->is<language::unary_minus>() or n->children[0]->is<language::unary_not>() or
-                 n->children[0]->is<language::unary_minusminus>() or n->children[0]->is<language::unary_plusplus>()) {
-        n->remove_content();
-        auto expression     = std::move(n->children[1]);
-        auto unary_operator = std::move(n->children[0]);
-        unary_operator->children.emplace_back(std::move(expression));
-        n = std::move(unary_operator);
-        n->remove_content();
-        transform(n, st...);
-      } else if (n->children[1]->is<language::post_minusminus>() or n->children[1]->is<language::post_plusplus>()) {
-        n->remove_content();
-        auto expression     = std::move(n->children[0]);
-        auto unary_operator = std::move(n->children[1]);
-        unary_operator->children.emplace_back(std::move(expression));
-        n = std::move(unary_operator);
-        n->remove_content();
-        transform(n, st...);
-      }
-    }
-  }
-};
-
-struct simplify_statement_bloc : parse_tree::apply<simplify_statement_bloc>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&... st)
-  {
-    if (n->children.size() == 1) {
-      if (not n->children[0]->is<language::declaration>()) {
-        n->remove_content();
-        n = std::move(n->children.back());
-        transform(n, st...);
-      } else {
-        n->id = typeid(language::bloc);
-      }
-    }
-  }
-};
-
-struct simplify_for_statement_bloc : parse_tree::apply<simplify_for_statement_bloc>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&... st)
-  {
-    if (n->children.size() == 1) {
-      n->remove_content();
-      n = std::move(n->children.back());
-      transform(n, st...);
-    }
-  }
-};
-
-struct simplify_for_init : parse_tree::apply<simplify_for_init>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&...)
-  {
-    Assert(n->children.size() <= 1);
-    if (n->children.size() == 1) {
-      n->remove_content();
-      n = std::move(n->children.back());
-    }
-  }
-};
-
-struct simplify_for_test : parse_tree::apply<simplify_for_test>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&...)
-  {
-    Assert(n->children.size() <= 1);
-    if (n->children.size() == 1) {
-      n->remove_content();
-      n = std::move(n->children.back());
-    }
-  }
-};
-
-struct simplify_for_post : parse_tree::apply<simplify_for_post>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&...)
-  {
-    Assert(n->children.size() <= 1);
-    if (n->children.size() == 1) {
-      n->remove_content();
-      n = std::move(n->children.back());
-    }
-  }
-};
-
-struct simplify_stream_statement : parse_tree::apply<simplify_stream_statement>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<Node>& n, States&&...)
-  {
-    for (size_t i = 1; i < n->children.size(); ++i) {
-      n->children[0]->children.emplace_back(std::move(n->children[i]));
-    }
-    n->remove_content();
-    n = std::move(n->children[0]);
-  }
-};
-
-template <typename Rule>
-using selector = parse_tree::selector<Rule,
-                                      parse_tree::store_content::on<true_kw,
-                                                                    false_kw,
-                                                                    integer,
-                                                                    real,
-                                                                    name,
-                                                                    B_set,
-                                                                    N_set,
-                                                                    Z_set,
-                                                                    R_set,
-                                                                    cout_kw,
-                                                                    cerr_kw,
-                                                                    clog_kw,
-                                                                    declaration,
-                                                                    if_statement,
-                                                                    do_while_statement,
-                                                                    while_statement,
-                                                                    for_statement,
-                                                                    break_kw,
-                                                                    continue_kw>,
-                                      rearrange::on<product, affectation, expression>,
-                                      simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>,
-                                      parse_tree::remove_content::on<plus_op,
-                                                                     minus_op,
-                                                                     multiply_op,
-                                                                     divide_op,
-                                                                     lesser_op,
-                                                                     lesser_or_eq_op,
-                                                                     greater_op,
-                                                                     greater_or_eq_op,
-                                                                     eqeq_op,
-                                                                     not_eq_op,
-                                                                     and_op,
-                                                                     or_op,
-                                                                     xor_op,
-                                                                     bitand_op,
-                                                                     bitor_op,
-                                                                     eq_op,
-                                                                     multiplyeq_op,
-                                                                     divideeq_op,
-                                                                     pluseq_op,
-                                                                     minuseq_op,
-                                                                     // shift_left_op,
-                                                                     // shift_right_op,
-                                                                     bit_andeq_op,
-                                                                     bit_xoreq_op,
-                                                                     bit_oreq_op,
-                                                                     unary_plusplus,
-                                                                     unary_minusminus,
-                                                                     post_minusminus,
-                                                                     post_plusplus>,
-                                      simplify_for_statement_bloc::on<for_statement_bloc>,
-                                      parse_tree::discard_empty::on<ignored, semicol, bloc>,
-                                      simplify_statement_bloc::on<statement_bloc>,
-                                      simplify_for_init::on<for_init>,
-                                      simplify_for_test::on<for_test>,
-                                      simplify_for_post::on<for_post>,
-                                      simplify_stream_statement::on<ostream_statement>>;
-
-class SymbolTable
-{
-  class Attributes
-  {
-    bool m_is_initialized{false};
-    DataType m_data_type{DataType::undefined_t};
-    DataVariant m_value;
-
-   public:
-    auto&
-    value()
-    {
-      return m_value;
-    }
-
-    const auto&
-    value() const
-    {
-      return m_value;
-    }
-
-    const bool&
-    isInitialized() const
-    {
-      return m_is_initialized;
-    }
-
-    void
-    setIsInitialized()
-    {
-      m_is_initialized = true;
-    }
-
-    const DataType&
-    dataType() const
-    {
-      return m_data_type;
-    }
-
-    void
-    setDataType(const DataType& data_type)
-    {
-      m_data_type = data_type;
-    }
-
-    friend std::ostream&
-    operator<<(std::ostream& os, const Attributes& attributes)
-    {
-      std::visit(
-        [&](const auto& value) {
-          using T = std::decay_t<decltype(value)>;
-          if constexpr (std::is_same_v<T, std::monostate>) {
-            os << "--";
-          } else {
-            os << value;
-          }
-        },
-        attributes.m_value);
-
-      return os;
-    }
-  };
-
- private:
-  std::vector<std::pair<std::string, Attributes>> m_symbol_list;
-  std::shared_ptr<SymbolTable> m_parent_table;
-
- public:
-  friend std::ostream&
-  operator<<(std::ostream& os, const SymbolTable& symbol_table)
-  {
-    os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n";
-    for (auto i_symbol : symbol_table.m_symbol_list) {
-      os << ' ' << i_symbol.first << ": " << std::boolalpha << i_symbol.second << '\n';
-    }
-    os << "------------------------\n";
-    return os;
-  }
-
-  auto
-  find(const std::string& symbol)
-  {
-    auto i_symbol = m_symbol_list.end();
-
-    for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) {
-      if (i_stored_symbol->first == symbol) {
-        i_symbol = i_stored_symbol;
-        break;
-      }
-    }
-
-    if (i_symbol != m_symbol_list.end()) {
-      return std::make_pair(i_symbol, true);
-    } else {
-      if (m_parent_table) {
-        return m_parent_table->find(symbol);
-      } else {
-        return std::make_pair(i_symbol, false);
-      }
-    }
-  }
-
-  auto
-  add(const std::string& symbol)
-  {
-    for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) {
-      if (i_stored_symbol->first == symbol) {
-        return std::make_pair(i_stored_symbol, false);
-      }
-    }
-    return std::make_pair(m_symbol_list.emplace(m_symbol_list.end(), std::make_pair(symbol, Attributes())), true);
-  }
-
-  SymbolTable(const std::shared_ptr<SymbolTable>& parent_table = nullptr) : m_parent_table(parent_table)
-  {
-    ;
-  }
-};
-
-class NodeList final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  NodeList(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    for (auto& child : m_node.children) {
-      child->execute(exec_policy);
-    }
-  }
-};
-
-template <typename Op>
-struct AffOp;
-
-template <>
-struct AffOp<language::eq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a = b;
-  }
-};
-
-template <>
-struct AffOp<language::multiplyeq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a *= b;
-  }
-};
-
-template <>
-struct AffOp<language::divideeq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a /= b;
-  }
-};
-
-template <>
-struct AffOp<language::pluseq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a += b;
-  }
-};
-
-template <>
-struct AffOp<language::minuseq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a -= b;
-  }
-};
-
-template <>
-struct AffOp<language::bit_andeq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a &= b;
-  }
-};
-
-template <>
-struct AffOp<language::bit_xoreq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a ^= b;
-  }
-};
-
-template <>
-struct AffOp<language::bit_oreq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE void
-  eval(A& a, const B& b)
-  {
-    a |= b;
-  }
-};
-
-template <typename OperatorT, typename ValueT, typename DataT>
-class AffectationProcessor final : public INodeProcessor
-{
- private:
-  Node& m_node;
-  DataVariant* p_value{nullptr};
-
-  static inline const bool _is_defined{[] {
-    if constexpr (std::is_same_v<OperatorT, language::bit_andeq_op> or
-                  std::is_same_v<OperatorT, language::bit_xoreq_op> or
-                  std::is_same_v<OperatorT, language::bit_oreq_op>) {
-      return std::is_same_v<std::decay_t<ValueT>, std::decay_t<DataT>> and std::is_integral_v<std::decay_t<ValueT>>;
-    } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) {
-      if constexpr (not std::is_same_v<OperatorT, language::eq_op>) {
-        return false;
-      }
-    }
-    return true;
-  }()};
-
- public:
-  AffectationProcessor(Node& node) : m_node{node}
-  {
-    if constexpr (_is_defined) {
-      const std::string& symbol = m_node.children[0]->string();
-      auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
-      Assert(found);
-      p_value = &i_symbol->second.value();
-    } else {
-      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
-    }
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    if constexpr (_is_defined) {
-      m_node.children[1]->execute(exec_policy);
-
-      if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
-        if constexpr (std::is_same_v<ValueT, DataT>) {
-          *p_value = m_node.children[1]->m_value;
-        } else {
-          *p_value = static_cast<ValueT>(std::get<DataT>(m_node.children[1]->m_value));
-        }
-      } else {
-        AffOp<OperatorT>().eval(std::get<ValueT>(*p_value), std::get<DataT>(m_node.children[1]->m_value));
-      }
-    }
-  }
-};
-
-class NoProcess final : public INodeProcessor
-{
- public:
-  NoProcess() {}
-
-  PUGS_INLINE
-  void
-  execute(ExecUntilBreakOrContinue&)
-  {
-    ;
-  }
-};
-
-template <typename Op>
-struct UnaryOp;
-
-template <>
-struct UnaryOp<language::unary_minus>
-{
-  template <typename A>
-  PUGS_INLINE A
-  eval(const A& a)
-  {
-    return -a;
-  }
-};
-
-template <>
-struct UnaryOp<language::unary_not>
-{
-  template <typename A>
-  PUGS_INLINE bool
-  eval(const A& a)
-  {
-    return not a;
-  }
-};
-
-template <typename UnaryOpT, typename ValueT, typename DataT>
-class UnaryExpressionProcessor final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  PUGS_INLINE ValueT
-  eval(const DataVariant& a)
-  {
-    return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a));
-  }
-
- public:
-  UnaryExpressionProcessor(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    m_node.children[0]->execute(exec_policy);
-    m_node.m_value = eval(m_node.children[0]->m_value);
-  }
-};
-
-template <typename Op>
-struct IncDecOp;
-
-template <>
-struct IncDecOp<language::unary_minusminus>
-{
-  template <typename A>
-  PUGS_INLINE A
-  eval(A& a)
-  {
-    return --a;
-  }
-};
-
-template <>
-struct IncDecOp<language::unary_plusplus>
-{
-  template <typename A>
-  PUGS_INLINE A
-  eval(A& a)
-  {
-    return ++a;
-  }
-};
-
-template <>
-struct IncDecOp<language::post_minusminus>
-{
-  template <typename A>
-  PUGS_INLINE A
-  eval(A& a)
-  {
-    return a--;
-  }
-};
-
-template <>
-struct IncDecOp<language::post_plusplus>
-{
-  template <typename A>
-  PUGS_INLINE A
-  eval(A& a)
-  {
-    return a++;
-  }
-};
-
-template <typename IncDecOpT, typename ValueT, typename DataT>
-class IncDecExpressionProcessor final : public INodeProcessor
-{
-  Node& m_node;
-  DataVariant* p_value{nullptr};
-
-  static inline const bool _is_defined{[] {
-    if constexpr (std::is_same_v<IncDecOpT, language::unary_minusminus> or
-                  std::is_same_v<IncDecOpT, language::unary_plusplus> or
-                  std::is_same_v<IncDecOpT, language::post_minusminus> or
-                  std::is_same_v<IncDecOpT, language::post_plusplus>) {
-      return not std::is_same_v<std::decay_t<DataT>, bool>;
-    }
-    return true;
-  }()};
-
- public:
-  IncDecExpressionProcessor(Node& node) : m_node{node}
-  {
-    if constexpr (_is_defined) {
-      Assert(m_node.children[0]->is<language::name>());
-      // It is sure at this point that children 0 is a variable name
-      const std::string& symbol = m_node.children[0]->string();
-      auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
-      Assert(found);
-      p_value = &i_symbol->second.value();
-    } else {
-      throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()});
-    }
-  }
-  void
-  execute(ExecUntilBreakOrContinue&)
-  {
-    if constexpr (_is_defined) {
-      m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value));
-    }
-  }
-};
-
-template <typename Op>
-struct BinOp;
-
-template <>
-struct BinOp<language::and_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a and b)
-  {
-    return a and b;
-  }
-};
-
-template <>
-struct BinOp<language::or_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a or b)
-  {
-    return a or b;
-  }
-};
-
-template <>
-struct BinOp<language::xor_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a xor b)
-  {
-    return a xor b;
-  }
-};
-
-template <>
-struct BinOp<language::bitand_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a & b)
-  {
-    return a & b;
-  }
-};
-
-template <>
-struct BinOp<language::bitor_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a | b)
-  {
-    return a | b;
-  }
-};
-
-template <>
-struct BinOp<language::eqeq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a == b)
-  {
-    return a == b;
-  }
-};
-
-template <>
-struct BinOp<language::not_eq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a != b)
-  {
-    return a != b;
-  }
-};
-
-template <>
-struct BinOp<language::lesser_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a < b)
-  {
-    return a < b;
-  }
-};
-
-template <>
-struct BinOp<language::lesser_or_eq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a <= b)
-  {
-    return a <= b;
-  }
-};
-
-template <>
-struct BinOp<language::greater_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a > b)
-  {
-    return a > b;
-  }
-};
-
-template <>
-struct BinOp<language::greater_or_eq_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a >= b)
-  {
-    return a >= b;
-  }
-};
-
-template <>
-struct BinOp<language::plus_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a + b)
-  {
-    return a + b;
-  }
-};
-
-template <>
-struct BinOp<language::minus_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a - b)
-  {
-    return a - b;
-  }
-};
-
-template <>
-struct BinOp<language::multiply_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a * b)
-  {
-    return a * b;
-  }
-};
-
-template <>
-struct BinOp<language::divide_op>
-{
-  template <typename A, typename B>
-  PUGS_INLINE auto
-  eval(const A& a, const B& b) -> decltype(a / b)
-  {
-    return a / b;
-  }
-};
-
-template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
-class BinaryExpressionProcessor final : public INodeProcessor
-{
-  Node& m_node;
-
-  PUGS_INLINE ValueT
-  eval(const DataVariant& a, const DataVariant& b)
-  {
-    // Add 'signed' when necessary to avoid signed/unsigned comparison warnings
-    if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and
-                  (std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or
-                   std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::bitand_op> or
-                   std::is_same_v<BinaryOpT, language::bitor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or
-                   std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or
-                   std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or
-                   std::is_same_v<BinaryOpT, language::greater_op> or
-                   std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and
-                  (std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) {
-      if constexpr (std::is_unsigned_v<A_DataT>) {
-        using signed_A_DataT          = std::make_signed_t<A_DataT>;
-        const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a));
-        return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b));
-      } else {
-        using signed_B_DataT          = std::make_signed_t<B_DataT>;
-        const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b));
-        return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
-      }
-    } else {
-      return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b));
-    }
-  }
-
-  static inline const bool _is_defined{[] {
-    if constexpr (std::is_same_v<BinaryOpT, language::bitand_op> or std::is_same_v<BinaryOpT, language::xor_op> or
-                  std::is_same_v<BinaryOpT, language::bitor_op>) {
-      return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>;
-    }
-    return true;
-  }()};
-
- public:
-  BinaryExpressionProcessor(Node& node) : m_node{node}
-  {
-    if constexpr (not _is_defined) {
-      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
-    }
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    if constexpr (_is_defined) {
-      m_node.children[0]->execute(exec_policy);
-      m_node.children[1]->execute(exec_policy);
-
-      m_node.m_value = eval(m_node.children[0]->m_value, m_node.children[1]->m_value);
-    }
-  }
-};
-
-class IfStatement final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  IfStatement(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    m_node.children[0]->execute(exec_policy);
-    const bool is_true = static_cast<bool>(std::visit(
-      [](const auto& value) -> bool {
-        using T = std::decay_t<decltype(value)>;
-        if constexpr (std::is_same_v<T, std::monostate>) {
-          return false;
-        } else {
-          return value;
-        }
-      },
-      m_node.children[0]->m_value));
-    if (is_true) {
-      Assert(m_node.children[1] != nullptr);
-      m_node.children[1]->execute(exec_policy);
-    } else {
-      if (m_node.children.size() == 3) {
-        // else statement
-        Assert(m_node.children[2] != nullptr);
-        m_node.children[2]->execute(exec_policy);
-      }
-    }
-  }
-};
-
-class DoWhileStatement final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  DoWhileStatement(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    bool continuation_test = true;
-    ExecUntilBreakOrContinue exec_until_jump;
-    do {
-      m_node.children[0]->execute(exec_until_jump);
-      if (not exec_until_jump.exec()) {
-        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
-          break;
-        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
-          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
-        }
-      }
-      m_node.children[1]->execute(exec_policy);
-      continuation_test = static_cast<bool>(std::visit(
-        [](const auto& value) -> bool {
-          using T = std::decay_t<decltype(value)>;
-          if constexpr (std::is_same_v<T, std::monostate>) {
-            return false;
-          } else {
-            return value;
-          }
-        },
-        m_node.children[1]->m_value));
-    } while (continuation_test);
-  }
-};
-
-class WhileStatement final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  WhileStatement(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    ExecUntilBreakOrContinue exec_until_jump;
-    while ([&]() {
-      m_node.children[0]->execute(exec_policy);
-      return static_cast<bool>(std::visit(
-        [](const auto& value) -> bool {
-          using T = std::decay_t<decltype(value)>;
-          if constexpr (std::is_same_v<T, std::monostate>) {
-            return false;
-          } else {
-            return value;
-          }
-        },
-        m_node.children[0]->m_value));
-    }()) {
-      m_node.children[1]->execute(exec_until_jump);
-      if (not exec_until_jump.exec()) {
-        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
-          break;
-        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
-          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
-        }
-      }
-    }
-  }
-};
-
-class ForStatement final : public INodeProcessor
-{
-  Node& m_node;
-
- public:
-  ForStatement(Node& node) : m_node{node} {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    ExecUntilBreakOrContinue exec_until_jump;
-    m_node.children[0]->execute(exec_policy);
-    while ([&]() {
-      m_node.children[1]->execute(exec_policy);
-      return static_cast<bool>(std::visit(
-        [](const auto& value) -> bool {
-          using T = std::decay_t<decltype(value)>;
-          if constexpr (std::is_same_v<T, std::monostate>) {
-            return false;
-          } else {
-            return value;
-          }
-        },
-        m_node.children[1]->m_value));
-    }()) {
-      m_node.children[3]->execute(exec_until_jump);
-      if (not exec_until_jump.exec()) {
-        if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) {
-          break;
-        } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) {
-          exec_until_jump = ExecUntilBreakOrContinue{};   // getting ready for next loop traversal
-        }
-      }
-
-      m_node.children[2]->execute(exec_policy);
-    }
-  }
-};
-
-class NameExpression final : public INodeProcessor
-{
-  Node& m_node;
-  DataVariant* p_value{nullptr};
-
- public:
-  NameExpression(Node& node) : m_node{node}
-  {
-    const std::string& symbol = m_node.string();
-    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol);
-    Assert(found);
-    p_value = &(i_symbol->second.value());
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue&)
-  {
-    m_node.m_value = *p_value;
-  }
-};
-
-class BreakExpression final : public INodeProcessor
-{
- public:
-  BreakExpression() {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::break_jump);
-  }
-};
-
-class ContinueExpression final : public INodeProcessor
-{
- public:
-  ContinueExpression() {}
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::continue_jump);
-  }
-};
-
-class OStreamObject final : public INodeProcessor
-{
-  Node& m_node;
-  std::ostream& m_os;
-
- public:
-  OStreamObject(Node& node, std::ostream& os) : m_node{node}, m_os(os)
-  {
-    ;
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    for (size_t i = 0; i < m_node.children.size(); ++i) {
-      m_node.children[i]->execute(exec_policy);
-      std::visit(
-        [&](auto&& value) {
-          using ValueT = std::decay_t<decltype(value)>;
-          if constexpr (not std::is_same_v<std::monostate, ValueT>) {
-            if constexpr (std::is_same_v<bool, ValueT>) {
-              m_os << std::boolalpha << value;
-            } else {
-              m_os << value;
-            }
-          }
-        },
-        m_node.children[i]->m_value);
-    }
-  }
-};
-
-namespace internal
-{
-void
-build_node_type(Node& n)
-{
-  auto set_unary_operator_processor = [](Node& n, const auto& operator_v) {
-    auto set_unary_operator_processor_for_data = [&](const auto& value, const DataType& data_type) {
-      using OperatorT = std::decay_t<decltype(operator_v)>;
-      using ValueT    = std::decay_t<decltype(value)>;
-      switch (data_type) {
-      case DataType::bool_t: {
-        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, bool>>(n);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, uint64_t>>(n);
-        break;
-      }
-      case DataType::int_t: {
-        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, int64_t>>(n);
-        break;
-      }
-      case DataType::double_t: {
-        n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, double>>(n);
-        break;
-      }
-      default: {
-        throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()});
-      }
-      }
-    };
-
-    auto set_unary_operator_processor_for_value = [&](const DataType& value_type) {
-      const DataType data_type = n.children[0]->m_data_type;
-      switch (value_type) {
-      case DataType::bool_t: {
-        set_unary_operator_processor_for_data(bool{}, data_type);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        set_unary_operator_processor_for_data(uint64_t{}, data_type);
-        break;
-      }
-      case DataType::int_t: {
-        set_unary_operator_processor_for_data(int64_t{}, data_type);
-        break;
-      }
-      case DataType::double_t: {
-        set_unary_operator_processor_for_data(double{}, data_type);
-        break;
-      }
-      default: {
-        throw parse_error("undefined value type for unary operator", std::vector{n.begin()});
-      }
-      }
-    };
-
-    set_unary_operator_processor_for_value(n.m_data_type);
-  };
-
-  auto set_inc_dec_operator_processor = [](Node& n, const auto& operator_v) {
-    auto set_inc_dec_operator_processor_for_data = [&](const auto& value, const DataType& data_type) {
-      using OperatorT = std::decay_t<decltype(operator_v)>;
-      using ValueT    = std::decay_t<decltype(value)>;
-      switch (data_type) {
-      case DataType::bool_t: {
-        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, bool>>(n);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, uint64_t>>(n);
-        break;
-      }
-      case DataType::int_t: {
-        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, int64_t>>(n);
-        break;
-      }
-      case DataType::double_t: {
-        n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, double>>(n);
-        break;
-      }
-      default: {
-        throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()});
-      }
-      }
-    };
-
-    auto set_inc_dec_processor_for_value = [&](const DataType& value_type) {
-      const DataType data_type = n.children[0]->m_data_type;
-      switch (value_type) {
-      case DataType::bool_t: {
-        set_inc_dec_operator_processor_for_data(bool{}, data_type);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        set_inc_dec_operator_processor_for_data(uint64_t{}, data_type);
-        break;
-      }
-      case DataType::int_t: {
-        set_inc_dec_operator_processor_for_data(int64_t{}, data_type);
-        break;
-      }
-      case DataType::double_t: {
-        set_inc_dec_operator_processor_for_data(double{}, data_type);
-        break;
-      }
-      default: {
-        throw parse_error("undefined value type for unary operator", std::vector{n.begin()});
-      }
-      }
-    };
-
-    if (not n.children[0]->is<language::name>()) {
-      throw parse_error("invalid operand type for unary operator", std::vector{n.begin()});
-    }
-
-    set_inc_dec_processor_for_value(n.m_data_type);
-  };
-
-  auto set_binary_operator_processor = [](Node& n, const auto& operator_v) {
-    auto set_binary_operator_processor_for_data_b = [&](const auto value, const auto data_a,
-                                                        const DataType& data_type_b) {
-      using OperatorT = std::decay_t<decltype(operator_v)>;
-      using ValueT    = std::decay_t<decltype(value)>;
-      using DataTA    = std::decay_t<decltype(data_a)>;
-      switch (data_type_b) {
-      case DataType::bool_t: {
-        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, bool>>(n);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, uint64_t>>(n);
-        break;
-      }
-      case DataType::int_t: {
-        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, int64_t>>(n);
-        break;
-      }
-      case DataType::double_t: {
-        n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, double>>(n);
-        break;
-      }
-      default: {
-        throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
-      }
-      }
-    };
-
-    auto set_binary_operator_processor_for_data_a = [&](const auto value, const DataType& data_type_a) {
-      const DataType data_type_b = n.children[1]->m_data_type;
-      switch (data_type_a) {
-      case DataType::bool_t: {
-        set_binary_operator_processor_for_data_b(value, bool{}, data_type_b);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        set_binary_operator_processor_for_data_b(value, uint64_t{}, data_type_b);
-        break;
-      }
-      case DataType::int_t: {
-        set_binary_operator_processor_for_data_b(value, int64_t{}, data_type_b);
-        break;
-      }
-      case DataType::double_t: {
-        set_binary_operator_processor_for_data_b(value, double{}, data_type_b);
-        break;
-      }
-      default: {
-        throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()});
-      }
-      }
-    };
-
-    auto set_binary_operator_processor_for_value = [&](const DataType& value_type) {
-      const DataType data_type_a = n.children[0]->m_data_type;
-      switch (value_type) {
-      case DataType::bool_t: {
-        set_binary_operator_processor_for_data_a(bool{}, data_type_a);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        set_binary_operator_processor_for_data_a(uint64_t{}, data_type_a);
-        break;
-      }
-      case DataType::int_t: {
-        set_binary_operator_processor_for_data_a(int64_t{}, data_type_a);
-        break;
-      }
-      case DataType::double_t: {
-        set_binary_operator_processor_for_data_a(double{}, data_type_a);
-        break;
-      }
-      default: {
-        throw parse_error("undefined value type for binary operator", std::vector{n.begin()});
-      }
-      }
-    };
-
-    set_binary_operator_processor_for_value(n.m_data_type);
-  };
-
-  auto set_affectation_processor = [](Node& n, const auto& operator_v) {
-    auto set_affectation_processor_for_data = [&](const auto& value, const DataType& data_type) {
-      using OperatorT = std::decay_t<decltype(operator_v)>;
-      using ValueT    = std::decay_t<decltype(value)>;
-      switch (data_type) {
-      case DataType::bool_t: {
-        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n);
-        break;
-      }
-      case DataType::int_t: {
-        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n);
-        break;
-      }
-      case DataType::double_t: {
-        n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n);
-        break;
-      }
-      default: {
-        throw parse_error("undefined operand type for affectation", std::vector{n.children[0]->begin()});
-      }
-      }
-    };
-
-    auto set_affectation_processor_for_value = [&](const DataType& value_type) {
-      const DataType data_type = n.children[1]->m_data_type;
-      switch (value_type) {
-      case DataType::bool_t: {
-        set_affectation_processor_for_data(bool{}, data_type);
-        break;
-      }
-      case DataType::unsigned_int_t: {
-        set_affectation_processor_for_data(uint64_t{}, data_type);
-        break;
-      }
-      case DataType::int_t: {
-        set_affectation_processor_for_data(int64_t{}, data_type);
-        break;
-      }
-      case DataType::double_t: {
-        set_affectation_processor_for_data(double{}, data_type);
-        break;
-      }
-      default: {
-        throw parse_error("undefined value type for affectation", std::vector{n.begin()});
-      }
-      }
-    };
-
-    set_affectation_processor_for_value(n.m_data_type);
-  };
-
-  if (n.is_root()) {
-    n.m_node_processor = std::make_unique<NodeList>(n);
-  } else if (n.is<language::bloc>()) {
-    n.m_node_processor = std::make_unique<NodeList>(n);
-  } else if (n.is<language::declaration>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::eq_op>()) {
-    set_affectation_processor(n, language::eq_op{});
-  } else if (n.is<language::multiplyeq_op>()) {
-    set_affectation_processor(n, language::multiplyeq_op{});
-  } else if (n.is<language::divideeq_op>()) {
-    set_affectation_processor(n, language::divideeq_op{});
-  } else if (n.is<language::pluseq_op>()) {
-    set_affectation_processor(n, language::pluseq_op{});
-  } else if (n.is<language::minuseq_op>()) {
-    set_affectation_processor(n, language::minuseq_op{});
-  } else if (n.is<language::bit_andeq_op>()) {
-    set_affectation_processor(n, language::bit_andeq_op{});
-  } else if (n.is<language::bit_xoreq_op>()) {
-    set_affectation_processor(n, language::bit_xoreq_op{});
-  } else if (n.is<language::bit_oreq_op>()) {
-    set_affectation_processor(n, language::bit_oreq_op{});
-
-  } else if (n.is<language::real>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::integer>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-
-  } else if (n.is<language::name>()) {
-    n.m_node_processor = std::make_unique<NameExpression>(n);
-
-  } else if (n.is<language::unary_minus>()) {
-    set_unary_operator_processor(n, language::unary_minus{});
-  } else if (n.is<language::unary_not>()) {
-    set_unary_operator_processor(n, language::unary_not{});
-
-  } else if (n.is<language::unary_minusminus>()) {
-    set_inc_dec_operator_processor(n, language::unary_minusminus{});
-  } else if (n.is<language::unary_plusplus>()) {
-    set_inc_dec_operator_processor(n, language::unary_plusplus{});
-  } else if (n.is<language::post_minusminus>()) {
-    set_inc_dec_operator_processor(n, language::post_minusminus{});
-  } else if (n.is<language::post_plusplus>()) {
-    set_inc_dec_operator_processor(n, language::post_plusplus{});
+#include <ASTBuilder.hpp>
+#include <PEGGrammar.hpp>
+#include <SymbolTable.hpp>
 
-  } else if (n.is<language::multiply_op>()) {
-    set_binary_operator_processor(n, language::multiply_op{});
-  } else if (n.is<language::divide_op>()) {
-    set_binary_operator_processor(n, language::divide_op{});
-  } else if (n.is<language::plus_op>()) {
-    set_binary_operator_processor(n, language::plus_op{});
-  } else if (n.is<language::minus_op>()) {
-    set_binary_operator_processor(n, language::minus_op{});
-  } else if (n.is<language::or_op>()) {
-    set_binary_operator_processor(n, language::or_op{});
-  } else if (n.is<language::and_op>()) {
-    set_binary_operator_processor(n, language::and_op{});
+#include <ASTNodeExpressionBuilder.hpp>
 
-  } else if (n.is<language::xor_op>()) {
-    set_binary_operator_processor(n, language::xor_op{});
-  } else if (n.is<language::bitand_op>()) {
-    set_binary_operator_processor(n, language::bitand_op{});
-  } else if (n.is<language::bitor_op>()) {
-    set_binary_operator_processor(n, language::bitor_op{});
-
-  } else if (n.is<language::greater_op>()) {
-    set_binary_operator_processor(n, language::greater_op{});
-  } else if (n.is<language::greater_or_eq_op>()) {
-    set_binary_operator_processor(n, language::greater_or_eq_op{});
-  } else if (n.is<language::lesser_op>()) {
-    set_binary_operator_processor(n, language::lesser_op{});
-  } else if (n.is<language::lesser_or_eq_op>()) {
-    set_binary_operator_processor(n, language::lesser_or_eq_op{});
-  } else if (n.is<language::eqeq_op>()) {
-    set_binary_operator_processor(n, language::eqeq_op{});
-  } else if (n.is<language::not_eq_op>()) {
-    set_binary_operator_processor(n, language::not_eq_op{});
-  } else if (n.is<language::B_set>()) {
-  } else if (n.is<language::N_set>()) {
-  } else if (n.is<language::Z_set>()) {
-  } else if (n.is<language::cout_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamObject>(n, std::cout);
-  } else if (n.is<language::cerr_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamObject>(n, std::cerr);
-  } else if (n.is<language::clog_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamObject>(n, std::clog);
-  } else if (n.is<language::R_set>()) {
-  } else if (n.is<language::if_statement>()) {
-    n.m_node_processor = std::make_unique<IfStatement>(n);
-  } else if (n.is<language::statement_bloc>()) {
-    n.m_node_processor = std::make_unique<NodeList>(n);
-  } else if (n.is<language::do_while_statement>()) {
-    n.m_node_processor = std::make_unique<DoWhileStatement>(n);
-  } else if (n.is<language::while_statement>()) {
-    n.m_node_processor = std::make_unique<WhileStatement>(n);
-  } else if (n.is<language::for_statement>()) {
-    n.m_node_processor = std::make_unique<ForStatement>(n);
-  } else if (n.is<language::for_statement_bloc>()) {
-    n.m_node_processor = std::make_unique<NodeList>(n);
-  } else if (n.is<language::for_init>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::for_post>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::for_test>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::break_kw>()) {
-    n.m_node_processor = std::make_unique<BreakExpression>();
-  } else if (n.is<language::continue_kw>()) {
-    n.m_node_processor = std::make_unique<ContinueExpression>();
-  } else if (n.is<language::true_kw>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else if (n.is<language::false_kw>()) {
-    n.m_node_processor = std::make_unique<NoProcess>();
-  } else {
-    std::ostringstream error_message;
-    error_message << "undefined node type '" << rang::fgB::red << n.name() << rang::fg::reset << "'";
-    throw parse_error{error_message.str(), std::vector{n.begin()}};
-  }
-
-  for (auto& child : n.children) {
-    internal::build_node_type(*child);
-  }
-}
-}   // namespace internal
-
-void
-build_node_type(Node& n)
+namespace language
 {
-  Assert(n.is_root());
-  Assert(n.is<void>());
-  n.m_node_processor = std::make_unique<NodeList>(n);
-  for (auto& child : n.children) {
-    internal::build_node_type(*child);
-  }
-  std::cout << " - build node types\n";
-}
-
 namespace internal
 {
 void
@@ -2478,9 +519,9 @@ parser(const std::string& filename)
             << rang::style::reset << " ...\n";
 
   std::unique_ptr<language::Node> root_node;
-  read_input in(filename);
+  read_input input(filename);
   try {
-    root_node = parse_tree::parse<language::grammar, language::Node, language::selector, nothing, language::errors>(in);
+    root_node = buildAST(input);
     std::cout << " - AST is built ...... [done]\n";
 
     language::build_symbol_table_and_check_declarations(*root_node);
@@ -2515,7 +556,7 @@ parser(const std::string& filename)
     std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.byte_in_line << ": " << rang::style::reset
               << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset
               << '\n'
-              << in.line_at(p) << '\n'
+              << input.line_at(p) << '\n'
               << std::string(p.byte_in_line, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << std::endl;
     std::exit(1);
   }
diff --git a/src/language/SymbolTable.hpp b/src/language/SymbolTable.hpp
new file mode 100644
index 000000000..e2e874f5b
--- /dev/null
+++ b/src/language/SymbolTable.hpp
@@ -0,0 +1,126 @@
+#ifndef SYMBOL_TABLE_HPP
+#define SYMBOL_TABLE_HPP
+
+namespace language
+{
+class SymbolTable
+{
+  class Attributes
+  {
+    bool m_is_initialized{false};
+    DataType m_data_type{DataType::undefined_t};
+    DataVariant m_value;
+
+   public:
+    auto&
+    value()
+    {
+      return m_value;
+    }
+
+    const auto&
+    value() const
+    {
+      return m_value;
+    }
+
+    const bool&
+    isInitialized() const
+    {
+      return m_is_initialized;
+    }
+
+    void
+    setIsInitialized()
+    {
+      m_is_initialized = true;
+    }
+
+    const DataType&
+    dataType() const
+    {
+      return m_data_type;
+    }
+
+    void
+    setDataType(const DataType& data_type)
+    {
+      m_data_type = data_type;
+    }
+
+    friend std::ostream&
+    operator<<(std::ostream& os, const Attributes& attributes)
+    {
+      std::visit(
+        [&](const auto& value) {
+          using T = std::decay_t<decltype(value)>;
+          if constexpr (std::is_same_v<T, std::monostate>) {
+            os << "--";
+          } else {
+            os << value;
+          }
+        },
+        attributes.m_value);
+
+      return os;
+    }
+  };
+
+ private:
+  std::vector<std::pair<std::string, Attributes>> m_symbol_list;
+  std::shared_ptr<SymbolTable> m_parent_table;
+
+ public:
+  friend std::ostream&
+  operator<<(std::ostream& os, const SymbolTable& symbol_table)
+  {
+    os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n";
+    for (auto i_symbol : symbol_table.m_symbol_list) {
+      os << ' ' << i_symbol.first << ": " << std::boolalpha << i_symbol.second << '\n';
+    }
+    os << "------------------------\n";
+    return os;
+  }
+
+  auto
+  find(const std::string& symbol)
+  {
+    auto i_symbol = m_symbol_list.end();
+
+    for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) {
+      if (i_stored_symbol->first == symbol) {
+        i_symbol = i_stored_symbol;
+        break;
+      }
+    }
+
+    if (i_symbol != m_symbol_list.end()) {
+      return std::make_pair(i_symbol, true);
+    } else {
+      if (m_parent_table) {
+        return m_parent_table->find(symbol);
+      } else {
+        return std::make_pair(i_symbol, false);
+      }
+    }
+  }
+
+  auto
+  add(const std::string& symbol)
+  {
+    for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) {
+      if (i_stored_symbol->first == symbol) {
+        return std::make_pair(i_stored_symbol, false);
+      }
+    }
+    return std::make_pair(m_symbol_list.emplace(m_symbol_list.end(), std::make_pair(symbol, Attributes())), true);
+  }
+
+  SymbolTable(const std::shared_ptr<SymbolTable>& parent_table = nullptr) : m_parent_table(parent_table)
+  {
+    ;
+  }
+};
+}   // namespace language
+
+#endif   // SYMBOL_TABLE_HPP
-- 
GitLab