diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index b68a1dd76592987a57990e6dfbf3cac602592b3f..d2cd7c480bb635a83b3f60a4c49b5cf7cae6815b 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -50,6 +50,9 @@ struct real
 struct escaped_c : one< '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v' > {};
 struct character : if_must_else< one< '\\' >, escaped_c, ascii::any> {};
 
+struct open_parent : seq< one< '(' >, ignored > {};
+struct close_parent : seq< one< ')' >, ignored > {};
+
 struct literal : if_must< one< '"' >, until< one< '"' >, character > > {};
 
 struct import_kw :  TAO_PEGTL_KEYWORD("import") {};
@@ -72,11 +75,13 @@ struct vector_type : seq< R_set, ignored, one< '^' >, ignored, integer >{};
 struct basic_type : sor< scalar_type, string_type >{};
 
 struct type_name_id;
-struct type_specifier : sor< vector_type, basic_type, type_name_id >{};
+struct simple_type_specifier : sor< vector_type, basic_type, type_name_id >{};
+
+struct tuple_type_specifier : seq<open_parent, simple_type_specifier, ignored, close_parent>{};
 
-struct TYPE_SPECIFIER : seq< type_specifier, ignored >{};
+struct TYPE_SPECIFIER : seq< sor<simple_type_specifier, tuple_type_specifier>, ignored >{};
 
-struct type_expression : list_must< type_specifier, seq< ignored, one< '*' >, ignored > >{};
+struct type_expression : list_must< TYPE_SPECIFIER, seq< ignored, one< '*' >, ignored > >{};
 struct TYPE_EXPRESSION : seq< type_expression, ignored >{};
 
 struct and_kw : TAO_PEGTL_KEYWORD("and") {};
@@ -142,9 +147,6 @@ struct COLUMN : seq< column , ignored > {};
 struct comma : one< ',' > {};
 struct COMMA : seq< comma , 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 >{};
 
diff --git a/src/language/ast/ASTBuilder.cpp b/src/language/ast/ASTBuilder.cpp
index b0969abbb5d19f3c55fadf21a1d518621e9b6a7d..cef779ffce63b9c2ad808ca94b993e7eff59d4ff 100644
--- a/src/language/ast/ASTBuilder.cpp
+++ b/src/language/ast/ASTBuilder.cpp
@@ -275,6 +275,7 @@ using selector = parse_tree::selector<
                                  language::unary_plus,
                                  language::unary_not,
                                  language::subscript_expression,
+                                 language::tuple_type_specifier,
                                  language::type_expression,
                                  language::unary_expression,
                                  language::name_subscript_expression>,
diff --git a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
index b0b9455dba6e7339a5ea5a6caebbcf60c07e9a98..1295383c4df4b97e784a3862bfb502c95564c0ba 100644
--- a/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeAffectationExpressionBuilder.cpp
@@ -5,6 +5,8 @@
 #include <language/ast/ASTNodeNaturalConversionChecker.hpp>
 #include <language/node_processor/AffectationProcessor.hpp>
 
