From 11a0626fe1136adcc956359002730b874cc7294f Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Wed, 26 Feb 2020 19:18:07 +0100
Subject: [PATCH] Continue generalization of BuiltinFunctionEmbedder

A fake (pugs) function, corresponding to `readGmsh(std::string)`, is now
properly registered to the builtin-function table... work in progress.
---
 ...STNodeBuiltinFunctionExpressionBuilder.cpp | 29 +++++++++++++++
 src/language/ASTNodeDataType.cpp              | 12 +++---
 src/language/ASTNodeDataType.hpp              | 14 -------
 src/language/BuiltinFunctionEmbedder.hpp      | 37 +++++++++++++++++--
 src/language/DataHandler.hpp                  |  2 +-
 src/language/MeshModule.cpp                   | 14 +++++--
 ...STNodeBuiltinFunctionExpressionBuilder.cpp | 29 +++++++++------
 7 files changed, 98 insertions(+), 39 deletions(-)

diff --git a/src/language/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 13c1297bd..5b324f104 100644
--- a/src/language/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -38,6 +38,32 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
   };
 
+  auto get_function_argument_to_string_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
+    switch (argument_node_sub_data_type.m_data_type) {
+    case ASTNodeDataType::bool_t: {
+      return std::make_unique<FunctionArgumentConverter<std::string, bool>>(argument_number);
+    }
+    case ASTNodeDataType::unsigned_int_t: {
+      return std::make_unique<FunctionArgumentConverter<std::string, uint64_t>>(argument_number);
+    }
+    case ASTNodeDataType::int_t: {
+      return std::make_unique<FunctionArgumentConverter<std::string, int64_t>>(argument_number);
+    }
+    case ASTNodeDataType::double_t: {
+      return std::make_unique<FunctionArgumentConverter<std::string, double>>(argument_number);
+    }
+    case ASTNodeDataType::string_t: {
+      return std::make_unique<FunctionArgumentConverter<std::string, std::string>>(argument_number);
+    }
+      // LCOV_EXCL_START
+    default: {
+      throw parse_error("unexpected error: invalid argument type for function",
+                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
+    }
+      // LCOV_EXCL_STOP
+    }
+  };
+
   auto get_function_argument_converter_for_argument_type = [&]() {
     switch (parameter_type) {
     case ASTNodeDataType::bool_t: {
@@ -51,6 +77,9 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
     }
     case ASTNodeDataType::double_t: {
       return get_function_argument_converter_for(double{});
+    }
+    case ASTNodeDataType::string_t: {
+      return get_function_argument_to_string_converter();
     }
       // LCOV_EXCL_START
     default: {
diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
index b779d7f2c..e2b1f3057 100644
--- a/src/language/ASTNodeDataType.cpp
+++ b/src/language/ASTNodeDataType.cpp
@@ -94,19 +94,19 @@ isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& tar
     if (data_type != ASTNodeDataType::type_id_t) {
       return true;
     } else {
-      return {data_type.typeName() == target_data_type.typeName()};
+      return (data_type.typeName() == target_data_type.typeName());
     }
   } else if (target_data_type == ASTNodeDataType::bool_t) {
     return false;
   } else if (target_data_type == ASTNodeDataType::unsigned_int_t) {
-    return {(data_type == ASTNodeDataType::int_t) or (data_type == ASTNodeDataType::bool_t)};
+    return ((data_type == ASTNodeDataType::int_t) or (data_type == ASTNodeDataType::bool_t));
   } else if (target_data_type == ASTNodeDataType::int_t) {
-    return {(data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::bool_t)};
+    return ((data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::bool_t));
   } else if (target_data_type == ASTNodeDataType::double_t) {
-    return {(data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::int_t) or
-            (data_type == ASTNodeDataType::bool_t)};
+    return ((data_type == ASTNodeDataType::unsigned_int_t) or (data_type == ASTNodeDataType::int_t) or
+            (data_type == ASTNodeDataType::bool_t));
   } else if (target_data_type == ASTNodeDataType::string_t) {
-    return {(data_type >= ASTNodeDataType::bool_t) and (data_type < ASTNodeDataType::string_t)};
+    return ((data_type >= ASTNodeDataType::bool_t) and (data_type < ASTNodeDataType::string_t));
   }
   return false;
 }
diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp
index eb7e9b8d3..7209d1c4f 100644
--- a/src/language/ASTNodeDataType.hpp
+++ b/src/language/ASTNodeDataType.hpp
@@ -78,18 +78,4 @@ ASTNodeDataType dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTN
 
 bool isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type);
 
-// Traits ast_node_data_type_from_pod
-
-template <typename T>
-inline ASTNodeDataType ast_node_data_type_from_pod = ASTNodeDataType::undefined_t;
-
-template <>
-inline ASTNodeDataType ast_node_data_type_from_pod<bool> = ASTNodeDataType::bool_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from_pod<int64_t> = ASTNodeDataType::int_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from_pod<uint64_t> = ASTNodeDataType::unsigned_int_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from_pod<double> = ASTNodeDataType::double_t;
-
 #endif   // AST_NODE_DATA_TYPE_HPP
diff --git a/src/language/BuiltinFunctionEmbedder.hpp b/src/language/BuiltinFunctionEmbedder.hpp
index b9e4e96ca..66c094587 100644
--- a/src/language/BuiltinFunctionEmbedder.hpp
+++ b/src/language/BuiltinFunctionEmbedder.hpp
@@ -7,6 +7,22 @@
 #include <ASTNodeDataType.hpp>
 #include <DataVariant.hpp>
 
