From 5e89fc1ac26945dbf64df712ff6b89fc63577f3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Tue, 10 Nov 2020 22:38:04 +0100
Subject: [PATCH] Add getModuleInfo function in core module (string -> string)

This function lists  is functions and types provided by a module
---
 src/language/ast/ASTNodeDataType.cpp      | 18 ++++++++++++
 src/language/ast/ASTNodeDataType.hpp      |  2 ++
 src/language/modules/CoreModule.cpp       | 11 +++++++
 src/language/modules/ModuleRepository.cpp | 35 +++++++++++++++++++++++
 src/language/modules/ModuleRepository.hpp |  1 +
 5 files changed, 67 insertions(+)

diff --git a/src/language/ast/ASTNodeDataType.cpp b/src/language/ast/ASTNodeDataType.cpp
index ce2bbcc60..1f0847f86 100644
--- a/src/language/ast/ASTNodeDataType.cpp
+++ b/src/language/ast/ASTNodeDataType.cpp
@@ -84,6 +84,24 @@ dataTypeName(const ASTNodeDataType& data_type)
   return name;
 }
 
+std::string
+dataTypeName(const std::vector<ASTNodeDataType>& data_type_vector)
+{
+  if (data_type_vector.size() == 0) {
+    return dataTypeName(ASTNodeDataType::build<ASTNodeDataType::void_t>());
+  } else if (data_type_vector.size() == 1) {
+    return dataTypeName(data_type_vector[0]);
+  } else {
+    std::ostringstream os;
+    os << '(' << dataTypeName(data_type_vector[0]);
+    for (size_t i = 1; i < data_type_vector.size(); ++i) {
+      os << ',' << dataTypeName(data_type_vector[i]);
+    }
+    os << ')';
+    return os.str();
+  }
+}
+
 ASTNodeDataType
 dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2)
 {
diff --git a/src/language/ast/ASTNodeDataType.hpp b/src/language/ast/ASTNodeDataType.hpp
index 98dfaecf8..951aff6e4 100644
--- a/src/language/ast/ASTNodeDataType.hpp
+++ b/src/language/ast/ASTNodeDataType.hpp
@@ -14,6 +14,8 @@ class ASTNodeDataType;
 
 ASTNodeDataType getVectorDataType(const ASTNode& type_node);
 
+std::string dataTypeName(const std::vector<ASTNodeDataType>& data_type_vector);
+
 std::string dataTypeName(const ASTNodeDataType& data_type);
 
 ASTNodeDataType dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& data_type_2);
diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index d3408934d..14a954823 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -30,4 +30,15 @@ CoreModule::CoreModule() : BuiltinModule(true)
                                                      }
 
                                                      ));
+
+  this->_addBuiltinFunction("getModuleInfo", std::make_shared<BuiltinFunctionEmbedder<std::string(const std::string&)>>(
+
+                                               [](const std::string& module_name) -> std::string {
+                                                 const ModuleRepository& repository =
+                                                   ASTExecutionInfo::current().moduleRepository();
+
+                                                 return repository.getModuleInfo(module_name);
+                                               }
+
+                                               ));
 }
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index 13cc6f079..abb5d527d 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -11,6 +11,7 @@
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/ParseError.hpp>
 #include <language/utils/SymbolTable.hpp>
+#include <language/utils/TypeDescriptor.hpp>
 #include <utils/PugsAssert.hpp>
 
 #include <algorithm>
@@ -115,3 +116,37 @@ ModuleRepository::getAvailableModules() const
 
   return os.str();
 }
+
+std::string
+ModuleRepository::getModuleInfo(const std::string& module_name) const
+{
+  std::stringstream os;
+  auto i_module = m_module_set.find(module_name);
+  if (i_module != m_module_set.end()) {
+    os << rang::fgB::yellow << "Module '" << rang::fgB::blue << module_name << rang::fgB::yellow << "' provides"
+       << rang::style::reset << '\n';
+    const auto& builtin_function_map = i_module->second->getNameBuiltinFunctionMap();
+    if (builtin_function_map.size() > 0) {
+      os << "  functions\n";
+      for (auto& [name, function] : builtin_function_map) {
+        os << "    " << rang::fgB::green << name << rang::style::reset << ": ";
+        os << dataTypeName(function->getParameterDataTypes());
+        os << rang::fgB::yellow << " -> " << rang::style::reset;
+        os << dataTypeName(function->getReturnDataType()) << '\n';
+      }
+    }
+
+    const auto& builtin_type_map = i_module->second->getNameTypeMap();
+    if (builtin_type_map.size() > 0) {
+      os << "  types\n";
+      for (auto& [name, descriptor] : builtin_type_map) {
+        os << "    " << rang::fgB::green << name << rang::style::reset << '\n';
+      }
+    }
+
+  } else {
+    throw NormalError(std::string{"could not find module "} + module_name);
+  }
+
+  return os.str();
+}
diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp
index 5a211f2bb..c224f6491 100644
--- a/src/language/modules/ModuleRepository.hpp
+++ b/src/language/modules/ModuleRepository.hpp
@@ -31,6 +31,7 @@ class ModuleRepository
   void populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
 
   std::string getAvailableModules() const;
+  std::string getModuleInfo(const std::string& module_name) const;
 
   const ModuleRepository& operator=(const ModuleRepository&) = delete;
   const ModuleRepository& operator=(ModuleRepository&&) = delete;
-- 
GitLab