+#include <utils/Exceptions.hpp>
+
 ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode& n)
 {
   auto set_affectation_processor = [](ASTNode& n, const auto& operator_v) {
@@ -206,6 +208,31 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
           break;
         }
           // LCOV_EXCL_START
+        default: {
+          throw parse_error("unexpected error: undefined operand type for embedded data affectation",
+                            std::vector{n.children[1]->begin()});
+        }
+          // LCOV_EXCL_STOP
+        }
+      } else {
+        throw parse_error("invalid operator for '" + data_type.typeName() + "' affectation", std::vector{n.begin()});
+      }
+    };
+
+    auto set_affectation_processor_for_tuple_data = [&](const ASTNodeDataType& content_data_type,
+                                                        const ASTNodeDataType& data_type) {
+      if (content_data_type != ASTNodeDataType::type_id_t) {
+        throw NotImplementedError(dataTypeName(content_data_type) + " argument to tuple ");
+      }
+
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
+        switch (data_type) {
+        case ASTNodeDataType::list_t: {
+          n.m_node_processor = std::make_unique<AffectationFromListProcessor<OperatorT, EmbeddedData>>(n);
+          break;
+        }
+        // LCOV_EXCL_START
         default: {
           throw parse_error("unexpected error: undefined operand type for string affectation",
                             std::vector{n.children[1]->begin()});
@@ -267,6 +294,11 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         set_affectation_processor_for_embedded_data(data_type);
         break;
       }
+      case ASTNodeDataType::tuple_t: {
+        const ASTNodeDataType& content_type = value_type.contentType();
+        set_affectation_processor_for_tuple_data(content_type, data_type);
+        break;
+      }
       default: {
         throw parse_error("unexpected error: undefined value type for affectation",
                           std::vector{n.children[0]->begin()});
diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index cda5d08cd26517038b3fa6969191806a68ccea3e..0ccb025730f0605af9119589f37ac71da5ae37da 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -76,6 +76,20 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
   };
 
+  auto get_function_argument_to_tuple_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
+    switch (argument_node_sub_data_type.m_data_type) {
+    case ASTNodeDataType::tuple_t: {
+      return std::make_unique<FunctionArgumentConverter<EmbeddedData, EmbeddedData>>(argument_number);
+    }
+    case ASTNodeDataType::list_t: {
+      return std::make_unique<FunctionListArgumentConverter<EmbeddedData, EmbeddedData>>(argument_number);
+    }
+    default: {
+      throw UnexpectedError(dataTypeName(argument_node_sub_data_type.m_data_type) + " argument to tuple ");
+    }
+    }
+  };
+
   auto get_function_argument_to_function_id_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
     switch (argument_node_sub_data_type.m_data_type) {
     case ASTNodeDataType::function_t: {
@@ -115,6 +129,12 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
     case ASTNodeDataType::function_t: {
       return get_function_argument_to_function_id_converter();
+    }
+    case ASTNodeDataType::tuple_t: {
+      if (parameter_type.contentType() != ASTNodeDataType::type_id_t) {
+        throw NotImplementedError(dataTypeName(parameter_type.contentType()) + " argument to tuple ");
+      }
+      return get_function_argument_to_tuple_converter();
     }
       // LCOV_EXCL_START
     default: {
diff --git a/src/language/ast/ASTNodeDataType.cpp b/src/language/ast/ASTNodeDataType.cpp
index 0befade165ce5812e0a3fb78f700481b99cfe867..923c751f8c858674123d99458f7322b8c80652b4 100644
--- a/src/language/ast/ASTNodeDataType.cpp
+++ b/src/language/ast/ASTNodeDataType.cpp
@@ -41,6 +41,12 @@ dataTypeName(const ASTNodeDataType& data_type)
   case ASTNodeDataType::vector_t:
     name = "R^" + std::to_string(data_type.dimension());
     break;
+  case ASTNodeDataType::tuple_t:
+    name = "tuple(" + dataTypeName(data_type.contentType()) + ')';
+    break;
+  case ASTNodeDataType::list_t:
+    name = "list";
+    break;
   case ASTNodeDataType::string_t:
     name = "string";
     break;
@@ -62,9 +68,6 @@ dataTypeName(const ASTNodeDataType& data_type)
   case ASTNodeDataType::void_t:
     name = "void";
     break;
-  case ASTNodeDataType::list_t:
-    name = "list";
-    break;
   }
   return name;
 }
diff --git a/src/language/ast/ASTNodeDataType.hpp b/src/language/ast/ASTNodeDataType.hpp
index 7209d1c4f184dd4ebaf9cd835a940dba975699ec..3c65905181878ab0d05887ddd92128003aa5cfcc 100644
--- a/src/language/ast/ASTNodeDataType.hpp
+++ b/src/language/ast/ASTNodeDataType.hpp
@@ -1,7 +1,10 @@
 #ifndef AST_NODE_DATA_TYPE_HPP
 #define AST_NODE_DATA_TYPE_HPP
 
+#include <utils/PugsAssert.hpp>
+
 #include <limits>
+#include <memory>
 #include <string>
 
 class ASTNode;
@@ -17,8 +20,9 @@ class ASTNodeDataType
     unsigned_int_t     = 2,
     double_t           = 3,
     vector_t           = 4,
-    list_t             = 5,
-    string_t           = 6,
+    tuple_t            = 5,
+    list_t             = 6,
+    string_t           = 7,
     typename_t         = 10,
     type_name_id_t     = 11,
     type_id_t          = 21,
@@ -29,6 +33,7 @@ class ASTNodeDataType
 
  private:
   DataType m_data_type;
+  std::shared_ptr<ASTNodeDataType> m_content_type;
   size_t m_dimension;
   std::string m_type_name;
 
@@ -39,13 +44,20 @@ class ASTNodeDataType
     return m_dimension;
   }
 
+  const ASTNodeDataType&
+  contentType() const
+  {
+    Assert(m_content_type);
+    return *m_content_type;
+  }
+
   const std::string&
   typeName() const
   {
     return m_type_name;
   }
 
-  operator DataType() const
+  operator const DataType&() const
   {
     return m_data_type;
   }
@@ -53,14 +65,23 @@ class ASTNodeDataType
   ASTNodeDataType& operator=(const ASTNodeDataType&) = default;
   ASTNodeDataType& operator=(ASTNodeDataType&&) = default;
 
-  ASTNodeDataType(DataType data_type) : m_data_type{data_type}, m_dimension{1}, m_type_name{"unknown"} {}
+  ASTNodeDataType(DataType data_type)
+    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_type_name{"unknown"}
+  {}
+
+  ASTNodeDataType(DataType data_type, const ASTNodeDataType& content_type)
+    : m_data_type{data_type},
+      m_content_type{std::make_shared<ASTNodeDataType>(content_type)},
+      m_dimension{1},
+      m_type_name{"unknown"}
+  {}
 
   ASTNodeDataType(DataType data_type, size_t dimension)
-    : m_data_type{data_type}, m_dimension{dimension}, m_type_name{"unknown"}
+    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{dimension}, m_type_name{"unknown"}
   {}
 
   ASTNodeDataType(DataType data_type, const std::string& type_name)
-    : m_data_type{data_type}, m_dimension{1}, m_type_name{type_name}
+    : m_data_type{data_type}, m_content_type{nullptr}, m_dimension{1}, m_type_name{type_name}
   {}
 
   ASTNodeDataType(const ASTNodeDataType&) = default;
diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp
index 973d0fc99b74f90e1f069dff6de78346f2c6e772..ba69d9d89959ec630a414ac5a0ddac701dd4bb87 100644
--- a/src/language/ast/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp
@@ -37,6 +37,43 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
       data_type = ASTNodeDataType::double_t;
     } else if (type_node.is_type<language::vector_type>()) {
       data_type = getVectorDataType(type_node);
+    } else if (type_node.is_type<language::tuple_type_specifier>()) {
+      auto& content_node = type_node.children[0];
+
+      if (content_node->is_type<language::type_name_id>()) {
+        const std::string& type_name_id = content_node->string();
+
+        auto& symbol_table = *type_node.m_symbol_table;
+
+        auto [i_type_symbol, found] = symbol_table.find(type_name_id, content_node->begin());
+        if (not found) {
+          throw parse_error("undefined type identifier", std::vector{content_node->begin()});
+        } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) {
+          std::ostringstream os;
+          os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '"
+             << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends;
+          throw parse_error(os.str(), std::vector{content_node->begin()});
+        }
+
+        content_node->m_data_type = ASTNodeDataType{ASTNodeDataType::type_id_t, type_name_id};
+        i_type_symbol->attributes().setDataType(content_node->m_data_type);
+      } else if (content_node->is_type<language::B_set>()) {
+        data_type = ASTNodeDataType::bool_t;
+      } else if (content_node->is_type<language::Z_set>()) {
+        data_type = ASTNodeDataType::int_t;
+      } else if (content_node->is_type<language::N_set>()) {
+        data_type = ASTNodeDataType::unsigned_int_t;
+      } else if (content_node->is_type<language::R_set>()) {
+        data_type = ASTNodeDataType::double_t;
+      } else if (content_node->is_type<language::vector_type>()) {
+        data_type = getVectorDataType(type_node);
+      } else if (content_node->is_type<language::string_type>()) {
+        data_type = ASTNodeDataType::string_t;
+      } else {
+        throw UnexpectedError("unexpected content type in tuple");
+      }
+
+      data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, content_node->m_data_type};
     } else if (type_node.is_type<language::string_type>()) {
       data_type = ASTNodeDataType::string_t;
     } else if (type_node.is_type<language::type_name_id>()) {
diff --git a/src/language/ast/ASTNodeExpressionBuilder.cpp b/src/language/ast/ASTNodeExpressionBuilder.cpp
index 48b807c2f841166371bf3d5d977216e0a081746d..1f73444e167a5524e6d4cb818ca76fe3885ece80 100644
--- a/src/language/ast/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeExpressionBuilder.cpp
@@ -19,6 +19,7 @@
 #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>
 #include <language/node_processor/WhileProcessor.hpp>
 
@@ -49,11 +50,9 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
       n.m_node_processor = std::make_unique<TupleToTinyVectorProcessor<ASTNodeExpressionListProcessor, 3>>(n);
       break;
     }
