diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
index 5eaa3f785656e2c21061e546cf3ac2fa4a823b0b..221ef79b738512674908acd4fbd1ca1bc3f6c604 100644
--- a/src/language/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -1,163 +1,8 @@
 #include <ASTNodeAffectationExpressionBuilder.hpp>
 #include <PEGGrammar.hpp>
-#include <SymbolTable.hpp>
 
-#include <Demangle.hpp>
-
-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 <typename OperatorT, typename ValueT, typename DataT>
-class AffectationProcessor final : public INodeProcessor
-{
- private:
-  ASTNode& m_node;
-  ASTNodeDataVariant* p_value{nullptr};
-
-  static inline const bool _is_defined{[] {
-    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:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  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));
-      }
-    }
-  }
-
-  AffectationProcessor(ASTNode& 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, m_node.children[0]->begin());
-      Assert(found);
-      p_value = &i_symbol->second.value();
-    } else {
-      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
-    }
-  }
-};
-
-template <typename OperatorT, typename DataT>
-class AffectationToStringProcessor final : public INodeProcessor
-{
- private:
-  ASTNode& m_node;
-  ASTNodeDataVariant* p_value{nullptr};
-
- public:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    m_node.children[1]->execute(exec_policy);
-
-    if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
-      if constexpr (std::is_same_v<std::string, DataT>) {
-        *p_value = m_node.children[1]->m_value;
-      } else {
-        *p_value = std::to_string(std::get<DataT>(m_node.children[1]->m_value));
-      }
-    } else if constexpr (std::is_same_v<OperatorT, language::pluseq_op>) {
-      if constexpr (std::is_same_v<std::string, DataT>) {
-        std::get<std::string>(*p_value) += std::get<std::string>(m_node.children[1]->m_value);
-      } else {
-        std::get<std::string>(*p_value) += std::to_string(std::get<DataT>(m_node.children[1]->m_value));
-      }
-    }
-  }
-
-  AffectationToStringProcessor(ASTNode& node) : m_node{node}
-  {
-    const std::string& symbol = m_node.children[0]->string();
-    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
-    Assert(found);
-    p_value = &i_symbol->second.value();
-  }
-};
+#include <node_processor/AffectationProcessor.hpp>
+#include <node_processor/AffectationToStringProcessor.hpp>
 
 ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode& n)
 {
diff --git a/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
index 496668c57a7738cbcd351d3834ba0c7800c51d3c..3d16d8fa4a4fab1673da8aa346d9027c95ca65d8 100644
--- a/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
+++ b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp
@@ -1,259 +1,8 @@
 #include <ASTNodeBinaryOperatorExpressionBuilder.hpp>
 #include <PEGGrammar.hpp>
-#include <SymbolTable.hpp>
 
-#include <Demangle.hpp>
-
-#include <type_traits>
-
-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::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 A_DataT, typename B_DataT>
-class BinaryExpressionProcessor final : public INodeProcessor
-{
-  ASTNode& m_node;
-
-  PUGS_INLINE auto
-  _eval(const ASTNodeDataVariant& a, const ASTNodeDataVariant& b, ASTNodeDataVariant& value)
-  {
-    // 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::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));
-        value                         = 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));
-        value                         = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
-      }
-    } else {
-      auto result = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b));
-      if constexpr (std::is_same_v<decltype(result), int>) {
-        value = static_cast<int64_t>(result);
-      } else {
-        value = result;
-      }
-    }
-  }
-
-  static inline const bool _is_defined{[] {
-    if constexpr (std::is_same_v<BinaryOpT, language::xor_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:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    if constexpr (_is_defined) {
-      m_node.children[0]->execute(exec_policy);
-      m_node.children[1]->execute(exec_policy);
-
-      this->_eval(m_node.children[0]->m_value, m_node.children[1]->m_value, m_node.m_value);
-    }
-  }
-
-  BinaryExpressionProcessor(ASTNode& node) : m_node{node}
-  {
-    if constexpr (not _is_defined) {
-      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
-    }
-  }
-};
-
-template <typename B_DataT>
-class ConcatExpressionProcessor final : public INodeProcessor
-{
-  ASTNode& m_node;
-
-  PUGS_INLINE auto
-  _eval(const std::string& a, const ASTNodeDataVariant& b, ASTNodeDataVariant& value)
-  {
-    if constexpr (std::is_same_v<B_DataT, std::string>) {
-      value = a + std::get<B_DataT>(b);
-    } else {
-      value = a + std::to_string(std::get<B_DataT>(b));
-    }
-  }
-
- public:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    m_node.children[0]->execute(exec_policy);
-    m_node.children[1]->execute(exec_policy);
-
-    this->_eval(std::get<std::string>(m_node.children[0]->m_value), m_node.children[1]->m_value, m_node.m_value);
-  }
-
-  ConcatExpressionProcessor(ASTNode& node) : m_node{node} {}
-};
+#include <node_processor/BinaryExpressionProcessor.hpp>
+#include <node_processor/ConcatExpressionProcessor.hpp>
 
 ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(ASTNode& n)
 {
diff --git a/src/language/ASTNodeIncDecExpressionBuilder.cpp b/src/language/ASTNodeIncDecExpressionBuilder.cpp
index 485c5d6532f08b624f60563ffae966860836d129..12e4f0fd6ad9cb61458a16b2aa2ed8bbf55e453b 100644
--- a/src/language/ASTNodeIncDecExpressionBuilder.cpp
+++ b/src/language/ASTNodeIncDecExpressionBuilder.cpp
@@ -1,101 +1,7 @@
 #include <ASTNodeIncDecExpressionBuilder.hpp>
 #include <PEGGrammar.hpp>
-#include <SymbolTable.hpp>
 
-#include <Demangle.hpp>
-
-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
-{
-  ASTNode& m_node;
-  ASTNodeDataVariant* 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:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue&)
-  {
-    if constexpr (_is_defined) {
-      m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value));
-    }
-  }
-
-  IncDecExpressionProcessor(ASTNode& 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, m_node.children[0]->begin());
-      Assert(found);
-      p_value = &i_symbol->second.value();
-    } else {
-      throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()});
-    }
-  }
-};
+#include <node_processor/IncDecExpressionProcessor.hpp>
 
 ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
 {
diff --git a/src/language/ASTNodeUnaryOperatorExpressionBuilder.cpp b/src/language/ASTNodeUnaryOperatorExpressionBuilder.cpp
index 8d70f9f65173548335dd944deeebe837eb379a77..4e59b0dace058546ba18bef7b45ac799050d8f5d 100644
--- a/src/language/ASTNodeUnaryOperatorExpressionBuilder.cpp
+++ b/src/language/ASTNodeUnaryOperatorExpressionBuilder.cpp
@@ -1,61 +1,7 @@
 #include <ASTNodeUnaryOperatorExpressionBuilder.hpp>
 #include <PEGGrammar.hpp>
-#include <SymbolTable.hpp>
 
-#include <Demangle.hpp>
-
-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
-{
-  ASTNode& m_node;
-
-  PUGS_INLINE ValueT
-  _eval(const ASTNodeDataVariant& a)
-  {
-    return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a));
-  }
-
- public:
-  std::string
-  describe() const
-  {
-    return demangle<decltype(*this)>();
-  }
-
-  void
-  execute(ExecUntilBreakOrContinue& exec_policy)
-  {
-    m_node.children[0]->execute(exec_policy);
-    m_node.m_value = this->_eval(m_node.children[0]->m_value);
-  }
-
-  UnaryExpressionProcessor(ASTNode& node) : m_node{node} {}
-};
+#include <node_processor/UnaryExpressionProcessor.hpp>
 
 ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(ASTNode& n)
 {
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ed12a1d33aaea2d71a8dace679ab8fc5a9cb54e
--- /dev/null
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -0,0 +1,122 @@
+#ifndef AFFECTATION_PROCESSOR_HPP
+#define AFFECTATION_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <SymbolTable.hpp>
+
+#include <Demangle.hpp>
+
+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 <typename OperatorT, typename ValueT, typename DataT>
+class AffectationProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+  ASTNodeDataVariant* p_value{nullptr};
+
+  static inline const bool _is_defined{[] {
+    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:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  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));
+      }
+    }
+  }
+
+  AffectationProcessor(ASTNode& 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, m_node.children[0]->begin());
+      Assert(found);
+      p_value = &i_symbol->second.value();
+    } else {
+      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
+    }
+  }
+};
+
+#endif // AFFECTATION_PROCESSOR_HPP
diff --git a/src/language/node_processor/AffectationToStringProcessor.hpp b/src/language/node_processor/AffectationToStringProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..456a65deb46455c62e1343b5bf95d82bb63df5c5
--- /dev/null
+++ b/src/language/node_processor/AffectationToStringProcessor.hpp
@@ -0,0 +1,53 @@
+#ifndef AFFECTATION_TO_STRING_PROCESSOR_HPP
+#define AFFECTATION_TO_STRING_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <SymbolTable.hpp>
+
+#include <Demangle.hpp>
+
+template <typename OperatorT, typename DataT>
+class AffectationToStringProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+  ASTNodeDataVariant* p_value{nullptr};
+
+ public:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    m_node.children[1]->execute(exec_policy);
+
+    if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
+      if constexpr (std::is_same_v<std::string, DataT>) {
+        *p_value = m_node.children[1]->m_value;
+      } else {
+        *p_value = std::to_string(std::get<DataT>(m_node.children[1]->m_value));
+      }
+    } else if constexpr (std::is_same_v<OperatorT, language::pluseq_op>) {
+      if constexpr (std::is_same_v<std::string, DataT>) {
+        std::get<std::string>(*p_value) += std::get<std::string>(m_node.children[1]->m_value);
+      } else {
+        std::get<std::string>(*p_value) += std::to_string(std::get<DataT>(m_node.children[1]->m_value));
+      }
+    }
+  }
+
+  AffectationToStringProcessor(ASTNode& node) : m_node{node}
+  {
+    const std::string& symbol = m_node.children[0]->string();
+    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
+    Assert(found);
+    p_value = &i_symbol->second.value();
+  }
+};
+
+#endif // AFFECTATION_TO_STRING_PROCESSOR_HPP
diff --git a/src/language/node_processor/BinaryExpressionProcessor.hpp b/src/language/node_processor/BinaryExpressionProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6fa8d683b78072194c15984aa8a480f0775c3376
--- /dev/null
+++ b/src/language/node_processor/BinaryExpressionProcessor.hpp
@@ -0,0 +1,225 @@
+#ifndef BINARY_EXPRESSION_PROCESSOR_HPP
+#define BINARY_EXPRESSION_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <Demangle.hpp>
+
+#include <type_traits>
+
+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::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 A_DataT, typename B_DataT>
+class BinaryExpressionProcessor final : public INodeProcessor
+{
+  ASTNode& m_node;
+
+  PUGS_INLINE auto
+  _eval(const ASTNodeDataVariant& a, const ASTNodeDataVariant& b, ASTNodeDataVariant& value)
+  {
+    // 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::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));
+        value                         = 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));
+        value                         = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
+      }
+    } else {
+      auto result = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b));
+      if constexpr (std::is_same_v<decltype(result), int>) {
+        value = static_cast<int64_t>(result);
+      } else {
+        value = result;
+      }
+    }
+  }
+
+  static inline const bool _is_defined{[] {
+    if constexpr (std::is_same_v<BinaryOpT, language::xor_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:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    if constexpr (_is_defined) {
+      m_node.children[0]->execute(exec_policy);
+      m_node.children[1]->execute(exec_policy);
+
+      this->_eval(m_node.children[0]->m_value, m_node.children[1]->m_value, m_node.m_value);
+    }
+  }
+
+  BinaryExpressionProcessor(ASTNode& node) : m_node{node}
+  {
+    if constexpr (not _is_defined) {
+      throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
+    }
+  }
+};
+
+#endif // BINARY_EXPRESSION_PROCESSOR_HPP
diff --git a/src/language/node_processor/ConcatExpressionProcessor.hpp b/src/language/node_processor/ConcatExpressionProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f0c80bed669c5efd6b72db0d042e4902f663c30
--- /dev/null
+++ b/src/language/node_processor/ConcatExpressionProcessor.hpp
@@ -0,0 +1,44 @@
+#ifndef CONCAT_EXPRESSION_PROCESSOR_HPP
+#define CONCAT_EXPRESSION_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <Demangle.hpp>
+
+#include <type_traits>
+
+template <typename B_DataT>
+class ConcatExpressionProcessor final : public INodeProcessor
+{
+  ASTNode& m_node;
+
+  PUGS_INLINE auto
+  _eval(const std::string& a, const ASTNodeDataVariant& b, ASTNodeDataVariant& value)
+  {
+    if constexpr (std::is_same_v<B_DataT, std::string>) {
+      value = a + std::get<B_DataT>(b);
+    } else {
+      value = a + std::to_string(std::get<B_DataT>(b));
+    }
+  }
+
+ public:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    m_node.children[0]->execute(exec_policy);
+    m_node.children[1]->execute(exec_policy);
+
+    this->_eval(std::get<std::string>(m_node.children[0]->m_value), m_node.children[1]->m_value, m_node.m_value);
+  }
+
+  ConcatExpressionProcessor(ASTNode& node) : m_node{node} {}
+};
+
+#endif // CONCAT_EXPRESSION_PROCESSOR_HPP
diff --git a/src/language/node_processor/IncDecExpressionProcessor.hpp b/src/language/node_processor/IncDecExpressionProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..df85452a26cb74b79ca0929a9b806b63bdd24102
--- /dev/null
+++ b/src/language/node_processor/IncDecExpressionProcessor.hpp
@@ -0,0 +1,103 @@
+#ifndef INC_DEC_EXPRESSION_PROCESSOR_HPP
+#define INC_DEC_EXPRESSION_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <SymbolTable.hpp>
+
+#include <Demangle.hpp>
+
+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
+{
+  ASTNode& m_node;
+  ASTNodeDataVariant* 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:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue&)
+  {
+    if constexpr (_is_defined) {
+      m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value));
+    }
+  }
+
+  IncDecExpressionProcessor(ASTNode& 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, m_node.children[0]->begin());
+      Assert(found);
+      p_value = &i_symbol->second.value();
+    } else {
+      throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()});
+    }
+  }
+};
+
+#endif // INC_DEC_EXPRESSION_PROCESSOR_HPP
diff --git a/src/language/node_processor/UnaryExpressionProcessor.hpp b/src/language/node_processor/UnaryExpressionProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..61f294e111c01805b95ecb64adeb08e175ea4aa1
--- /dev/null
+++ b/src/language/node_processor/UnaryExpressionProcessor.hpp
@@ -0,0 +1,63 @@
+#ifndef UNARY_EXPRESSION_PROCESSOR_HPP
+#define UNARY_EXPRESSION_PROCESSOR_HPP
+
+#include <node_processor/INodeProcessor.hpp>
+
+#include <SymbolTable.hpp>
+
+#include <Demangle.hpp>
+
+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
+{
+  ASTNode& m_node;
+
+  PUGS_INLINE ValueT
+  _eval(const ASTNodeDataVariant& a)
+  {
+    return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a));
+  }
+
+ public:
+  std::string
+  describe() const
+  {
+    return demangle<decltype(*this)>();
+  }
+
+  void
+  execute(ExecUntilBreakOrContinue& exec_policy)
+  {
+    m_node.children[0]->execute(exec_policy);
+    m_node.m_value = this->_eval(m_node.children[0]->m_value);
+  }
+
+  UnaryExpressionProcessor(ASTNode& node) : m_node{node} {}
+};
+
+#endif // UNARY_EXPRESSION_PROCESSOR_HPP