diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 70d8e3b3ac10456eb28c0036fdfa31eb1630bcab..54b0970eff20190d4b57d2adfc596ba71cf174d0 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -231,9 +231,6 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
       case ASTNodeDataType::double_t: {
         return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, double>>(argument_number);
-      }
-      case ASTNodeDataType::function_t: {
-        return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, FunctionSymbolId>>(argument_number);
       }
         // LCOV_EXCL_START
       default: {
@@ -513,11 +510,13 @@ ASTNodeBuiltinFunctionExpressionBuilder::_buildArgumentProcessors(
   const size_t parameters_number = parameter_type_list.size();
 
   if (arguments_number != parameters_number) {
+    // LCOV_EXCL_START
     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());
+    throw UnexpectedError(error_message.str());
+    // LCOV_EXCL_STOP
   }
 
   for (size_t i = 0; i < arguments_number; ++i) {
diff --git a/src/language/ast/ASTNodeDataTypeFlattener.cpp b/src/language/ast/ASTNodeDataTypeFlattener.cpp
index 7212d6b001a12de45e6b81e2955a80fe71cd07b4..9cc1fa483196815ed97b3b8134797b79aeea770e 100644
--- a/src/language/ast/ASTNodeDataTypeFlattener.cpp
+++ b/src/language/ast/ASTNodeDataTypeFlattener.cpp
@@ -40,9 +40,11 @@ ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataT
               {ASTNodeDataType::build<ASTNodeDataType::type_id_t>(image_sub_domain->m_data_type.nameOfTypeId()), node});
             break;
           }
+            // LCOV_EXCL_START
           default: {
             throw UnexpectedError("invalid data type");
           }
+            // LCOV_EXCL_STOP
           }
         }
         break;
diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
index 6c1db0335b2f46a8410baed7f02e59efa6ae49c8..6a91a15d13978b423daa563c1b668c5fe0f93489 100644
--- a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
@@ -523,9 +523,11 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
       case ASTNodeDataType::type_id_t: {
         return ASTNodeDataType::build<ASTNodeDataType::type_id_t>(image_domain_node.m_data_type.nameOfTypeId());
       }
+        // LCOV_EXCL_START
       default: {
         throw UnexpectedError("invalid function return type");
       }
+        // LCOV_EXCL_STOP
       }
     }();
 
@@ -546,9 +548,11 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
     case ASTNodeDataType::type_id_t: {
       return ASTNodeDataType::build<ASTNodeDataType::type_id_t>(function_image_domain.m_data_type.nameOfTypeId());
     }
+      // LCOV_EXCL_START
     default: {
       throw UnexpectedError("invalid function return type");
     }
+      // LCOV_EXCL_STOP
     }
   }();
 
diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
index dc438e61f5aa8ea2ad0f4d3d2b0879c0e2ec0f0e..edec0c149615f28a35256afc62f3ceef3182c3e1 100644
--- a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp
@@ -133,7 +133,8 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
         // LCOV_EXCL_STOP
       }
     } else {
-      throw ParseError("unexpected error: undefined operator type for string affectation", std::vector{m_node.begin()});
+      throw ParseError("unexpected error: undefined operator type for embedded data affectation",
+                       std::vector{m_node.begin()});
     }
   };
 
@@ -286,11 +287,11 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
   if (optional_processor_builder.has_value()) {
     add_affectation_processor_for_value(value_node.m_data_type, rhs_node_sub_data_type);
   } else {
+    // LCOV_EXCL_START
     std::ostringstream error_message;
-    error_message << "undefined affectation type: ";
-    error_message << rang::fgB::red << affectation_name << rang::fg::reset;
-
-    throw ParseError(error_message.str(), std::vector{m_node.children[0]->begin()});
+    error_message << "undefined affectation type: " << rang::fgB::red << affectation_name << rang::fg::reset;
+    throw UnexpectedError(error_message.str());
+    // LCOV_EXCL_STOP
   }
 }
 
diff --git a/src/language/utils/BuiltinFunctionEmbedderUtils.cpp b/src/language/utils/BuiltinFunctionEmbedderUtils.cpp
index 1c7723ff1c3f2b510db742dd9b647f643b83d303..ba6658ff7b5dc901182c62f7a07c0018ed94bd5a 100644
--- a/src/language/utils/BuiltinFunctionEmbedderUtils.cpp
+++ b/src/language/utils/BuiltinFunctionEmbedderUtils.cpp
@@ -28,8 +28,9 @@ getBuiltinFunctionEmbedder(ASTNode& n)
 
         FunctionDescriptor& function_descriptor = argument_node.m_symbol_table->functionTable()[function_id];
         ASTNode& function_image_domain          = *function_descriptor.domainMappingNode().children[1];
