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