diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index a3ad0342839eb5cc5ee6693e4a49e22d99cf41d2..723d9a710f277aff551508ef849632c24e727575 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -126,11 +126,7 @@ 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 keyword : sor < basic_type, import_kw, true_kw, false_kw, let_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, not_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {};
+struct keyword : sor < basic_type, import_kw, true_kw, false_kw, let_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, not_kw, break_kw, continue_kw> {};
 
 struct identifier_minus_keyword : minus< identifier, keyword > {};
 
@@ -218,7 +214,9 @@ 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 shift : list_must<sum, sor< shift_left_op, shift_right_op > >{};
+
+struct compare : list_must<shift, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{};
 
 struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{};
 
@@ -289,15 +287,11 @@ struct for_statement_block;
 
 struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_block >{};
 
-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_statement,
           if_must<do_while_statement, semicol>,
           while_statement,
           for_statement,
-          if_must< ostream_statement, semicol >,
           if_must< BREAK, semicol >,
           if_must< CONTINUE, semicol >,
           block,
diff --git a/src/language/ast/ASTBuilder.cpp b/src/language/ast/ASTBuilder.cpp
index 0c433bbfd21704702ed87012d5956519a0f93bde..a4dc8c822bab53a67be975b6444eb9dffa9bb6be 100644
--- a/src/language/ast/ASTBuilder.cpp
+++ b/src/language/ast/ASTBuilder.cpp
@@ -214,20 +214,6 @@ struct ASTBuilder::simplify_for_post : TAO_PEGTL_NAMESPACE::parse_tree::apply<AS
   }
 };
 
-struct ASTBuilder::simplify_stream_statement
-  : TAO_PEGTL_NAMESPACE::parse_tree::apply<ASTBuilder::simplify_stream_statement>
-{
-  template <typename... States>
-  static void
-  transform(std::unique_ptr<ASTNode>& n, States&&...)
-  {
-    for (size_t i = 1; i < n->children.size(); ++i) {
-      n->children[0]->children.emplace_back(std::move(n->children[i]));
-    }
-    n = std::move(n->children[0]);
-  }
-};
-
 template <typename Rule>
 using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector<
   Rule,
@@ -248,9 +234,6 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector<
                                                      language::vector_type,
                                                      language::matrix_type,
                                                      language::string_type,
-                                                     language::cout_kw,
-                                                     language::cerr_kw,
-                                                     language::clog_kw,
                                                      language::var_declaration,
                                                      language::fct_declaration,
                                                      language::type_mapping,
@@ -269,6 +252,7 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector<
                             language::equality,
                             language::compare,
                             language::sum,
+                            language::shift,
                             language::product,
                             language::affectation,
                             language::expression>,
@@ -282,6 +266,8 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector<
                                  language::name_subscript_expression>,
   TAO_PEGTL_NAMESPACE::parse_tree::remove_content::on<language::plus_op,
                                                       language::minus_op,
+                                                      language::shift_left_op,
+                                                      language::shift_right_op,
                                                       language::multiply_op,
                                                       language::divide_op,
                                                       language::lesser_op,
@@ -308,8 +294,7 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector<
   ASTBuilder::simplify_statement_block::on<language::statement_block>,
   ASTBuilder::simplify_for_init::on<language::for_init>,
   ASTBuilder::simplify_for_test::on<language::for_test>,
-  ASTBuilder::simplify_for_post::on<language::for_post>,
-  ASTBuilder::simplify_stream_statement::on<language::ostream_statement>>;
+  ASTBuilder::simplify_for_post::on<language::for_post>>;
 
 template <typename InputT>
 std::unique_ptr<ASTNode>