-
-        if (function_image_domain.children.size() > 0) {
+        if (not(function_image_domain.is_type<language::vector_type>() or
+                function_image_domain.is_type<language::matrix_type>()) and
+            function_image_domain.children.size() > 0) {
           for (size_t i = 0; i < function_image_domain.children.size(); ++i) {
             arg_type_list.push_back(function_image_domain.children[i]->m_data_type);
           }
@@ -43,9 +44,11 @@ getBuiltinFunctionEmbedder(ASTNode& n)
         arg_type_list.push_back(builtin_function->getReturnDataType());
         break;
       }
+        // LCOV_EXCL_START
       default: {
         throw UnexpectedError("unexpected function type");
       }
+        // LCOV_EXCL_STOP
       }
     } else {
       arg_type_list.push_back(argument_node.m_data_type);
diff --git a/src/language/utils/SymbolTable.hpp b/src/language/utils/SymbolTable.hpp
index 7321994564a8810b10e81d60503a55226abf0c56..ca674a1bb7e8053b1f2401b066d0a5c38c6f8151 100644
--- a/src/language/utils/SymbolTable.hpp
+++ b/src/language/utils/SymbolTable.hpp
@@ -285,14 +285,13 @@ class SymbolTable
     std::vector<Symbol> builtin_function_symbol_list;
 
     for (auto i_stored_symbol : m_symbol_list) {
-      if (use_position.byte < i_stored_symbol.attributes().position().byte)
-        continue;
-
       // Symbol must be defined before the call
-      std::string_view stored_symbol_name = i_stored_symbol.name();
-      if ((stored_symbol_name.size() > symbol.size()) and (stored_symbol_name[symbol.size()] == ':')) {
-        if (stored_symbol_name.substr(0, symbol.size()) == symbol) {
-          builtin_function_symbol_list.push_back(i_stored_symbol);
+      if (use_position.byte >= i_stored_symbol.attributes().position().byte) {
+        std::string_view stored_symbol_name = i_stored_symbol.name();
+        if ((stored_symbol_name.size() > symbol.size()) and (stored_symbol_name[symbol.size()] == ':')) {
+          if (stored_symbol_name.substr(0, symbol.size()) == symbol) {
+            builtin_function_symbol_list.push_back(i_stored_symbol);
+          }
         }
       }
     }
@@ -308,15 +307,14 @@ class SymbolTable
   has(const std::string& symbol, const TAO_PEGTL_NAMESPACE::position& use_position)
   {
     for (auto i_stored_symbol : m_symbol_list) {
-      if (use_position.byte < i_stored_symbol.attributes().position().byte)
-        continue;
-
       // Symbol must be defined before the call
-      std::string_view stored_symbol_name = i_stored_symbol.name();
-      if ((stored_symbol_name.size() == symbol.size()) or
-          (stored_symbol_name.size() > symbol.size() and (stored_symbol_name[symbol.size()] == ':'))) {
-        if (stored_symbol_name.substr(0, symbol.size()) == symbol) {
-          return true;
+      if (use_position.byte >= i_stored_symbol.attributes().position().byte) {
+        std::string_view stored_symbol_name = i_stored_symbol.name();
+        if ((stored_symbol_name.size() == symbol.size()) or
+            (stored_symbol_name.size() > symbol.size() and (stored_symbol_name[symbol.size()] == ':'))) {
+          if (stored_symbol_name.substr(0, symbol.size()) == symbol) {
+            return true;
+          }
         }
       }
     }
@@ -355,15 +353,8 @@ class SymbolTable
   add(const std::string& symbol_name, const TAO_PEGTL_NAMESPACE::position& symbol_position)
   {
     for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) {
-      std::string_view stored_symbol_name = i_stored_symbol->name();
-      if (stored_symbol_name.size() == symbol_name.size()) {
-        if (stored_symbol_name == symbol_name) {
-          return std::make_pair(i_stored_symbol, false);
-        } else if (stored_symbol_name.size() > symbol_name.size() and (stored_symbol_name[symbol_name.size()] == ':')) {
-          if (stored_symbol_name.substr(0, symbol_name.size()) == symbol_name) {
-            return std::make_pair(i_stored_symbol, false);
-          }
-        }
+      if (i_stored_symbol->name() == symbol_name) {
+        return std::make_pair(i_stored_symbol, false);
       }
     }
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 06967be54d53c7ff8e88d6ec38d675381cd8ad07..8cea83f7294e107b28db9f223cd989c33a5a6c2d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -47,6 +47,7 @@ add_executable (unit_tests
   test_BiCGStab.cpp
   test_BuildInfo.cpp
   test_BuiltinFunctionEmbedder.cpp
+  test_BuiltinFunctionEmbedderUtils.cpp
   test_BuiltinFunctionEmbedderTable.cpp
   test_BuiltinFunctionProcessor.cpp
   test_CastArray.cpp
diff --git a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
index d7cd62afe7e4260d14640287ad440355dab59898..7fb68cd69c16331c07db8354a40dcb029fcb5c14 100644
--- a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -1664,6 +1664,42 @@ fidToR(f);
 
       CHECK_AST(data, result);
     }
+
+    SECTION("tuple(FunctionSymbolId) -> R")
+    {
+      std::string_view data = R"(
+let f : R^3 -> R, x -> 0;
+fidTupleToR((f,f));
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:fidTupleToR:FakeProcessor)
+     `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor>)
+         +-(language::name:f:NameProcessor)
+         `-(language::name:f:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(FunctionSymbolId) -> R  [with single value tuple]")
+    {
+      std::string_view data = R"(
+let f : R^3 -> R, x -> 0;
+fidTupleToR(f);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:fidTupleToR:FakeProcessor)
+     `-(language::name:f:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
   }
 
   SECTION("errors")
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index 346807df3b58e189a7e1283850fbdda54264abbb..96af38a0b905014ea518653795ba95850e486055 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -1002,6 +1002,21 @@ let cat : string*N -> string, (s,n) -> s+n;
       CHECK_AST(data, result);
     }
 
+    SECTION("builtin-functions")
+    {
+      std::string_view data = R"(
+let foo : builtin_t*N -> builtin_t, (b,n) -> b;
+)";
+
+      std::string_view result = R"(
+(root:void)
+ `-(language::fct_declaration:void)
+     `-(language::name:foo:function)
+)";
+
+      CHECK_AST_WITH_BUILTIN(data, result);
+    }
+
     SECTION("errors")
     {
       SECTION("wrong parameter number")
@@ -1312,6 +1327,35 @@ let s : string, s = cat("foo", "bar");
       CHECK_AST(data, result);
     }
 
+    SECTION("bultin_t-function")
+    {
+      std::string_view data = R"(
+let foo : builtin_t*N -> builtin_t, (b,n) -> b;
+let b0: builtin_t;
+let b : builtin_t, b = foo(b0, 1);
+)";
+
+      std::string_view result = R"(
+(root:void)
+ +-(language::fct_declaration:void)
+ |   `-(language::name:foo:function)
+ +-(language::var_declaration:void)
+ |   +-(language::name:b0:builtin_t)
+ |   `-(language::type_name_id:builtin_t)
+ `-(language::var_declaration:void)
+     +-(language::name:b:builtin_t)
+     +-(language::type_name_id:builtin_t)
+     +-(language::name:b:builtin_t)
+     `-(language::function_evaluation:builtin_t)
+         +-(language::name:foo:function)
+         `-(language::function_argument_list:builtin_t*Z)
+             +-(language::name:b0:builtin_t)
+             `-(language::integer:1:Z)
+)";
+
+      CHECK_AST_WITH_BUILTIN(data, result);
+    }
+
     SECTION("compound return function")
     {
       std::string_view data = R"(
diff --git a/tests/test_ASTNodeDataTypeFlattener.cpp b/tests/test_ASTNodeDataTypeFlattener.cpp
index d4b4bbe6c65e7bc0a110d70b406b24f678f82576..aaa3739b2266f45e9c62b8a606000749468c33d8 100644
--- a/tests/test_ASTNodeDataTypeFlattener.cpp
+++ b/tests/test_ASTNodeDataTypeFlattener.cpp
@@ -8,6 +8,9 @@
 #include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
 #include <language/ast/ASTNodeTypeCleaner.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/BasicAffectationRegistrerFor.hpp>
+#include <language/utils/TypeDescriptor.hpp>
 
 #include <test_BuiltinFunctionRegister.hpp>
 
@@ -106,11 +109,11 @@ f(2);
       REQUIRE(&flattened_datatype_list[0].m_parent_node == root_node->children[0].get());
     }
 
-    SECTION("function evaluation -> N*R*B*string*Z")
+    SECTION("function evaluation -> N*R*B*string*Z*builtin_t")
     {
       std::string_view data = R"(
-let f: N -> N*R*B*string*Z, n -> (n, 0.5*n, n>2, n, 3-n);
-f(2);
+let f: N*builtin_t -> N*R*B*string*Z*builtin_t, (n,b) -> (n, 0.5*n, n>2, n, 3-n, b);
+f(2, b);
 )";
 
       TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
@@ -118,6 +121,21 @@ f(2);
 
       ASTModulesImporter{*root_node};
       ASTNodeTypeCleaner<language::import_instruction>{*root_node};
+      SymbolTable& symbol_table = *root_node->m_symbol_table;
+
+      auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), root_node->begin());
+      if (not success) {
+        throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");
+      }
+
+      i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());
+      i_symbol->attributes().setIsInitialized();
+      i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();
+      symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId()));
+
+      auto [i_b_symbol, b_success] = symbol_table.add("b", root_node->begin());
+      i_b_symbol->attributes().setDataType(ast_node_data_type_from<std::shared_ptr<const double>>);
+      i_b_symbol->attributes().setIsInitialized();
 
       ASTSymbolTableBuilder{*root_node};
       ASTNodeDataTypeBuilder{*root_node};
@@ -133,12 +151,13 @@ f(2);
       ASTNodeDataTypeFlattener::FlattenedDataTypeList flattened_datatype_list;
       ASTNodeDataTypeFlattener{*root_node->children[0], flattened_datatype_list};
 
-      REQUIRE(flattened_datatype_list.size() == 5);
+      REQUIRE(flattened_datatype_list.size() == 6);
       REQUIRE(flattened_datatype_list[0].m_data_type == ASTNodeDataType::unsigned_int_t);
       REQUIRE(flattened_datatype_list[1].m_data_type == ASTNodeDataType::double_t);
       REQUIRE(flattened_datatype_list[2].m_data_type == ASTNodeDataType::bool_t);
       REQUIRE(flattened_datatype_list[3].m_data_type == ASTNodeDataType::string_t);
       REQUIRE(flattened_datatype_list[4].m_data_type == ASTNodeDataType::int_t);
+      REQUIRE(flattened_datatype_list[5].m_data_type == ASTNodeDataType::type_id_t);
     }
 
     SECTION("function evaluation -> R*R^3")
diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
index d10d243a8de7b16b3b6c33bc81d55343b2298953..b37dd10869bb5665c9292b22e363af09be4b9ead 100644
--- a/tests/test_ASTNodeFunctionExpressionBuilder.cpp
+++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
@@ -9,34 +9,54 @@
 #include <language/ast/ASTNodeFunctionExpressionBuilder.hpp>
 #include <language/ast/ASTNodeTypeCleaner.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
 #include <language/utils/ASTPrinter.hpp>
+#include <language/utils/BasicAffectationRegistrerFor.hpp>
+#include <language/utils/TypeDescriptor.hpp>
 #include <utils/Demangle.hpp>
 
 #include <pegtl/string_input.hpp>
 
-#define CHECK_AST(data, expected_output)                                                            \
-  {                                                                                                 \
-    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_output)>, std::string_view>) or    \
-                  (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>));          \
-                                                                                                    \
-    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};                                      \
-    auto ast = ASTBuilder::build(input);                                                            \
-                                                                                                    \
-    ASTModulesImporter{*ast};                                                                       \
-    ASTNodeTypeCleaner<language::import_instruction>{*ast};                                         \
-                                                                                                    \
-    ASTSymbolTableBuilder{*ast};                                                                    \
-    ASTNodeDataTypeBuilder{*ast};                                                                   \
-                                                                                                    \
-    ASTNodeTypeCleaner<language::var_declaration>{*ast};                                            \
-    ASTNodeTypeCleaner<language::fct_declaration>{*ast};                                            \
-    ASTNodeExpressionBuilder{*ast};                                                                 \
-                                                                                                    \
-    std::stringstream ast_output;                                                                   \
-    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \
-                                                                                                    \
-    REQUIRE(ast_output.str() == expected_output);                                                   \
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t");
+const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>;
+
+#define CHECK_AST(data, expected_output)                                                                        \
+  {                                                                                                             \
+    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_output)>, std::string_view>) or                \
+                  (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>));                      \
+                                                                                                                \
+    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};                                                  \
+    auto ast = ASTBuilder::build(input);                                                                        \
+                                                                                                                \
+    ASTModulesImporter{*ast};                                                                                   \
+    BasicAffectationRegisterFor<EmbeddedData>{ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t")}; \
+                                                                                                                \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};                                                     \
+    SymbolTable& symbol_table = *ast->m_symbol_table;                                                           \
+    auto [i_symbol, success]  = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin());               \
+    if (not success) {                                                                                          \
+      throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");          \
+    }                                                                                                           \
+                                                                                                                \
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());              \
+    i_symbol->attributes().setIsInitialized();                                                                  \
+    i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();                                   \
+    symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId()));   \
+                                                                                                                \
+    ASTSymbolTableBuilder{*ast};                                                                                \
+    ASTNodeDataTypeBuilder{*ast};                                                                               \
+                                                                                                                \
+    ASTNodeTypeCleaner<language::var_declaration>{*ast};                                                        \
+    ASTNodeTypeCleaner<language::fct_declaration>{*ast};                                                        \
+    ASTNodeExpressionBuilder{*ast};                                                                             \
+                                                                                                                \
+    std::stringstream ast_output;                                                                               \
+    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}};             \
+                                                                                                                \
+    REQUIRE(ast_output.str() == expected_output);                                                               \
   }
 
 #define CHECK_AST_THROWS(data)                                                     \
@@ -938,6 +958,27 @@ f(2,(1,2,3),(2,3,-1,1.3));
     }
   }
 
+  SECTION("return a builtin_t")
+  {
+    SECTION("builtin_t argument")
+    {
+      std::string_view data = R"(
+let foo : builtin_t -> builtin_t, b -> b;
+let b0 : builtin_t;
+foo(b0);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:foo:NameProcessor)
+     `-(language::name:b0:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+  }
+
   SECTION("errors")
   {
     SECTION("wrong argument number")
diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
index 8ae86fa804a704c10e32c3fe3e5b986987e22de0..6eab14fe5162b64a1d883cd54d8b9a70e20a5d66 100644
--- a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
+++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp
@@ -9,36 +9,56 @@
 #include <language/ast/ASTNodeListAffectationExpressionBuilder.hpp>
 #include <language/ast/ASTNodeTypeCleaner.hpp>
 #include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
 #include <language/utils/ASTPrinter.hpp>
+#include <language/utils/BasicAffectationRegistrerFor.hpp>
+#include <language/utils/TypeDescriptor.hpp>
 #include <utils/Demangle.hpp>
 
 #include <pegtl/string_input.hpp>
 
-#define CHECK_AST(data, expected_output)                                                            \
-  {                                                                                                 \
-    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_output)>, std::string_view> or      \
-                  std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>);            \
-                                                                                                    \
-    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};                                      \
-    auto ast = ASTBuilder::build(input);                                                            \
-                                                                                                    \
-    ASTModulesImporter{*ast};                                                                       \
-    ASTNodeTypeCleaner<language::import_instruction>{*ast};                                         \
-                                                                                                    \
-    ASTSymbolTableBuilder{*ast};                                                                    \
-    ASTNodeDataTypeBuilder{*ast};                                                                   \
-                                                                                                    \
-    ASTNodeDeclarationToAffectationConverter{*ast};                                                 \
-    ASTNodeTypeCleaner<language::var_declaration>{*ast};                                            \
-    ASTNodeTypeCleaner<language::fct_declaration>{*ast};                                            \
-                                                                                                    \
-    ASTNodeExpressionBuilder{*ast};                                                                 \
-                                                                                                    \
-    std::stringstream ast_output;                                                                   \
-    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \
-                                                                                                    \
-    REQUIRE(ast_output.str() == expected_output);                                                   \
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> =
+  ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t");
+const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>;
+
+#define CHECK_AST(data, expected_output)                                                                        \
+  {                                                                                                             \
+    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_output)>, std::string_view> or                  \
+                  std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>);                        \
+                                                                                                                \
+    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};                                                  \
+    auto ast = ASTBuilder::build(input);                                                                        \
+                                                                                                                \
+    ASTModulesImporter{*ast};                                                                                   \
+    BasicAffectationRegisterFor<EmbeddedData>{ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t")}; \
+                                                                                                                \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};                                                     \
+    SymbolTable& symbol_table = *ast->m_symbol_table;                                                           \
+    auto [i_symbol, success]  = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin());               \
+    if (not success) {                                                                                          \
+      throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing");          \
+    }                                                                                                           \
+                                                                                                                \
+    i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>());              \
+    i_symbol->attributes().setIsInitialized();                                                                  \
+    i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size();                                   \
+    symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId()));   \
+                                                                                                                \
+    ASTSymbolTableBuilder{*ast};                                                                                \
+    ASTNodeDataTypeBuilder{*ast};                                                                               \
+                                                                                                                \
+    ASTNodeDeclarationToAffectationConverter{*ast};                                                             \
+    ASTNodeTypeCleaner<language::var_declaration>{*ast};                                                        \
+    ASTNodeTypeCleaner<language::fct_declaration>{*ast};                                                        \
+                                                                                                                \
+    ASTNodeExpressionBuilder{*ast};                                                                             \
+                                                                                                                \
+    std::stringstream ast_output;                                                                               \
+    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}};             \
+                                                                                                                \
+    REQUIRE(ast_output.str() == expected_output);                                                               \
   }
 
 #define CHECK_AST_THROWS_WITH(data, error)                                         \
