./f18
*.o
*~
+*#
CMakeCache.txt
CMakeFiles/*
cmake_install.cmake
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})
--- /dev/null
+#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
#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_;
};
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;
++at_;
return *this;
}
- iterator &operator++(int) {
+ iterator operator++(int) {
iterator result{*this};
++at_;
return result;
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:
Provenance start_;
size_t bytes_;
};
+} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PROVENANCE_H_
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 {