diff --git a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
index b6904220a9c42f2fcbfd49e8ce5881fbd9b7cf3a..c96b8799e3edbd037f70f8e68453bf700ced0fa2 100644
--- a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp
@@ -22,6 +22,11 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A
     } else if (n.is_type<language::minus_op>()) {
       return binaryOperatorMangler<language::minus_op>(lhs_data_type, rhs_data_type);
 
+    } else if (n.is_type<language::shift_left_op>()) {
+      return binaryOperatorMangler<language::shift_left_op>(lhs_data_type, rhs_data_type);
+    } else if (n.is_type<language::shift_right_op>()) {
+      return binaryOperatorMangler<language::shift_right_op>(lhs_data_type, rhs_data_type);
+
     } else if (n.is_type<language::or_op>()) {
       return binaryOperatorMangler<language::or_op>(lhs_data_type, rhs_data_type);
     } else if (n.is_type<language::and_op>()) {
diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp
index eb307e2c16893be52128166c973f4992e86f3cb4..cb9e479df5f2e1f64edb4d5cb732acebcb505af6 100644
--- a/src/language/ast/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp
@@ -161,8 +161,6 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
       } else if (n.is_type<language::literal>()) {
         n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>();
-      } else if (n.is_type<language::cout_kw>() or n.is_type<language::cerr_kw>() or n.is_type<language::clog_kw>()) {
-        n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>();
       } else if (n.is_type<language::var_declaration>()) {
         auto& name_node = *(n.children[0]);
         auto& type_node = *(n.children[1]);
@@ -460,6 +458,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
       }
     } else if (n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or
                n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or
+               n.is_type<language::shift_left_op>() or n.is_type<language::shift_right_op>() or
                n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or
                n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or
                n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>() or n.is_type<language::and_op>() or
@@ -482,6 +481,12 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
           return operator_repository.getBinaryOperatorValueType(
             binaryOperatorMangler<language::divide_op>(type_0, type_1));
 
+        } else if (n.is_type<language::shift_left_op>()) {
+          return operator_repository.getBinaryOperatorValueType(
+            binaryOperatorMangler<language::shift_left_op>(type_0, type_1));
+        } else if (n.is_type<language::shift_right_op>()) {
+          return operator_repository.getBinaryOperatorValueType(
+            binaryOperatorMangler<language::shift_right_op>(type_0, type_1));
         } else if (n.is_type<language::lesser_op>()) {
           return operator_repository.getBinaryOperatorValueType(
             binaryOperatorMangler<language::lesser_op>(type_0, type_1));
diff --git a/src/language/ast/ASTNodeExpressionBuilder.cpp b/src/language/ast/ASTNodeExpressionBuilder.cpp
index d9b3b4e439183e1f3a205a7c94e47252ac7a42f2..bbbcda43e788356d6bf4ec338643a79049069fc0 100644
--- a/src/language/ast/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeExpressionBuilder.cpp
@@ -18,7 +18,6 @@
 #include <language/node_processor/IfProcessor.hpp>
 #include <language/node_processor/LocalNameProcessor.hpp>
 #include <language/node_processor/NameProcessor.hpp>
-#include <language/node_processor/OStreamProcessor.hpp>
 #include <language/node_processor/TupleToTinyVectorProcessor.hpp>
 #include <language/node_processor/TupleToVectorProcessor.hpp>
 #include <language/node_processor/ValueProcessor.hpp>
@@ -105,17 +104,12 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
   } else if (n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or n.is_type<language::plus_op>() or
              n.is_type<language::minus_op>() or n.is_type<language::or_op>() or n.is_type<language::and_op>() or
              n.is_type<language::xor_op>() or n.is_type<language::greater_op>() or
+             n.is_type<language::shift_left_op>() or n.is_type<language::shift_right_op>() or
              n.is_type<language::greater_or_eq_op>() or n.is_type<language::lesser_op>() or
              n.is_type<language::lesser_or_eq_op>() or n.is_type<language::eqeq_op>() or
              n.is_type<language::not_eq_op>()) {
     ASTNodeBinaryOperatorExpressionBuilder{n};
 
-  } else if (n.is_type<language::cout_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cout);
-  } else if (n.is_type<language::cerr_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cerr);
-  } else if (n.is_type<language::clog_kw>()) {
-    n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::clog);
   } else if (n.is_type<language::if_statement>()) {
     n.m_node_processor = std::make_unique<IfProcessor>(n);
   } else if (n.is_type<language::statement_block>()) {
diff --git a/src/language/modules/BuiltinModule.cpp b/src/language/modules/BuiltinModule.cpp
index 98d8f71c6c91bd83ac53ff8d45b98f419c283fe9..cc76f78f7369f057c476a1ae15b953798d88903b 100644
--- a/src/language/modules/BuiltinModule.cpp
+++ b/src/language/modules/BuiltinModule.cpp
@@ -2,6 +2,7 @@
 
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/TypeDescriptor.hpp>
+#include <language/utils/ValueDescriptor.hpp>
 #include <utils/Exceptions.hpp>
 
 #include <memory>
@@ -44,6 +45,17 @@ BuiltinModule::_addBuiltinFunction(const std::string& name,
   }
 }
 
+void
+BuiltinModule::_addNameValue(const std::string& name, const ASTNodeDataType& type, const DataVariant& data)
+{
+  std::shared_ptr value_descriptor = std::make_shared<ValueDescriptor>(type, data);
+
+  auto [i_type, success] = m_name_value_map.insert(std::make_pair(name, value_descriptor));
+  if (not success) {
+    throw NormalError("variable '" + name + "' cannot be added!\n");
+  }
+}
+
 void
 BuiltinModule::_addTypeDescriptor(const ASTNodeDataType& ast_node_data_type)
 {
diff --git a/src/language/modules/BuiltinModule.hpp b/src/language/modules/BuiltinModule.hpp
index 2be1d162578fb0d111e6eac7ae93e10dae981bce..3dd9ad1dbb9895f3f79ba04ec2702cc7ee0bd15f 100644
--- a/src/language/modules/BuiltinModule.hpp
+++ b/src/language/modules/BuiltinModule.hpp
@@ -6,18 +6,22 @@
 
 class IBuiltinFunctionEmbedder;
 class TypeDescriptor;
+class ValueDescriptor;
 
 class BuiltinModule : public IModule
 {
  protected:
   NameBuiltinFunctionMap m_name_builtin_function_map;
   NameTypeMap m_name_type_map;
+  NameValueMap m_name_value_map;
 
   void _addBuiltinFunction(const std::string& name,
                            std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder);
 
   void _addTypeDescriptor(const ASTNodeDataType& type);
 
+  void _addNameValue(const std::string& name, const ASTNodeDataType& type, const DataVariant& data);
+
   const bool m_is_mandatory;
 
  public:
@@ -39,6 +43,12 @@ class BuiltinModule : public IModule
     return m_name_type_map;
   }
 
+  const NameValueMap&
+  getNameValueMap() const final
+  {
+    return m_name_value_map;
+  }
+
   BuiltinModule(bool is_mandatory = false);
 
   ~BuiltinModule() = default;
diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index 1cc699455e23c123fbd1fee059f5296917a46b9b..9b70144e8559ccf97515bed9b71b174afb1a9311 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -22,6 +22,8 @@
 #include <language/utils/IncDecOperatorRegisterForN.hpp>
 #include <language/utils/IncDecOperatorRegisterForR.hpp>
 #include <language/utils/IncDecOperatorRegisterForZ.hpp>
+#include <language/utils/OFStream.hpp>
+#include <language/utils/OStream.hpp>
 #include <language/utils/UnaryOperatorRegisterForB.hpp>
 #include <language/utils/UnaryOperatorRegisterForN.hpp>
 #include <language/utils/UnaryOperatorRegisterForR.hpp>
@@ -83,6 +85,25 @@ CoreModule::CoreModule() : BuiltinModule(true)
                                                  []() { RandomEngine::instance().resetRandomSeed(); }
 
                                                  ));
+
+  this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const OStream>>);
+
+  this
+    ->_addBuiltinFunction("ofstream",
+                          std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const OStream>(const std::string&)>>(
+
+                            [](const std::string& filename) { return std::make_shared<const OFStream>(filename); }
+
+                            ));
+
+  this->_addNameValue("cout", ast_node_data_type_from<std::shared_ptr<const OStream>>,
+                      EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cout))});
+
+  this->_addNameValue("cerr", ast_node_data_type_from<std::shared_ptr<const OStream>>,
+                      EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cerr))});
+
+  this->_addNameValue("clog", ast_node_data_type_from<std::shared_ptr<const OStream>>,
+                      EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::clog))});
 }
 
 void
