From 707ffa6a34ceaad3ca81f80ae3699b4758bd39ef Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Thu, 12 Dec 2019 17:16:06 +0100
Subject: [PATCH] Overload ASTNode::string() and ASTNode::string_view()
 functions

This allows to retrieve associate string for nodes whose content has been
removed while rewriting the AST. For instance expressions such as 'x*x' can be
written.

Without this change, calls to 'string()' or 'string_view()' could produce
segmentation faults when reporting syntax errors... Now these calls can never
produce errors.
---
 src/language/ASTNode.hpp              | 58 ++++++++++++++++++++++++++-
 tests/test_ASTNodeDataTypeBuilder.cpp | 13 ++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/src/language/ASTNode.hpp b/src/language/ASTNode.hpp
index 0e09c2f33..d1d9bc7a6 100644
--- a/src/language/ASTNode.hpp
+++ b/src/language/ASTNode.hpp
@@ -16,13 +16,69 @@ using namespace TAO_PEGTL_NAMESPACE;
 
 class SymbolTable;
 
-struct ASTNode : public parse_tree::basic_node<ASTNode>
+class ASTNode : public parse_tree::basic_node<ASTNode>
 {
+ private:
+  PUGS_INLINE
+  decltype(m_end)
+  _getEnd() const
+  {
+    if (not this->has_content()) {
+      if (this->children.size() > 0) {
+        return this->children[children.size() - 1]->_getEnd();
+      }
+    }
+    return m_end;
+  }
+
+  PUGS_INLINE
+  decltype(m_begin)
+  _getBegin() const
+  {
+    if (not this->has_content()) {
+      if (this->children.size() > 0) {
+        return this->children[0]->_getBegin();
+      }
+    }
+    return m_begin;
+  }
+
+ public:
   std::shared_ptr<SymbolTable> m_symbol_table;
   std::unique_ptr<INodeProcessor> m_node_processor;
 
   ASTNodeDataType m_data_type{ASTNodeDataType::undefined_t};
 
+  [[nodiscard]] PUGS_INLINE std::string
+  string() const
+  {
+    if (this->has_content()) {
+      return this->parse_tree::basic_node<ASTNode>::string();
+    } else {
+      auto end   = this->_getEnd();
+      auto begin = this->_getBegin();
+      if (end.data != nullptr) {
+        return std::string{begin.data, end.data};
+      }
+      return {"<optimized out>"};
+    }
+  }
+
+  [[nodiscard]] PUGS_INLINE std::string_view
+  string_view() const
+  {
+    if (this->has_content()) {
+      return this->parse_tree::basic_node<ASTNode>::string_view();
+    } else {
+      auto end   = this->_getEnd();
+      auto begin = this->_getBegin();
+      if (end.data != nullptr) {
+        return std::string_view(begin.data, end.data - begin.data);
+      }
+      return {"<optimized out>"};
+    }
+  }
+
   PUGS_INLINE
   std::string
   name() const noexcept
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index 8e297e78b..e65254e01 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -379,6 +379,19 @@ let f : R*Z -> B, (x,z) -> (3, x);
         REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast},
                             "note: number of image spaces (1) B differs from number of expressions (2) (3, x)");
       }
+
+      SECTION("wrong image size 2")
+      {
+        std::string_view data = R"(
+let f : R -> R*R, x -> x*x*x;
+)";
+        string_input input{data, "test.pgs"};
+        auto ast = ASTBuilder::build(input);
+        ASTSymbolTableBuilder{*ast};
+
+        REQUIRE_THROWS_WITH(ASTNodeDataTypeBuilder{*ast},
+                            "note: number of image spaces (2) R*R differs from number of expressions (1) x*x*x");
+      }
     }
   }
 
-- 
GitLab