From e00fe905e89c0d13463023eb4f292af7a15e4632 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 24 Jan 2020 17:45:39 +0100
Subject: [PATCH] Terminate R^d vectors declarations and affectation

One can now write
``
R^3 u = (1, 2, 3);
R^3 v = u;

R^3 w = 0; // One cannot give another scalar value: just the constant value 0
           // that is `R^3 w = 1-1;` is an error!

w += u;    // w and u belong to the same space R^d (with d=3 here)

v *= 2.5-1;// the right hand side is a scalar expression that can be naturally
           // cast to an R

v -= u;
``
These constructions are allowed for small vectors: valid types are `R^1`, `R^2`
and `R^3`.

Remark: tuples are only allowed in initialization:
``
R^2 v = (0,1); // ok

R^2 w ;
w = (2,3);     // ok

w += (1,4);    // forbidden
``
---
 .../ASTNodeAffectationExpressionBuilder.cpp   | 100 ++++++++++++++++--
 src/language/ASTNodeDataType.cpp              |   2 +-
 .../node_processor/AffectationProcessor.hpp   |  71 +++++++++++++
 3 files changed, 165 insertions(+), 8 deletions(-)

diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
index e30b0380a..8c615e6e2 100644
--- a/src/language/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -44,21 +44,91 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
       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>) {
+      if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
         switch (data_type) {
         case ASTNodeDataType::vector_t: {
           n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, ValueT>>(n);
           break;
+        }
+        case ASTNodeDataType::list_t: {
+          n.m_node_processor = std::make_unique<AffectationFromListProcessor<OperatorT, ValueT>>(n);
+          break;
+        }
+        case ASTNodeDataType::bool_t: {
+          if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+            n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n);
+            break;
+          }
+        }
+        case ASTNodeDataType::unsigned_int_t: {
+          if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+            n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n);
+            break;
+          }
+        }
+        case ASTNodeDataType::int_t: {
+          if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+            n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n);
+            break;
+          } else {
+            if (n.children[1]->is_type<language::integer>()) {
+              if (std::stoi(n.children[1]->string()) == 0) {
+                n.m_node_processor = std::make_unique<AffectationFromZeroProcessor<ValueT>>(n);
+                break;
+              }
+            }
+          }
+          throw parse_error("invalid operand value", std::vector{n.children[1]->begin()});
+        }
+        case ASTNodeDataType::double_t: {
+          if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+            n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n);
+            break;
+          }
         }
           // LCOV_EXCL_START
         default: {
-          throw parse_error("unexpected error: undefined operand type for vector affectation",
-                            std::vector{n.children[1]->begin()});
+          throw parse_error("invalid operand type", std::vector{n.children[1]->begin()});
         }
           // LCOV_EXCL_STOP
         }
+      } else if constexpr (std::is_same_v<OperatorT, language::pluseq_op> or
+                           std::is_same_v<OperatorT, language::minuseq_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("invalid operand type", std::vector{n.children[1]->begin()});
+        }
+          // LCOV_EXCL_STOP
+        }
+      } else if constexpr (std::is_same_v<OperatorT, language::multiplyeq_op>) {
+        switch (data_type) {
+        case ASTNodeDataType::bool_t: {
+          n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n);
+          break;
+        }
+        case ASTNodeDataType::unsigned_int_t: {
+          n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n);
+          break;
+        }
+        case ASTNodeDataType::int_t: {
+          n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n);
+          break;
+        }
+        case ASTNodeDataType::double_t: {
+          n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n);
+          break;
+        }
+        default: {
+          throw parse_error("invalid operand", std::vector{n.children[1]->begin()});
+        }
+        }
       } else {
-        throw parse_error("unexpected error: undefined operator type", std::vector{n.children[0]->begin()});
+        throw parse_error("invalid operator type", std::vector{n.begin()});
       }
     };
 
@@ -120,7 +190,23 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         break;
       }
       case ASTNodeDataType::vector_t: {
-        set_affectation_processor_for_vector_data(TinyVector<3>{}, data_type);
+        switch (value_type.dimension()) {
+        case 1: {
+          set_affectation_processor_for_vector_data(TinyVector<1>{}, data_type);
+          break;
+        }
+        case 2: {
+          set_affectation_processor_for_vector_data(TinyVector<2>{}, data_type);
+          break;
+        }
+        case 3: {
+          set_affectation_processor_for_vector_data(TinyVector<3>{}, data_type);
+          break;
+        }
+        default: {
+          throw parse_error("unexpected error: unexpected vector dimension", std::vector{n.begin()});
+        }
+        }
         break;
       }
       case ASTNodeDataType::string_t: {
@@ -144,16 +230,16 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
         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()) {
+        if (data_node.m_data_type.dimension() != 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 {
diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
index 9e5dc669a..faf26caef 100644
--- a/src/language/ASTNodeDataType.cpp
+++ b/src/language/ASTNodeDataType.cpp
@@ -21,7 +21,7 @@ dataTypeName(const ASTNodeDataType& data_type)
     name = "R";
     break;
   case ASTNodeDataType::vector_t:
-    name = "vector";
+    name = "vector[" + std::to_string(data_type.dimension()) + "]";
     break;
   case ASTNodeDataType::string_t:
     name = "string";
diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index 0c9b751ea..a84e42c76 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -146,6 +146,77 @@ class AffectationProcessor final : public INodeProcessor
   }
 };
 
+template <typename OperatorT, typename ValueT>
+class AffectationFromListProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+
+  DataVariant* m_lhs;
+
+ public:
+  DataVariant
+  execute(ExecutionPolicy& exec_policy)
+  {
+    AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
+
+    static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to vectors");
+
+    ValueT v;
+    for (size_t i = 0; i < v.dimension(); ++i) {
+      std::visit(
+        [&](auto&& child_value) {
+          using T = std::decay_t<decltype(child_value)>;
+          if constexpr (std::is_same_v<T, bool> or std::is_same_v<T, uint64_t> or std::is_same_v<T, int64_t> or
+                        std::is_same_v<T, double>) {
+            v[i] = child_value;
+          } else {
+            throw parse_error("unexpected error: unexpected right hand side type in affectation", m_node.begin());
+          }
+        },
+        children_values[i]);
+    }
+
+    *m_lhs = v;
+    return {};
+  }
+
+  AffectationFromListProcessor(ASTNode& node) : m_node{node}
+  {
+    const std::string& symbol = m_node.children[0]->string();
+    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
+    Assert(found);
+
+    m_lhs = &i_symbol->attributes().value();
+  }
+};
+
+template <typename ValueT>
+class AffectationFromZeroProcessor final : public INodeProcessor
+{
+ private:
+  ASTNode& m_node;
+
+  DataVariant* m_lhs;
+
+ public:
+  DataVariant
+  execute(ExecutionPolicy&)
+  {
+    *m_lhs = ValueT{zero};
+    return {};
+  }
+
+  AffectationFromZeroProcessor(ASTNode& node) : m_node{node}
+  {
+    const std::string& symbol = m_node.children[0]->string();
+    auto [i_symbol, found]    = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
+    Assert(found);
+
+    m_lhs = &i_symbol->attributes().value();
+  }
+};
+
 template <typename OperatorT>
 class ListAffectationProcessor final : public INodeProcessor
 {
-- 
GitLab