[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:
peter klausler
2018-02-07 16:24:02 -08:00
committed by GitHub
parent ea69370e52
commit 3558c22101
5 changed files with 158 additions and 36 deletions

1
flang/.gitignore vendored
View File

@@ -4,6 +4,7 @@ tags
./f18
*.o
*~
*#
CMakeCache.txt
CMakeFiles/*
cmake_install.cmake

View 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})

View 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

View 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 {
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_

View 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 {