From d080ce5f52421e4a756d2bebb4ac614f3ab3592c Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 10 Feb 2020 18:41:25 +0100
Subject: [PATCH] Fix initialization checker for subscript expressions and add
 tests

The subscript initialization checker is definitely not satisfactory, but it is
an on going fact: many treatment (none trivial ones should be performed).

By now it is just a simple helper, and should require much improvements. Not
sure that it is the right strategy. One should maybe force initialization...

However, this is a second-order question that should be addressed in a far(?)
future.
---
 src/language/ASTBuilder.cpp                   |  2 +
 .../ASTSymbolInitializationChecker.cpp        |  6 ++
 tests/test_ASTSymbolInitializationChecker.cpp | 87 +++++++++++++++++++
 3 files changed, 95 insertions(+)

diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp
index 11ad02381..6a90a29c5 100644
--- a/src/language/ASTBuilder.cpp
+++ b/src/language/ASTBuilder.cpp
@@ -122,6 +122,8 @@ struct ASTBuilder::simplify_unary : parse_tree::apply<ASTBuilder::simplify_unary
 
           std::swap(array_subscript_expression->children[0], array_subscript_expression->children[1]);
 
+          array_subscript_expression->m_begin = array_subscript_expression->children[0]->m_begin;
+
           transform(n, st...);
         }
       }
diff --git a/src/language/ASTSymbolInitializationChecker.cpp b/src/language/ASTSymbolInitializationChecker.cpp
index e8c75adb3..c5cad3347 100644
--- a/src/language/ASTSymbolInitializationChecker.cpp
+++ b/src/language/ASTSymbolInitializationChecker.cpp
@@ -54,6 +54,12 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
 
     if (node.children[0]->is_type<language::name>()) {
       set_is_initialized(*node.children[0]);
+    } else if (node.children[0]->is_type<language::subscript_expression>()) {
+      ASTNode& subscript_node = *node.children[0];
+      ASTNode& name_node      = *subscript_node.children[0];
+
+      Assert(name_node.is_type<language::name>());
+      set_is_initialized(name_node);
     } else if (node.children[0]->is_type<language::name_list>() or node.children[0]->is_type<language::lvalue_list>()) {
       ASTNode& list_node = *node.children[0];
       for (auto& child_node : list_node.children) {
diff --git a/tests/test_ASTSymbolInitializationChecker.cpp b/tests/test_ASTSymbolInitializationChecker.cpp
index 46c9add1f..a9faafc59 100644
--- a/tests/test_ASTSymbolInitializationChecker.cpp
+++ b/tests/test_ASTSymbolInitializationChecker.cpp
@@ -37,6 +37,27 @@ N p;
     REQUIRE(not symbol_p->attributes().isInitialized());
   }
 
+  SECTION("Array subscript initialization")
+  {
+    std::string_view data = R"(
+R^3 x;
+x[0] = 1;
+)";
+
+    string_input input{data, "test.pgs"};
+    auto ast = ASTBuilder::build(input);
+
+    ASTSymbolTableBuilder{*ast};
+    ASTSymbolInitializationChecker{*ast};
+
+    position position{internal::iterator{"fixture"}, "fixture"};
+    position.byte = data.size();   // ensure that variables are declared at this point
+
+    auto [symbol_m, found_m] = ast->m_symbol_table->find("x", position);
+    REQUIRE(found_m);
+    REQUIRE(symbol_m->attributes().isInitialized());
+  }
+
   SECTION("Declaration plus affectation")
   {
     std::string_view data = R"(
@@ -115,6 +136,26 @@ R*R (x,y) = (2.3, 4.1);
       REQUIRE(symbol_y->attributes().isInitialized());
     }
 
+    SECTION("Declarative initialization")
+    {
+      std::string_view data = R"(
+R^2 x = (2.3, 4.1);
+)";
+
+      string_input input{data, "test.pgs"};
+      auto ast = ASTBuilder::build(input);
+
+      ASTSymbolTableBuilder{*ast};
+      ASTSymbolInitializationChecker{*ast};
+
+      position position{internal::iterator{"fixture"}, "fixture"};
+      position.byte = data.size();   // ensure that variables are declared at this point
+
+      auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position);
+      REQUIRE(found_x);
+      REQUIRE(symbol_x->attributes().isInitialized());
+    }
+
     SECTION("Not initialized")
     {
       std::string_view data = R"(
@@ -164,6 +205,52 @@ R*R (x,y);
       REQUIRE(found_y);
       REQUIRE(symbol_y->attributes().isInitialized());
     }
+
+    SECTION("Affectation")
+    {
+      std::string_view data = R"(
+R^3*R (x,y);
+(x,y) = ((2.3, 2, 5), 4.1);
+)";
+
+      string_input input{data, "test.pgs"};
+      auto ast = ASTBuilder::build(input);
+
+      ASTSymbolTableBuilder{*ast};
+      ASTSymbolInitializationChecker{*ast};
+
+      position position{internal::iterator{"fixture"}, "fixture"};
+      position.byte = data.size();   // ensure that variables are declared at this point
+
+      auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position);
+      REQUIRE(found_x);
+      REQUIRE(symbol_x->attributes().isInitialized());
+
+      auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position);
+      REQUIRE(found_y);
+      REQUIRE(symbol_y->attributes().isInitialized());
+    }
+  }
+
+  SECTION("Affectation")
+  {
+    std::string_view data = R"(
+R^3 x;
+(x[2], x[1], x[0]) = (1, 2, 3);
+)";
+
+    string_input input{data, "test.pgs"};
+    auto ast = ASTBuilder::build(input);
+
+    ASTSymbolTableBuilder{*ast};
+    ASTSymbolInitializationChecker{*ast};
+
+    position position{internal::iterator{"fixture"}, "fixture"};
+    position.byte = data.size();   // ensure that variables are declared at this point
+
+    auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position);
+    REQUIRE(found_x);
+    REQUIRE(symbol_x->attributes().isInitialized());
   }
 
   SECTION("errors")
-- 
GitLab