From ac9400d4df4d8f00a70c4f513934400b2a47df37 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Thu, 23 Jan 2020 11:27:43 +0100
Subject: [PATCH] Continue introduction of R^d vectors with d in {1,2,3}

These are the so-called `TinyVector` (their size is known at compilation time).

On the way ASTNodeDataType has evolved from an `enum class` to a real `class` to
allow the description of more complex types. In is no more just a flag.

First new data is the dimension of the object.
---
 .../ASTNodeAffectationExpressionBuilder.cpp   | 57 ++++++++++++++++++-
 src/language/ASTNodeDataType.cpp              |  3 +
 src/language/ASTNodeDataType.hpp              | 55 ++++++++++++++----
 src/language/ASTNodeDataTypeBuilder.cpp       | 12 +++-
 src/language/DataVariant.hpp                  | 19 ++++++-
 5 files changed, 126 insertions(+), 20 deletions(-)

diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
index f0b5a93be..e30b0380a 100644
--- a/src/language/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -5,6 +5,8 @@
 
 #include <node_processor/AffectationProcessor.hpp>
 
+#include <../algebra/TinyVector.hpp>
+
 ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode& n)
 {
   auto set_affectation_processor = [](ASTNode& n, const auto& operator_v) {
@@ -38,6 +40,28 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
       }
     };
 
+    auto set_affectation_processor_for_vector_data = [&](const auto& value, const ASTNodeDataType& data_type) {
+      using OperatorT = std::decay_t<decltype(operator_v)>;
+      using ValueT    = std::decay_t<decltype(value)>;
+
+      if constexpr (std::is_same_v<OperatorT, language::eq_op> or std::is_same_v<OperatorT, language::pluseq_op>) {
+        switch (data_type) {
+        case ASTNodeDataType::vector_t: {
+          n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, ValueT>>(n);
+          break;
+        }
+          // LCOV_EXCL_START
+        default: {
+          throw parse_error("unexpected error: undefined operand type for vector affectation",
+                            std::vector{n.children[1]->begin()});
+        }
+          // LCOV_EXCL_STOP
+        }
+      } else {
+        throw parse_error("unexpected error: undefined operator type", std::vector{n.children[0]->begin()});
+      }
+    };
+
     auto set_affectation_processor_for_string_data = [&](const ASTNodeDataType& data_type) {
       using OperatorT = std::decay_t<decltype(operator_v)>;
 
@@ -78,8 +102,6 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
     auto set_affectation_processor_for_value = [&](const ASTNodeDataType& value_type) {
       const ASTNodeDataType data_type = n.children[1]->m_data_type;
 
-      ASTNodeNaturalConversionChecker{n, data_type, value_type};
-
       switch (value_type) {
       case ASTNodeDataType::bool_t: {
         set_affectation_processor_for_data(bool{}, data_type);
@@ -97,6 +119,10 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         set_affectation_processor_for_data(double{}, data_type);
         break;
       }
+      case ASTNodeDataType::vector_t: {
+        set_affectation_processor_for_vector_data(TinyVector<3>{}, data_type);
+        break;
+      }
       case ASTNodeDataType::string_t: {
         set_affectation_processor_for_string_data(data_type);
         break;
@@ -107,6 +133,33 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
       }
     };
 
+    if (n.m_data_type == ASTNodeDataType::vector_t) {
+      // Only real data are considered
+      const ASTNode& data_node = *n.children[1];
+      switch (data_node.m_data_type) {
+      case ASTNodeDataType::list_t: {
+        if (data_node.children.size() != n.m_data_type.dimension()) {
+          throw parse_error("incompatible dimensions in affectation", std::vector{n.begin()});
+        }
+        for (const auto& child : data_node.children) {
+          ASTNodeNaturalConversionChecker{n, child->m_data_type, ASTNodeDataType::double_t};
+        }
+        break;
+      }
+      case ASTNodeDataType::vector_t: {
+        if (data_node.children.size() != n.m_data_type.dimension()) {
+          throw parse_error("incompatible dimensions in affectation", std::vector{n.begin()});
+        }
+        break;
+      }
+      default: {
+        throw parse_error("invalid operand for affectation", std::vector{n.children[1]->begin()});
+      }
+      }
+    } else {
+      ASTNodeNaturalConversionChecker{n, n.children[1]->m_data_type, n.m_data_type};
+    }
+
     set_affectation_processor_for_value(n.m_data_type);
   };
 
diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
index f510344bf..9e5dc669a 100644
--- a/src/language/ASTNodeDataType.cpp
+++ b/src/language/ASTNodeDataType.cpp
@@ -38,6 +38,9 @@ dataTypeName(const ASTNodeDataType& data_type)
   case ASTNodeDataType::void_t:
     name = "void";
     break;
+  case ASTNodeDataType::list_t:
+    name = "list";
+    break;
   }
   return name;
 }
diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp
index 214ce45df..79ae74453 100644
--- a/src/language/ASTNodeDataType.hpp
+++ b/src/language/ASTNodeDataType.hpp
@@ -6,19 +6,50 @@
 
 class ASTNode;
 
-enum class ASTNodeDataType : int32_t
+class ASTNodeDataType
 {
-  undefined_t    = -1,
-  bool_t         = 0,
-  int_t          = 1,
-  unsigned_int_t = 2,
-  double_t       = 3,
-  vector_t       = 4,
-  string_t       = 5,
-  typename_t     = 10,
-  function_t     = 11,
-  c_function_t   = 12,
-  void_t         = std::numeric_limits<int32_t>::max()
+ public:
+  enum DataType : int32_t
+  {
+    undefined_t    = -1,
+    bool_t         = 0,
+    int_t          = 1,
+    unsigned_int_t = 2,
+    double_t       = 3,
+    vector_t       = 4,
+    list_t         = 5,
+    string_t       = 6,
+    typename_t     = 10,
+    function_t     = 11,
+    c_function_t   = 12,
+    void_t         = std::numeric_limits<int32_t>::max()
+  };
+
+ private:
+  DataType m_data_type;
+  size_t m_dimension;
+
+ public:
+  size_t
+  dimension() const
+  {
+    return m_dimension;
+  }
+
+  operator DataType() const
+  {
+    return m_data_type;
+  }
+
+  ASTNodeDataType& operator=(const ASTNodeDataType&) = default;
+
+  constexpr ASTNodeDataType(DataType data_type) : m_data_type{data_type}, m_dimension{1} {}
+
+  ASTNodeDataType(DataType data_type, size_t dimension) : m_data_type{data_type}, m_dimension{dimension} {}
+
+  ASTNodeDataType(const ASTNodeDataType&) = default;
+
+  ~ASTNodeDataType() = default;
 };
 
 std::string dataTypeName(const ASTNodeDataType& data_type);
diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index ad39a0183..b7e349374 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -38,7 +38,12 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo
     } else if (type_node.is_type<language::R_set>()) {
       data_type = ASTNodeDataType::double_t;
     } else if (type_node.is_type<language::vector_type>()) {
-      data_type = ASTNodeDataType::vector_t;
+      ASTNode& dimension_node = *type_node.children[1];
+      if (not dimension_node.is_type<language::integer>()) {
+        throw parse_error("unexpected non integer constant dimension", dimension_node.begin());
+      }
+      const size_t dimension = std::stol(dimension_node.string());
+      data_type              = ASTNodeDataType{ASTNodeDataType::vector_t, dimension};
     } else if (type_node.is_type<language::string_type>()) {
       data_type = ASTNodeDataType::string_t;
     }
@@ -387,9 +392,10 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
     } else if (n.is_type<language::B_set>() or n.is_type<language::Z_set>() or n.is_type<language::N_set>() or
                n.is_type<language::R_set>() or n.is_type<language::string_type>()) {
       n.m_data_type = ASTNodeDataType::typename_t;
-    } else if (n.is_type<language::name_list>() or n.is_type<language::expression_list>() or
-               n.is_type<language::function_argument_list>()) {
+    } else if (n.is_type<language::name_list>() or n.is_type<language::function_argument_list>()) {
       n.m_data_type = ASTNodeDataType::void_t;
+    } else if (n.is_type<language::expression_list>()) {
+      n.m_data_type = ASTNodeDataType::list_t;
     }
   }
 }
diff --git a/src/language/DataVariant.hpp b/src/language/DataVariant.hpp
index 9c19870f5..54abc6692 100644
--- a/src/language/DataVariant.hpp
+++ b/src/language/DataVariant.hpp
@@ -5,11 +5,22 @@
 #include <variant>
 #include <vector>
 
+#include <../algebra/TinyVector.hpp>
+
 #include <PugsAssert.hpp>
 
 class AggregateDataVariant;
 
-using DataVariant = std::variant<std::monostate, bool, uint64_t, int64_t, double, std::string, AggregateDataVariant>;
+using DataVariant = std::variant<std::monostate,
+                                 bool,
+                                 uint64_t,
+                                 int64_t,
+                                 double,
+                                 std::string,
+                                 AggregateDataVariant,
+                                 TinyVector<1>,
+                                 TinyVector<2>,
+                                 TinyVector<3>>;
 
 class AggregateDataVariant   // LCOV_EXCL_LINE
 {
@@ -60,14 +71,16 @@ class AggregateDataVariant   // LCOV_EXCL_LINE
   }
 
   PUGS_INLINE
-  DataVariant& operator[](size_t i)
+  DataVariant&
+  operator[](size_t i)
   {
     Assert(i < m_data_vector.size());
     return m_data_vector[i];
   }
 
   PUGS_INLINE
-  const DataVariant& operator[](size_t i) const
+  const DataVariant&
+  operator[](size_t i) const
   {
     Assert(i < m_data_vector.size());
     return m_data_vector[i];
-- 
GitLab