-      // LCOV_EXCL_START
     default: {
-      throw parse_error("unexpected error: invalid tuple size", n.begin());
+      n.m_node_processor = std::make_unique<TupleToVectorProcessor<ASTNodeExpressionListProcessor>>(n);
     }
-      // LCOV_EXCL_STOP
     }
   } else if (n.is_type<language::function_definition>()) {
     n.m_node_processor = std::make_unique<FakeProcessor>();
diff --git a/src/language/ast/ASTNodeNaturalConversionChecker.cpp b/src/language/ast/ASTNodeNaturalConversionChecker.cpp
index c32f77d3078a36ca29ed94166dae1be97b8e9993..8a6820d189ade9907e217d499b544e510d5f41b8 100644
--- a/src/language/ast/ASTNodeNaturalConversionChecker.cpp
+++ b/src/language/ast/ASTNodeNaturalConversionChecker.cpp
@@ -58,6 +58,15 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalExpressionConversion(const ASTNo
       this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
     }
     }
+  } else if (target_data_type == ASTNodeDataType::tuple_t) {
+    const ASTNodeDataType& target_content_type = target_data_type.contentType();
+    if (node.m_data_type == ASTNodeDataType::list_t) {
+      for (const auto& child : node.children) {
+        this->_checkIsNaturalExpressionConversion(*child, child->m_data_type, target_content_type);
+      }
+    } else {
+      this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
+    }
   } else {
     this->_checkIsNaturalTypeConversion(node, data_type, target_data_type);
   }
diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index 651516402260052ca69947415aaaea281af72f7e..176489a7f9d4e9520b1822108b0cee4f8e0ef493 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -26,24 +26,10 @@ struct GlaceScheme
 
   const MeshType& m_mesh;
 
-  GlaceScheme(const IMesh& mesh,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_0,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_1,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_2,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_3,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_4,
-              std::shared_ptr<const IBoundaryConditionDescriptor> boundary_5)
+  GlaceScheme(const IMesh& mesh, std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>> bc_descriptor_list)
     : m_mesh{dynamic_cast<const MeshType&>(mesh)}
   {
     MeshDataType mesh_data(m_mesh);
-    std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>> bc_descriptor_list;
-    if constexpr (Dimension == 1) {
-      bc_descriptor_list = {boundary_0, boundary_1};
-    } else if constexpr (Dimension == 2) {
-      bc_descriptor_list = {boundary_0, boundary_1, boundary_2, boundary_3};
-    } else if constexpr (Dimension == 3) {
-      bc_descriptor_list = {boundary_0, boundary_1, boundary_2, boundary_3, boundary_4, boundary_5};
-    }
 
     std::cout << "number of bc descr = " << bc_descriptor_list.size() << '\n';
 
@@ -177,50 +163,35 @@ SchemeModule::SchemeModule()
 
                             ));
 
