2018-02-16 20:42:17 +01:00
|
|
|
#ifndef FORTRAN_PARSER_PROVENANCE_H_
|
|
|
|
#define FORTRAN_PARSER_PROVENANCE_H_
|
2018-02-13 23:22:08 +01:00
|
|
|
|
2018-04-21 01:56:58 +02:00
|
|
|
#include "char-block.h"
|
2018-02-09 23:04:11 +01:00
|
|
|
#include "char-buffer.h"
|
2018-02-15 19:42:36 +01:00
|
|
|
#include "idioms.h"
|
2018-03-20 18:59:07 +01:00
|
|
|
#include "interval.h"
|
2018-02-07 22:18:36 +01:00
|
|
|
#include "source.h"
|
2018-03-20 18:59:07 +01:00
|
|
|
#include <cstddef>
|
2018-02-13 21:24:54 +01:00
|
|
|
#include <map>
|
2018-02-13 23:22:08 +01:00
|
|
|
#include <memory>
|
2018-02-15 19:42:36 +01:00
|
|
|
#include <ostream>
|
2018-02-13 23:22:08 +01:00
|
|
|
#include <sstream>
|
2018-02-07 22:18:36 +01:00
|
|
|
#include <string>
|
2018-02-09 23:04:11 +01:00
|
|
|
#include <utility>
|
2018-02-07 22:18:36 +01:00
|
|
|
#include <variant>
|
2018-02-09 23:04:11 +01:00
|
|
|
#include <vector>
|
2018-02-13 23:22:08 +01:00
|
|
|
|
2018-02-07 22:18:36 +01:00
|
|
|
namespace Fortran {
|
2018-02-08 01:24:02 +01:00
|
|
|
namespace parser {
|
2018-02-07 22:18:36 +01:00
|
|
|
|
2018-02-09 23:04:11 +01:00
|
|
|
// Each character in the contiguous source stream built by the
|
|
|
|
// prescanner corresponds to a particular character in a source file,
|
|
|
|
// include file, macro expansion, or compiler-inserted padding.
|
|
|
|
// The location of this original character to which a parsable character
|
|
|
|
// corresponds is its provenance.
|
|
|
|
//
|
2018-02-15 19:42:36 +01:00
|
|
|
// Provenances are offsets into an (unmaterialized) marshaling of the
|
|
|
|
// entire contents of all the original source files, include files, macro
|
2018-02-09 23:04:11 +01:00
|
|
|
// expansions, &c. for each visit to each source. These origins of the
|
|
|
|
// original source characters constitute a forest whose roots are
|
|
|
|
// the original source files named on the compiler's command line.
|
2018-02-15 19:42:36 +01:00
|
|
|
// Given a Provenance, we can find the tree node that contains it in time
|
|
|
|
// O(log(# of origins)), and describe the position precisely by walking
|
|
|
|
// up the tree. (It would be possible, via a time/space trade-off, to
|
|
|
|
// cap the time by the use of an intermediate table that would be indexed
|
|
|
|
// by the upper bits of an offset, but that does not appear to be
|
|
|
|
// necessary.)
|
|
|
|
|
|
|
|
class Provenance {
|
|
|
|
public:
|
|
|
|
Provenance() {}
|
2018-03-20 18:59:07 +01:00
|
|
|
Provenance(std::size_t offset) : offset_{offset} { CHECK(offset > 0); }
|
2018-02-15 19:42:36 +01:00
|
|
|
Provenance(const Provenance &that) = default;
|
|
|
|
Provenance(Provenance &&that) = default;
|
|
|
|
Provenance &operator=(const Provenance &that) = default;
|
|
|
|
Provenance &operator=(Provenance &&that) = default;
|
2018-03-19 19:48:49 +01:00
|
|
|
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t offset() const { return offset_; }
|
2018-03-19 19:48:49 +01:00
|
|
|
|
2018-02-15 19:42:36 +01:00
|
|
|
Provenance operator+(ptrdiff_t n) const {
|
|
|
|
CHECK(n > -static_cast<ptrdiff_t>(offset_));
|
2018-03-20 18:59:07 +01:00
|
|
|
return {offset_ + static_cast<std::size_t>(n)};
|
2018-02-15 19:42:36 +01:00
|
|
|
}
|
2018-03-20 18:59:07 +01:00
|
|
|
Provenance operator+(std::size_t n) const { return {offset_ + n}; }
|
|
|
|
std::size_t operator-(Provenance that) const {
|
2018-02-27 23:02:10 +01:00
|
|
|
CHECK(that <= *this);
|
|
|
|
return offset_ - that.offset_;
|
|
|
|
}
|
2018-02-15 19:42:36 +01:00
|
|
|
bool operator<(Provenance that) const { return offset_ < that.offset_; }
|
2018-02-15 22:13:28 +01:00
|
|
|
bool operator<=(Provenance that) const { return !(that < *this); }
|
2018-02-15 19:42:36 +01:00
|
|
|
bool operator==(Provenance that) const { return offset_ == that.offset_; }
|
2018-02-15 22:13:28 +01:00
|
|
|
bool operator!=(Provenance that) const { return !(*this == that); }
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-02-15 19:42:36 +01:00
|
|
|
private:
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t offset_{0};
|
2018-02-09 23:04:11 +01:00
|
|
|
};
|
|
|
|
|
2018-02-27 23:02:10 +01:00
|
|
|
using ProvenanceRange = Interval<Provenance>;
|
|
|
|
|
2018-02-15 19:42:36 +01:00
|
|
|
// Maps 0-based local offsets in some contiguous range (e.g., a token
|
|
|
|
// sequence) to their provenances. Lookup time is on the order of
|
|
|
|
// O(log(#of intervals with contiguous provenances)). As mentioned
|
|
|
|
// above, this time could be capped via a time/space trade-off.
|
2018-02-09 23:04:11 +01:00
|
|
|
class OffsetToProvenanceMappings {
|
|
|
|
public:
|
|
|
|
OffsetToProvenanceMappings() {}
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t size() const;
|
2018-02-10 00:56:02 +01:00
|
|
|
void clear();
|
2018-02-09 23:04:11 +01:00
|
|
|
void shrink_to_fit() { provenanceMap_.shrink_to_fit(); }
|
|
|
|
void Put(ProvenanceRange);
|
|
|
|
void Put(const OffsetToProvenanceMappings &);
|
2018-03-20 18:59:07 +01:00
|
|
|
ProvenanceRange Map(std::size_t at) const;
|
|
|
|
void RemoveLastBytes(std::size_t);
|
2018-02-15 19:42:36 +01:00
|
|
|
void Dump(std::ostream &) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-02-08 01:24:02 +01:00
|
|
|
private:
|
2018-02-09 23:04:11 +01:00
|
|
|
struct ContiguousProvenanceMapping {
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t start;
|
2018-02-09 23:04:11 +01:00
|
|
|
ProvenanceRange range;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<ContiguousProvenanceMapping> provenanceMap_;
|
2018-02-07 22:18:36 +01:00
|
|
|
};
|
|
|
|
|
2018-02-09 23:04:11 +01:00
|
|
|
class AllSources {
|
2018-02-07 22:18:36 +01:00
|
|
|
public:
|
2018-02-13 21:24:54 +01:00
|
|
|
AllSources();
|
2018-02-13 23:22:08 +01:00
|
|
|
~AllSources();
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t size() const { return range_.size(); }
|
2018-02-09 23:04:11 +01:00
|
|
|
const char &operator[](Provenance) const;
|
|
|
|
|
2018-02-14 00:24:43 +01:00
|
|
|
void PushSearchPathDirectory(std::string);
|
|
|
|
std::string PopSearchPathDirectory();
|
2018-02-13 23:22:08 +01:00
|
|
|
const SourceFile *Open(std::string path, std::stringstream *error);
|
2018-04-06 19:34:59 +02:00
|
|
|
const SourceFile *ReadStandardInput(std::stringstream *error);
|
2018-02-13 23:22:08 +01:00
|
|
|
|
2018-02-15 22:13:28 +01:00
|
|
|
ProvenanceRange AddIncludedFile(
|
|
|
|
const SourceFile &, ProvenanceRange, bool isModule = false);
|
2018-02-09 23:04:11 +01:00
|
|
|
ProvenanceRange AddMacroCall(
|
|
|
|
ProvenanceRange def, ProvenanceRange use, const std::string &expansion);
|
2018-02-15 19:42:36 +01:00
|
|
|
ProvenanceRange AddCompilerInsertion(std::string);
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-02-15 19:42:36 +01:00
|
|
|
bool IsValid(Provenance at) const { return range_.Contains(at); }
|
|
|
|
bool IsValid(ProvenanceRange range) const {
|
|
|
|
return range.size() > 0 && range_.Contains(range);
|
|
|
|
}
|
2018-04-21 01:56:58 +02:00
|
|
|
void Identify(std::ostream &, ProvenanceRange, const std::string &prefix,
|
2018-02-15 22:13:28 +01:00
|
|
|
bool echoSourceLine = false) const;
|
2018-03-20 18:59:07 +01:00
|
|
|
const SourceFile *GetSourceFile(
|
|
|
|
Provenance, std::size_t *offset = nullptr) const;
|
2018-02-15 19:42:36 +01:00
|
|
|
ProvenanceRange GetContiguousRangeAround(ProvenanceRange) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
std::string GetPath(Provenance) const; // __FILE__
|
|
|
|
int GetLineNumber(Provenance) const; // __LINE__
|
2018-02-16 20:14:11 +01:00
|
|
|
Provenance CompilerInsertionProvenance(char ch);
|
2018-03-20 18:59:07 +01:00
|
|
|
Provenance CompilerInsertionProvenance(const char *, std::size_t);
|
2018-02-15 19:42:36 +01:00
|
|
|
void Dump(std::ostream &) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-02-07 22:18:36 +01:00
|
|
|
private:
|
2018-02-08 01:24:02 +01:00
|
|
|
struct Inclusion {
|
|
|
|
const SourceFile &source;
|
2018-02-15 19:42:36 +01:00
|
|
|
bool isModule;
|
|
|
|
};
|
|
|
|
struct Module {
|
|
|
|
const SourceFile &source;
|
2018-02-08 01:24:02 +01:00
|
|
|
};
|
|
|
|
struct Macro {
|
|
|
|
ProvenanceRange definition;
|
|
|
|
std::string expansion;
|
|
|
|
};
|
2018-02-09 23:04:11 +01:00
|
|
|
struct CompilerInsertion {
|
|
|
|
std::string text;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Origin {
|
2018-02-15 19:42:36 +01:00
|
|
|
Origin(ProvenanceRange, const SourceFile &);
|
|
|
|
Origin(ProvenanceRange, const SourceFile &, ProvenanceRange,
|
2018-02-15 22:13:28 +01:00
|
|
|
bool isModule = false);
|
2018-02-15 19:42:36 +01:00
|
|
|
Origin(ProvenanceRange, ProvenanceRange def, ProvenanceRange use,
|
2018-02-09 23:04:11 +01:00
|
|
|
const std::string &expansion);
|
2018-02-15 19:42:36 +01:00
|
|
|
Origin(ProvenanceRange, const std::string &);
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-03-20 18:59:07 +01:00
|
|
|
const char &operator[](std::size_t) const;
|
2018-02-07 22:18:36 +01:00
|
|
|
|
2018-02-09 23:04:11 +01:00
|
|
|
std::variant<Inclusion, Macro, CompilerInsertion> u;
|
2018-02-15 19:42:36 +01:00
|
|
|
ProvenanceRange covers, replaces;
|
2018-02-07 22:18:36 +01:00
|
|
|
};
|
2018-02-09 23:04:11 +01:00
|
|
|
|
|
|
|
const Origin &MapToOrigin(Provenance) const;
|
|
|
|
|
|
|
|
std::vector<Origin> origin_;
|
2018-02-15 19:42:36 +01:00
|
|
|
ProvenanceRange range_;
|
2018-02-13 21:24:54 +01:00
|
|
|
std::map<char, Provenance> compilerInsertionProvenance_;
|
2018-02-13 23:22:08 +01:00
|
|
|
std::vector<std::unique_ptr<SourceFile>> ownedSourceFiles_;
|
2018-02-14 00:24:43 +01:00
|
|
|
std::vector<std::string> searchPath_;
|
2018-02-07 22:18:36 +01:00
|
|
|
};
|
|
|
|
|
2018-02-09 23:04:11 +01:00
|
|
|
class CookedSource {
|
2018-02-07 22:18:36 +01:00
|
|
|
public:
|
2018-03-23 23:14:52 +01:00
|
|
|
explicit CookedSource(AllSources &sources) : allSources_{sources} {}
|
2018-02-07 22:18:36 +01:00
|
|
|
|
2018-03-20 18:59:07 +01:00
|
|
|
std::size_t size() const { return data_.size(); }
|
|
|
|
const char &operator[](std::size_t n) const { return data_[n]; }
|
|
|
|
const char &at(std::size_t n) const { return data_.at(n); }
|
2018-02-07 22:18:36 +01:00
|
|
|
|
2018-03-23 23:14:52 +01:00
|
|
|
AllSources &allSources() const { return allSources_; }
|
|
|
|
|
|
|
|
bool IsValid(const char *p) const {
|
|
|
|
return p >= &data_.front() && p <= &data_.back() + 1;
|
|
|
|
}
|
2018-04-21 01:56:58 +02:00
|
|
|
bool IsValid(CharBlock range) const {
|
|
|
|
return range.empty() ||
|
|
|
|
(IsValid(range.begin()) && IsValid(range.end() - 1));
|
|
|
|
}
|
2018-03-23 23:14:52 +01:00
|
|
|
bool IsValid(Provenance p) const { return allSources_.IsValid(p); }
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-04-21 01:56:58 +02:00
|
|
|
ProvenanceRange GetProvenance(CharBlock) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-03-20 18:59:07 +01:00
|
|
|
void Put(const char *data, std::size_t bytes) { buffer_.Put(data, bytes); }
|
2018-02-09 23:04:11 +01:00
|
|
|
void Put(char ch) { buffer_.Put(&ch, 1); }
|
|
|
|
void Put(char ch, Provenance p) {
|
|
|
|
buffer_.Put(&ch, 1);
|
|
|
|
provenanceMap_.Put(ProvenanceRange{p, 1});
|
2018-02-07 22:18:36 +01:00
|
|
|
}
|
2018-02-13 02:03:26 +01:00
|
|
|
void PutProvenanceMappings(const OffsetToProvenanceMappings &pm) {
|
|
|
|
provenanceMap_.Put(pm);
|
|
|
|
}
|
2018-02-15 19:42:36 +01:00
|
|
|
void Marshal(); // marshals all text into one contiguous block
|
|
|
|
void Dump(std::ostream &) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-02-07 22:18:36 +01:00
|
|
|
private:
|
2018-03-23 23:14:52 +01:00
|
|
|
AllSources &allSources_;
|
2018-02-09 23:04:11 +01:00
|
|
|
CharBuffer buffer_; // before Marshal()
|
|
|
|
std::vector<char> data_; // all of it, prescanned and preprocessed
|
|
|
|
OffsetToProvenanceMappings provenanceMap_;
|
2018-02-07 22:18:36 +01:00
|
|
|
};
|
2018-02-08 01:24:02 +01:00
|
|
|
} // namespace parser
|
2018-02-07 22:18:36 +01:00
|
|
|
} // namespace Fortran
|
2018-02-16 20:42:17 +01:00
|
|
|
#endif // FORTRAN_PARSER_PROVENANCE_H_
|