+#include <DataHandler.hpp>
+
+template <typename T>
+inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType::undefined_t;
+
+template <>
+inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::bool_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::int_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::unsigned_int_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::double_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::string_t;
+
 class IBuiltinFunctionEmbedder
 {
  public:
@@ -36,6 +52,8 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
       [&](auto v_i) {
         if constexpr (std::is_arithmetic_v<decltype(v_i)>) {
           std::get<I>(t) = v_i;
+        } else if constexpr (std::is_same_v<decltype(v_i), std::string>) {
+          throw std::runtime_error("NIY!");
         } else {
           throw std::runtime_error("unexpected argument type!");
         }
@@ -55,7 +73,7 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
   PUGS_INLINE ASTNodeDataType
   _getOneParameterDataType(ArgsTuple& t) const
   {
-    return ast_node_data_type_from_pod<std::decay_t<decltype(std::get<I>(t))>>;
+    return ast_node_data_type_from<std::decay_t<decltype(std::get<I>(t))>>;
   }
 
   template <size_t... I>
@@ -71,7 +89,7 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
   PUGS_INLINE ASTNodeDataType
   getReturnDataType() const final
   {
-    return ast_node_data_type_from_pod<FX>;
+    return ast_node_data_type_from<FX>;
   }
 
   PUGS_INLINE std::vector<ASTNodeDataType>
@@ -90,6 +108,15 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
     return sizeof...(Args);
   }
 
+ private:
+  template <typename T>
+  PUGS_INLINE std::shared_ptr<IDataHandler>
+  _createHandler(std::shared_ptr<T> data) const
+  {
+    return std::make_shared<DataHandler<T>>(data);
+  }
+
+ public:
   PUGS_INLINE
   DataVariant
   apply(const std::vector<DataVariant>& x) const final
@@ -99,7 +126,11 @@ class BuiltinFunctionEmbedder : public IBuiltinFunctionEmbedder
     using IndexSequence = std::make_index_sequence<N>;
 
     this->_copy_from_vector(t, x, IndexSequence{});
-    return {std::apply(m_f, t)};
+    if constexpr (std::is_arithmetic_v<FX>) {
+      return {std::apply(m_f, t)};
+    } else {
+      return EmbeddedData(_createHandler(std::apply(m_f, t)));
+    }
   }
 
   template <typename FX2, typename... Args2>
diff --git a/src/language/DataHandler.hpp b/src/language/DataHandler.hpp
index 78cf0587d..9a62a233f 100644
--- a/src/language/DataHandler.hpp
+++ b/src/language/DataHandler.hpp
@@ -14,7 +14,7 @@ class IDataHandler
 };
 
 template <typename DataT>
-class DataHandler
+class DataHandler : public IDataHandler
 {
  private:
   std::shared_ptr<DataT> m_data;
diff --git a/src/language/MeshModule.cpp b/src/language/MeshModule.cpp
index a145db0e7..9c0862e01 100644
--- a/src/language/MeshModule.cpp
+++ b/src/language/MeshModule.cpp
@@ -3,11 +3,17 @@
 #include <BuiltinFunctionEmbedder.hpp>
 #include <TypeDescriptor.hpp>
 
+class IMesh;
+
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<IMesh>> = {ASTNodeDataType::type_id_t, "mesh"};
+
 MeshModule::MeshModule()
 {
-  this->_addTypeDescriptor(std::make_shared<TypeDescriptor>(std::string{"mesh"}));
+  this->_addTypeDescriptor(
+    std::make_shared<TypeDescriptor>(ast_node_data_type_from<std::shared_ptr<IMesh>>.typeName()));
 
-  this->_addBuiltinFunction("readGmsh", std::make_shared<BuiltinFunctionEmbedder<double, std::string>>(
-                                          std::function<double(std::string)>{
-                                            [](std::string filename) -> double { return filename.size(); }}));
+  this->_addBuiltinFunction("readGmsh", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<IMesh>, std::string>>(
+                                          std::function<std::shared_ptr<IMesh>(std::string)>{
+                                            [](std::string) -> std::shared_ptr<IMesh> { return {}; }}));
 }
diff --git a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
index d8ea59f78..1279d0cae 100644
--- a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -54,9 +54,8 @@ class BuiltinFunctionRegister
                        std::function<bool(double, double)>{[](double x, double y) -> bool { return x > y; }})));
 
     m_name_builtin_function_map.insert(
-      std::make_pair("StoB_invalid",
-                     std::make_shared<BuiltinFunctionEmbedder<bool, std::string>>(
-                       std::function<bool(std::string)>{[](std::string s) -> bool { return s.size() > 0; }})));
+      std::make_pair("StoB", std::make_shared<BuiltinFunctionEmbedder<bool, std::string>>(
+                               std::function<bool(std::string)>{[](std::string s) -> bool { return s.size() > 0; }})));
   }
 
  public:
@@ -339,6 +338,22 @@ R2toB(1., 0.);
     CHECK_AST(data, result);
   }
 
+  SECTION("string -> B")
+  {
+    std::string_view data = R"(
+StoB("foo");
+)";
+
+    std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:StoB:NameProcessor)
+     `-(language::literal:"foo":ValueProcessor)
+)";
+
+    CHECK_AST(data, result);
+  }
+
   SECTION("errors")
   {
     SECTION("bad number of arguments")
@@ -364,13 +379,5 @@ RtoR("foo");
 )";
       CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"});
     }
-
-    SECTION("invalid function parameter type")
-    {
-      std::string_view data = R"(
-StoB_invalid(3);
-)";
-      CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> undefined"});
-    }
   }
 }
-- 
GitLab