-  this->_addBuiltinFunction("glace",
-                            std::make_shared<BuiltinFunctionEmbedder<
-                              void, std::shared_ptr<const IMesh>, std::shared_ptr<const IBoundaryConditionDescriptor>,
-                              std::shared_ptr<const IBoundaryConditionDescriptor>,
-                              std::shared_ptr<const IBoundaryConditionDescriptor>,
-                              std::shared_ptr<const IBoundaryConditionDescriptor>,
-                              std::shared_ptr<const IBoundaryConditionDescriptor>,
-                              std::shared_ptr<const IBoundaryConditionDescriptor>>>(
-                              std::function<void(std::shared_ptr<const IMesh>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>,
-                                                 std::shared_ptr<const IBoundaryConditionDescriptor>)>{
-
-                                [](std::shared_ptr<const IMesh> p_mesh,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_0,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_1,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_2,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_3,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_4,
-                                   std::shared_ptr<const IBoundaryConditionDescriptor> boundary_5) -> void {
-                                  switch (p_mesh->dimension()) {
-                                  case 1: {
-                                    GlaceScheme<1>{*p_mesh,    boundary_0, boundary_1, boundary_2,
-                                                   boundary_3, boundary_4, boundary_5};
-                                    break;
-                                  }
-                                  case 2: {
-                                    GlaceScheme<2>{*p_mesh,    boundary_0, boundary_1, boundary_2,
-                                                   boundary_3, boundary_4, boundary_5};
-                                    break;
-                                  }
-                                  case 3: {
-                                    GlaceScheme<3>{*p_mesh,    boundary_0, boundary_1, boundary_2,
-                                                   boundary_3, boundary_4, boundary_5};
-                                    break;
-                                  }
-                                  default: {
-                                    throw UnexpectedError("invalid mesh dimension");
-                                  }
-                                  }
-                                }}
-
-                              ));
+  this
+    ->_addBuiltinFunction("glace",
+                          std::make_shared<
+                            BuiltinFunctionEmbedder<void, std::shared_ptr<const IMesh>,
+                                                    std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>>>(
+                            std::function<void(std::shared_ptr<const IMesh>,
+                                               std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>)>{
+
+                              [](std::shared_ptr<const IMesh> p_mesh,
+                                 const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
+                                   bc_descriptor_list) -> void {
+                                switch (p_mesh->dimension()) {
+                                case 1: {
+                                  GlaceScheme<1>{*p_mesh, bc_descriptor_list};
+                                  break;
+                                }
+                                case 2: {
+                                  GlaceScheme<2>{*p_mesh, bc_descriptor_list};
+                                  break;
+                                }
+                                case 3: {
+                                  GlaceScheme<3>{*p_mesh, bc_descriptor_list};
+                                  break;
+                                }
+                                default: {
+                                  throw UnexpectedError("invalid mesh dimension");
+                                }
+                                }
+                              }
+
+                            }));
 }
diff --git a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
index e75992ee7e5670e948a9c064a76b0610f4b75cf4..ec37d74ee5c815695c229d3b93d5d0acdb79bc9d 100644
--- a/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
+++ b/src/language/node_processor/ASTNodeExpressionListProcessor.hpp
@@ -20,8 +20,12 @@ class ASTNodeExpressionListProcessor final : public INodeProcessor
       [&](auto&& v) {
         using ValueT = std::decay_t<decltype(v)>;
         if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) {
-          for (size_t i = 0; i < v.size(); ++i) {
-            _flattenResults(std::move(v[i]), list_values);
+          if (v.isFlattenable()) {
+            for (size_t i = 0; i < v.size(); ++i) {
+              _flattenResults(std::move(v[i]), list_values);
+            }
+          } else {
+            list_values.emplace_back(v);
           }
         } else {
           list_values.emplace_back(v);
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index bd0431e5da9424d9bb184d7976caa1c30be1770a..93d1396afc97da5eb39a24b7b25dc3ad6506b665 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -361,6 +361,52 @@ class AffectationFromListProcessor final : public INodeProcessor
   }
 };
 
