diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index dfde6bb6ad0ce993f5367a468b583103ad4bd240..3e003392007b8ccc5250c14fed31a94e36d3be22 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -320,8 +320,9 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 
         ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
         if (image_domain_node.children.size() > 0) {
-          throw parse_error("compound data type is not implemented yet", image_domain_node.begin());
+          data_type = image_domain_node.m_data_type;
         } else {
+#warning check if it is really useful to compute exact types here?
           if (image_domain_node.is_type<language::B_set>()) {
             data_type = ASTNodeDataType::bool_t;
           } else if (image_domain_node.is_type<language::Z_set>()) {
diff --git a/src/language/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ASTNodeFunctionExpressionBuilder.cpp
index ebf00082e315227a23ab2a5f9f520d6a758cc398..8833958c6009246f8fbb3a0745bf2912786929b1 100644
--- a/src/language/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeFunctionExpressionBuilder.cpp
@@ -140,26 +140,30 @@ PUGS_INLINE
 std::unique_ptr<INodeProcessor>
 ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType expression_value_type,
                                                         const ASTNodeDataType return_value_type,
-                                                        ASTNode& node)
+                                                        ASTNode& node,
+                                                        ASTNode& function_component_expression,
+                                                        ASTNodeDataVariant& node_value)
 {
   auto get_function_processor_for_expression_value = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
     using ReturnT = std::decay_t<decltype(return_v)>;
     switch (expression_value_type) {
     case ASTNodeDataType::bool_t: {
-      return std::make_unique<FunctionExpressionProcessor<ReturnT, bool>>(node);
+      return std::make_unique<FunctionExpressionProcessor<ReturnT, bool>>(function_component_expression, node_value);
     }
     case ASTNodeDataType::unsigned_int_t: {
-      return std::make_unique<FunctionExpressionProcessor<ReturnT, uint64_t>>(node);
+      return std::make_unique<FunctionExpressionProcessor<ReturnT, uint64_t>>(function_component_expression,
+                                                                              node_value);
     }
     case ASTNodeDataType::int_t: {
-      return std::make_unique<FunctionExpressionProcessor<ReturnT, int64_t>>(node);
+      return std::make_unique<FunctionExpressionProcessor<ReturnT, int64_t>>(function_component_expression, node_value);
     }
     case ASTNodeDataType::double_t: {
-      return std::make_unique<FunctionExpressionProcessor<ReturnT, double>>(node);
+      return std::make_unique<FunctionExpressionProcessor<ReturnT, double>>(function_component_expression, node_value);
     }
     case ASTNodeDataType::string_t: {
       if constexpr (std::is_same_v<ReturnT, std::string>) {
-        return std::make_unique<FunctionExpressionProcessor<ReturnT, std::string>>(node);
+        return std::make_unique<FunctionExpressionProcessor<ReturnT, std::string>>(function_component_expression,
+                                                                                   node_value);
       } else {
         throw parse_error("invalid string conversion", std::vector{node.children[1]->begin()});
       }
@@ -211,21 +215,52 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
 
   FunctionDescriptor& function_descriptor = node.m_symbol_table->functionTable()[function_id];
 
-  if (function_descriptor.definitionNode().children[1]->is_type<language::expression_list>()) {
-    // LCOV_EXCL_START
-    throw parse_error("unexpected error: function expression list is not implemented yet",
-                      std::vector{function_descriptor.definitionNode().children[1]->begin()});
-    // LCOV_EXCL_STOP
-  }
-
   std::unique_ptr function_processor = std::make_unique<FunctionProcessor>();
 
   this->_buildArgumentProcessors(function_descriptor, node, *function_processor);
 
-  const ASTNodeDataType expression_value_type = function_descriptor.definitionNode().children[1]->m_data_type;
-  const ASTNodeDataType return_value_type     = node.m_data_type;
-  function_processor->addFunctionExpressionProcessor(
-    this->_getFunctionProcessor(expression_value_type, return_value_type, node));
+  ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1];
+  ASTNode& function_expression   = *function_descriptor.definitionNode().children[1];
+
+  auto add_component_expression = [&](ASTNode& expression_node, ASTNode& domain_node, ASTNodeDataVariant& value) {
+    ASTNodeDataType expression_value_type = expression_node.m_data_type;
+    ASTNodeDataType return_value_type     = ASTNodeDataType::undefined_t;
+
+    ASTNode& image_domain_node = domain_node;
+
+    if (image_domain_node.is_type<language::B_set>()) {
+      return_value_type = ASTNodeDataType::bool_t;
+    } else if (image_domain_node.is_type<language::Z_set>()) {
+      return_value_type = ASTNodeDataType::int_t;
+    } else if (image_domain_node.is_type<language::N_set>()) {
+      return_value_type = ASTNodeDataType::unsigned_int_t;
+    } else if (image_domain_node.is_type<language::R_set>()) {
+      return_value_type = ASTNodeDataType::double_t;
+    } else if (image_domain_node.is_type<language::string_type>()) {
+      return_value_type = ASTNodeDataType::string_t;
+    }
+
+    Assert(return_value_type != ASTNodeDataType::undefined_t);
+
+    function_processor->addFunctionExpressionProcessor(
+      this->_getFunctionProcessor(expression_value_type, return_value_type, node, expression_node, value));
+  };
+
+  if (function_expression.is_type<language::expression_list>()) {
+    Assert(function_image_domain.is_type<language::type_expression>());
+    ASTNode& image_domain_node = function_image_domain;
+    const size_t& nb_component = function_expression.children.size();
+
+    AggregateDataVariant aggregate_value(nb_component);
+
+    for (size_t i = 0; i < function_expression.children.size(); ++i) {
+      add_component_expression(*function_expression.children[i], *image_domain_node.children[i], aggregate_value[i]);
+    }
+
+    node.m_value = std::move(aggregate_value);
+  } else {
+    add_component_expression(function_expression, function_image_domain, node.m_value);
+  }
 
   node.m_node_processor = std::move(function_processor);
 }
diff --git a/src/language/ASTNodeFunctionExpressionBuilder.hpp b/src/language/ASTNodeFunctionExpressionBuilder.hpp
index 4bcd172b9a46b8300d0e14c6eb1db4b182564ea1..f8f69e9c6c9f3363db9d9e3c57fdf0c8d6bbc521 100644
--- a/src/language/ASTNodeFunctionExpressionBuilder.hpp
+++ b/src/language/ASTNodeFunctionExpressionBuilder.hpp
@@ -27,7 +27,9 @@ class ASTNodeFunctionExpressionBuilder
   PUGS_INLINE
   std::unique_ptr<INodeProcessor> _getFunctionProcessor(const ASTNodeDataType expression_value_type,
                                                         const ASTNodeDataType return_value_type,
-                                                        ASTNode& node);
+                                                        ASTNode& node,
+                                                        ASTNode& function_component_expression,
+                                                        ASTNodeDataVariant& node_value);
 
  public:
   ASTNodeFunctionExpressionBuilder(ASTNode& node);
