Skip to content
Snippets Groups Projects
Select Git revision
  • f25b9639bbe06abde2e9b00fb5ebd40786eb26bf
  • develop default protected
  • feature/advection
  • feature/composite-scheme-other-fluxes
  • origin/stage/bouguettaia
  • save_clemence
  • feature/local-dt-fsi
  • feature/variational-hydro
  • feature/gmsh-reader
  • feature/reconstruction
  • feature/kinetic-schemes
  • feature/composite-scheme-sources
  • feature/serraille
  • feature/composite-scheme
  • hyperplastic
  • feature/polynomials
  • feature/gks
  • feature/implicit-solver-o2
  • feature/coupling_module
  • feature/implicit-solver
  • feature/merge-local-dt-fsi
  • v0.5.0 protected
  • v0.4.1 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0 protected
  • Kidder
  • v0.0.4 protected
  • v0.0.3 protected
  • v0.0.2 protected
  • v0 protected
  • v0.0.1 protected
33 results

ConnectivityComputer.cpp

Blame
  • ASTNodeFunctionExpressionBuilder.cpp 27.95 KiB
    #include <language/ast/ASTNodeFunctionExpressionBuilder.hpp>
    
    #include <language/PEGGrammar.hpp>
    #include <language/ast/ASTNodeDataTypeFlattener.hpp>
    #include <language/node_processor/FunctionProcessor.hpp>
    #include <language/node_processor/TupleToTinyMatrixProcessor.hpp>
    #include <language/node_processor/TupleToTinyVectorProcessor.hpp>
    #include <language/utils/ASTNodeNaturalConversionChecker.hpp>
    #include <language/utils/FunctionTable.hpp>
    #include <language/utils/SymbolTable.hpp>
    #include <utils/Exceptions.hpp>
    
    template <typename SymbolType>
    std::unique_ptr<IFunctionArgumentConverter>
    ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_symbol,
                                                            const ASTNodeSubDataType& node_sub_data_type)
    {
      const size_t parameter_id = std::get<size_t>(parameter_symbol.attributes().value());
    
      ASTNodeNaturalConversionChecker{node_sub_data_type, parameter_symbol.attributes().dataType()};
    
      auto get_function_argument_converter_for =
        [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> {
        using ParameterT = std::decay_t<decltype(parameter_v)>;
        switch (node_sub_data_type.m_data_type) {
        case ASTNodeDataType::bool_t: {
          return std::make_unique<FunctionArgumentConverter<ParameterT, bool>>(parameter_id);
        }
        case ASTNodeDataType::unsigned_int_t: {
          return std::make_unique<FunctionArgumentConverter<ParameterT, uint64_t>>(parameter_id);
        }
        case ASTNodeDataType::int_t: {
          return std::make_unique<FunctionArgumentConverter<ParameterT, int64_t>>(parameter_id);
        }
        case ASTNodeDataType::double_t: {
          return std::make_unique<FunctionArgumentConverter<ParameterT, double>>(parameter_id);
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: invalid argument type",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_argument_converter_for_type_id =
        [&](const std::string& type_id_name) -> std::unique_ptr<IFunctionArgumentConverter> {
        switch (node_sub_data_type.m_data_type) {
        case ASTNodeDataType::type_id_t: {
          if (node_sub_data_type.m_data_type.nameOfTypeId() == type_id_name) {
            return std::make_unique<FunctionArgumentConverter<EmbeddedData, EmbeddedData>>(parameter_id);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid argument type",
                             std::vector{node_sub_data_type.m_parent_node.begin()});
            // LCOV_EXCL_STOP
          }
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: invalid argument type",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_argument_converter_for_vector =
        [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> {
        using ParameterT = std::decay_t<decltype(parameter_v)>;
        switch (node_sub_data_type.m_data_type) {
        case ASTNodeDataType::vector_t: {
          if (node_sub_data_type.m_data_type.dimension() == parameter_v.dimension()) {
            return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid argument dimension",
                             std::vector{node_sub_data_type.m_parent_node.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::list_t: {
          if (node_sub_data_type.m_parent_node.children.size() == parameter_v.dimension()) {
            return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ParameterT>>(parameter_id);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid argument dimension",
                             std::vector{node_sub_data_type.m_parent_node.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::int_t: {
          if (node_sub_data_type.m_parent_node.is_type<language::integer>()) {
            if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) {
              return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ZeroType>>(parameter_id);
            }
          }
          [[fallthrough]];
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: invalid argument type",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_argument_converter_for_matrix =
        [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> {
        using ParameterT = std::decay_t<decltype(parameter_v)>;
        switch (node_sub_data_type.m_data_type) {
        case ASTNodeDataType::matrix_t: {
          if ((node_sub_data_type.m_data_type.numberOfRows() == parameter_v.numberOfRows()) and
              (node_sub_data_type.m_data_type.numberOfColumns() == parameter_v.numberOfColumns())) {
            return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, ParameterT>>(parameter_id);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid argument dimension",
                             std::vector{node_sub_data_type.m_parent_node.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::list_t: {
          if (node_sub_data_type.m_parent_node.children.size() == parameter_v.dimension()) {
            return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, ParameterT>>(parameter_id);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid argument dimension",
                             std::vector{node_sub_data_type.m_parent_node.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::int_t: {
          if (node_sub_data_type.m_parent_node.is_type<language::integer>()) {
            if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) {
              return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, ZeroType>>(parameter_id);
            }
          }
          [[fallthrough]];
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: invalid argument type",
                           std::vector{node_sub_data_type.m_parent_node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_argument_converter_for_string = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
        return std::make_unique<FunctionArgumentToStringConverter>(parameter_id);
      };
    
      auto get_function_argument_converter_for_parameter_type = [&]() {
        switch (parameter_symbol.attributes().dataType()) {
        case ASTNodeDataType::bool_t: {
          return get_function_argument_converter_for(bool{});
        }
        case ASTNodeDataType::unsigned_int_t: {
          return get_function_argument_converter_for(uint64_t{});
        }
        case ASTNodeDataType::int_t: {
          return get_function_argument_converter_for(int64_t{});
        }
        case ASTNodeDataType::double_t: {
          return get_function_argument_converter_for(double{});
        }
        case ASTNodeDataType::string_t: {
          return get_function_argument_converter_for_string();
        }
        case ASTNodeDataType::vector_t: {
          switch (parameter_symbol.attributes().dataType().dimension()) {
          case 1: {
            return get_function_argument_converter_for_vector(TinyVector<1>{});
          }
          case 2: {
            return get_function_argument_converter_for_vector(TinyVector<2>{});
          }
          case 3: {
            return get_function_argument_converter_for_vector(TinyVector<3>{});
          }
          }
          // LCOV_EXCL_START
          throw ParseError("unexpected error: undefined parameter type", std::vector{m_node.begin()});
          // LCOV_EXCL_STOP
        }
        case ASTNodeDataType::matrix_t: {
          Assert(parameter_symbol.attributes().dataType().numberOfRows() ==
                 parameter_symbol.attributes().dataType().numberOfColumns());
    
          switch (parameter_symbol.attributes().dataType().numberOfRows()) {
          case 1: {
            return get_function_argument_converter_for_matrix(TinyMatrix<1>{});
          }
          case 2: {
            return get_function_argument_converter_for_matrix(TinyMatrix<2>{});
          }
          case 3: {
            return get_function_argument_converter_for_matrix(TinyMatrix<3>{});
          }
          }
          // LCOV_EXCL_START
          throw ParseError("unexpected error: undefined parameter type", std::vector{m_node.begin()});
          // LCOV_EXCL_STOP
        }
        case ASTNodeDataType::type_id_t: {
          return get_function_argument_converter_for_type_id(parameter_symbol.attributes().dataType().nameOfTypeId());
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined parameter type", std::vector{m_node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      return get_function_argument_converter_for_parameter_type();
    }
    
    void
    ASTNodeFunctionExpressionBuilder::_storeArgumentConverter(ASTNode& parameter_variable,
                                                              ASTNodeSubDataType& node_sub_data_type,
                                                              FunctionProcessor& function_processor)
    {
      Assert(parameter_variable.is_type<language::name>(), "unexpected parameter type!");
    
      auto [i_parameter_symbol, found] =
        parameter_variable.m_symbol_table->find(parameter_variable.string(), parameter_variable.begin());
      Assert(found);
    
      function_processor.addArgumentConverter(this->_getArgumentConverter(*i_parameter_symbol, node_sub_data_type));
    }
    
    std::unique_ptr<FunctionProcessor>
    ASTNodeFunctionExpressionBuilder::_buildArgumentConverter(FunctionDescriptor& function_descriptor, ASTNode& node)
    {
      ASTNode& function_expression = *function_descriptor.definitionNode().children[1];
    
      Assert(function_expression.m_symbol_table->hasContext());
      const SymbolTable::Context& context = function_expression.m_symbol_table->context();
    
      const ASTNode& definition_node = function_descriptor.definitionNode();
      ASTNode& parameter_variables   = *definition_node.children[0];
    
      ASTNode& argument_nodes = *node.children[1];
    
      std::unique_ptr function_processor = std::make_unique<FunctionProcessor>(argument_nodes, context);
    
      ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list;
      ASTNodeDataTypeFlattener{argument_nodes, flattened_datatype_list};
    
      const size_t arguments_number = flattened_datatype_list.size();
    
      const size_t parameters_number =
        parameter_variables.is_type<language::name_list>() ? parameter_variables.children.size() : 1;
    
      if (arguments_number != parameters_number) {
        std::ostringstream error_message;
        error_message << "bad number of arguments: expecting " << rang::fgB::yellow << parameters_number
                      << rang::style::reset << rang::style::bold << ", provided " << rang::fgB::yellow << arguments_number
                      << rang::style::reset;
        throw ParseError(error_message.str(), argument_nodes.begin());
      }
    
      if (arguments_number > 1) {
        for (size_t i = 0; i < arguments_number; ++i) {
          ASTNode& parameter_variable = *parameter_variables.children[i];
          this->_storeArgumentConverter(parameter_variable, flattened_datatype_list[i], *function_processor);
        }
      } else {
        this->_storeArgumentConverter(parameter_variables, flattened_datatype_list[0], *function_processor);
      }
    
      return function_processor;
    }
    
    std::unique_ptr<INodeProcessor>
    ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType& return_value_type,
                                                            ASTNode& node,
                                                            ASTNode& function_component_expression)
    {
      auto get_function_processor_for_expression_value = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
        using ReturnT = std::decay_t<decltype(return_v)>;
        switch (function_component_expression.m_data_type) {
        case ASTNodeDataType::bool_t: {
          return std::make_unique<FunctionExpressionProcessor<ReturnT, bool>>(function_component_expression);
        }
        case ASTNodeDataType::unsigned_int_t: {
          return std::make_unique<FunctionExpressionProcessor<ReturnT, uint64_t>>(function_component_expression);
        }
        case ASTNodeDataType::int_t: {
          return std::make_unique<FunctionExpressionProcessor<ReturnT, int64_t>>(function_component_expression);
        }
        case ASTNodeDataType::double_t: {
          return std::make_unique<FunctionExpressionProcessor<ReturnT, double>>(function_component_expression);
        }
        case ASTNodeDataType::string_t: {
          if constexpr (std::is_same_v<ReturnT, std::string>) {
            return std::make_unique<FunctionExpressionProcessor<ReturnT, std::string>>(function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid string conversion", std::vector{node.children[1]->begin()});
            // LCOV_EXCL_STOP
          }
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{node.children[1]->begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_processor_for_expression_vector = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
        using ReturnT = std::decay_t<decltype(return_v)>;
        switch (function_component_expression.m_data_type) {
        case ASTNodeDataType::vector_t: {
          if (function_component_expression.m_data_type.dimension() == return_v.dimension()) {
            return std::make_unique<FunctionExpressionProcessor<ReturnT, ReturnT>>(function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid dimension for returned vector",
                             std::vector{function_component_expression.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::list_t: {
          if (function_component_expression.children.size() == return_v.dimension()) {
            return std::make_unique<FunctionExpressionProcessor<ReturnT, AggregateDataVariant>>(
              function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid dimension for returned vector",
                             std::vector{function_component_expression.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::int_t: {
          if (function_component_expression.is_type<language::integer>()) {
            if (std::stoi(function_component_expression.string()) == 0) {
              return std::make_unique<FunctionExpressionProcessor<ReturnT, ZeroType>>(function_component_expression);
            }
          }
          // LCOV_EXCL_START
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{function_component_expression.begin()});
          // LCOV_EXCL_STOP
        }
        // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{function_component_expression.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_processor_for_expression_matrix = [&](const auto& return_v) -> std::unique_ptr<INodeProcessor> {
        using ReturnT = std::decay_t<decltype(return_v)>;
        switch (function_component_expression.m_data_type) {
        case ASTNodeDataType::matrix_t: {
          if ((function_component_expression.m_data_type.numberOfRows() == return_v.numberOfRows()) and
              (function_component_expression.m_data_type.numberOfColumns() == return_v.numberOfColumns())) {
            return std::make_unique<FunctionExpressionProcessor<ReturnT, ReturnT>>(function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid dimension for returned vector",
                             std::vector{function_component_expression.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::list_t: {
          if (function_component_expression.children.size() == return_v.dimension()) {
            return std::make_unique<FunctionExpressionProcessor<ReturnT, AggregateDataVariant>>(
              function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: invalid dimension for returned vector",
                             std::vector{function_component_expression.begin()});
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::int_t: {
          if (function_component_expression.is_type<language::integer>()) {
            if (std::stoi(function_component_expression.string()) == 0) {
              return std::make_unique<FunctionExpressionProcessor<ReturnT, ZeroType>>(function_component_expression);
            }
          }
          // LCOV_EXCL_START
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{function_component_expression.begin()});
          // LCOV_EXCL_STOP
        }
        // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{function_component_expression.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_processor_for_expression_type_id =
        [&](const std::string& type_id_name) -> std::unique_ptr<INodeProcessor> {
        switch (function_component_expression.m_data_type) {
        case ASTNodeDataType::type_id_t: {
          if (function_component_expression.m_data_type.nameOfTypeId() == type_id_name) {
            return std::make_unique<FunctionExpressionProcessor<EmbeddedData, EmbeddedData>>(function_component_expression);
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: undefined expression value type for function",
                             std::vector{node.children[1]->begin()});
            // LCOV_EXCL_STOP
          }
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined expression value type for function",
                           std::vector{node.children[1]->begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      auto get_function_processor_for_value = [&]() {
        switch (return_value_type) {
        case ASTNodeDataType::bool_t: {
          return get_function_processor_for_expression_value(bool{});
        }
        case ASTNodeDataType::unsigned_int_t: {
          return get_function_processor_for_expression_value(uint64_t{});
        }
        case ASTNodeDataType::int_t: {
          return get_function_processor_for_expression_value(int64_t{});
        }
        case ASTNodeDataType::double_t: {
          return get_function_processor_for_expression_value(double{});
        }
        case ASTNodeDataType::vector_t: {
          switch (return_value_type.dimension()) {
          case 1: {
            if (function_component_expression.m_data_type == ASTNodeDataType::vector_t) {
              return get_function_processor_for_expression_vector(TinyVector<1>{});
            } else {
              return get_function_processor_for_expression_value(TinyVector<1>{});
            }
          }
          case 2: {
            return get_function_processor_for_expression_vector(TinyVector<2>{});
          }
          case 3: {
            return get_function_processor_for_expression_vector(TinyVector<3>{});
          }
            // LCOV_EXCL_START
          default: {
            throw ParseError("unexpected error: invalid dimension in returned type", std::vector{node.begin()});
          }
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::matrix_t: {
          Assert(return_value_type.numberOfRows() == return_value_type.numberOfColumns());
    
          switch (return_value_type.numberOfRows()) {
          case 1: {
            if (function_component_expression.m_data_type == ASTNodeDataType::matrix_t) {
              return get_function_processor_for_expression_matrix(TinyMatrix<1>{});
            } else {
              return get_function_processor_for_expression_value(TinyMatrix<1>{});
            }
          }
          case 2: {
            return get_function_processor_for_expression_matrix(TinyMatrix<2>{});
          }
          case 3: {
            return get_function_processor_for_expression_matrix(TinyMatrix<3>{});
          }
            // LCOV_EXCL_START
          default: {
            throw ParseError("unexpected error: invalid dimension in returned type", std::vector{node.begin()});
          }
            // LCOV_EXCL_STOP
          }
        }
        case ASTNodeDataType::string_t: {
          return get_function_processor_for_expression_value(std::string{});
        }
        case ASTNodeDataType::type_id_t: {
          return get_function_processor_for_expression_type_id(return_value_type.nameOfTypeId());
        }
          // LCOV_EXCL_START
        default: {
          throw ParseError("unexpected error: undefined return type for function", std::vector{node.begin()});
        }
          // LCOV_EXCL_STOP
        }
      };
    
      return get_function_processor_for_value();
    }
    
    ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node) : m_node(node)
    {
      auto [i_function_symbol, found] = node.m_symbol_table->find(node.children[0]->string(), node.begin());
      Assert(found);
      Assert(i_function_symbol->attributes().dataType() == ASTNodeDataType::function_t);
    
      uint64_t function_id = std::get<uint64_t>(i_function_symbol->attributes().value());
    
      FunctionDescriptor& function_descriptor = node.m_symbol_table->functionTable()[function_id];
    
      std::unique_ptr function_processor = this->_buildArgumentConverter(function_descriptor, node);
    
      auto add_component_expression = [&](ASTNode& expression_node, const ASTNode& image_domain_node) {
        const ASTNodeDataType return_value_type = [&] {
          switch (image_domain_node.m_data_type) {
          case ASTNodeDataType::typename_t: {
            return image_domain_node.m_data_type.contentType();
          }
          case ASTNodeDataType::type_id_t: {
            return ASTNodeDataType::build<ASTNodeDataType::type_id_t>(image_domain_node.m_data_type.nameOfTypeId());
          }
          default: {
            throw UnexpectedError("invalid function return type");
          }
          }
        }();
    
        ASTNodeNaturalConversionChecker<AllowRToR1Conversion>{expression_node, return_value_type};
    
        function_processor->addFunctionExpressionProcessor(
          this->_getFunctionProcessor(return_value_type, node, expression_node));
      };
    
      ASTNode& function_image_domain = *function_descriptor.domainMappingNode().children[1];
      ASTNode& function_expression   = *function_descriptor.definitionNode().children[1];
    
      const ASTNodeDataType function_return_type = [&] {
        switch (function_image_domain.m_data_type) {
        case ASTNodeDataType::typename_t: {
          return function_image_domain.m_data_type.contentType();
        }
        case ASTNodeDataType::type_id_t: {
          return ASTNodeDataType::build<ASTNodeDataType::type_id_t>(function_image_domain.m_data_type.nameOfTypeId());
        }
        default: {
          throw UnexpectedError("invalid function return type");
        }
        }
      }();
    
      if (function_image_domain.is_type<language::vector_type>()) {
        ASTNodeDataType vector_type = getVectorDataType(function_image_domain);
    
        ASTNodeNaturalConversionChecker<AllowRToR1Conversion>{function_expression, vector_type};
    
        if (function_expression.is_type<language::expression_list>()) {
          Assert(vector_type.dimension() == function_expression.children.size());
    
          for (size_t i = 0; i < vector_type.dimension(); ++i) {
            function_processor->addFunctionExpressionProcessor(
              this->_getFunctionProcessor(ASTNodeDataType::build<ASTNodeDataType::double_t>(), node,
                                          *function_expression.children[i]));
          }
    
          switch (vector_type.dimension()) {
          case 2: {
            node.m_node_processor =
              std::make_unique<TupleToTinyVectorProcessor<FunctionProcessor, 2>>(node, std::move(function_processor));
            break;
          }
          case 3: {
            node.m_node_processor =
              std::make_unique<TupleToTinyVectorProcessor<FunctionProcessor, 3>>(node, std::move(function_processor));
            break;
          }
            // LCOV_EXCL_START
          default: {
            throw ParseError("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
          }
            // LCOV_EXCL_STOP
          }
        } else if (function_expression.is_type<language::integer>()) {
          if (std::stoi(function_expression.string()) == 0) {
            switch (vector_type.dimension()) {
            case 1: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyVector<1>, ZeroType>>(function_expression);
              break;
            }
            case 2: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyVector<2>, ZeroType>>(function_expression);
              break;
            }
            case 3: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyVector<3>, ZeroType>>(function_expression);
              break;
            }
              // LCOV_EXCL_START
            default: {
              throw ParseError("unexpected error: invalid vector_t dimension", std::vector{node.begin()});
            }
              // LCOV_EXCL_STOP
            }
          } else {
            // LCOV_EXCL_START
            throw ParseError("unexpected error: expecting 0", std::vector{function_expression.begin()});
            // LCOV_EXCL_STOP
          }
        } else {
          function_processor->addFunctionExpressionProcessor(
            this->_getFunctionProcessor(vector_type, node, function_expression));
    
          node.m_node_processor = std::move(function_processor);
        }
    
      } else if (function_image_domain.is_type<language::matrix_type>()) {
        ASTNodeDataType matrix_type = getMatrixDataType(function_image_domain);
    
        ASTNodeNaturalConversionChecker<AllowRToR1Conversion>{function_expression, matrix_type};
    
        if (function_expression.is_type<language::expression_list>()) {
          Assert(matrix_type.numberOfRows() * matrix_type.numberOfColumns() == function_expression.children.size());
    
          for (size_t i = 0; i < matrix_type.numberOfRows() * matrix_type.numberOfColumns(); ++i) {
            function_processor->addFunctionExpressionProcessor(
              this->_getFunctionProcessor(ASTNodeDataType::build<ASTNodeDataType::double_t>(), node,
                                          *function_expression.children[i]));
          }
    
          switch (matrix_type.numberOfRows()) {
          case 2: {
            node.m_node_processor =
              std::make_unique<TupleToTinyMatrixProcessor<FunctionProcessor, 2>>(node, std::move(function_processor));
            break;
          }
          case 3: {
            node.m_node_processor =
              std::make_unique<TupleToTinyMatrixProcessor<FunctionProcessor, 3>>(node, std::move(function_processor));
            break;
          }
            // LCOV_EXCL_START
          default: {
            throw ParseError("unexpected error: invalid matrix_t dimensions", std::vector{node.begin()});
          }
            // LCOV_EXCL_STOP
          }
        } else if (function_expression.is_type<language::integer>()) {
          if (std::stoi(function_expression.string()) == 0) {
            switch (matrix_type.numberOfRows()) {
            case 1: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyMatrix<1>, ZeroType>>(function_expression);
              break;
            }
            case 2: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyMatrix<2>, ZeroType>>(function_expression);
              break;
            }
            case 3: {
              node.m_node_processor =
                std::make_unique<FunctionExpressionProcessor<TinyMatrix<3>, ZeroType>>(function_expression);
              break;
            }
              // LCOV_EXCL_START
            default: {
              throw UnexpectedError("invalid matrix dimensions");
            }
              // LCOV_EXCL_STOP
            }
          } else {
            // LCOV_EXCL_START
            throw UnexpectedError("expecting 0");
            // LCOV_EXCL_STOP
          }
        } else {
          function_processor->addFunctionExpressionProcessor(
            this->_getFunctionProcessor(matrix_type, node, function_expression));
    
          node.m_node_processor = std::move(function_processor);
        }
    
      } else {
        if (function_expression.is_type<language::expression_list>()) {
          ASTNode& image_domain_node = function_image_domain;
    
          for (size_t i = 0; i < function_expression.children.size(); ++i) {
            add_component_expression(*function_expression.children[i], *image_domain_node.children[i]);
          }
        } else {
          add_component_expression(function_expression, function_image_domain);
        }
    
        node.m_node_processor = std::move(function_processor);
      }
    }