constexpr WithinCharLiteral(const WithinCharLiteral &) = default;
constexpr WithinCharLiteral(const PA &parser) : parser_{parser} {}
std::optional<resultType> Parse(ParseState *state) const {
- bool was = state->set_inCharLiteral(true);
+ bool was{state->inCharLiteral()};
std::optional<resultType> result{parser_.Parse(state)};
state->set_inCharLiteral(was);
return result;
using resultType = std::string;
static std::optional<std::string> Parse(ParseState *state) {
std::string str;
- CHECK(!state->set_inCharLiteral(true));
+ CHECK(!state->inCharLiteral());
static constexpr auto nextch = attempt(CharLiteralChar{});
while (std::optional<CharLiteralChar::Result> ch{nextch.Parse(state)}) {
if (ch->ch == quote && !ch->wasEscaped) {
return {};
}
std::string content;
- CHECK(!state->set_inCharLiteral(true));
+ CHECK(!state->inCharLiteral());
+ state->set_inCharLiteral(true);
for (auto j = *charCount; j-- > 0;) {
std::optional<char> ch{cookedNextChar.Parse(state)};
if (!ch || !isprint(*ch)) {
namespace Fortran {
namespace parser {
-void Message::Emit(std::ostream &o, const AllSources &sources) const {
- if (context_) {
- context_->Emit(o, sources);
+Provenance Message::Emit(
+ std::ostream &o, const AllSources &sources, bool echoSourceLine) const {
+ if (!context_ || context_->Emit(o, sources, false) != provenance_) {
+ sources.Identify(o, provenance_, "", echoSourceLine);
}
- sources.Identify(o, provenance_, "");
o << " " << message_ << '\n';
+ return provenance_;
}
void Messages::Emit(std::ostream &o) const {
for (const auto &msg : messages_) {
+ if (msg.context()) {
+ o << "In the context ";
+ }
msg.Emit(o, allSources_);
}
}
std::string message() const { return message_; }
MessageContext context() const { return context_; }
- void Emit(std::ostream &, const AllSources &) const;
+ Provenance Emit(
+ std::ostream &, const AllSources &, bool echoSourceLine = true) const;
private:
Provenance provenance_;
if (IsIdentifierFirstCharacter(tok)) {
auto it = args.find(tok.ToString());
if (it != args.end()) {
- result.Put(it->second, token.GetProvenance(j));
+ result.Put(it->second, token.GetTokenProvenance(j));
continue;
}
}
size_t argBytes{args[index][k].size()};
for (size_t n{0}; n < argBytes; ++n) {
char ch{arg[n]};
- Provenance from{args[index].GetProvenance(k, n)};
+ Provenance from{args[index].GetTokenProvenance(k, n)};
if (ch == '"' || ch == '\\') {
result.PutNextTokenChar(ch, from);
}
if (!repl.empty()) {
ProvenanceRange insert{allSources_->AddCompilerInsertion(repl)};
ProvenanceRange call{allSources_->AddMacroCall(
- insert, input.GetProvenanceRange(j), repl)};
+ insert, input.GetTokenProvenanceRange(j), repl)};
result->Put(repl, call.LocalOffsetToProvenance(0));
continue;
}
}
def.set_isDisabled(true);
- result->Put(ReplaceMacros(def.replacement(), prescanner));
+ TokenSequence replaced{ReplaceMacros(def.replacement(), prescanner)};
def.set_isDisabled(false);
+ ProvenanceRange from{def.replacement().GetProvenanceRange()};
+ ProvenanceRange use{input.GetTokenProvenanceRange(j)};
+ ProvenanceRange newRange{
+ allSources_->AddMacroCall(from, use, replaced.ToString())};
+ result->Put(replaced, newRange);
continue;
}
// Possible function-like macro call. Skip spaces and newlines to see
result->Put(input, j);
continue;
}
- j = k; // advance to the terminal ')'
std::vector<TokenSequence> args;
- for (k = 0; k < argStart.size(); ++k) {
- size_t at{argStart[k]};
- size_t count{(k + 1 == argStart.size() ? j : argStart[k + 1] - 1) - at};
+ for (size_t n{0}; n < argStart.size(); ++n) {
+ size_t at{argStart[n]};
+ size_t count{(n + 1 == argStart.size() ? k : argStart[n + 1] - 1) - at};
args.emplace_back(TokenSequence(input, at, count));
}
def.set_isDisabled(true);
- result->Put(ReplaceMacros(def.Apply(args, *allSources_), prescanner));
+ TokenSequence replaced{
+ ReplaceMacros(def.Apply(args, *allSources_), prescanner)};
def.set_isDisabled(false);
+ ProvenanceRange from{def.replacement().GetProvenanceRange()};
+ ProvenanceRange use{input.GetIntervalProvenanceRange(j, k - j)};
+ ProvenanceRange newRange{
+ allSources_->AddMacroCall(from, use, replaced.ToString())};
+ result->Put(replaced, newRange);
+ j = k; // advance to the terminal ')'
}
return true;
}
prescanner->Complain("#include: missing name of file to include");
return false;
}
- ProvenanceRange includeDirRange{dir.GetProvenanceRange(j)};
std::string include;
if (dir[j].ToString() == "<") {
if (dir[tokens - 1].ToString() != ">") {
return false;
}
ProvenanceRange fileRange{
- allSources_->AddIncludedFile(*included, includeDirRange)};
+ allSources_->AddIncludedFile(*included, dir.GetProvenanceRange())};
return Prescanner{*prescanner}.Prescan(fileRange);
}
prescanner->Complain("#"s + dirName + ": unknown or unimplemented directive");
return covers;
}
-void AllSources::Identify(
- std::ostream &o, Provenance at, const std::string &prefix) const {
+void AllSources::Identify(std::ostream &o, Provenance at,
+ const std::string &prefix, bool echoSourceLine) const {
CHECK(IsValid(at));
static const std::string indented{prefix + " "};
const Origin &origin{MapToOrigin(at)};
[&](const Inclusion &inc) {
size_t offset{origin.covers.ProvenanceToLocalOffset(at)};
std::pair<int, int> pos{inc.source.FindOffsetLineAndColumn(offset)};
- o << prefix << "at line " << pos.first << ", column " << pos.second
- << " in the " << (inc.isModule ? "module " : "file ")
+ o << prefix << "at line " << pos.first << ", column " << pos.second;
+ if (echoSourceLine) {
+ o << ":\n" << indented << " ";
+ const char *text{inc.source.content() +
+ inc.source.GetLineStartOffset(pos.first)};
+ for (const char *p{text}; *p != '\n'; ++p) {
+ o << *p;
+ }
+ o << '\n' << indented << " ";
+ for (int j{1}; j < pos.second; ++j) {
+ char ch{text[j - 1]};
+ o << (ch == '\t' ? '\t' : ' ');
+ }
+ o << "^\n" << prefix;
+ } else {
+ o << ' ';
+ }
+ o << "in the " << (inc.isModule ? "module " : "file ")
<< inc.source.path() << '\n';
if (IsValid(origin.replaces)) {
- o << prefix << " that was " << (inc.isModule ? "used\n" : "included\n");
+ o << prefix << " that was "
+ << (inc.isModule ? "used\n" : "included\n");
Identify(o, origin.replaces.LocalOffsetToProvenance(0), indented);
}
},
AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &source)
: u{Inclusion{source}}, covers{r} {}
-AllSources::Origin::Origin(
- ProvenanceRange r, const SourceFile &included, ProvenanceRange from,
- bool isModule)
+AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &included,
+ ProvenanceRange from, bool isModule)
: u{Inclusion{included, isModule}}, covers{r}, replaces{from} {}
AllSources::Origin::Origin(ProvenanceRange r, ProvenanceRange def,
ProvenanceRange use, const std::string &expansion)
m.covers.Dump(o);
o << " -> ";
std::visit(visitors{[&](const Inclusion &inc) {
- if (inc.isModule) { o << "module "; }
+ if (inc.isModule) {
+ o << "module ";
+ }
o << "file " << inc.source.path();
},
[&](const Macro &mac) { o << "macro " << mac.expansion; },
}
Provenance operator+(size_t n) const { return {offset_ + n}; }
bool operator<(Provenance that) const { return offset_ < that.offset_; }
- bool operator<=(Provenance that) const { return offset_ <= that.offset_; }
+ bool operator<=(Provenance that) const { return !(that < *this); }
bool operator==(Provenance that) const { return offset_ == that.offset_; }
+ bool operator!=(Provenance that) const { return !(*this == that); }
size_t offset() const { return offset_; }
private:
std::string PopSearchPathDirectory();
const SourceFile *Open(std::string path, std::stringstream *error);
- ProvenanceRange AddIncludedFile(const SourceFile &, ProvenanceRange,
- bool isModule = false);
+ ProvenanceRange AddIncludedFile(
+ const SourceFile &, ProvenanceRange, bool isModule = false);
ProvenanceRange AddMacroCall(
ProvenanceRange def, ProvenanceRange use, const std::string &expansion);
ProvenanceRange AddCompilerInsertion(std::string);
bool IsValid(ProvenanceRange range) const {
return range.size() > 0 && range_.Contains(range);
}
- void Identify(std::ostream &, Provenance, const std::string &prefix) const;
+ void Identify(std::ostream &, Provenance, const std::string &prefix,
+ bool echoSourceLine = false) const;
const SourceFile *GetSourceFile(Provenance, size_t *offset = nullptr) const;
ProvenanceRange GetContiguousRangeAround(ProvenanceRange) const;
std::string GetPath(Provenance) const; // __FILE__
struct Origin {
Origin(ProvenanceRange, const SourceFile &);
Origin(ProvenanceRange, const SourceFile &, ProvenanceRange,
- bool isModule = false);
+ bool isModule = false);
Origin(ProvenanceRange, ProvenanceRange def, ProvenanceRange use,
const std::string &expansion);
Origin(ProvenanceRange, const std::string &);
bool Open(std::string path, std::stringstream *error);
void Close();
std::pair<int, int> FindOffsetLineAndColumn(size_t) const;
+ size_t GetLineStartOffset(int lineNumber) const {
+ return lineStart_.at(lineNumber - 1);
+ }
private:
std::string path_;
provenances_.Put(that.provenances_);
}
+void TokenSequence::Put(const TokenSequence &that, ProvenanceRange range) {
+ size_t offset{0};
+ for (size_t j{0}; j < that.size(); ++j) {
+ CharPointerWithLength tok{that[j]};
+ Put(tok, range.LocalOffsetToProvenance(offset));
+ offset += tok.size();
+ }
+ CHECK(offset == range.size());
+}
+
void TokenSequence::Put(const TokenSequence &that, size_t at, size_t tokens) {
ProvenanceRange provenance;
size_t offset{0};
void TokenSequence::Put(const CharPointerWithLength &t, Provenance provenance) {
Put(&t[0], t.size(), provenance);
}
+
void TokenSequence::Put(const std::string &s, Provenance provenance) {
Put(s.data(), s.size(), provenance);
}
return {&char_[0], char_.size()};
}
-Provenance TokenSequence::GetProvenance(size_t token, size_t offset) const {
+Provenance TokenSequence::GetTokenProvenance(
+ size_t token, size_t offset) const {
ProvenanceRange range{provenances_.Map(start_[token] + offset)};
return range.LocalOffsetToProvenance(0);
}
-ProvenanceRange TokenSequence::GetProvenanceRange(
+ProvenanceRange TokenSequence::GetTokenProvenanceRange(
size_t token, size_t offset) const {
ProvenanceRange range{provenances_.Map(start_[token] + offset)};
return range.Prefix(TokenBytes(token) - offset);
}
+
+ProvenanceRange TokenSequence::GetIntervalProvenanceRange(
+ size_t token, size_t tokens) const {
+ if (tokens == 0) {
+ return {};
+ }
+ ProvenanceRange range{provenances_.Map(start_[token])};
+ while (--tokens > 0 &&
+ range.AnnexIfPredecessor(provenances_.Map(start_[++token]))) {
+ }
+ return range;
+}
+
+ProvenanceRange TokenSequence::GetProvenanceRange() const {
+ return GetIntervalProvenanceRange(0, start_.size());
+}
} // namespace parser
} // namespace Fortran
}
void Put(const TokenSequence &);
+ void Put(const TokenSequence &, ProvenanceRange);
void Put(const TokenSequence &, size_t at, size_t tokens = 1);
void Put(const char *, size_t, Provenance);
void Put(const CharPointerWithLength &, Provenance);
void Put(const std::stringstream &, Provenance);
void EmitWithCaseConversion(CookedSource *) const;
std::string ToString() const;
- Provenance GetProvenance(size_t token, size_t offset = 0) const;
- ProvenanceRange GetProvenanceRange(size_t token, size_t offset = 0) const;
+ Provenance GetTokenProvenance(size_t token, size_t offset = 0) const;
+ ProvenanceRange GetTokenProvenanceRange(
+ size_t token, size_t offset = 0) const;
+ ProvenanceRange GetIntervalProvenanceRange(
+ size_t token, size_t tokens = 1) const;
+ ProvenanceRange GetProvenanceRange() const;
private:
size_t TokenBytes(size_t token) const {
Fortran::parser::ParseState state{cooked};
Fortran::parser::UserState ustate;
state.set_inFixedForm(fixedForm)
- .set_enableBackslashEscapesInCharLiterals(backslashEscapes)
- .set_strictConformance(standard)
- .set_columns(columns)
- .set_enableOldDebugLines(enableOldDebugLines)
- .set_userState(&ustate);
+ .set_enableBackslashEscapesInCharLiterals(backslashEscapes)
+ .set_strictConformance(standard)
+ .set_columns(columns)
+ .set_enableOldDebugLines(enableOldDebugLines)
+ .set_userState(&ustate);
if (dumpCookedChars) {
while (std::optional<char> och{