diff --git a/src/language/node_processor/FunctionProcessor.hpp b/src/language/node_processor/FunctionProcessor.hpp
index a4e803b14093b55fdf9259f2be53c4555ac3bfe8..ccc7ce560b9ca09213dd4a8aebc796dfea66442b 100644
--- a/src/language/node_processor/FunctionProcessor.hpp
+++ b/src/language/node_processor/FunctionProcessor.hpp
@@ -39,7 +39,7 @@ template <typename ReturnType, typename ExpressionValueType>
 class FunctionExpressionProcessor final : public INodeProcessor
 {
  private:
-  ASTNode& m_node;
+  ASTNodeDataVariant& m_value;
   ASTNode& m_function_expression;
 
  public:
@@ -49,23 +49,16 @@ class FunctionExpressionProcessor final : public INodeProcessor
     m_function_expression.execute(exec_policy);
 
     if constexpr (std::is_same_v<ReturnType, ExpressionValueType>) {
-      m_node.m_value = m_function_expression.m_value;
+      m_value = m_function_expression.m_value;
     } else if constexpr (std::is_same_v<ReturnType, std::string>) {
-      m_node.m_value = std::to_string(std::get<ExpressionValueType>(m_function_expression.m_value));
+      m_value = std::to_string(std::get<ExpressionValueType>(m_function_expression.m_value));
     } else {
-      m_node.m_value = static_cast<ReturnType>(std::get<ExpressionValueType>(m_function_expression.m_value));
+      m_value = static_cast<ReturnType>(std::get<ExpressionValueType>(m_function_expression.m_value));
     }
   }
 
-  FunctionExpressionProcessor(ASTNode& node)
-    : m_node{node}, m_function_expression{[&]() -> ASTNode& {
-        auto [i_symbol, found] = m_node.m_symbol_table->find(m_node.children[0]->string(), m_node.begin());
-        Assert(found);
-        uint64_t function_id = std::get<uint64_t>(i_symbol->attributes().value());
-
-        FunctionDescriptor& function_descriptor = m_node.m_symbol_table->functionTable()[function_id];
-        return *function_descriptor.definitionNode().children[1];
-      }()}
+  FunctionExpressionProcessor(ASTNode& function_component_expression, ASTNodeDataVariant& value)
+    : m_value{value}, m_function_expression{function_component_expression}
   {}
 };