From 5af5af83bb01bc5cfd6a6d56f3d38acdfdb87bad 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 16:28:16 +0100
Subject: [PATCH] Add a mandatory property to IModule

Mandatory modules are load without the need to be explicitly imported
in the script file.

By now the only required module is 'core'.
---
 src/language/ast/ASTModulesImporter.cpp   |  2 +-
 src/language/modules/BuiltinModule.cpp    |  2 ++
 src/language/modules/BuiltinModule.hpp    | 10 +++++-
 src/language/modules/CoreModule.cpp       |  2 +-
 src/language/modules/IModule.hpp          |  2 ++
 src/language/modules/ModuleRepository.cpp | 41 +++++++++++++----------
 src/language/modules/ModuleRepository.hpp |  2 +-
 7 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/src/language/ast/ASTModulesImporter.cpp b/src/language/ast/ASTModulesImporter.cpp
index 5ef3b5804..d52b964a8 100644
--- a/src/language/ast/ASTModulesImporter.cpp
+++ b/src/language/ast/ASTModulesImporter.cpp
@@ -37,7 +37,7 @@ ASTModulesImporter::_importAllModules(ASTNode& node)
 ASTModulesImporter::ASTModulesImporter(ASTNode& root_node) : m_symbol_table{*root_node.m_symbol_table}
 {
   Assert(root_node.is_root());
-  m_module_repository.populateCoreSymbolTable(root_node, m_symbol_table);
+  m_module_repository.populateMandatorySymbolTable(root_node, m_symbol_table);
 
   this->_importAllModules(root_node);
   std::cout << " - loaded modules\n";
diff --git a/src/language/modules/BuiltinModule.cpp b/src/language/modules/BuiltinModule.cpp
index 0ab791139..22d23f803 100644
--- a/src/language/modules/BuiltinModule.cpp
+++ b/src/language/modules/BuiltinModule.cpp
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+BuiltinModule::BuiltinModule(bool is_mandatory) : m_is_mandatory{is_mandatory} {}
+
 void
 BuiltinModule::_addBuiltinFunction(const std::string& name,
                                    std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder)
diff --git a/src/language/modules/BuiltinModule.hpp b/src/language/modules/BuiltinModule.hpp
index bf8743c9e..6ea3ee56a 100644
--- a/src/language/modules/BuiltinModule.hpp
+++ b/src/language/modules/BuiltinModule.hpp
@@ -18,7 +18,15 @@ class BuiltinModule : public IModule
 
   void _addTypeDescriptor(const ASTNodeDataType& type);
 
+  const bool m_is_mandatory;
+
  public:
+  bool
+  isMandatory() const final
+  {
+    return m_is_mandatory;
+  }
+
   const NameBuiltinFunctionMap&
   getNameBuiltinFunctionMap() const final
   {
@@ -31,7 +39,7 @@ class BuiltinModule : public IModule
     return m_name_type_map;
   }
 
-  BuiltinModule() = default;
+  BuiltinModule(bool is_mandatory = false);
 
   ~BuiltinModule() = default;
 };
diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index c9a214306..d3408934d 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -6,7 +6,7 @@
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <utils/PugsUtils.hpp>
 
-CoreModule::CoreModule()
+CoreModule::CoreModule() : BuiltinModule(true)
 {
   this->_addBuiltinFunction("getPugsVersion", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>(
 
diff --git a/src/language/modules/IModule.hpp b/src/language/modules/IModule.hpp
index b839ed496..48e4b1536 100644
--- a/src/language/modules/IModule.hpp
+++ b/src/language/modules/IModule.hpp
@@ -19,6 +19,8 @@ class IModule
   IModule(IModule&&) = default;
   IModule& operator=(IModule&&) = default;
 
+  virtual bool isMandatory() const = 0;
+
   virtual const NameBuiltinFunctionMap& getNameBuiltinFunctionMap() const = 0;
 
   virtual const NameTypeMap& getNameTypeMap() const = 0;
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index 1fff5dda8..13cc6f079 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -13,6 +13,8 @@
 #include <language/utils/SymbolTable.hpp>
 #include <utils/PugsAssert.hpp>
 
+#include <algorithm>
+
 void
 ModuleRepository::_subscribe(std::unique_ptr<IModule> m)
 {
@@ -80,23 +82,18 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab
 }
 
 void
-ModuleRepository::populateCoreSymbolTable(const ASTNode& root_node, SymbolTable& symbol_table)
+ModuleRepository::populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table)
 {
-  const std::string& module_name = "core";
-
-  auto i_module = m_module_set.find(module_name);
-  if (i_module != m_module_set.end()) {
-    const IModule& populating_module = *i_module->second;
-
-    this->_populateEmbedderTableT(root_node, module_name, populating_module.getNameBuiltinFunctionMap(),
-                                  ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>(), symbol_table,
-                                  symbol_table.builtinFunctionEmbedderTable());
-
-    this->_populateEmbedderTableT(root_node, module_name, populating_module.getNameTypeMap(),
-                                  ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
-                                  symbol_table.typeEmbedderTable());
-  } else {
-    throw ParseError(std::string{"could not find module "} + module_name, std::vector{root_node.begin()});
+  for (auto&& [module_name, i_module] : m_module_set) {
+    if (i_module->isMandatory()) {
+      this->_populateEmbedderTableT(root_node, module_name, i_module->getNameBuiltinFunctionMap(),
+                                    ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>(), symbol_table,
+                                    symbol_table.builtinFunctionEmbedderTable());
+
+      this->_populateEmbedderTableT(root_node, module_name, i_module->getNameTypeMap(),
+                                    ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
+                                    symbol_table.typeEmbedderTable());
+    }
   }
 }
 
@@ -104,9 +101,17 @@ std::string
 ModuleRepository::getAvailableModules() const
 {
   std::stringstream os;
-  os << rang::fgB::yellow << "Available modules" << rang::style::reset << '\n';
+  os << rang::fgB::yellow << "Available modules" << rang::fg::blue << " [modules tagged with a " << rang::style::reset
+     << rang::style::bold << '*' << rang::style::reset << rang::fg::blue << " are automatically imported]"
+     << rang::style::reset << '\n';
   for (auto& [name, i_module] : m_module_set) {
-    os << "  " << rang::fg::green << name << rang::style::reset << '\n';
+    if (i_module->isMandatory()) {
+      os << rang::style::bold << " *" << rang::style::reset;
+    } else {
+      os << "  ";
+    }
+    os << rang::fgB::green << name << rang::style::reset << '\n';
   }
+
   return os.str();
 }
diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp
index b6983eb54..5a211f2bb 100644
--- a/src/language/modules/ModuleRepository.hpp
+++ b/src/language/modules/ModuleRepository.hpp
@@ -28,7 +28,7 @@ class ModuleRepository
 
  public:
   void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table);
-  void populateCoreSymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
+  void populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
 
   std::string getAvailableModules() const;
 
-- 
GitLab