[flang] Some initial clean-up in messages, use std::variant to make component possibi...
authorpeter klausler <pklausler@nvidia.com>
Fri, 4 May 2018 20:00:35 +0000 (13:00 -0700)
committerpeter klausler <pklausler@nvidia.com>
Fri, 4 May 2018 20:00:35 +0000 (13:00 -0700)
Original-commit: flang-compiler/f18@9b7eeb23548b75138f3956ec06dbb582da1aa1d9
Reviewed-on: https://github.com/flang-compiler/f18/pull/83
Tree-same-pre-rewrite: false

flang/lib/parser/char-block.h
flang/lib/parser/instrumented-parser.cc
flang/lib/parser/interval.h
flang/lib/parser/message.cc
flang/lib/parser/message.h

index fc89ca35a8d913b2525bf184505d7fc363ddc06d..2a52639ec5d4f95129f3a417deb2a6726b336806 100644 (file)
@@ -28,21 +28,25 @@ namespace Fortran::parser {
 
 class CharBlock {
 public:
-  CharBlock() {}
-  CharBlock(const char *x, std::size_t n = 1) : interval_{x, n} {}
-  CharBlock(const char *b, const char *ep1)
+  constexpr CharBlock() {}
+  constexpr CharBlock(const char *x, std::size_t n = 1) : interval_{x, n} {}
+  constexpr CharBlock(const char *b, const char *ep1)
     : interval_{b, static_cast<std::size_t>(ep1 - b)} {}
   CharBlock(const std::string &s) : interval_{s.data(), s.size()} {}
-  CharBlock(const CharBlock &) = default;
-  CharBlock(CharBlock &&) = default;
-  CharBlock &operator=(const CharBlock &) = default;
-  CharBlock &operator=(CharBlock &&) = default;
+  constexpr CharBlock(const CharBlock &) = default;
+  constexpr CharBlock(CharBlock &&) = default;
+  constexpr CharBlock &operator=(const CharBlock &) = default;
+  constexpr CharBlock &operator=(CharBlock &&) = default;
 
-  bool empty() const { return interval_.empty(); }
-  std::size_t size() const { return interval_.size(); }
-  const char *begin() const { return interval_.start(); }
-  const char *end() const { return interval_.start() + interval_.size(); }
-  const char &operator[](std::size_t j) const { return interval_.start()[j]; }
+  constexpr bool empty() const { return interval_.empty(); }
+  constexpr std::size_t size() const { return interval_.size(); }
+  constexpr const char *begin() const { return interval_.start(); }
+  constexpr const char *end() const {
+    return interval_.start() + interval_.size();
+  }
+  constexpr const char &operator[](std::size_t j) const {
+    return interval_.start()[j];
+  }
 
   bool IsBlank() const {
     for (char ch : *this) {
@@ -57,6 +61,12 @@ public:
     return std::string{interval_.start(), interval_.size()};
   }
 
+  // Convert to string, stopping early at any embedded '\0'.
+  std::string NULTerminatedToString() const {
+    return std::string{interval_.start(),
+        /*not in std::*/ strnlen(interval_.start(), interval_.size())};
+  }
+
   bool operator<(const CharBlock &that) const { return Compare(that) < 0; }
   bool operator<=(const CharBlock &that) const { return Compare(that) <= 0; }
   bool operator==(const CharBlock &that) const { return Compare(that) == 0; }
index 5f378295ff3a61c9c8b2132c46d7f4a79f891ad0..3cdf43d9617a3e3e17912b433c9559c793c97ddd 100644 (file)
@@ -25,7 +25,7 @@ void ParsingLog::clear() { perPos_.clear(); }
 // In the logs, just use the addresses of the message texts to sort the
 // map keys.
 bool operator<(const MessageFixedText &x, const MessageFixedText &y) {
-  return x.str() < y.str();
+  return x.text().begin() < y.text().begin();
 }
 
 bool ParsingLog::Fails(
index a728a1ce7ccde5245b463411c26bad40ad7314f7..e83651667f646ddea265ffbfad0c3b6e7d6a6861 100644 (file)
@@ -27,30 +27,33 @@ namespace Fortran::parser {
 template<typename A> class Interval {
 public:
   using type = A;
-  Interval() {}
-  Interval(const A &s, std::size_t n = 1) : start_{s}, size_{n} {}
-  Interval(A &&s, std::size_t n = 1) : start_{std::move(s)}, size_{n} {}
-  Interval(const Interval &) = default;
-  Interval(Interval &&) = default;
-  Interval &operator=(const Interval &) = default;
-  Interval &operator=(Interval &&) = default;
+  constexpr Interval() {}
+  constexpr Interval(const A &s, std::size_t n = 1) : start_{s}, size_{n} {}
+  constexpr Interval(A &&s, std::size_t n = 1)
+    : start_{std::move(s)}, size_{n} {}
+  constexpr Interval(const Interval &) = default;
+  constexpr Interval(Interval &&) = default;
+  constexpr Interval &operator=(const Interval &) = default;
+  constexpr Interval &operator=(Interval &&) = default;
 
-  bool operator==(const Interval &that) const {
+  constexpr bool operator==(const Interval &that) const {
     return start_ == that.start_ && size_ == that.size_;
   }
-  bool operator!=(const Interval &that) const {
+  constexpr bool operator!=(const Interval &that) const {
     return start_ != that.start_ || size_ != that.size_;
   }
 
-  const A &start() const { return start_; }
-  std::size_t size() const { return size_; }
-  bool empty() const { return size_ == 0; }
+  constexpr const A &start() const { return start_; }
+  constexpr std::size_t size() const { return size_; }
+  constexpr bool empty() const { return size_ == 0; }
 
-  bool Contains(const A &x) const { return start_ <= x && x < start_ + size_; }
-  bool Contains(const Interval &that) const {
+  constexpr bool Contains(const A &x) const {
+    return start_ <= x && x < start_ + size_;
+  }
+  constexpr bool Contains(const Interval &that) const {
     return Contains(that.start_) && Contains(that.start_ + (that.size_ - 1));
   }
-  bool ImmediatelyPrecedes(const Interval &that) const {
+  constexpr bool ImmediatelyPrecedes(const Interval &that) const {
     return NextAfter() == that.start_;
   }
   void Annex(const Interval &that) {
@@ -73,9 +76,11 @@ public:
     return start_ + n;
   }
 
-  A Last() const { return start_ + (size_ - 1); }
-  A NextAfter() const { return start_ + size_; }
-  Interval Prefix(std::size_t n) const { return {start_, std::min(size_, n)}; }
+  constexpr A Last() const { return start_ + (size_ - 1); }
+  constexpr A NextAfter() const { return start_ + size_; }
+  constexpr Interval Prefix(std::size_t n) const {
+    return {start_, std::min(size_, n)};
+  }
   Interval Suffix(std::size_t n) const {
     CHECK(n <= size_);
     return {start_ + n, size_ - n};
index 1a94d1757994f0ffcf13009e088215d9b085ee95..bba56c5ccd91b379308f6f003fdc5fa3c53eaa23 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "message.h"
 #include "char-set.h"
+#include "idioms.h"
 #include <algorithm>
 #include <cstdarg>
 #include <cstddef>
 namespace Fortran::parser {
 
 std::ostream &operator<<(std::ostream &o, const MessageFixedText &t) {
-  for (std::size_t j{0}; j < t.size(); ++j) {
-    o << t.str()[j];
+  std::size_t n{t.text().size()};
+  for (std::size_t j{0}; j < n; ++j) {
+    o << t.text()[j];
   }
   return o;
 }
 
-std::string MessageFixedText::ToString() const {
-  return std::string{str_, /*not in std::*/ strnlen(str_, bytes_)};
-}
-
 MessageFormattedText::MessageFormattedText(MessageFixedText text, ...)
   : isFatal_{text.isFatal()} {
-  const char *p{text.str()};
+  const char *p{text.text().begin()};
   std::string asString;
-  if (p[text.size()] != '\0') {
+  if (*text.text().end() != '\0') {
     // not NUL-terminated
-    asString = text.ToString();
+    asString = text.text().NULTerminatedToString();
     p = asString.data();
   }
   char buffer[256];
@@ -52,63 +50,75 @@ MessageFormattedText::MessageFormattedText(MessageFixedText text, ...)
   string_ = buffer;
 }
 
+std::string MessageExpectedText::ToString() const {
+  return std::visit(
+      visitors{[](const CharBlock &cb) {
+                 return MessageFormattedText("expected '%s'"_err_en_US,
+                     cb.NULTerminatedToString().data())
+                     .MoveString();
+               },
+          [](const SetOfChars &set) {
+            SetOfChars expect{set};
+            if (expect.Has('\n')) {
+              expect = expect.Difference('\n');
+              if (expect.empty()) {
+                return "expected end of line"_err_en_US.text().ToString();
+              } else {
+                std::string s{expect.ToString()};
+                if (s.size() == 1) {
+                  return MessageFormattedText(
+                      "expected end of line or '%s'"_err_en_US, s.data())
+                      .MoveString();
+                } else {
+                  return MessageFormattedText(
+                      "expected end of line or one of '%s'"_err_en_US, s.data())
+                      .MoveString();
+                }
+              }
+            }
+            std::string s{expect.ToString()};
+            if (s.size() != 1) {
+              return MessageFormattedText(
+                  "expected one of '%s'"_err_en_US, s.data())
+                  .MoveString();
+            } else {
+              return MessageFormattedText("expected '%s'"_err_en_US, s.data())
+                  .MoveString();
+            }
+          }},
+      u_);
+}
+
+void MessageExpectedText::Incorporate(const MessageExpectedText &that) {
+  std::visit(
+      visitors{[&](SetOfChars &s1, const SetOfChars &s2) { s1.Union(s2); },
+          [](const auto &, const auto &) {}},
+      u_, that.u_);
+}
+
 void Message::Incorporate(Message &that) {
-  if (provenanceRange_.start() == that.provenanceRange_.start() &&
-      cookedSourceRange_.begin() == that.cookedSourceRange_.begin() &&
-      !expected_.empty()) {
-    expected_ = expected_.Union(that.expected_);
-  }
+  std::visit(
+      visitors{[&](MessageExpectedText &e1, const MessageExpectedText &e2) {
+                 e1.Incorporate(e2);
+               },
+          [](const auto &, const auto &) {}},
+      text_, that.text_);
 }
 
 std::string Message::ToString() const {
-  std::string s{string_};
-  bool isExpected{isExpected_};
-  if (string_.empty()) {
-    if (fixedText_ != nullptr) {
-      if (fixedBytes_ > 0 && fixedBytes_ < std::string::npos) {
-        s = std::string(fixedText_, fixedBytes_);
-      } else {
-        s = std::string{fixedText_};  // NUL-terminated
-      }
-    } else {
-      SetOfChars expect{expected_};
-      if (expect.Has('\n')) {
-        expect = expect.Difference('\n');
-        if (expect.empty()) {
-          return "expected end of line"_err_en_US.ToString();
-        } else {
-          s = expect.ToString();
-          if (s.size() == 1) {
-            return MessageFormattedText(
-                "expected end of line or '%s'"_err_en_US, s.data())
-                .MoveString();
-          } else {
-            return MessageFormattedText(
-                "expected end of line or one of '%s'"_err_en_US, s.data())
-                .MoveString();
-          }
-        }
-      }
-      s = expect.ToString();
-      if (s.size() != 1) {
-        return MessageFormattedText("expected one of '%s'"_err_en_US, s.data())
-            .MoveString();
-      }
-      isExpected = true;
-    }
-  }
-  if (isExpected) {
-    return MessageFormattedText("expected '%s'"_err_en_US, s.data())
-        .MoveString();
-  }
-  return s;
+  return std::visit(
+      visitors{[](const CharBlock &cb) { return cb.NULTerminatedToString(); },
+          [](const std::string &s) { return s; },
+          [](const MessageExpectedText &e) { return e.ToString(); }},
+      text_);
 }
 
 ProvenanceRange Message::GetProvenanceRange(const CookedSource &cooked) const {
-  if (cookedSourceRange_.begin() != nullptr) {
-    return cooked.GetProvenanceRange(cookedSourceRange_);
-  }
-  return provenanceRange_;
+  return std::visit(visitors{[&](const CharBlock &cb) {
+                               return cooked.GetProvenanceRange(cb);
+                             },
+                        [](const ProvenanceRange &pr) { return pr; }},
+      location_);
 }
 
 void Message::Emit(
@@ -133,6 +143,37 @@ void Message::Emit(
   }
 }
 
+bool Message::AtSameLocation(const Message &that) const {
+  return std::visit(
+      visitors{[](const CharBlock &cb1, const CharBlock &cb2) {
+                 return cb1.begin() == cb2.begin();
+               },
+          [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {
+            return pr1.start() == pr2.start();
+          },
+          [](const auto &, const auto &) { return false; }},
+      location_, that.location_);
+}
+
+bool Message::operator<(const Message &that) const {
+  // Messages from prescanning have ProvenanceRange values for their locations,
+  // while messages from later phases have CharBlock values, since the
+  // conversion of cooked source stream locations to provenances is not
+  // free and needs to be deferred, since many messages created during parsing
+  // are speculative.  Messages with ProvenanceRange locations are ordered
+  // before others for sorting.
+  return std::visit(
+      visitors{[](const CharBlock &cb1, const CharBlock &cb2) {
+                 return cb1.begin() < cb2.begin();
+               },
+          [](const CharBlock &, const ProvenanceRange &) { return false; },
+          [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {
+            return pr1.start() < pr2.start();
+          },
+          [](const ProvenanceRange &, const CharBlock &) { return true; }},
+      location_, that.location_);
+}
+
 void Messages::Incorporate(Messages &that) {
   if (messages_.empty()) {
     *this = std::move(that);
index 32c300631283e9f344dca70495e51560d1cb814a..179e4ced358886f760a085e0a79f68daf4c6cc55 100644 (file)
@@ -18,6 +18,7 @@
 // Defines a representation for sequences of compiler messages.
 // Supports nested contextualization.
 
+#include "char-block.h"
 #include "char-set.h"
 #include "idioms.h"
 #include "provenance.h"
@@ -29,6 +30,7 @@
 #include <ostream>
 #include <string>
 #include <utility>
+#include <variant>
 
 namespace Fortran::parser {
 
@@ -39,22 +41,17 @@ public:
   MessageFixedText() {}
   constexpr MessageFixedText(
       const char str[], std::size_t n, bool isFatal = false)
-    : str_{str}, bytes_{n}, isFatal_{isFatal} {}
+    : text_{str, n}, isFatal_{isFatal} {}
   constexpr MessageFixedText(const MessageFixedText &) = default;
   MessageFixedText(MessageFixedText &&) = default;
   constexpr MessageFixedText &operator=(const MessageFixedText &) = default;
   MessageFixedText &operator=(MessageFixedText &&) = default;
 
-  const char *str() const { return str_; }
-  std::size_t size() const { return bytes_; }
-  bool empty() const { return bytes_ == 0; }
+  const CharBlock &text() const { return text_; }
   bool isFatal() const { return isFatal_; }
 
-  std::string ToString() const;
-
 private:
-  const char *str_{nullptr};
-  std::size_t bytes_{0};
+  CharBlock text_;
   bool isFatal_{false};
 };
 
@@ -81,65 +78,45 @@ private:
 };
 
 // Represents a formatted rendition of "expected '%s'"_err_en_US
-// on a constant text.
+// on a constant text or a set of characters.
 class MessageExpectedText {
 public:
-  MessageExpectedText(const char *s, std::size_t n) : str_{s}, bytes_{n} {
-    if (n == std::string::npos) {
-      bytes_ = std::strlen(s);
-    }
-  }
-  MessageExpectedText(MessageExpectedText &&) = default;
-  explicit MessageExpectedText(char ch) : set_{ch} {}
-  explicit MessageExpectedText(SetOfChars set) : set_{set} {}
+  MessageExpectedText(const char *s, std::size_t n)
+    : u_{CharBlock{s, n == std::string::npos ? std::strlen(s) : n}} {}
+  constexpr explicit MessageExpectedText(CharBlock cb) : u_{cb} {}
+  constexpr explicit MessageExpectedText(char ch) : u_{SetOfChars{ch}} {}
+  constexpr explicit MessageExpectedText(SetOfChars set) : u_{set} {}
+  MessageExpectedText(const MessageExpectedText &) = default;
 
-  const char *str() const { return str_; }
-  std::size_t size() const { return bytes_; }
-  SetOfChars set() const { return set_; }
+  std::string ToString() const;
+  void Incorporate(const MessageExpectedText &);
 
 private:
-  const char *str_{nullptr};
-  std::size_t bytes_{0};
-  SetOfChars set_;
+  std::variant<CharBlock, SetOfChars> u_;
 };
 
 class Message : public ReferenceCounted<Message> {
 public:
   using Context = CountedReference<Message>;
 
-  Message() {}
   Message(const Message &) = default;
   Message(Message &&) = default;
   Message &operator=(const Message &that) = default;
   Message &operator=(Message &&that) = default;
 
   Message(ProvenanceRange pr, MessageFixedText t)
-    : provenanceRange_{pr}, fixedText_{t.str()},
-      fixedBytes_{t.size()}, isFatal_{t.isFatal()} {}
+    : location_{pr}, text_{t.text()}, isFatal_{t.isFatal()} {}
   Message(ProvenanceRange pr, MessageFormattedText &&s)
-    : provenanceRange_{pr}, string_{s.MoveString()}, isFatal_{s.isFatal()} {}
+    : location_{pr}, text_{s.MoveString()}, isFatal_{s.isFatal()} {}
   Message(ProvenanceRange pr, MessageExpectedText t)
-    : provenanceRange_{pr}, fixedText_{t.str()}, fixedBytes_{t.size()},
-      isExpected_{true}, expected_{t.set()}, isFatal_{true} {}
+    : location_{pr}, text_{t}, isFatal_{true} {}
 
   Message(CharBlock csr, MessageFixedText t)
-    : cookedSourceRange_{csr}, fixedText_{t.str()},
-      fixedBytes_{t.size()}, isFatal_{t.isFatal()} {}
+    : location_{csr}, text_{t.text()}, isFatal_{t.isFatal()} {}
   Message(CharBlock csr, MessageFormattedText &&s)
-    : cookedSourceRange_{csr}, string_{s.MoveString()}, isFatal_{s.isFatal()} {}
+    : location_{csr}, text_{s.MoveString()}, isFatal_{s.isFatal()} {}
   Message(CharBlock csr, MessageExpectedText t)
-    : cookedSourceRange_{csr}, fixedText_{t.str()}, fixedBytes_{t.size()},
-      isExpected_{true}, expected_{t.set()}, isFatal_{true} {}
-
-  bool operator<(const Message &that) const {
-    if (cookedSourceRange_.begin() != nullptr) {
-      return cookedSourceRange_.begin() < that.cookedSourceRange_.begin();
-    } else if (that.cookedSourceRange_.begin() != nullptr) {
-      return false;
-    } else {
-      return provenanceRange_.start() < that.provenanceRange_.start();
-    }
-  }
+    : location_{csr}, text_{t}, isFatal_{true} {}
 
   Context context() const { return context_; }
   Message &set_context(Message *c) {
@@ -148,6 +125,7 @@ public:
   }
   bool isFatal() const { return isFatal_; }
 
+  bool operator<(const Message &that) const;
   void Incorporate(Message &);
   std::string ToString() const;
   ProvenanceRange GetProvenanceRange(const CookedSource &) const;
@@ -155,13 +133,10 @@ public:
       std::ostream &, const CookedSource &, bool echoSourceLine = true) const;
 
 private:
-  ProvenanceRange provenanceRange_;
-  CharBlock cookedSourceRange_;
-  const char *fixedText_{nullptr};
-  std::size_t fixedBytes_{0};
-  bool isExpected_{false};
-  std::string string_;
-  SetOfChars expected_;
+  bool AtSameLocation(const Message &) const;
+
+  std::variant<ProvenanceRange, CharBlock> location_;
+  std::variant<CharBlock, MessageExpectedText, std::string> text_;
   Context context_;
   bool isFatal_{false};
 };