diff --git a/src/language/modules/IModule.hpp b/src/language/modules/IModule.hpp
index ceb3fd3dffc7d0af7f6423e3a21e7e8aa9686ffc..04aefbe91b57ab1925f55bae62ad233c1ea135cf 100644
--- a/src/language/modules/IModule.hpp
+++ b/src/language/modules/IModule.hpp
@@ -1,6 +1,8 @@
 #ifndef IMODULE_HPP
 #define IMODULE_HPP
 
+#include <language/utils/DataVariant.hpp>
+
 #include <memory>
 #include <string>
 #include <string_view>
@@ -8,12 +10,14 @@
 
 class IBuiltinFunctionEmbedder;
 class TypeDescriptor;
+class ValueDescriptor;
 
 class IModule
 {
  public:
   using NameBuiltinFunctionMap = std::unordered_map<std::string, std::shared_ptr<IBuiltinFunctionEmbedder>>;
   using NameTypeMap            = std::unordered_map<std::string, std::shared_ptr<TypeDescriptor>>;
+  using NameValueMap           = std::unordered_map<std::string, std::shared_ptr<ValueDescriptor>>;
 
   IModule()          = default;
   IModule(IModule&&) = default;
@@ -25,6 +29,8 @@ class IModule
 
   virtual const NameTypeMap& getNameTypeMap() const = 0;
 
+  virtual const NameValueMap& getNameValueMap() const = 0;
+
   virtual void registerOperators() const = 0;
 
   virtual std::string_view name() const = 0;
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index e516ab800833f5503de27bcfdd73e8b8381e06e6..71a1368b9dc374b19562bae27cc14a5d2b54c233 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -13,6 +13,8 @@
 #include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
 #include <language/utils/TypeDescriptor.hpp>
+#include <language/utils/ValueDescriptor.hpp>
+
 #include <utils/PugsAssert.hpp>
 
 #include <algorithm>
@@ -85,6 +87,28 @@ ModuleRepository::_populateEmbedderTableT(const ASTNode& module_node,
   }
 }
 
+void
+ModuleRepository::_populateSymbolTable(const ASTNode& module_node,
+                                       const std::string& module_name,
+                                       const IModule::NameValueMap& name_value_descriptor_map,
+                                       SymbolTable& symbol_table)
+{
+  for (auto [symbol_name, value_descriptor] : name_value_descriptor_map) {
+    auto [i_symbol, success] = symbol_table.add(symbol_name, module_node.begin());
+
+    if (not success) {
+      std::ostringstream error_message;
+      error_message << "importing module '" << module_name << "', cannot add symbol '" << symbol_name
+                    << "', it is already defined!";
+      throw ParseError(error_message.str(), module_node.begin());
+    }
+
+    i_symbol->attributes().setDataType(value_descriptor->type());
+    i_symbol->attributes().setIsInitialized();
+    i_symbol->attributes().value() = value_descriptor->value();
+  }
+}
+
 void
 ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table)
 {
@@ -110,6 +134,8 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab
                                   ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
                                   symbol_table.typeEmbedderTable());
 
+    this->_populateSymbolTable(module_name_node, module_name, populating_module.getNameValueMap(), symbol_table);
+
     for (auto [symbol_name, embedded] : populating_module.getNameTypeMap()) {
       BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name));
     }
@@ -132,6 +158,12 @@ ModuleRepository::populateMandatorySymbolTable(const ASTNode& root_node, SymbolT
                                     ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
                                     symbol_table.typeEmbedderTable());
 
+      this->_populateSymbolTable(root_node, module_name, i_module->getNameValueMap(), symbol_table);
+
+      for (auto [symbol_name, embedded] : i_module->getNameTypeMap()) {
+        BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name));
+      }
+
       i_module->registerOperators();
     }
   }
diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp
index c4c9870fcedf550c82f94374f759f94d4c9cc878..c7289c8d1c4b9c7f795925bfdbf65e3f526082e7 100644
--- a/src/language/modules/ModuleRepository.hpp
+++ b/src/language/modules/ModuleRepository.hpp
@@ -26,6 +26,11 @@ class ModuleRepository
                                SymbolTable& symbol_table,
                                EmbedderTableT& embedder_table);
 
+  void _populateSymbolTable(const ASTNode& module_node,
+                            const std::string& module_name,
+                            const IModule::NameValueMap& name_value_map,
+                            SymbolTable& symbol_table);
+
  public:
   void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table);
   void populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
diff --git a/src/language/node_processor/BinaryExpressionProcessor.hpp b/src/language/node_processor/BinaryExpressionProcessor.hpp
index 3af45c3871d6d6b4886f3bd3bf510d7c53f333aa..8cc1a430f96d2892110afaff0b1ac8bc6ccaf347 100644
--- a/src/language/node_processor/BinaryExpressionProcessor.hpp
+++ b/src/language/node_processor/BinaryExpressionProcessor.hpp
@@ -82,6 +82,34 @@ struct BinOp<language::lesser_op>
   }
 };
 