+template <typename OperatorT>
+class AffectationFromListProcessor<OperatorT, EmbeddedData> final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+
+  DataVariant* m_lhs;
+
+ public:
+  DataVariant
+  execute(ExecutionPolicy& exec_policy)
+  {
+    AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
+
+    static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to vectors");
+
+    std::vector<EmbeddedData> tuple_value(children_values.size());
+    for (size_t i = 0; i < children_values.size(); ++i) {
+      std::visit(
+        [&](auto&& child_value) {
+          using T = std::decay_t<decltype(child_value)>;
+          if constexpr (std::is_same_v<T, EmbeddedData>) {
+            tuple_value[i] = child_value;
+          } else {
+            // LCOV_EXCL_START
+            throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin());
+            // LCOV_EXCL_STOP
+          }
+        },
+        children_values[i]);
+    }
+
+    *m_lhs = std::move(tuple_value);
+    return {};
+  }
+
+  AffectationFromListProcessor(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);
+
+    m_lhs = &i_symbol->attributes().value();
+  }
+};
+
 template <typename ValueT>
 class AffectationFromZeroProcessor final : public INodeProcessor
 {
diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp
index 8733211dcefd7f25deb31345c6b66800de971ec2..445bf7ea975aaa2409a2ee0691613a1b2911dadc 100644
--- a/src/language/node_processor/FunctionArgumentConverter.hpp
+++ b/src/language/node_processor/FunctionArgumentConverter.hpp
@@ -3,6 +3,7 @@
 
 #include <language/node_processor/ExecutionPolicy.hpp>
 #include <language/utils/DataVariant.hpp>
+#include <utils/Exceptions.hpp>
 
 class IFunctionArgumentConverter
 {
@@ -43,6 +44,40 @@ class FunctionArgumentConverter final : public IFunctionArgumentConverter
   FunctionArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
 };
 
+template <typename ExpectedValueType, typename ProvidedValueType>
+class FunctionListArgumentConverter final : public IFunctionArgumentConverter
+{
+ private:
+  size_t m_argument_id;
+
+ public:
+  DataVariant
+  convert(ExecutionPolicy& exec_policy, DataVariant&& value)
+  {
+    if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) {
+      std::visit(
+        [&](auto&& v) {
+          using Value_T = std::decay_t<decltype(v)>;
+          if constexpr (std::is_same_v<Value_T, AggregateDataVariant>) {
+            std::vector<ExpectedValueType> list_value;
+            for (size_t i = 0; i < v.size(); ++i) {
+              list_value.emplace_back(std::get<ProvidedValueType>(v[i]));
+            }
+            exec_policy.currentContext()[m_argument_id] = std::move(list_value);
+          } else {
+            throw UnexpectedError("unexpected value type");
+          }
+        },
+        value);
+    }
+    static_assert(std::is_same_v<ExpectedValueType, ProvidedValueType>, "conversion is not implemented");
+
+    return {};
+  }
+
+  FunctionListArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
+};
+
 class FunctionArgumentToFunctionSymbolIdConverter final : public IFunctionArgumentConverter
 {
  private:
diff --git a/src/language/node_processor/OStreamProcessor.hpp b/src/language/node_processor/OStreamProcessor.hpp
index bc5778bc02a64aa32083c81e8675b331384e361b..43d07364c645385f54080ae563eec41e47ae4c9d 100644
--- a/src/language/node_processor/OStreamProcessor.hpp
+++ b/src/language/node_processor/OStreamProcessor.hpp
@@ -21,6 +21,15 @@ class OStreamProcessor final : public INodeProcessor
           if constexpr (not std::is_same_v<std::monostate, ValueT>) {
             if constexpr (std::is_same_v<bool, ValueT>) {
               m_os << std::boolalpha << value;
+            } else if constexpr (std::is_same_v<std::vector<EmbeddedData>, ValueT>) {
+              m_os << '(';
+              if (value.size() > 0) {
+                m_os << value[0];
+              }
+              for (size_t i = 1; i < value.size(); ++i) {
+                m_os << ", " << value[i];
+              }
+              m_os << ')';
             } else {
               m_os << value;
             }
diff --git a/src/language/node_processor/TupleToVectorProcessor.hpp b/src/language/node_processor/TupleToVectorProcessor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4908bfaa58d582e441cd2500e16da8b5c685582b
--- /dev/null
+++ b/src/language/node_processor/TupleToVectorProcessor.hpp
@@ -0,0 +1,32 @@
+#ifndef TUPLE_TO_VECTOR_PROCESSOR_HPP
+#define TUPLE_TO_VECTOR_PROCESSOR_HPP
+
+#include <language/ast/ASTNode.hpp>
+#include <language/node_processor/INodeProcessor.hpp>
+
+template <typename TupleProcessorT>
+class TupleToVectorProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+
+  std::unique_ptr<TupleProcessorT> m_tuple_processor;
+
+ public:
+  DataVariant
+  execute(ExecutionPolicy& exec_policy)
+  {
+    AggregateDataVariant v = std::get<AggregateDataVariant>(m_tuple_processor->execute(exec_policy));
+
+    v.setIsFlattenable(false);
+    return DataVariant{std::move(v)};
+  }
+
+  TupleToVectorProcessor(ASTNode& node) : m_node{node}, m_tuple_processor{std::make_unique<TupleProcessorT>(node)} {}
+
+  TupleToVectorProcessor(ASTNode& node, std::unique_ptr<TupleProcessorT>&& tuple_processor)
+    : m_node{node}, m_tuple_processor{std::move(tuple_processor)}
+  {}
+};
+
+#endif   // TUPLE_TO_TINY_VECTOR_PROCESSOR_HPP
diff --git a/src/language/utils/ASTNodeDataTypeTraits.hpp b/src/language/utils/ASTNodeDataTypeTraits.hpp
index 44d40a771edc24c189331a491d3ac0652708f4fa..1956f2bc2bf5dc9e1d2c137bd877ef99bba1dadb 100644
--- a/src/language/utils/ASTNodeDataTypeTraits.hpp
+++ b/src/language/utils/ASTNodeDataTypeTraits.hpp
@@ -25,4 +25,8 @@ inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> = ASTNodeDataTy
 template <size_t N>
 inline ASTNodeDataType ast_node_data_type_from<TinyVector<N>> = {ASTNodeDataType::vector_t, N};
 
+template <typename T>
+inline ASTNodeDataType ast_node_data_type_from<std::vector<T>> =
+  ASTNodeDataType{ASTNodeDataType::tuple_t, ast_node_data_type_from<T>};
+
 #endif   // AST_NODE_DATA_TYPE_TRAITS_H
diff --git a/src/language/utils/BuiltinFunctionEmbedder.hpp b/src/language/utils/BuiltinFunctionEmbedder.hpp
index 78efd7d30f96f83b8ff65dced9d56d546fa5409d..4df112ac258f7aea6e673c4395d8aece63723502 100644
--- a/src/language/utils/BuiltinFunctionEmbedder.hpp
+++ b/src/language/utils/BuiltinFunctionEmbedder.hpp
@@ -61,6 +61,21 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
           } else {
             throw UnexpectedError("unexpected argument types while casting: expecting EmbeddedData");
           }
