From b797c9f28ba96a50f8ac49517587fa54cc1b595e Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 26 Jul 2019 12:04:47 +0200
Subject: [PATCH] Continue clean-up. Add ASTNodeValueBuilder and its tests.

---
 src/language/ASTNodeValueBuilder.cpp |  55 +++++++++++
 src/language/ASTNodeValueBuilder.hpp |  15 +++
 src/language/CMakeLists.txt          |   5 +-
 src/language/PugsParser.cpp          |  61 +-----------
 tests/CMakeLists.txt                 |   3 +-
 tests/test_ASTNodeValueBuilder.cpp   | 138 +++++++++++++++++++++++++++
 6 files changed, 216 insertions(+), 61 deletions(-)
 create mode 100644 src/language/ASTNodeValueBuilder.cpp
 create mode 100644 src/language/ASTNodeValueBuilder.hpp
 create mode 100644 tests/test_ASTNodeValueBuilder.cpp

diff --git a/src/language/ASTNodeValueBuilder.cpp b/src/language/ASTNodeValueBuilder.cpp
new file mode 100644
index 000000000..19886da79
--- /dev/null
+++ b/src/language/ASTNodeValueBuilder.cpp
@@ -0,0 +1,55 @@
+#include <ASTNodeValueBuilder.hpp>
+
+#include <PEGGrammar.hpp>
+#include <PugsAssert.hpp>
+
+#include <EscapedString.hpp>
+
+void
+ASTNodeValueBuilder::_buildNodeValue(ASTNode& n)
+{
+  if (n.is<language::bloc>()) {
+    if (!n.children.empty()) {
+      for (auto& child : n.children) {
+        this->_buildNodeValue(*child);
+      }
+    }
+    n.m_data_type = ASTNodeDataType::void_t;
+  } else {
+    for (auto& child : n.children) {
+      this->_buildNodeValue(*child);
+    }
+
+    if (n.has_content()) {
+      if (n.is<language::real>()) {
+        std::stringstream ss(n.string());
+        double v;
+        ss >> v;
+        n.m_value = v;
+      } else if (n.is<language::integer>()) {
+        std::stringstream ss(n.string());
+        int64_t v;
+        ss >> v;
+        n.m_value = v;
+      } else if (n.is<language::literal>()) {
+        n.m_value = unescapeString(n.string());
+      } else if (n.is<language::for_test>()) {
+        // if AST contains a for_test statement, it means that no test were
+        // given to the for-loop, so its value is always true
+        n.m_value = true;
+      } else if (n.is<language::true_kw>()) {
+        n.m_value = true;
+      } else if (n.is<language::false_kw>()) {
+        n.m_value = false;
+      }
+    }
+  }
+}
+
+ASTNodeValueBuilder::ASTNodeValueBuilder(ASTNode& n)
+{
+  Assert(n.is_root());
+  n.m_data_type = ASTNodeDataType::void_t;
+  this->_buildNodeValue(n);
+  std::cout << " - build node data types\n";
+}
diff --git a/src/language/ASTNodeValueBuilder.hpp b/src/language/ASTNodeValueBuilder.hpp
new file mode 100644
index 000000000..0e60ccc71
--- /dev/null
+++ b/src/language/ASTNodeValueBuilder.hpp
@@ -0,0 +1,15 @@
+#ifndef AST_NODE_VALUE_BUILDER_HPP
+#define AST_NODE_VALUE_BUILDER_HPP
+
+#include <ASTNode.hpp>
+
+class ASTNodeValueBuilder
+{
+ private:
+  void _buildNodeValue(ASTNode& node);
+
+ public:
+  ASTNodeValueBuilder(ASTNode& root_node);
+};
+
+#endif   // AST_NODE_VALUE_BUILDER_HPP
diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt
index 5b14863b4..b6a386df0 100644
--- a/src/language/CMakeLists.txt
+++ b/src/language/CMakeLists.txt
@@ -7,14 +7,15 @@ add_library(
   PugsLanguage
   ASTBuilder.cpp
   ASTDotPrinter.cpp
+  ASTNodeAffectationExpressionBuilder.cpp
+  ASTNodeBinaryOperatorExpressionBuilder.cpp
   ASTNodeDataType.cpp
   ASTNodeDataTypeBuilder.cpp
   ASTNodeDataTypeChecker.cpp
-  ASTNodeAffectationExpressionBuilder.cpp
-  ASTNodeBinaryOperatorExpressionBuilder.cpp
   ASTNodeExpressionBuilder.cpp
   ASTNodeIncDecExpressionBuilder.cpp
   ASTNodeUnaryOperatorExpressionBuilder.cpp
+  ASTNodeValueBuilder.cpp
   ASTPrinter.cpp
   ASTSymbolTableBuilder.cpp
   ASTSymbolInitializationChecker.cpp
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index f0a3ebb05..b9b0a4677 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -22,8 +22,6 @@
 #include <ASTNodeDataTypeBuilder.hpp>
 #include <ASTNodeDataTypeChecker.hpp>
 
-#include <EscapedString.hpp>
-
 #include <ASTNodeExpressionBuilder.hpp>
 
 #include <ASTSymbolInitializationChecker.hpp>
@@ -32,63 +30,10 @@
 #include <ASTDotPrinter.hpp>
 #include <ASTPrinter.hpp>
 
-namespace language
-{
-namespace internal
-{
-void
-build_node_values(ASTNode& n, std::shared_ptr<SymbolTable>& symbol_table)
-{
-  if (n.is<language::bloc>()) {
-    if (!n.children.empty()) {
-      std::shared_ptr bloc_symbol_table = std::make_shared<SymbolTable>(symbol_table);
-      for (auto& child : n.children) {
-        build_node_values(*child, bloc_symbol_table);
-      }
-    }
-    n.m_data_type = ASTNodeDataType::void_t;
-  } else {
-    for (auto& child : n.children) {
-      build_node_values(*child, symbol_table);
-    }
+#include <ASTNodeValueBuilder.hpp>
 
-    if (n.has_content()) {
-      if (n.is<language::real>()) {
-        std::stringstream ss(n.string());
-        double v;
-        ss >> v;
-        n.m_value = v;
-      } else if (n.is<language::integer>()) {
-        std::stringstream ss(n.string());
-        int64_t v;
-        ss >> v;
-        n.m_value = v;
-      } else if (n.is<language::literal>()) {
-        n.m_value = unescapeString(n.string());
-      } else if (n.is<language::for_test>()) {
-        // if AST contains a for_test statement, it means that no test were
-        // given to the for-loop, so its value is always true
-        n.m_value = true;
-      } else if (n.is<language::true_kw>()) {
-        n.m_value = true;
-      } else if (n.is<language::false_kw>()) {
-        n.m_value = false;
-      }
-    }
-  }
-}
-}   // namespace internal
-
-void
-build_node_values(ASTNode& n)
+namespace language
 {
-  Assert(n.is_root());
-  n.m_data_type                = ASTNodeDataType::void_t;
-  std::shared_ptr symbol_table = std::make_shared<SymbolTable>();
-  internal::build_node_values(n, symbol_table);
-  std::cout << " - build node data types\n";
-}
-
 namespace internal
 {
 void
@@ -179,7 +124,7 @@ parser(const std::string& filename)
     ASTNodeDataTypeBuilder{*root_node};
     ASTNodeDataTypeChecker{*root_node};
 
-    language::build_node_values(*root_node);
+    ASTNodeValueBuilder{*root_node};
 
     language::check_break_or_continue_placement(*root_node);
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 21c8a1b23..c3c89e619 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -5,11 +5,12 @@ add_executable (unit_tests
   test_main.cpp
   test_Array.cpp
   test_ArrayUtils.cpp
-  test_ASTDotPrinter.cpp
   test_ASTBuilder.cpp
+  test_ASTDotPrinter.cpp
   test_ASTNodeDataType.cpp
   test_ASTNodeDataTypeBuilder.cpp
   test_ASTNodeDataTypeChecker.cpp
+  test_ASTNodeValueBuilder.cpp
   test_ASTPrinter.cpp
   test_ASTSymbolTableBuilder.cpp
   test_ASTSymbolInitializationChecker.cpp
diff --git a/tests/test_ASTNodeValueBuilder.cpp b/tests/test_ASTNodeValueBuilder.cpp
new file mode 100644
index 000000000..70364828f
--- /dev/null
+++ b/tests/test_ASTNodeValueBuilder.cpp
@@ -0,0 +1,138 @@
+#include <catch2/catch.hpp>
+
+#include <ASTNodeValueBuilder.hpp>
+
+#include <ASTBuilder.hpp>
+#include <ASTNodeDataTypeBuilder.hpp>
+
+#include <ASTSymbolTableBuilder.hpp>
+
+#include <ASTPrinter.hpp>
+
+#define CHECK_AST_VALUES(data, expected_output)                                                      \
+  {                                                                                                  \
+    static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>);                   \
+    static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>);        \
+                                                                                                     \
+    string_input input{data, "test.pgs"};                                                            \
+    auto ast = ASTBuilder::build(input);                                                             \
+                                                                                                     \
+    ASTSymbolTableBuilder{*ast};                                                                     \
+    ASTNodeDataTypeBuilder{*ast};                                                                    \
+    ASTNodeValueBuilder{*ast};                                                                       \
+                                                                                                     \
+    std::stringstream ast_output;                                                                    \
+    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::data_value}}; \
+                                                                                                     \
+    REQUIRE(ast_output.str() == expected_output);                                                    \
+  }
+
+TEST_CASE("ASTNodeValuebuilder", "[language]")
+{
+  SECTION("integer")
+  {
+    std::string_view data = R"(
+01;
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::integer:01:1)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("real")
+  {
+    std::string_view data = R"(
+1.300;
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::real:1.300:1.3)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("true")
+  {
+    std::string_view data = R"(
+true;
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::true_kw:1)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("false")
+  {
+    std::string_view data = R"(
+false;
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::false_kw:0)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("string")
+  {
+    std::string_view data = R"(
+"\"foo\" or \"bar\"";
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::literal:"\"foo\" or \"bar\"":"\"foo\" or \"bar\"")
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("for empty test")
+  {
+    std::string_view data = R"(
+for(;;);
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::for_statement:--)
+     +-(language::for_init:--)
+     +-(language::for_test:1)
+     +-(language::for_post:--)
+     `-(language::for_statement_bloc:--)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+
+  SECTION("bloc values")
+  {
+    std::string_view data = R"(
+{
+  1;
+  2.3;
+}
+)";
+
+    std::string_view result = R"(
+(root:--)
+ `-(language::bloc:--)
+     +-(language::integer:1:1)
+     `-(language::real:2.3:2.3)
+)";
+
+    CHECK_AST_VALUES(data, result);
+  }
+}
-- 
GitLab