From 8e5a94314f75949ff67a89cab77a610cb584633c Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Tue, 11 Feb 2020 17:40:24 +0100
Subject: [PATCH] Add missing tests for ASTNodeExpressionBuilder

By the way fix a bunch of bugs related to R -> R^1 conversions.
There are probably other bugs especially in the case of function whose
args/return contain R^1.
---
 .../ASTNodeAffectationExpressionBuilder.cpp   | 14 ++--
 src/language/ASTNodeExpressionBuilder.cpp     |  7 +-
 ...STNodeListAffectationExpressionBuilder.cpp | 35 +++++++---
 tests/test_ASTNodeExpressionBuilder.cpp       | 68 +++++++++++++++++++
 4 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp
index 592c9295c..8c018fe3b 100644
--- a/src/language/ASTNodeAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp
@@ -67,14 +67,20 @@ ASTNodeAffectationExpressionBuilder::ASTNodeAffectationExpressionBuilder(ASTNode
           }
         }
         case ASTNodeDataType::int_t: {
-          if (n.children[1]->is_type<language::integer>()) {
+          if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+            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;
+              }
+            }
+            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;
             }
-          } else if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
-            n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n);
-            break;
           }
           // LCOV_EXCL_START
           throw parse_error("unexpected error: invalid integral value", std::vector{n.children[1]->begin()});
diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp
index 55d2db53a..ff21fb58b 100644
--- a/src/language/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ASTNodeExpressionBuilder.cpp
@@ -42,10 +42,7 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
 
   } else if (n.is_type<language::tuple_expression>()) {
     switch (n.children.size()) {
-    case 1: {
-      n.m_node_processor = std::make_unique<TupleToVectorProcessor<ASTNodeExpressionListProcessor, 1>>(n);
-      break;
-    }
+      // tuples are made of at least two elements
     case 2: {
       n.m_node_processor = std::make_unique<TupleToVectorProcessor<ASTNodeExpressionListProcessor, 2>>(n);
       break;
@@ -54,9 +51,11 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
       n.m_node_processor = std::make_unique<TupleToVectorProcessor<ASTNodeExpressionListProcessor, 3>>(n);
       break;
     }
+      // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: invalid tuple size", n.begin());
     }
+      // LCOV_EXCL_STOP
     }
   } else if (n.is_type<language::function_definition>()) {
     n.m_node_processor = std::make_unique<FakeProcessor>();
diff --git a/src/language/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ASTNodeListAffectationExpressionBuilder.cpp
index 2c14148ec..2829e8715 100644
--- a/src/language/ASTNodeListAffectationExpressionBuilder.cpp
+++ b/src/language/ASTNodeListAffectationExpressionBuilder.cpp
@@ -44,21 +44,33 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
   auto add_affectation_processor_for_vector_data = [&](const auto& value,
                                                        const ASTNodeSubDataType& node_sub_data_type) {
     using ValueT = std::decay_t<decltype(value)>;
-    if (node_sub_data_type.m_data_type.dimension() == value.dimension()) {
-      list_affectation_processor->template add<ValueT, ValueT>(value_node);
-    } else if (node_sub_data_type.m_parent_node.is_type<language::integer>()) {
-      if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) {
-        list_affectation_processor->template add<ValueT, ZeroType>(value_node);
+    if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
+      if ((node_sub_data_type.m_data_type == ASTNodeDataType::vector_t) and
+          (node_sub_data_type.m_data_type.dimension() == value.dimension())) {
+        list_affectation_processor->template add<ValueT, ValueT>(value_node);
       } else {
-        throw parse_error("invalid operand value", std::vector{node_sub_data_type.m_parent_node.begin()});
+        add_affectation_processor_for_data(value, node_sub_data_type);
+      }
+    } else if constexpr (std::is_same_v<ValueT, TinyVector<2>> or std::is_same_v<ValueT, TinyVector<3>>) {
+      if ((node_sub_data_type.m_data_type == ASTNodeDataType::vector_t) and
+          (node_sub_data_type.m_data_type.dimension() == value.dimension())) {
+        list_affectation_processor->template add<ValueT, ValueT>(value_node);
+      } else if (node_sub_data_type.m_parent_node.is_type<language::integer>()) {
+        if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) {
+          list_affectation_processor->template add<ValueT, ZeroType>(value_node);
+        } else {
+          throw parse_error("invalid operand value", std::vector{node_sub_data_type.m_parent_node.begin()});
+        }
+      } else {
+        throw parse_error("invalid dimension", std::vector{node_sub_data_type.m_parent_node.begin()});
       }
     } else {
-      throw parse_error("invalid dimension", std::vector{node_sub_data_type.m_parent_node.begin()});
+      throw parse_error("unexpected error: invalid value type");
     }
   };
 
   auto add_affectation_processor_for_string_data = [&](const ASTNodeSubDataType& node_sub_data_type) {
-    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 (node_sub_data_type.m_data_type) {
       case ASTNodeDataType::bool_t: {
         list_affectation_processor->template add<std::string, bool>(value_node);
@@ -145,7 +157,12 @@ ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor(
     }
   };
 
-  ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, value_node.m_data_type};
+  if ((value_node.m_data_type != rhs_node_sub_data_type.m_data_type) and
+      (value_node.m_data_type == ASTNodeDataType::vector_t) and (value_node.m_data_type.dimension() == 1)) {
+    ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, ASTNodeDataType::double_t};
+  } else {
+    ASTNodeNaturalConversionChecker{rhs_node_sub_data_type, value_node.m_data_type};
+  }
 
   add_affectation_processor_for_value(value_node.m_data_type, rhs_node_sub_data_type);
 }
diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp
index bee00ca0a..e2e14d267 100644
--- a/tests/test_ASTNodeExpressionBuilder.cpp
+++ b/tests/test_ASTNodeExpressionBuilder.cpp
@@ -264,6 +264,51 @@ z -= 2;
 
       CHECK_AST(data, result);
     }
+
+    SECTION("tuple -> R^3")
+    {
+      std::string_view data = R"(
+R*R^3 (t,x) = (0,(1,2,3));
+)";
+
+      std::string result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::eq_op:ListAffectationProcessor<language::eq_op>)
+     +-(language::name_list:FakeProcessor)
+     |   +-(language::name:t:NameProcessor)
+     |   `-(language::name:x:NameProcessor)
+     `-(language::expression_list:ASTNodeExpressionListProcessor)
+         +-(language::integer:0:ValueProcessor)
+         `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor, 3ul>)
+             +-(language::integer:1:ValueProcessor)
+             +-(language::integer:2:ValueProcessor)
+             `-(language::integer:3:ValueProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple -> R^2")
+    {
+      std::string_view data = R"(
+R*R^2 (t,x) = (0,(1,2));
+)";
+
+      std::string result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::eq_op:ListAffectationProcessor<language::eq_op>)
+     +-(language::name_list:FakeProcessor)
+     |   +-(language::name:t:NameProcessor)
+     |   `-(language::name:x:NameProcessor)
+     `-(language::expression_list:ASTNodeExpressionListProcessor)
+         +-(language::integer:0:ValueProcessor)
+         `-(language::tuple_expression:TupleToVectorProcessor<ASTNodeExpressionListProcessor, 2ul>)
+             +-(language::integer:1:ValueProcessor)
+             `-(language::integer:2:ValueProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
   }
 
   SECTION("unary operators")
@@ -409,6 +454,29 @@ a--;
 
       CHECK_AST(data, result);
     }
+
+    SECTION("array subscript")
+    {
+      std::string_view data = R"(
+R^3 x = (1, 2, 3);
+x[2];
+)";
+
+      std::string result = R"(
+(root:ASTNodeListProcessor)
+ +-(language::eq_op:AffectationFromListProcessor<language::eq_op, TinyVector<3ul, double> >)
+ |   +-(language::name:x:NameProcessor)
+ |   `-(language::expression_list:ASTNodeExpressionListProcessor)
+ |       +-(language::integer:1:ValueProcessor)
+ |       +-(language::integer:2:ValueProcessor)
+ |       `-(language::integer:3:ValueProcessor)
+ `-(language::subscript_expression:ArraySubscriptProcessor<TinyVector<3ul, double> >)
+     +-(language::name:x:NameProcessor)
+     `-(language::integer:2:ValueProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
   }
 
   SECTION("binary operators")
-- 
GitLab