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/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_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);
+    }
+  }
+}