+class OStream;
+
+template <>
+struct BinOp<language::shift_left_op>
+{
+  template <typename A, typename B>
+  PUGS_INLINE auto
+  eval(const A& a, const B& b) -> decltype(a << b)
+  {
+    if constexpr (std::is_same_v<A, std::shared_ptr<const OStream>> and std::is_same_v<B, bool>) {
+      return a << std::boolalpha << b;
+    } else {
+      return a << b;
+    }
+  }
+};
+
+template <>
+struct BinOp<language::shift_right_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>
 {
@@ -286,7 +314,8 @@ struct BinaryExpressionProcessor<BinaryOpT, std::shared_ptr<ValueT>, std::shared
   PUGS_INLINE DataVariant
   _eval(const DataVariant& a, const DataVariant& b)
   {
-    if constexpr ((std::is_arithmetic_v<B_DataT>) or (is_tiny_matrix_v<B_DataT>) or (is_tiny_vector_v<B_DataT>)) {
+    if constexpr ((std::is_arithmetic_v<B_DataT>) or (is_tiny_matrix_v<B_DataT>) or (is_tiny_vector_v<B_DataT>) or
+                  (std::is_same_v<std::string, B_DataT>)) {
       const auto& embedded_a = std::get<EmbeddedData>(a);
       const auto& b_value    = std::get<B_DataT>(b);
 
diff --git a/src/language/node_processor/OStreamProcessor.hpp b/src/language/node_processor/OStreamProcessor.hpp
deleted file mode 100644
index e67dd7b6d9fcfa2440a59367efecd42ffd35a8ca..0000000000000000000000000000000000000000
--- a/src/language/node_processor/OStreamProcessor.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef OSTREAM_PROCESSOR_HPP
-#define OSTREAM_PROCESSOR_HPP
-
-#include <language/ast/ASTNode.hpp>
-#include <language/node_processor/INodeProcessor.hpp>
-#include <language/utils/ParseError.hpp>
-
-class OStreamProcessor final : public INodeProcessor
-{
- private:
-  ASTNode& m_node;
-  std::ostream& m_os;
-
- public:
-  DataVariant
-  execute(ExecutionPolicy& exec_policy)
-  {
-    for (size_t i = 0; i < m_node.children.size(); ++i) {
-      m_os << m_node.children[i]->execute(exec_policy);
-    }
-
-    return {};
-  }
-
-  OStreamProcessor(ASTNode& node, std::ostream& os) : m_node{node}, m_os(os)
-  {
-    for (auto& child : m_node.children) {
-      if ((child->m_data_type == ASTNodeDataType::type_name_id_t) or
-          (child->m_data_type == ASTNodeDataType::function_t) or
-          (child->m_data_type == ASTNodeDataType::builtin_function_t)) {
-        throw ParseError("invalid argument, cannot print a '" + dataTypeName(child->m_data_type) + "'",
-                         std::vector{child->begin()});
-      }
-    }
-  }
-};
-
-#endif   // OSTREAM_PROCESSOR_HPP
diff --git a/src/language/utils/BinaryOperatorMangler.hpp b/src/language/utils/BinaryOperatorMangler.hpp
index f3648f3fb860a6207b70ad712aee9935b669e493..d7f0c6c79358ffb555f20b1f55036cde2ce47504 100644
--- a/src/language/utils/BinaryOperatorMangler.hpp
+++ b/src/language/utils/BinaryOperatorMangler.hpp
@@ -13,6 +13,9 @@ struct divide_op;
 struct plus_op;
 struct minus_op;
 
+struct shift_left_op;
+struct shift_right_op;
+
 struct or_op;
 struct and_op;
 struct xor_op;
@@ -56,6 +59,10 @@ binaryOperatorMangler(const ASTNodeDataType& lhs_data_type, const ASTNodeDataTyp
       return "==";
     } else if constexpr (std::is_same_v<BinaryOperatorT, language::not_eq_op>) {
       return "!=";
+    } else if constexpr (std::is_same_v<BinaryOperatorT, language::shift_left_op>) {
+      return "<<";
+    } else if constexpr (std::is_same_v<BinaryOperatorT, language::shift_right_op>) {
+      return ">>";
     } else {
       static_assert(std::is_same_v<language::multiply_op, BinaryOperatorT>, "undefined binary operator");
     }
diff --git a/src/language/utils/BinaryOperatorRegisterForB.cpp b/src/language/utils/BinaryOperatorRegisterForB.cpp
index cba803aaf3e3d7d4c72be7b69ca1a835203a49b2..dc228471d52330e486887e523c83dfa2d1917cef 100644
--- a/src/language/utils/BinaryOperatorRegisterForB.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForB.cpp
@@ -1,6 +1,18 @@
 #include <language/utils/BinaryOperatorRegisterForB.hpp>
 
 #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
+
+void
+BinaryOperatorRegisterForB::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, bool>>());
+}
 
 void
 BinaryOperatorRegisterForB::_register_comparisons()
@@ -61,6 +73,7 @@ BinaryOperatorRegisterForB::_register_divide()
 
 BinaryOperatorRegisterForB::BinaryOperatorRegisterForB()
 {
+  this->_register_ostream();
   this->_register_comparisons();
   this->_register_logical_operators();
   this->_register_plus();
diff --git a/src/language/utils/BinaryOperatorRegisterForB.hpp b/src/language/utils/BinaryOperatorRegisterForB.hpp
index 651411bf7f2cd8e8386d26c071220d36cb79a691..545b49c5010e063654fea2b8570e4fd6e490f0e6 100644
--- a/src/language/utils/BinaryOperatorRegisterForB.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForB.hpp
@@ -4,6 +4,7 @@
 class BinaryOperatorRegisterForB
 {
  private:
+  void _register_ostream();
   void _register_comparisons();
   void _register_logical_operators();
   void _register_plus();
diff --git a/src/language/utils/BinaryOperatorRegisterForN.cpp b/src/language/utils/BinaryOperatorRegisterForN.cpp
index 66d589405545924af9e2de137f7738c9b40b8430..e32e2b53a5fb70af8b84069790dd8435a362e051 100644
--- a/src/language/utils/BinaryOperatorRegisterForN.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForN.cpp
@@ -1,6 +1,18 @@
 #include <language/utils/BinaryOperatorRegisterForN.hpp>
 
 #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
+
+void
+BinaryOperatorRegisterForN::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, uint64_t>>());
+}
 
 void
 BinaryOperatorRegisterForN::_register_comparisons()
@@ -42,6 +54,7 @@ BinaryOperatorRegisterForN::_register_minus()
 
 BinaryOperatorRegisterForN::BinaryOperatorRegisterForN()
 {
+  this->_register_ostream();
   this->_register_comparisons();
   this->_register_arithmetic<language::plus_op>();
   this->_register_minus();
diff --git a/src/language/utils/BinaryOperatorRegisterForN.hpp b/src/language/utils/BinaryOperatorRegisterForN.hpp
index 80dc52b013f36e05e08f7bf561f2ac3b41ccbfbf..997b6be7ab35284723ee64b6630ecb514f773bcd 100644
--- a/src/language/utils/BinaryOperatorRegisterForN.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForN.hpp
@@ -4,6 +4,7 @@
 class BinaryOperatorRegisterForN
 {
  private:
+  void _register_ostream();
   template <typename OperatorT>
   void _register_arithmetic();
   void _register_comparisons();
diff --git a/src/language/utils/BinaryOperatorRegisterForR.cpp b/src/language/utils/BinaryOperatorRegisterForR.cpp
index 4f69988925e373fbd7369bff3d0bb87860b1aa3d..cc8ba8a79dc59c447317200a308103b8d7dfc1d8 100644
--- a/src/language/utils/BinaryOperatorRegisterForR.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForR.cpp
@@ -1,6 +1,18 @@
 #include <language/utils/BinaryOperatorRegisterForR.hpp>
 
 #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
+
+void
+BinaryOperatorRegisterForR::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, double>>());
+}
 
 void
 BinaryOperatorRegisterForR::_register_comparisons()
@@ -44,6 +56,7 @@ BinaryOperatorRegisterForR::_register_arithmetic()
 
 BinaryOperatorRegisterForR::BinaryOperatorRegisterForR()
 {
+  this->_register_ostream();
   this->_register_comparisons();
   this->_register_arithmetic<language::plus_op>();
   this->_register_arithmetic<language::minus_op>();
diff --git a/src/language/utils/BinaryOperatorRegisterForR.hpp b/src/language/utils/BinaryOperatorRegisterForR.hpp
index cbde82fb3d36e565ef84d99b95b58c6c0556eb01..c14fa410f9a4dac520ae4482d3a62114f4840029 100644
--- a/src/language/utils/BinaryOperatorRegisterForR.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForR.hpp
@@ -4,6 +4,7 @@
 class BinaryOperatorRegisterForR
 {
  private:
+  void _register_ostream();
   template <typename OperatorT>
   void _register_arithmetic();
   void _register_comparisons();
diff --git a/src/language/utils/BinaryOperatorRegisterForRn.cpp b/src/language/utils/BinaryOperatorRegisterForRn.cpp
index 41e5b031f7e3db02d8e59a9962e028c046f813a8..6e900d036871ed79eb13dfa737445becd50a1a9a 100644
--- a/src/language/utils/BinaryOperatorRegisterForRn.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForRn.cpp
@@ -1,8 +1,23 @@
 #include <language/utils/BinaryOperatorRegisterForRn.hpp>
 
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
 #include <language/utils/OperatorRepository.hpp>
 
+template <size_t Dimension>
+void
+BinaryOperatorRegisterForRn<Dimension>::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  using Rn = TinyVector<Dimension>;
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, Rn>>());
+}
+
 template <size_t Dimension>
 void
 BinaryOperatorRegisterForRn<Dimension>::_register_comparisons()
@@ -54,6 +69,8 @@ BinaryOperatorRegisterForRn<Dimension>::_register_arithmetic()
 template <size_t Dimension>
 BinaryOperatorRegisterForRn<Dimension>::BinaryOperatorRegisterForRn()
 {
+  this->_register_ostream();
+
   this->_register_comparisons();
 
   this->_register_product_by_a_scalar();
diff --git a/src/language/utils/BinaryOperatorRegisterForRn.hpp b/src/language/utils/BinaryOperatorRegisterForRn.hpp
index b9f27d4165d236b913e3393e342a144019fe6015..fc83d3a670a18b49824d7f59360c41dac9d39b6d 100644
--- a/src/language/utils/BinaryOperatorRegisterForRn.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForRn.hpp
@@ -7,10 +7,9 @@ template <size_t Dimension>
 class BinaryOperatorRegisterForRn
 {
  private:
+  void _register_ostream();
   void _register_comparisons();
-
   void _register_product_by_a_scalar();
-
   template <typename OperatorT>
   void _register_arithmetic();
 
diff --git a/src/language/utils/BinaryOperatorRegisterForRnxn.cpp b/src/language/utils/BinaryOperatorRegisterForRnxn.cpp
index 3d8850e79a4129c9a2098baa14b869f48bb8d1ce..f164203ddaca12e83f5ae5770dcb4848d366d3a4 100644
--- a/src/language/utils/BinaryOperatorRegisterForRnxn.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForRnxn.cpp
@@ -1,8 +1,23 @@
 #include <language/utils/BinaryOperatorRegisterForRnxn.hpp>
 
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
 #include <language/utils/OperatorRepository.hpp>
 
+template <size_t Dimension>
+void
+BinaryOperatorRegisterForRnxn<Dimension>::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  using Rnxn = TinyMatrix<Dimension>;
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, Rnxn>>());
+}
+
 template <size_t Dimension>
 void
 BinaryOperatorRegisterForRnxn<Dimension>::_register_comparisons()
@@ -68,6 +83,8 @@ BinaryOperatorRegisterForRnxn<Dimension>::_register_arithmetic()
 template <size_t Dimension>
 BinaryOperatorRegisterForRnxn<Dimension>::BinaryOperatorRegisterForRnxn()
 {
+  this->_register_ostream();
+
   this->_register_comparisons();
 
   this->_register_product_by_a_scalar();
diff --git a/src/language/utils/BinaryOperatorRegisterForRnxn.hpp b/src/language/utils/BinaryOperatorRegisterForRnxn.hpp
index 594740b629b0a7201d64139fd8e2ce4a12b38cd2..9edad436b51a5606fafc6aa980fd1578084f7e85 100644
--- a/src/language/utils/BinaryOperatorRegisterForRnxn.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForRnxn.hpp
@@ -7,11 +7,10 @@ template <size_t Dimension>
 class BinaryOperatorRegisterForRnxn
 {
  private:
+  void _register_ostream();
   void _register_comparisons();
-
   void _register_product_by_a_scalar();
   void _register_product_by_a_vector();
-
   template <typename OperatorT>
   void _register_arithmetic();
 
diff --git a/src/language/utils/BinaryOperatorRegisterForString.cpp b/src/language/utils/BinaryOperatorRegisterForString.cpp
index 0e89cbe00502938d817405c3f3f3d6d991f0433e..999950cf1b1310bbe52614cc6823f37be53f82a4 100644
--- a/src/language/utils/BinaryOperatorRegisterForString.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForString.cpp
@@ -2,8 +2,20 @@
 
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
 #include <language/utils/ConcatExpressionProcessorBuilder.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
 #include <language/utils/OperatorRepository.hpp>
 
+void
+BinaryOperatorRegisterForString::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, std::string>>());
+}
+
 void
 BinaryOperatorRegisterForString::_register_comparisons()
 {
@@ -27,6 +39,8 @@ BinaryOperatorRegisterForString::_register_concat()
 
 BinaryOperatorRegisterForString::BinaryOperatorRegisterForString()
 {
+  this->_register_ostream();
+
   this->_register_comparisons();
 
   this->_register_concat<bool>();
diff --git a/src/language/utils/BinaryOperatorRegisterForString.hpp b/src/language/utils/BinaryOperatorRegisterForString.hpp
index 36af13ee6442086244ee5234ad496f3580f79c22..b7d4a74402092b60ae958c1beb20e61b4151592d 100644
--- a/src/language/utils/BinaryOperatorRegisterForString.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForString.hpp
@@ -4,6 +4,8 @@
 class BinaryOperatorRegisterForString
 {
  private:
+  void _register_ostream();
+
   void _register_comparisons();
 
   template <typename RHS_T>
diff --git a/src/language/utils/BinaryOperatorRegisterForZ.cpp b/src/language/utils/BinaryOperatorRegisterForZ.cpp
index cc8b22d117a8bebc557efff84083b8e45dcf8602..1d318850226beac44d27fe5f4fdba6c8e36a4e61 100644
--- a/src/language/utils/BinaryOperatorRegisterForZ.cpp
+++ b/src/language/utils/BinaryOperatorRegisterForZ.cpp
@@ -1,6 +1,18 @@
 #include <language/utils/BinaryOperatorRegisterForZ.hpp>
 
 #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OStream.hpp>
+
+void
+BinaryOperatorRegisterForZ::_register_ostream()
+{
+  OperatorRepository& repository = OperatorRepository::instance();
+
+  repository.addBinaryOperator<language::shift_left_op>(
+    std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>,
+                                                    std::shared_ptr<const OStream>, int64_t>>());
+}
 
 void
 BinaryOperatorRegisterForZ::_register_comparisons()
@@ -36,6 +48,7 @@ BinaryOperatorRegisterForZ::_register_arithmetic()
 
 BinaryOperatorRegisterForZ::BinaryOperatorRegisterForZ()
 {
+  this->_register_ostream();
   this->_register_comparisons();
   this->_register_arithmetic<language::plus_op>();
   this->_register_arithmetic<language::minus_op>();
diff --git a/src/language/utils/BinaryOperatorRegisterForZ.hpp b/src/language/utils/BinaryOperatorRegisterForZ.hpp
index 3f9a7c30c2f8e3674e6ebda7e9069153a6162f13..cb734843dc5013637ec597a8357a50d05a3b5373 100644
--- a/src/language/utils/BinaryOperatorRegisterForZ.hpp
+++ b/src/language/utils/BinaryOperatorRegisterForZ.hpp
@@ -4,6 +4,7 @@
 class BinaryOperatorRegisterForZ
 {
  private:
+  void _register_ostream();
   template <typename OperatorT>
   void _register_arithmetic();
   void _register_comparisons();
diff --git a/src/language/utils/CMakeLists.txt b/src/language/utils/CMakeLists.txt
index 216a6be6a15971fe93ca2f4341f720e8b6e5cde3..c8928003d045b7216b8edd8ea13b989d697d3268 100644
--- a/src/language/utils/CMakeLists.txt
+++ b/src/language/utils/CMakeLists.txt
@@ -29,6 +29,7 @@ add_library(PugsLanguageUtils
   IncDecOperatorRegisterForN.cpp
   IncDecOperatorRegisterForR.cpp
   IncDecOperatorRegisterForZ.cpp
+  OFStream.cpp
   OperatorRepository.cpp
   UnaryOperatorRegisterForB.cpp
   UnaryOperatorRegisterForN.cpp
diff --git a/src/language/utils/OFStream.cpp b/src/language/utils/OFStream.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3bc5e29911abb17840429bb6025232c1cb5f4711
--- /dev/null
+++ b/src/language/utils/OFStream.cpp
@@ -0,0 +1,12 @@
+#include <language/utils/OFStream.hpp>
+
+#include <utils/Messenger.hpp>
+
+OFStream::OFStream(const std::string& filename)
+{
+  if (parallel::rank() == 0) {
+    m_fstream.open(filename);
+    Assert(m_ostream == nullptr, "ostream was already defined");
+    m_ostream = &m_fstream;
+  }
+}
diff --git a/src/language/utils/OFStream.hpp b/src/language/utils/OFStream.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..589f0fe2720b5cdfb1d6e718cc11b14d1d93592c
--- /dev/null
+++ b/src/language/utils/OFStream.hpp
@@ -0,0 +1,20 @@
+#ifndef OFSTREAM_HPP
+#define OFSTREAM_HPP
+
+#include <language/utils/OStream.hpp>
+
+#include <fstream>
+
+class OFStream : public OStream
+{
+ private:
+  std::ofstream m_fstream;
+
+ public:
+  OFStream(const std::string& filename);
+
+  OFStream()  = default;
+  ~OFStream() = default;
+};
+
+#endif   // OFSTREAM_HPP
diff --git a/src/language/utils/OStream.hpp b/src/language/utils/OStream.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6abbcf668c2e56ed668898d619004d0434cd0cb3
--- /dev/null
+++ b/src/language/utils/OStream.hpp
@@ -0,0 +1,36 @@
+#ifndef OSTREAM_HPP
+#define OSTREAM_HPP
+
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <utils/PugsAssert.hpp>
+
+#include <memory>
+
+class OStream
+{
+ protected:
+  mutable std::ostream* m_ostream = nullptr;
+
+ public:
+  template <typename DataT>
+  friend std::shared_ptr<const OStream>
+  operator<<(const std::shared_ptr<const OStream>& os, const DataT& t)
+  {
+    Assert(os.use_count() > 0);
+    if (os->m_ostream != nullptr) {
+      *os->m_ostream << t;
+    }
+    return os;
+  }
+
+  OStream(std::ostream& os) : m_ostream(&os) {}
+  OStream() = default;
+
+  virtual ~OStream() = default;
+};
+
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const OStream>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("ostream");
+
+#endif   // OSTREAM_HPP
diff --git a/src/language/utils/ValueDescriptor.hpp b/src/language/utils/ValueDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..36bca35356b0b4a9759aee028b1b1ac02d9f7120
--- /dev/null
+++ b/src/language/utils/ValueDescriptor.hpp
@@ -0,0 +1,36 @@
+#ifndef VALUE_DESCRIPTOR_HPP
+#define VALUE_DESCRIPTOR_HPP
+
+#include <language/utils/ASTNodeDataType.hpp>
+#include <language/utils/DataVariant.hpp>
+
+#include <string>
+
+class ValueDescriptor
+{
+ private:
+  const ASTNodeDataType m_type;
+  const DataVariant m_value;
+
+ public:
+  const ASTNodeDataType
+  type() const
+  {
+    return m_type;
+  }
+
+  const DataVariant
+  value() const
+  {
+    return m_value;
+  }
+
+  ValueDescriptor(const ASTNodeDataType& type, const DataVariant& value) : m_type{type}, m_value{value} {}
+
+  ValueDescriptor(const ValueDescriptor&) = delete;
+  ValueDescriptor(ValueDescriptor&&)      = delete;
+
+  ~ValueDescriptor() = default;
+};
+
+#endif   // VALUE_DESCRIPTOR_HPP
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 62a70aad353dbb9d9deb7fcc7688865ab1987024..3c7ab2eb4d336edf9eaf9d78c8b870130cadc871 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -86,7 +86,6 @@ add_executable (unit_tests
   test_MathModule.cpp
   test_NameProcessor.cpp
   test_NaNHelper.cpp
-  test_OStreamProcessor.cpp
   test_ParseError.cpp
   test_PETScUtils.cpp
   test_PugsAssert.cpp
diff --git a/tests/test_ASTBuilder.cpp b/tests/test_ASTBuilder.cpp
index 387e84b75b359b1cd4f95dd594f798e56b02208c..3ce2855eff1b059c0ac0e4215b8b1410e45af165 100644
--- a/tests/test_ASTBuilder.cpp
+++ b/tests/test_ASTBuilder.cpp
@@ -600,7 +600,7 @@ for(let i:N, i=0; i<10; ++i) {
       CHECK_AST(data, result);
     }
 
-    SECTION("ostream simplifications")
+    SECTION("ostream")
     {
       std::string_view data = R"(
 cout << 1+2 << "\n";
@@ -610,16 +610,22 @@ clog << "log " << l << "\n";
 
       std::string_view result = R"(
 (root)
- +-(language::cout_kw)
- |   +-(language::plus_op)
- |   |   +-(language::integer:1)
- |   |   `-(language::integer:2)
+ +-(language::shift_left_op)
+ |   +-(language::shift_left_op)
+ |   |   +-(language::name:cout)
+ |   |   `-(language::plus_op)
+ |   |       +-(language::integer:1)
+ |   |       `-(language::integer:2)
  |   `-(language::literal:"\n")
- +-(language::cerr_kw)
+ +-(language::shift_left_op)
+ |   +-(language::name:cerr)
  |   `-(language::literal:"error?\n")
- `-(language::clog_kw)
-     +-(language::literal:"log ")
-     +-(language::name:l)
+ `-(language::shift_left_op)
+     +-(language::shift_left_op)
+     |   +-(language::shift_left_op)
+     |   |   +-(language::name:clog)
+     |   |   `-(language::literal:"log ")
+     |   `-(language::name:l)
      `-(language::literal:"\n")
 )";
       CHECK_AST(data, result);
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index 96af38a0b905014ea518653795ba95850e486055..2e3835024a270781d0dccb37edd914abfdd63a51 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -1413,11 +1413,14 @@ clog << "clog\n";
 
     std::string_view result = R"(
 (root:void)
- +-(language::cout_kw:void)
+ +-(language::shift_left_op:ostream)
+ |   +-(language::name:cout:ostream)
  |   `-(language::literal:"cout\n":string)
- +-(language::cerr_kw:void)
+ +-(language::shift_left_op:ostream)
+ |   +-(language::name:cerr:ostream)
  |   `-(language::literal:"cerr\n":string)
- `-(language::clog_kw:void)
+ `-(language::shift_left_op:ostream)
+     +-(language::name:clog:ostream)
      `-(language::literal:"clog\n":string)
 )";
 
@@ -1445,8 +1448,10 @@ for (let i : N, i=0; i<3; ++i){
      |   `-(language::integer:3:Z)
      +-(language::unary_plusplus:N)
      |   `-(language::name:i:N)
-     `-(language::cout_kw:void)
-         +-(language::name:i:N)
+     `-(language::shift_left_op:ostream)
+         +-(language::shift_left_op:ostream)
+         |   +-(language::name:cout:ostream)
+         |   `-(language::name:i:N)
          `-(language::literal:"\n":string)
 )";
 
diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp
index cb6fdbfef85884a013e112a978207729ba965835..25a3d3a93f21294bbd04ae238ccbfcca5f4738fb 100644
--- a/tests/test_ASTNodeExpressionBuilder.cpp
+++ b/tests/test_ASTNodeExpressionBuilder.cpp
@@ -684,7 +684,7 @@ cout;
 
       std::string result = R"(
 (root:ASTNodeListProcessor)
- `-(language::cout_kw:OStreamProcessor)
+ `-(language::name:cout:NameProcessor)
 )";
 
       CHECK_AST(data, result);
@@ -698,7 +698,7 @@ cerr;
 
       std::string result = R"(
 (root:ASTNodeListProcessor)
- `-(language::cerr_kw:OStreamProcessor)
+ `-(language::name:cerr:NameProcessor)
 )";
 
       CHECK_AST(data, result);
@@ -712,7 +712,7 @@ clog;
 
       std::string result = R"(
 (root:ASTNodeListProcessor)
- `-(language::clog_kw:OStreamProcessor)
+ `-(language::name:clog:NameProcessor)
 )";
 
       CHECK_AST(data, result);
diff --git a/tests/test_ASTNodeTypeCleaner.cpp b/tests/test_ASTNodeTypeCleaner.cpp
index e1abf88d600d45ba9ae77d3c25b4904adf6992d4..d78d4ce17fba3046d75e3ea1108d3874a3636dec 100644
--- a/tests/test_ASTNodeTypeCleaner.cpp
+++ b/tests/test_ASTNodeTypeCleaner.cpp
@@ -42,9 +42,12 @@ cout << "two=" << 2 << "\n";
 
     std::string_view result = R"(
 (root)
- `-(language::cout_kw)
-     +-(language::literal:"two=")
-     +-(language::integer:2)
+ `-(language::shift_left_op)
+     +-(language::shift_left_op)
+     |   +-(language::shift_left_op)
+     |   |   +-(language::name:cout)
+     |   |   `-(language::literal:"two=")
+     |   `-(language::integer:2)
      `-(language::literal:"\n")
 )";
 
diff --git a/tests/test_OStreamProcessor.cpp b/tests/test_OStreamProcessor.cpp
deleted file mode 100644
index 22213d64bcbb70adf6ea6fab93f82e641870da29..0000000000000000000000000000000000000000
--- a/tests/test_OStreamProcessor.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <catch2/catch_test_macros.hpp>
-#include <catch2/matchers/catch_matchers_all.hpp>
-
-#include <language/ast/ASTBuilder.hpp>
-#include <language/ast/ASTNodeDataTypeBuilder.hpp>
-#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
-#include <language/ast/ASTNodeExpressionBuilder.hpp>
-#include <language/ast/ASTNodeTypeCleaner.hpp>
-#include <language/ast/ASTSymbolTableBuilder.hpp>
-#include <language/node_processor/OStreamProcessor.hpp>
-#include <utils/Demangle.hpp>
-
-#include <pegtl/string_input.hpp>
-
-#include <sstream>
-
-void
-_replaceOStream(ASTNode& node, std::ostringstream& sout)
-{
-  if (node.is_type<language::cout_kw>() or node.is_type<language::cerr_kw>()) {
-    node.m_node_processor = std::make_unique<OStreamProcessor>(node, sout);
-  } else {
-    for (auto& child_node : node.children) {
-      _replaceOStream(*child_node, sout);
-    }
-  }
-}
-
-#define CHECK_OSTREAM_EXPRESSION_RESULT(data, expected_value)  \
-  {                                                            \
-    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
-    auto ast = ASTBuilder::build(input);                       \
-                                                               \
-    ASTSymbolTableBuilder{*ast};                               \
-    ASTNodeDataTypeBuilder{*ast};                              \
-                                                               \
-    ASTNodeDeclarationToAffectationConverter{*ast};            \
-    ASTNodeTypeCleaner<language::var_declaration>{*ast};       \
-                                                               \
-    ASTNodeExpressionBuilder{*ast};                            \
-    ExecutionPolicy exec_policy;                               \
-                                                               \
-    std::ostringstream sout;                                   \
-    _replaceOStream(*ast, sout);                               \
-                                                               \
-    ast->execute(exec_policy);                                 \
-                                                               \
-    REQUIRE(sout.str() == expected_value);                     \
-  }
-
-#define CHECK_OSTREAM_EXPRESSION_THROWS(data, expected_error)                                   \
-  {                                                                                             \
-    static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>);              \
-    static_assert((std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view>) or \
-                  (std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>));       \
-                                                                                                \
-    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};                                  \
-    auto ast = ASTBuilder::build(input);                                                        \
-                                                                                                \
-    ASTSymbolTableBuilder{*ast};                                                                \
-    ASTNodeDataTypeBuilder{*ast};                                                               \
-                                                                                                \
-    ASTNodeDeclarationToAffectationConverter{*ast};                                             \
-    ASTNodeTypeCleaner<language::var_declaration>{*ast};                                        \
-    ASTNodeTypeCleaner<language::fct_declaration>{*ast};                                        \
-                                                                                                \
-    REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error);                        \
-  }
-
-// clazy:excludeall=non-pod-global-static
-
-TEST_CASE("OStreamProcessor", "[language]")
-{
-  SECTION("cout")
-  {
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << 2;)", "2");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << true;)", "true");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << false;)", "false");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << "x=" << 2 << "\n";)", "x=2\n");
-  }
-
-  SECTION("cerr")
-  {
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << 2;)", "2");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << true;)", "true");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << false;)", "false");
-    CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << "x=" << 2 << "\n";)", "x=2\n");
-  }
-
-  SECTION("runtime error")
-  {
-    std::string_view data_type = R"(
-let f : R -> R, x -> 2;
-cerr << "f=" << f << "\n";
-)";
-
-    std::string error_msg = "invalid argument, cannot print a 'function'";
-    CHECK_OSTREAM_EXPRESSION_THROWS(data_type, error_msg);
-  }
-}