[flang] Development of character provenance.
Original-commit: flang-compiler/f18@88c5329580 Reviewed-on: https://github.com/flang-compiler/f18/pull/9 Tree-same-pre-rewrite: false
This commit is contained in:
1
flang/.gitignore
vendored
1
flang/.gitignore
vendored
@@ -4,6 +4,7 @@ tags
|
||||
./f18
|
||||
*.o
|
||||
*~
|
||||
*#
|
||||
CMakeCache.txt
|
||||
CMakeFiles/*
|
||||
cmake_install.cmake
|
||||
|
||||
@@ -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})
|
||||
|
||||
87
flang/lib/parser/provenance.cc
Normal file
87
flang/lib/parser/provenance.cc
Normal file
@@ -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
|
||||
@@ -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 {
|
||||
public:
|
||||
Sources() {}
|
||||
Sources(Sources &&) = default;
|
||||
Sources &operator(Sources &&) = default;
|
||||
size_t size() const { return bytes_; }
|
||||
char &operator[size_t at] const;
|
||||
private:
|
||||
struct Context {
|
||||
struct Inclusion {
|
||||
const SourceFile &source;
|
||||
};
|
||||
struct MacroUse {
|
||||
ProvenanceRange definition;
|
||||
};
|
||||
class AllOfTheSource;
|
||||
|
||||
int myIndex; // *contexts[myIndex] == this;
|
||||
ProvenanceRange replaces;
|
||||
std::variant<SourceFile, Inclusion, MacroUse> v;
|
||||
class Origin {
|
||||
public:
|
||||
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 Inclusion {
|
||||
const SourceFile &source;
|
||||
};
|
||||
std::vector<std::unique_ptr<Context>> contexts_;
|
||||
struct Macro {
|
||||
ProvenanceRange definition;
|
||||
std::string expansion;
|
||||
};
|
||||
std::variant<Inclusion, Macro> u_;
|
||||
ProvenanceRange replaces_;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
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_
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user