From 8366faeb25f7d9958ababcb7459c0c8814d02555 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 31 Jan 2020 19:24:40 +0100
Subject: [PATCH] Continue vector component affectation (still buggy)

---
 .../node_processor/AffectationProcessor.hpp   | 135 +++++++++++++++++-
 1 file changed, 131 insertions(+), 4 deletions(-)

diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp
index 4080f3fc8..8e30fae59 100644
--- a/src/language/node_processor/AffectationProcessor.hpp
+++ b/src/language/node_processor/AffectationProcessor.hpp
@@ -54,7 +54,7 @@ struct AffOp<language::minuseq_op>
 
 struct IAffectationExecutor
 {
-  virtual void affect(DataVariant&& rhs) = 0;
+  virtual void affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) = 0;
 
   virtual ~IAffectationExecutor() = default;
 };
@@ -85,7 +85,7 @@ class AffectationExecutor final : public IAffectationExecutor
   }
 
   PUGS_INLINE void
-  affect(DataVariant&& rhs)
+  affect(ExecutionPolicy&, DataVariant&& rhs)
   {
     if constexpr (_is_defined) {
       if constexpr (std::is_same_v<ValueT, std::string>) {
@@ -118,6 +118,84 @@ class AffectationExecutor final : public IAffectationExecutor
   }
 };
 
+template <typename OperatorT, typename ArrayT, typename ValueT, typename DataT>
+class ComponentAffectationExecutor final : public IAffectationExecutor
+{
+ private:
+  ArrayT& m_lhs_array;
+  ASTNode& m_index_expression;
+
+  static inline const bool _is_defined{[] {
+    if constexpr (not std::is_same_v<typename ArrayT::data_type, ValueT>) {
+      return false;
+    } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) {
+      if constexpr (not std::is_same_v<OperatorT, language::eq_op>) {
+        return false;
+      }
+    }
+    return true;
+  }()};
+
+ public:
+  ComponentAffectationExecutor(ASTNode& node, ArrayT& lhs_array)
+    : m_lhs_array{lhs_array}, m_index_expression{*node.children[1]}
+  {
+    // LCOV_EXCL_START
+    if constexpr (not _is_defined) {
+      throw parse_error("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
+    }
+    // LCOV_EXCL_STOP
+  }
+
+  PUGS_INLINE void
+  affect(ExecutionPolicy& exec_policy, DataVariant&& rhs)
+  {
+    if constexpr (_is_defined) {
+      const int64_t index_value = [&](DataVariant&& value_variant) -> int64_t {
+        int64_t index_value = 0;
+        std::visit(
+          [&](auto&& value) {
+            using IndexValueT = std::decay_t<decltype(value)>;
+            if constexpr (std::is_integral_v<IndexValueT>) {
+              index_value = value;
+            } else {
+              throw parse_error("unexpected error: invalid index type", std::vector{m_index_expression.begin()});
+            }
+          },
+          value_variant);
+        return index_value;
+      }(m_index_expression.execute(exec_policy));
+
+      if constexpr (std::is_same_v<ValueT, std::string>) {
+        if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
+          if constexpr (std::is_same_v<std::string, DataT>) {
+            m_lhs_array[index_value] = std::get<DataT>(rhs);
+          } else {
+            m_lhs_array[index_value] = std::to_string(std::get<DataT>(rhs));
+          }
+        } else {
+          static_assert(std::is_same_v<OperatorT, language::pluseq_op>, "unexpected operator type");
+          if constexpr (std::is_same_v<std::string, DataT>) {
+            m_lhs_array[index_value] += std::get<std::string>(rhs);
+          } else {
+            m_lhs_array[index_value] += std::to_string(std::get<DataT>(rhs));
+          }
+        }
+      } else {
+        if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
+          if constexpr (std::is_same_v<ValueT, DataT>) {
+            m_lhs_array[index_value] = std::get<DataT>(rhs);
+          } else {
+            m_lhs_array[index_value] = static_cast<ValueT>(std::get<DataT>(rhs));
+          }
+        } else {
+          AffOp<OperatorT>().eval(m_lhs_array[index_value], std::get<DataT>(rhs));
+        }
+      }
+    }
+  }
+};
+
 template <typename OperatorT, typename ValueT, typename DataT>
 class AffectationProcessor final : public INodeProcessor
 {
@@ -130,7 +208,7 @@ class AffectationProcessor final : public INodeProcessor
   DataVariant
   execute(ExecutionPolicy& exec_policy)
   {
-    m_affectation_executor->affect(m_node.children[1]->execute(exec_policy));
+    m_affectation_executor->affect(exec_policy, m_node.children[1]->execute(exec_policy));
 
     return {};
   }
@@ -149,6 +227,55 @@ class AffectationProcessor final : public INodeProcessor
 
       using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>;
       m_affectation_executor     = std::make_unique<AffectationExecutorT>(m_node, std::get<ValueT>(value));
+    } else if (node.children[0]->is_type<language::subscript_expression>()) {
+      auto& array_subscript_expression = *node.children[0];
+
+      auto& array_expression = *array_subscript_expression.children[0];
+      Assert(array_expression.is_type<language::name>());
+
+      const std::string& symbol = array_expression.string();
+
+      auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
+      Assert(found);
+      DataVariant& value = i_symbol->attributes().value();
+
+      if (array_expression.m_data_type != ASTNodeDataType::vector_t) {
+        throw parse_error("unexpected error: invalid lhs (expecting R^d)", std::vector{node.children[0]->begin()});
+      }
+
+      switch (array_expression.m_data_type.dimension()) {
+      case 1: {
+        using ArrayTypeT = TinyVector<1>;
+        if (not std::holds_alternative<ArrayTypeT>(value)) {
+          value = ArrayTypeT{};
+        }
+        using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
+        m_affectation_executor     = std::make_unique<AffectationExecutorT>(m_node, std::get<ArrayTypeT>(value));
+        break;
+      }
+      case 2: {
+        using ArrayTypeT = TinyVector<2>;
+        if (not std::holds_alternative<ArrayTypeT>(value)) {
+          value = ArrayTypeT{};
+        }
+        using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
+        m_affectation_executor     = std::make_unique<AffectationExecutorT>(m_node, std::get<ArrayTypeT>(value));
+        break;
+      }
+      case 3: {
+        using ArrayTypeT = TinyVector<3>;
+        if (not std::holds_alternative<ArrayTypeT>(value)) {
+          value = ArrayTypeT{};
+        }
+        using AffectationExecutorT = ComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
+        m_affectation_executor     = std::make_unique<AffectationExecutorT>(m_node, std::get<ArrayTypeT>(value));
+        break;
+      }
+      default: {
+        throw parse_error("unexpected error: invalid vector dimension", std::vector{node.children[0]->begin()});
+      }
+      }
+
     } else {
       throw parse_error("unexpected error: invalid lhs", std::vector{node.children[0]->begin()});
     }
@@ -264,7 +391,7 @@ class ListAffectationProcessor final : public INodeProcessor
     Assert(m_affectation_executor_list.size() == children_values.size());
 
     for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) {
-      m_affectation_executor_list[i]->affect(std::move(children_values[i]));
+      m_affectation_executor_list[i]->affect(exec_policy, std::move(children_values[i]));
     }
 
     return {};
-- 
GitLab