+        } else if constexpr (std::is_same_v<Vi_Type, std::vector<EmbeddedData>>) {
+          if constexpr (is_vector_v<Ti_Type>) {
+            using Ti_value_type = typename Ti_Type::value_type;
+            static_assert(is_shared_ptr_v<Ti_value_type>, "expecting shared_ptr");
+
+            using Ti_handeled_type = typename Ti_value_type::element_type;
+            std::get<I>(t).resize(v_i.size());
+            for (size_t j = 0; j < v_i.size(); ++j) {
+              auto& data_handler = dynamic_cast<const DataHandler<Ti_handeled_type>&>(v_i[j].get());
+              std::get<I>(t)[j]  = data_handler.data_ptr();
+            }
+          } else {
+            throw UnexpectedError("Unexpected argument types while casting " + demangle<Vi_Type>() + " -> " +
+                                  demangle<Ti_Type>());
+          }
         } else {
           throw UnexpectedError("Unexpected argument types while casting " + demangle<Vi_Type>() + " -> " +
                                 demangle<Ti_Type>());
diff --git a/src/language/utils/DataVariant.hpp b/src/language/utils/DataVariant.hpp
index 1ca8a869d0b63348a735e1f5aa0c43fa2a32d80a..0bb9a656cf5c78acf700fe9752aebb0b8a27ac17 100644
--- a/src/language/utils/DataVariant.hpp
+++ b/src/language/utils/DataVariant.hpp
@@ -19,6 +19,7 @@ using DataVariant = std::variant<std::monostate,
                                  double,
                                  std::string,
                                  EmbeddedData,
+                                 std::vector<EmbeddedData>,
                                  AggregateDataVariant,
                                  FunctionSymbolId,
                                  TinyVector<1>,
@@ -29,6 +30,7 @@ class AggregateDataVariant   // LCOV_EXCL_LINE
 {
  private:
   std::vector<DataVariant> m_data_vector;
+  bool m_is_flattenable = true;
 
   std::ostream&
   _printComponent(std::ostream& os, const DataVariant& value) const
@@ -37,6 +39,15 @@ class AggregateDataVariant   // LCOV_EXCL_LINE
       [&](auto&& v) {
         if constexpr (std::is_same_v<std::decay_t<decltype(v)>, std::monostate>) {
           os << " -- ";
+        } else if constexpr (std::is_same_v<std::decay_t<decltype(v)>, std::vector<EmbeddedData>>) {
+          os << '(';
+          if (v.size() > 0) {
+            os << v[0];
+          }
+          for (size_t i = 1; i < v.size(); ++i) {
+            os << ", " << v[i];
+          }
+          os << ')';
         } else {
           os << v;
         }
@@ -66,6 +77,18 @@ class AggregateDataVariant   // LCOV_EXCL_LINE
     return compound._print(os);
   }
 
+  void
+  setIsFlattenable(bool is_flattenable)
+  {
+    m_is_flattenable = is_flattenable;
+  }
+
+  bool
+  isFlattenable() const
+  {
+    return m_is_flattenable;
+  }
+
   PUGS_INLINE
   size_t
   size() const
@@ -90,7 +113,7 @@ class AggregateDataVariant   // LCOV_EXCL_LINE
   AggregateDataVariant& operator=(const AggregateDataVariant&) = default;
   AggregateDataVariant& operator=(AggregateDataVariant&&) = default;
 
-  AggregateDataVariant(std::vector<DataVariant>&& data_vector) : m_data_vector(data_vector) {}
+  AggregateDataVariant(std::vector<DataVariant>&& data_vector) : m_data_vector{data_vector} {}
 
   AggregateDataVariant(const AggregateDataVariant&) = default;
   AggregateDataVariant(AggregateDataVariant&&)      = default;
diff --git a/src/language/utils/SymbolTable.hpp b/src/language/utils/SymbolTable.hpp
index 957251371b7393caebf0ce445c528d57a962fc1f..75baa7e7303b2aa05bb0e6156932d5a00130bafc 100644
--- a/src/language/utils/SymbolTable.hpp
+++ b/src/language/utils/SymbolTable.hpp
@@ -92,12 +92,23 @@ class SymbolTable
         os << "type_name_id:";
       } else if (attributes.m_data_type == ASTNodeDataType::type_id_t) {
         os << attributes.m_data_type.typeName() << ':';
+      } else if (attributes.m_data_type == ASTNodeDataType::tuple_t) {
+        os << attributes.m_data_type.typeName() << ':';
       }
       std::visit(
-        [&](const auto& value) {
+        [&](auto&& value) {
           using T = std::decay_t<decltype(value)>;
           if constexpr (std::is_same_v<T, std::monostate>) {
             os << "--";
+          } else if constexpr (std::is_same_v<T, std::vector<EmbeddedData>>) {
+            os << '(';
+            if (value.size() > 0) {
+              os << value[0];
+            }
+            for (size_t i = 1; i < value.size(); ++i) {
+              os << ", " << value[i];
+            }
+            os << ')';
           } else {
             os << value;
           }
diff --git a/src/utils/PugsTraits.hpp b/src/utils/PugsTraits.hpp
index 60316bfe4239a8427840da5853db8bf3bab78cb4..b6e627200725198a1fb0c088b81779cf478c6521 100644
--- a/src/utils/PugsTraits.hpp
+++ b/src/utils/PugsTraits.hpp
@@ -4,6 +4,7 @@
 #include <cstddef>
 #include <memory>
 #include <type_traits>
+#include <vector>
 
 template <size_t N, typename T>
 class TinyVector;
@@ -38,4 +39,12 @@ inline constexpr bool is_shared_ptr_v = false;
 template <typename T>
 inline constexpr bool is_shared_ptr_v<std::shared_ptr<T>> = true;
 
+// Traits is_vector
+
+template <typename T>
+inline constexpr bool is_vector_v = false;
+
+template <typename T>
+inline constexpr bool is_vector_v<std::vector<T>> = true;
+
 #endif   // PUGS_TRAITS_HPP