@@ -375,6 +395,26 @@ let  (r,s,t,u) : string*string*string*string,
 
       CHECK_AST(data, result);
     }
+
+    SECTION("embedded data")
+    {
+      std::string_view data = R"(
+let (b0,b1): builtin_t*builtin_t, (b0,b1) = (b0,b1);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::eq_op:ListAffectationProcessor<language::eq_op>)
+     +-(language::name_list:FakeProcessor)
+     |   +-(language::name:b0:NameProcessor)
+     |   `-(language::name:b1:NameProcessor)
+     `-(language::expression_list:ASTNodeExpressionListProcessor)
+         +-(language::name:b0:NameProcessor)
+         `-(language::name:b1:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
   }
 
   SECTION("Errors")
diff --git a/tests/test_BuiltinFunctionEmbedderUtils.cpp b/tests/test_BuiltinFunctionEmbedderUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..965d709b97187fbab363b4cacad7cde4f8ad7b7c
--- /dev/null
+++ b/tests/test_BuiltinFunctionEmbedderUtils.cpp
@@ -0,0 +1,1605 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <language/ast/ASTBuilder.hpp>
+#include <language/ast/ASTModulesImporter.hpp>
+#include <language/ast/ASTNode.hpp>
+#include <language/ast/ASTNodeDataTypeBuilder.hpp>
+#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp>
+#include <language/ast/ASTNodeTypeCleaner.hpp>
+#include <language/ast/ASTSymbolInitializationChecker.hpp>
+#include <language/ast/ASTSymbolTableBuilder.hpp>
+#include <language/utils/BuiltinFunctionEmbedder.hpp>
+#include <language/utils/BuiltinFunctionEmbedderUtils.hpp>
+#include <language/utils/SymbolTable.hpp>
+#include <utils/Exceptions.hpp>
+
+#include <pegtl/string_input.hpp>
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("BuiltinFunctionEmbedderUtils", "[language]")
+{
+  using FunctionList      = std::vector<std::pair<std::string, std::shared_ptr<IBuiltinFunctionEmbedder>>>;
+  auto register_functions = [](std::unique_ptr<ASTNode>& root_node, const FunctionList& function_list) {
+    ASTModulesImporter{*root_node};
+
+    std::shared_ptr root_st = root_node->m_symbol_table;
+
+    auto& embedder_table = root_st->builtinFunctionEmbedderTable();
+    for (auto&& [function_name, embedded_function] : function_list) {
+      auto [i_symbol, success] =
+        root_st->add(function_name + ':' + dataTypeName(embedded_function->getParameterDataTypes()),
+                     root_node->begin());
+
+      if (not success) {
+        throw UnexpectedError("cannot build test, function already registered");
+      }
+
+      i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>());
+      i_symbol->attributes().setIsInitialized();
+      i_symbol->attributes().value() = embedder_table.size();
+
+      embedder_table.add(embedded_function);
+    }
+
+    ASTSymbolTableBuilder{*root_node};
+    ASTNodeDataTypeBuilder{*root_node};
+
+    ASTNodeDeclarationToAffectationConverter{*root_node};
+    ASTNodeTypeCleaner<language::var_declaration>{*root_node};
+    ASTNodeTypeCleaner<language::fct_declaration>{*root_node};
+  };
+
+  SECTION("using simple arguments")
+  {
+    SECTION("builtin function R -> R")
+    {
+      std::string_view data = R"(
+foo(3);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+    }
+
+    SECTION("builtin function R*string -> R")
+    {
+      std::string_view data = R"(
+foo(3,"bar");
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; })),
+                                      std::make_pair("foo",
+                                                     std::make_shared<
+                                                       BuiltinFunctionEmbedder<double(double, const std::string&)>>(
+                                                       [](double x, const std::string&) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::string_t);
+    }
+
+    SECTION("builtin function R*string -> R (using builtin function result)")
+    {
+      std::string_view data = R"(
+foo(foo(3),"bar");
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; })),
+                                      std::make_pair("foo",
+                                                     std::make_shared<
+                                                       BuiltinFunctionEmbedder<double(double, const std::string&)>>(
+                                                       [](double x, const std::string&) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::string_t);
+    }
+
+    SECTION("builtin function N -> N (choosing appropriate candidate)")
+    {
+      std::string_view data = R"(
+foo(2);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; })),
+                                      std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<int64_t(int64_t)>>(
+                                                              [](int64_t n) -> int64_t { return n; })),
+                                      std::make_pair("foo",
+                                                     std::make_shared<
+                                                       BuiltinFunctionEmbedder<double(double, const std::string&)>>(
+                                                       [](double x, const std::string&) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::int_t);
+    }
+
+    SECTION("builtin function R -> R (using function result)")
+    {
+      std::string_view data = R"(
+let f: R -> R, x -> x+1;
+foo(f(3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+    }
+
+    SECTION("builtin function R*string -> R (using  function result)")
+    {
+      std::string_view data = R"(
+let f : R -> R*string, x -> (x,"bar"+x);
+foo(f(3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
+                                                              [](double x) -> double { return x; })),
+                                      std::make_pair("foo",
+                                                     std::make_shared<
+                                                       BuiltinFunctionEmbedder<double(double, const std::string&)>>(
+                                                       [](double x, const std::string&) -> double { return x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::string_t);
+    }
+  }
+
+  SECTION("using R^1 arguments")
+  {
+    SECTION("builtin function R*R^1 -> R^1")
+    {
+      std::string_view data = R"(
+let x:R^1;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<1>(double, const TinyVector<1>&)>>(
+                                            [](double a, const TinyVector<1>& x) -> TinyVector<1> { return a * x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 1);
+    }
+
+    SECTION("builtin function R*R^1 -> R^2")
+    {
+      std::string_view data = R"(
+foo(3,1);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<1>&)>>(
+                                            [](double a, const TinyVector<1>& x) -> TinyVector<2> {
+                                              return {a, x[0]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 1);
+    }
+
+    SECTION("builtin function R*R^1 -> R^2")
+    {
+      std::string_view data = R"(
+let f :  R -> R^1, x -> x;
+foo(3.1,f(1));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<1>&)>>(
+                                            [](double a, const TinyVector<1>& x) -> TinyVector<2> {
+                                              return {a, x[0]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 1);
+    }
+
+    SECTION("builtin function R^1 -> R^2 (from f: R -> R*R^1)")
+    {
+      std::string_view data = R"(
+let f :  R -> R*R^1, x -> (2+x, 2*x);
+foo(f(2));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<1>&)>>(
+                                            [](double a, const TinyVector<1>& x) -> TinyVector<2> {
+                                              return {a, x[0]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 1);
+    }
+  }
+
+  SECTION("using R^2 arguments")
+  {
+    SECTION("builtin function R*R^2 -> R^2")
+    {
+      std::string_view data = R"(
+let x:R^2;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<2>&)>>(
+                                            [](double a, const TinyVector<2>& x) -> TinyVector<2> { return a * x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 2);
+    }
+
+    SECTION("builtin function R*R^2 -> R^3")
+    {
+      std::string_view data = R"(
+foo(3,0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<3>(double, const TinyVector<2>&)>>(
+                                            [](double a, const TinyVector<2>& x) -> TinyVector<3> {
+                                              return {a, x[0], x[1]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 3);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 2);
+    }
+
+    SECTION("builtin function R*R^2 -> R^2 (R^2 from list)")
+    {
+      std::string_view data = R"(
+foo(3.1,(1,2.3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<2>&)>>(
+                                            [](double a, const TinyVector<2>& x) -> TinyVector<2> {
+                                              return {a * x[1], x[0]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 2);
+    }
+  }
+
+  SECTION("using R^3 arguments")
+  {
+    SECTION("builtin function R*R^3 -> R^2")
+    {
+      std::string_view data = R"(
+let x:R^3;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<3>&)>>(
+                                            [](double a, const TinyVector<3>& x) -> TinyVector<2> {
+                                              return {a * x[0], x[1] + x[2]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 3);
+    }
+
+    SECTION("builtin function R*R^3 -> R^3")
+    {
+      std::string_view data = R"(
+foo(3,0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<3>(double, const TinyVector<3>&)>>(
+                                            [](double a, const TinyVector<3>& x) -> TinyVector<3> {
+                                              return {a * x};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 3);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 3);
+    }
+
+    SECTION("builtin function R*R^3 -> R^2 (R^3 from list)")
+    {
+      std::string_view data = R"(
+foo(3.1,(1,2.3,4));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyVector<2>(double, const TinyVector<3>&)>>(
+                                            [](double a, const TinyVector<3>& x) -> TinyVector<2> {
+                                              return {a * x[1], x[0] * x[2]};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getReturnDataType().dimension() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].dimension() == 3);
+    }
+  }
+
+  SECTION("using R^1x1 arguments")
+  {
+    SECTION("builtin function R*R^1x1 -> R^1x1")
+    {
+      std::string_view data = R"(
+let x:R^1x1;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<1>(double, const TinyMatrix<1>&)>>(
+                                            [](double a, const TinyMatrix<1>& x) -> TinyMatrix<1> { return a * x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 1);
+    }
+
+    SECTION("builtin function R*R^1x1 -> R^2x2")
+    {
+      std::string_view data = R"(
+foo(3,1);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<1>&)>>(
+                                            [](double a, const TinyMatrix<1>& x) -> TinyMatrix<2> {
+                                              return {a, x(0, 0), a * x(0, 0), x(0, 0)};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 1);
+    }
+
+    SECTION("builtin function R*R^1x1 -> R^2x2")
+    {
+      std::string_view data = R"(
+let f :  R -> R^1x1, x -> x;
+foo(3.1,f(1));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<1>&)>>(
+                                            [](double a, const TinyMatrix<1>& x) -> TinyMatrix<2> {
+                                              return {a, x(0, 0), 2 + x(0, 0), 1};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 1);
+    }
+
+    SECTION("builtin function R^1x1 -> R^2x2 (from f: R -> R*R^1x1)")
+    {
+      std::string_view data = R"(
+let f :  R -> R*R^1x1, x -> (2+x, 2*x);
+foo(f(2));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<1>&)>>(
+                                            [](double a, const TinyMatrix<1>& x) -> TinyMatrix<2> {
+                                              return {a, x(0, 0), a + x(0, 0), 1};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfColumns() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 1);
+    }
+  }
+
+  SECTION("using R^2x2 arguments")
+  {
+    SECTION("builtin function R*R^2x2 -> R^2x2")
+    {
+      std::string_view data = R"(
+let x:R^2x2;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<2>&)>>(
+                                            [](double a, const TinyMatrix<2>& x) -> TinyMatrix<2> { return a * x; }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 2);
+    }
+
+    SECTION("builtin function R*R^2x2 -> R^3x3")
+    {
+      std::string_view data = R"(
+foo(3,0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<3>(double, const TinyMatrix<2>&)>>(
+                                            [](double a, const TinyMatrix<2>& x) -> TinyMatrix<3> {
+                                              return {a, x(0, 0), x(1, 0),   //
+                                                      a, x(1, 0), x(1, 1),   //
+                                                      a, x(0, 0), x(1, 1)};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 3);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 2);
+    }
+
+    SECTION("builtin function R*R^2x2 -> R^2x2 (R^2x2 from list)")
+    {
+      std::string_view data = R"(
+foo(3.1,(1,2.3,0,3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<2>&)>>(
+                                            [](double a, const TinyMatrix<2>& x) -> TinyMatrix<2> {
+                                              return {a * x(0, 0), x(1, 1), a, x(1, 0)};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 2);
+    }
+  }
+
+  SECTION("using R^3x3 arguments")
+  {
+    SECTION("builtin function R*R^3x3 -> R^2x2")
+    {
+      std::string_view data = R"(
+let x:R^3x3;
+foo(3,x);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<3>&)>>(
+                                            [](double a, const TinyMatrix<3>& x) -> TinyMatrix<2> {
+                                              return {a * x(0, 0), x(1, 0) + x(0, 1),   //
+                                                      a, x(1, 1)};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 3);
+    }
+
+    SECTION("builtin function R*R^3x3 -> R^3x3")
+    {
+      std::string_view data = R"(
+foo(3,0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<3>(double, const TinyMatrix<3>&)>>(
+                                            [](double a, const TinyMatrix<3>& x) -> TinyMatrix<3> {
+                                              return {a * x};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 3);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 3);
+    }
+
+    SECTION("builtin function R*R^3x3 -> R^2x2 (R^3x3 from list)")
+    {
+      std::string_view data = R"(
+foo(3.1,(1, 2.3, 4, 0.3, 2.5, 4.6, 2.7, 8.1, -9));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<TinyMatrix<2>(double, const TinyMatrix<3>&)>>(
+                                            [](double a, const TinyMatrix<3>& x) -> TinyMatrix<2> {
+                                              return {a * x(1, 1), x(1, 0),   //
+                                                      x(0, 1), a * x(0, 0)};
+                                            }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getReturnDataType().numberOfRows() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 2);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[1].numberOfRows() == 3);
+    }
+  }
+
+  SECTION("using tuple arguments")
+  {
+    SECTION("builtin function (R...) -> N (from (N...))")
+    {
+      std::string_view data = R"(
+let v:(N);
+foo(v);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<uint64_t(const std::vector<double>&)>>(
+                                            [](const std::vector<double>& x) -> uint64_t { return x.size(); }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::double_t);
+    }
+
+    SECTION("builtin function (R...) -> N (from Z)")
+    {
+      std::string_view data = R"(
+foo(-4);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<uint64_t(const std::vector<double>&)>>(
+                                            [](const std::vector<double>& x) -> uint64_t { return x.size(); }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::double_t);
+    }
+
+    SECTION("builtin function (R^1...) -> N (from (N...))")
+    {
+      std::string_view data = R"(
+let v:(N);
+foo(v);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<1>>&)>>(
+                                                              [](const std::vector<TinyVector<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 1);
+    }
+
+    SECTION("builtin function (R^1...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<1>>&)>>(
+                                                              [](const std::vector<TinyVector<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 1);
+    }
+
+    SECTION("builtin function (R...) -> N (from list)")
+    {
+      std::string_view data = R"(
+foo((1,2,3,5));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{
+                           std::make_pair("foo",
+                                          std::make_shared<
+                                            BuiltinFunctionEmbedder<uint64_t(const std::vector<double>&)>>(
+                                            [](const std::vector<double>& x) -> uint64_t { return x.size(); }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::double_t);
+    }
+
+    SECTION("builtin function (R^1...) -> N (from castable list)")
+    {
+      std::string_view data = R"(
+foo((1,2,3,5));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<1>>&)>>(
+                                                              [](const std::vector<TinyVector<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 1);
+    }
+
+    SECTION("builtin function (R^1...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^1;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<1>>&)>>(
+                                                              [](const std::vector<TinyVector<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 1);
+    }
+
+    SECTION("builtin function (R^1x1...) -> N (from castable list)")
+    {
+      std::string_view data = R"(
+foo((1,2,3,5));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<1>>&)>>(
+                                                              [](const std::vector<TinyMatrix<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 1);
+    }
+
+    SECTION("builtin function (R^1x1...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<1>>&)>>(
+                                                              [](const std::vector<TinyMatrix<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 1);
+    }
+
+    SECTION("builtin function (R^1x1...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^1x1;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<1>>&)>>(
+                                                              [](const std::vector<TinyMatrix<1>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 1);
+    }
+
+    SECTION("builtin function (R^2...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^2;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<2>>&)>>(
+                                                              [](const std::vector<TinyVector<2>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 2);
+    }
+
+    SECTION("builtin function (R^2...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<2>>&)>>(
+                                                              [](const std::vector<TinyVector<2>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 2);
+    }
+
+    SECTION("builtin function (R^2x2...) -> N (from castable list)")
+    {
+      std::string_view data = R"(
+foo((1,2,3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<2>>&)>>(
+                                                              [](const std::vector<TinyMatrix<2>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 2);
+    }
+
+    SECTION("builtin function (R^2x2...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<2>>&)>>(
+                                                              [](const std::vector<TinyMatrix<2>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 2);
+    }
+
+    SECTION("builtin function (R^2x2...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^2x2;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<2>>&)>>(
+                                                              [](const std::vector<TinyMatrix<2>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 2);
+    }
+
+    SECTION("builtin function (R^3...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^3;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<3>>&)>>(
+                                                              [](const std::vector<TinyVector<3>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 3);
+    }
+
+    SECTION("builtin function (R^3...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyVector<3>>&)>>(
+                                                              [](const std::vector<TinyVector<3>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::vector_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().dimension() == 3);
+    }
+
+    SECTION("builtin function (R^3x3...) -> N (from castable list)")
+    {
+      std::string_view data = R"(
+foo((1,2,3));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<3>>&)>>(
+                                                              [](const std::vector<TinyMatrix<3>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 3);
+    }
+
+    SECTION("builtin function (R^3x3...) -> N (from 0)")
+    {
+      std::string_view data = R"(
+foo(0);
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<3>>&)>>(
+                                                              [](const std::vector<TinyMatrix<3>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 3);
+    }
+
+    SECTION("builtin function (R^3x3...) -> N (from list)")
+    {
+      std::string_view data = R"(
+let x:R^3x3;
+foo((x,2*x));
+)";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+      register_functions(root_node,
+                         FunctionList{std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                              const std::vector<TinyMatrix<3>>&)>>(
+                                                              [](const std::vector<TinyMatrix<3>>& x) -> uint64_t {
+                                                                return x.size();
+                                                              }))});
+
+      auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+      REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::unsigned_int_t);
+      REQUIRE(function_embedder->getParameterDataTypes().size() == 1);
+      REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType() == ASTNodeDataType::matrix_t);
+      REQUIRE(function_embedder->getParameterDataTypes()[0].contentType().numberOfRows() == 3);
+    }
+  }
+
+  SECTION("complete case")
+  {
+    std::string_view data = R"(
+let x:R^3x3;
+foo(1, "bar", (x,2*x), (2,3));
+)";
+
+    TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+    auto root_node = ASTBuilder::build(input);
+    register_functions(root_node,
+                       FunctionList{
+                         std::make_pair("foo",
+                                        std::make_shared<BuiltinFunctionEmbedder<
+                                          std::tuple<uint64_t, double, std::string>(const double&, const std::string&,
+                                                                                    const std::vector<TinyMatrix<3>>&,
+                                                                                    const TinyVector<2>&)>>(
+                                          [](const double& a, const std::string& s, const std::vector<TinyMatrix<3>>& x,
+                                             const TinyVector<2>& y) -> std::tuple<uint64_t, double, std::string> {
+                                            return std::make_tuple(x.size(), a * y[0] + y[1], s + "_foo");
+                                          }))});
+
+    auto function_embedder = getBuiltinFunctionEmbedder(*root_node->children[0]);
+    REQUIRE(function_embedder->getReturnDataType() == ASTNodeDataType::list_t);
+    REQUIRE(function_embedder->getReturnDataType().contentTypeList().size() == 3);
+    REQUIRE(*function_embedder->getReturnDataType().contentTypeList()[0] == ASTNodeDataType::unsigned_int_t);
+    REQUIRE(*function_embedder->getReturnDataType().contentTypeList()[1] == ASTNodeDataType::double_t);
+    REQUIRE(*function_embedder->getReturnDataType().contentTypeList()[2] == ASTNodeDataType::string_t);
+    REQUIRE(function_embedder->getParameterDataTypes().size() == 4);
+    REQUIRE(function_embedder->getParameterDataTypes()[0] == ASTNodeDataType::double_t);
+    REQUIRE(function_embedder->getParameterDataTypes()[1] == ASTNodeDataType::string_t);
+    REQUIRE(function_embedder->getParameterDataTypes()[2] == ASTNodeDataType::tuple_t);
+    REQUIRE(function_embedder->getParameterDataTypes()[2].contentType() == ASTNodeDataType::matrix_t);
+    REQUIRE(function_embedder->getParameterDataTypes()[2].contentType().numberOfRows() == 3);
+    REQUIRE(function_embedder->getParameterDataTypes()[3] == ASTNodeDataType::vector_t);
+    REQUIRE(function_embedder->getParameterDataTypes()[3].dimension() == 2);
+  }
+
+  SECTION("errors")
+  {
+    SECTION("R^1: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^3;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^3\n"
+                              "note: candidates are\n"
+                              " foo: R^1 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<1>)>>(
+                                                                           [](const TinyVector<1>& x) -> double {
+                                                                             return x[0];
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^2: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^3;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^3\n"
+                              "note: candidates are\n"
+                              " foo: R^2 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<2>)>>(
+                                                                           [](const TinyVector<2>& x) -> double {
+                                                                             return x[1];
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^3: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^2;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^2\n"
+                              "note: candidates are\n"
+                              " foo: R^3 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<3>)>>(
+                                                                           [](const TinyVector<3>& x) -> double {
+                                                                             return x[1];
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^2: invalid argument list size")
+    {
+      std::string_view data = R"(
+foo((1,2,3,4));
+)";
+
+      std::string error_msg = "no matching function to call foo: Z*Z*Z*Z\n"
+                              "note: candidates are\n"
+                              " foo: R^2 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<2>)>>(
+                                                                           [](const TinyVector<2>& x) -> double {
+                                                                             return x[1];
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^3: invalid argument list size")
+    {
+      std::string_view data = R"(
+foo((1,2,3,4));
+)";
+
+      std::string error_msg = "no matching function to call foo: Z*Z*Z*Z\n"
+                              "note: candidates are\n"
+                              " foo: R^3 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<3>)>>(
+                                                                           [](const TinyVector<3>& x) -> double {
+                                                                             return x[1];
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^1x1: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^3x3;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^3x3\n"
+                              "note: candidates are\n"
+                              " foo: R^1x1 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyMatrix<1>)>>(
+                                                                           [](const TinyMatrix<1>& x) -> double {
+                                                                             return x(0, 0);
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^2x2: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^3x3;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^3x3\n"
+                              "note: candidates are\n"
+                              " foo: R^2x2 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyMatrix<2>)>>(
+                                                                           [](const TinyMatrix<2>& x) -> double {
+                                                                             return x(0, 0);
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^3x3: invalid conversion")
+    {
+      std::string_view data = R"(
+let x:R^2x2;
+foo(x);
+)";
+
+      std::string error_msg = "no matching function to call foo: R^2x2\n"
+                              "note: candidates are\n"
+                              " foo: R^3x3 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyMatrix<3>)>>(
+                                                                           [](const TinyMatrix<3>& x) -> double {
+                                                                             return x(1, 2);
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^2x2: invalid argument list size")
+    {
+      std::string_view data = R"(
+foo((1,2,3));
+)";
+
+      std::string error_msg = "no matching function to call foo: Z*Z*Z\n"
+                              "note: candidates are\n"
+                              " foo: R^2x2 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyMatrix<2>)>>(
+                                                                           [](const TinyMatrix<2>& x) -> double {
+                                                                             return x(0, 0);
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("R^3x3: invalid argument list size")
+    {
+      std::string_view data = R"(
+foo((1,2,3,4));
+)";
+
+      std::string error_msg = "no matching function to call foo: Z*Z*Z*Z\n"
+                              "note: candidates are\n"
+                              " foo: R^3x3 -> R\n"
+                              " foo: R -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyMatrix<3>)>>(
+                                                                           [](const TinyMatrix<3>& x) -> double {
+                                                                             return x(1, 2);
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           }))}),
+                          error_msg);
+    }
+
+    SECTION("(N...) invalid cast")
+    {
+      std::string_view data = R"(
+foo(1.34);
+)";
+
+      std::string error_msg = "no matching function to call foo: R\n"
+                              "note: candidates are\n"
+                              " foo: (N...) -> N";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{
+                                               std::make_pair("foo", std::make_shared<BuiltinFunctionEmbedder<uint64_t(
+                                                                       const std::vector<uint64_t>&)>>(
+                                                                       [](const std::vector<uint64_t>& t) -> uint64_t {
+                                                                         return t.size();
+                                                                       }))}),
+                          error_msg);
+    }
+
+    SECTION("ambiguous function call")
+    {
+      std::string_view data = R"(
+foo(1);
+)";
+
+      std::string error_msg = "ambiguous function call foo: Z\n"
+                              "note: candidates are\n"
+                              " foo: (R...) -> R\n"
+                              " foo: R -> R\n"
+                              " foo: R^1 -> R";
+
+      TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"};
+      auto root_node = ASTBuilder::build(input);
+
+      REQUIRE_THROWS_WITH(register_functions(root_node,
+                                             FunctionList{std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const std::vector<double>&)>>(
+                                                                           [](const std::vector<double>& x) -> double {
+                                                                             return x.size();
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const double&)>>(
+                                                                           [](const double& x) -> double {
+                                                                             return x;
+                                                                           })),
+                                                          std::make_pair("foo",
+                                                                         std::make_shared<BuiltinFunctionEmbedder<
+                                                                           double(const TinyVector<1>&)>>(
+                                                                           [](const TinyVector<1>& x) -> double {
+                                                                             return x[0];
+                                                                           }))}),
+                          error_msg);
+    }
+  }
+}
diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp
index 7c361c9df4a6e4c3071ccef00c070313dba2bb5b..0ac5226fcac218e5ad195e5f2ecbdef6aa058cb3 100644
--- a/tests/test_BuiltinFunctionRegister.hpp
+++ b/tests/test_BuiltinFunctionRegister.hpp
@@ -100,6 +100,11 @@ class test_BuiltinFunctionRegister
       std::make_pair("fidToR:function", std::make_shared<BuiltinFunctionEmbedder<double(const FunctionSymbolId&)>>(
                                           [](const FunctionSymbolId&) -> double { return 0; })));
 
+    m_name_builtin_function_map.insert(
+      std::make_pair("fidTupleToR:(function...)",
+                     std::make_shared<BuiltinFunctionEmbedder<double(const std::vector<FunctionSymbolId>)>>(
+                       [](const std::vector<FunctionSymbolId>&) -> double { return 0; })));
+
     m_name_builtin_function_map.insert(
       std::make_pair("builtinToBuiltin:builtin_t",
                      std::make_shared<
diff --git a/tests/test_SymbolTable.cpp b/tests/test_SymbolTable.cpp
index 2be1a3d81a104e631894184eaf67f0d2d63d44d2..78cd4373b9901aa69a65bc8bceaa4a7e68c1ad0b 100644
--- a/tests/test_SymbolTable.cpp
+++ b/tests/test_SymbolTable.cpp
@@ -3,6 +3,7 @@
 
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/SymbolTable.hpp>
+#include <language/utils/TypeDescriptor.hpp>
 
 #include <pegtl/internal/iterator.hpp>
 
@@ -186,6 +187,29 @@ TEST_CASE("SymbolTable", "[language]")
       value_output << symbol.attributes();
       REQUIRE(value_output.str() == "function_id:2");
     }
+
+    {
+      const SymbolTable::Symbol symbol_decl{i_symbol_a->name(), i_symbol_a->attributes()};
+      SymbolTable::Attributes attributes_b = attributes_a;
+      SymbolTable::Symbol symbol("foo", attributes_b);
+
+      symbol = symbol_decl;
+
+      std::stringstream value_output;
+      value_output << symbol.attributes();
+      REQUIRE(value_output.str() == "function_id:2");
+    }
+
+    {
+      SymbolTable::Attributes attributes_b = attributes_a;
+      SymbolTable::Symbol symbol("foo", attributes_b);
+
+      symbol = SymbolTable::Symbol{i_symbol_a->name(), i_symbol_a->attributes()};
+
+      std::stringstream value_output;
+      value_output << symbol.attributes();
+      REQUIRE(value_output.str() == "function_id:2");
+    }
   }
 
   SECTION("FunctionTable")
@@ -220,4 +244,20 @@ TEST_CASE("SymbolTable", "[language]")
     REQUIRE(builtin_function_table.size() == 1);
     REQUIRE(const_builtin_function_table.size() == 1);
   }
+
+  SECTION("TypeEmbedderTable")
+  {
+    std::shared_ptr root_st = std::make_shared<SymbolTable>();
+
+    auto& type_table = root_st->typeEmbedderTable();
+    REQUIRE(type_table.size() == 0);
+
+    const auto& const_type_table = static_cast<const SymbolTable&>(*root_st).typeEmbedderTable();
+    REQUIRE(const_type_table.size() == 0);
+
+    type_table.add(std::make_shared<TypeDescriptor>("a_type"));
+
+    REQUIRE(type_table.size() == 1);
+    REQUIRE(const_type_table.size() == 1);
+  }
 }