[flang] Development of character provenance.
authorpeter klausler <pklausler@nvidia.com>
Thu, 8 Feb 2018 00:24:02 +0000 (16:24 -0800)
committerGitHub <noreply@github.com>
Thu, 15 Feb 2018 23:58:44 +0000 (15:58 -0800)
Original-commit: flang-compiler/f18@88c532958006ad064cab88d2405055a456b07dcf
Reviewed-on: https://github.com/flang-compiler/f18/pull/9
Tree-same-pre-rewrite: false

flang/.gitignore
flang/CMakeLists.txt
flang/lib/parser/provenance.cc [new file with mode: 0644]
flang/lib/parser/provenance.h
flang/lib/parser/source.cc

index 4c1751e..b9f53cf 100644 (file)
@@ -4,6 +4,7 @@ tags
 ./f18
 *.o
 *~
+*#
 CMakeCache.txt
 CMakeFiles/*
 cmake_install.cmake
index 7fcd0a7..3bbe9ed 100644 (file)
@@ -17,6 +17,7 @@ set(SOURCES_F18
   lib/parser/position.cc
   lib/parser/preprocessor.cc
   lib/parser/prescan.cc
+  lib/parser/provenance.cc
   lib/parser/source.cc
 )
 add_executable(f18 ${SOURCES_F18})
diff --git a/flang/lib/parser/provenance.cc b/flang/lib/parser/provenance.cc
new file mode 100644 (file)
index 0000000..4050d9e
--- /dev/null
@@ -0,0 +1,87 @@
+#include "provenance.h"
+#include "idioms.h"
+#include "position.h"
+#include <utility>
+namespace Fortran {
+namespace parser {
+
+Origin::Origin(const SourceFile &source) : u_{Inclusion{source}} {}
+Origin::Origin(const SourceFile &included, ProvenanceRange from)
+  : u_{Inclusion{included}}, replaces_{from} {}
+Origin::Origin(ProvenanceRange def, ProvenanceRange use,
+    const std::string &expansion)
+  : u_{Macro{def, expansion}}, replaces_{use} {}
+
+size_t Origin::size() const {
+  return std::visit(
+      visitors{[](const Inclusion &inc) { return inc.source.bytes(); },
+           [](const Macro &mac) { return mac.expansion.size(); }},
+      u_);
+}
+
+const char &Origin::operator[](size_t n) const {
+  return std::visit(
+      visitors{[n](const Inclusion &inc) -> const char & {
+          return inc.source.content()[n]; },
+          [n](const Macro &mac) -> const char & { return mac.expansion[n]; }},
+      u_);
+}
+
+void Origin::Identify(std::ostream &o, const AllOfTheSource &sources, size_t at,
+                      const std::string &prefix) const {
+  static const std::string indented{prefix + "  "};
+  std::visit(
+      visitors{
+          [&](const Inclusion &inc) {
+              Position pos{inc.source.FindOffsetPosition(at)};
+              o << prefix << "at line " << pos.lineNumber() << ", column " <<
+                   pos.column() << "in the file " << inc.source.path() << '\n';
+              if (replaces_.bytes() > 0) {
+                o << prefix << " that was included\n";
+                sources.Identify(o, replaces_.start(), indented);
+              }
+          },
+          [&](const Macro &mac) {
+              o << prefix << "in the expansion of a macro that was defined\n";
+              sources.Identify(o, mac.definition.start(), indented);
+              o << prefix << "... and called\n";
+              sources.Identify(o, replaces_.start(), indented);
+              o << prefix << "... and expanded to\n" <<
+                   indented << mac.expansion << '\n'; }},
+      u_);
+}
+
+AllOfTheSource &AllOfTheSource::Add(Origin &&origin) {
+  size_t start{bytes_};
+  bytes_ += origin.size();
+  chunk_.emplace_back(Chunk{std::move(origin), start});
+  return *this;
+}
+
+const char &AllOfTheSource::operator[](Provenance at) const {
+  const Chunk &chunk{MapToChunk(at)};
+  return chunk.origin[at - chunk.start];
+}
+
+const AllOfTheSource::Chunk &AllOfTheSource::MapToChunk(Provenance at) const {
+  CHECK(at < bytes_);
+  size_t low{0}, count{chunk_.size()};
+  while (count > 1) {
+    size_t mid{low + (count >> 1)};
+    if (chunk_[mid].start > at) {
+      count = mid - low;
+    } else {
+      count -= mid - low;
+      low = mid;
+    }
+  }
+  return chunk_[low];
+}
+
+void AllOfTheSource::Identify(std::ostream &o, Provenance at,
+                              const std::string &prefix) const {
+  const Chunk &chunk{MapToChunk(at)};
+  return chunk.origin.Identify(o, *this, at - chunk.start, prefix);
+}
+}  // namespace parser
+}  // namespace Fortran
index 7d6a86f..9feb4b7 100644 (file)
@@ -1,40 +1,67 @@
 #ifndef FORTRAN_PROVENANCE_H_
 #define FORTRAN_PROVENANCE_H_
 #include "source.h"
+#include <memory>
+#include <ostream>
 #include <string>
 #include <variant>
 namespace Fortran {
-
-class SourceContexts;
+namespace parser {
 
 using Provenance = size_t;
 
-struct ProvenanceRange {
-  Provenance begin;
-  size_t bytes;
+class ProvenanceRange {
+public:
+  ProvenanceRange() {}
+  bool empty() const { return bytes_ == 0; }
+  Provenance start() const { return start_; }
+  size_t bytes() const { return bytes_; }
+private:
+  Provenance start_{0};
+  size_t bytes_{0};
 };
 
-class Sources {
+class AllOfTheSource;
+
+class Origin {
 public:
-  Sources() {}
-  Sources(Sources &&) = default;
-  Sources &operator(Sources &&) = default;
-  size_t size() const { return bytes_; }
-  char &operator[size_t at] const;
+  explicit Origin(const SourceFile &);  // initial source file
+  Origin(const SourceFile &, ProvenanceRange);  // included source file
+  Origin(ProvenanceRange def, ProvenanceRange use,  // macro call
+         const std::string &expansion);
+  size_t size() const;
+  const char &operator[](size_t) const;
+  void Identify(std::ostream &, const AllOfTheSource &, size_t,
+                const std::string &indent) const;
 private:
-  struct Context {
-    struct Inclusion {
-      const SourceFile &source;
-    };
-    struct MacroUse {
-      ProvenanceRange definition;
-    };
+  struct Inclusion {
+    const SourceFile &source;
+  };
+  struct Macro {
+    ProvenanceRange definition;
+    std::string expansion;
+  };
+  std::variant<Inclusion, Macro> u_;
+  ProvenanceRange replaces_;
+};
 
-    int myIndex;  // *contexts[myIndex] == this;
-    ProvenanceRange replaces;
-    std::variant<SourceFile, Inclusion, MacroUse> v;
+class AllOfTheSource {
+public:
+  AllOfTheSource() {}
+  AllOfTheSource(AllOfTheSource &&) = default;
+  AllOfTheSource &operator=(AllOfTheSource &&) = default;
+  size_t size() const { return bytes_; }
+  const char &operator[](Provenance) const;
+  AllOfTheSource &Add(Origin &&);
+  void Identify(std::ostream &, Provenance, const std::string &prefix) const;
+private:
+  struct Chunk {
+    Chunk(Origin &&origin, size_t at) : origin{std::move(origin)}, start{at} {}
+    Origin origin;
+    size_t start;
   };
-  std::vector<std::unique_ptr<Context>> contexts_;
+  const Chunk &MapToChunk(Provenance) const;
+  std::vector<Chunk> chunk_;
   size_t bytes_;
 };
 
@@ -51,11 +78,11 @@ class ProvenancedString {
 private:
   class iterator {
   public:
-    iterator(const Sources &sources, Provenance at)
+    iterator(const AllOfTheSource &sources, Provenance at)
       : sources_{&sources}, at_{at} {}
     iterator(const iterator &that)
       : sources_{that.sources_}, at_{that.at_} {}
-    iterator &operator(const iterator &that) {
+    iterator &operator=(const iterator &that) {
       sources_ = that.sources_;
       at_ = that.at_;
       return *this;
@@ -65,7 +92,7 @@ private:
       ++at_;
       return *this;
     }
-    iterator &operator++(int) {
+    iterator operator++(int) {
       iterator result{*this};
       ++at_;
       return result;
@@ -75,14 +102,14 @@ private:
     bool operator==(const iterator &that) { return at_ == that.at_; }
     bool operator!=(const iterator &that) { return at_ != that.at_; }
   private:
-    const Sources *sources_;
+    const AllOfTheSource *sources_;
     size_t at_;
   };
 
-  iterator begin(const Sources &sources) const {
+  iterator begin(const AllOfTheSource &sources) const {
     return iterator(sources, start_);
   }
-  iterator end(const Sources &sources) const {
+  iterator end(const AllOfTheSource &sources) const {
     return iterator(sources, start_ + bytes_);
   }
 public:
@@ -91,5 +118,6 @@ private:
   Provenance start_;
   size_t bytes_;
 };
+}  // namespace parser
 }  // namespace Fortran
 #endif  // FORTRAN_PROVENANCE_H_
index ff61130..2b5025e 100644 (file)
@@ -146,16 +146,21 @@ void SourceFile::Close() {
 
 Position SourceFile::FindOffsetPosition(size_t at) const {
   CHECK(at < bytes_);
-  size_t lo{0}, hi{lineStart_.size()};
-  while (lo < hi) {
-    size_t mid{(lo + hi) >> 1};
+  if (lineStart_.empty()) {
+    return {1, static_cast<int>(at + 1)};
+  }
+  size_t low{0}, count{lineStart_.size()};
+  while (count > 1) {
+    size_t mid{low + (count >> 1)};
     if (lineStart_[mid] > at) {
-      hi = mid;
+      count = mid - low;
     } else {
-      lo = mid;
+      count -= mid - low;
+      low = mid;
     }
   }
-  return {static_cast<int>(lo + 1), static_cast<int>(at - lineStart_[lo] + 1)};
+  return {static_cast<int>(low + 1),
+          static_cast<int>(at - lineStart_[low] + 1)};
 }
 
 size_t SourceFile::FindPositionOffset(int lineNumber, int column) const {