return provenanceMap_[low].range.Suffix(offset);
}
-std::optional<std::size_t> OffsetToProvenanceMappings::ReverseMap(
- Provenance at) const {
- for (const auto &[start, range] : provenanceMap_) {
- if (range.Contains(at)) {
- std::size_t offset{at.offset() - range.start().offset()};
- return start + offset;
- }
- }
- return std::nullopt;
-}
-
void OffsetToProvenanceMappings::RemoveLastBytes(std::size_t bytes) {
for (; bytes > 0; provenanceMap_.pop_back()) {
CHECK(!provenanceMap_.empty());
return {ProvenanceRange{first.start(), last.start() - first.start()}};
}
-std::optional<CharBlock> CookedSource::GetCharBlock(
- ProvenanceRange range) const {
- CHECK(!invertedMap_.empty() &&
- "CompileProvenanceRangeToOffsetMappings not called");
- if (auto to{invertedMap_.Map(range)}) {
- return CharBlock{data_.c_str() + *to, range.size()};
- } else {
- return std::nullopt;
- }
-}
-
std::optional<CharBlock> CookedSource::GetCharBlockFromLineAndColumns(
int line, int startColumn, int endColumn) const {
// 2nd column is exclusive, meaning it is target column + 1.
CHECK(line > 0 && startColumn > 0 && endColumn > 0);
+ CHECK(startColumn < endColumn);
auto provenanceStart{allSources_.GetFirstFileProvenance().value().start()};
if (auto sourceFile{allSources_.GetSourceFile(provenanceStart)}) {
CHECK(line <= static_cast<int>(sourceFile->lines()));
- if (auto firstOffset{
- provenanceMap_.ReverseMap(sourceFile->GetLineStartOffset(line) +
- provenanceStart.offset() + startColumn - 1)}) {
- if (auto secondOffset{
- provenanceMap_.ReverseMap(sourceFile->GetLineStartOffset(line) +
- provenanceStart.offset() + endColumn - 2)}) {
- if (*secondOffset >= *firstOffset) {
- // Returned 2nd column is also exclusive.
- return CharBlock(
- &data_[*firstOffset], *secondOffset - *firstOffset + 1);
- }
- }
- }
+ return GetCharBlock(ProvenanceRange(sourceFile->GetLineStartOffset(line) +
+ provenanceStart.offset() + startColumn - 1,
+ endColumn - startColumn));
}
+ return std::nullopt;
}
std::optional<std::pair<SourcePosition, SourcePosition>>
return std::nullopt;
}
+std::optional<CharBlock> CookedSource::GetCharBlock(
+ ProvenanceRange range) const {
+ CHECK(!invertedMap_.empty() &&
+ "CompileProvenanceRangeToOffsetMappings not called");
+ if (auto to{invertedMap_.Map(range)}) {
+ return CharBlock{data_.c_str() + *to, range.size()};
+ } else {
+ return std::nullopt;
+ }
+}
+
void CookedSource::Marshal() {
CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());
provenanceMap_.Put(allSources_.AddCompilerInsertion("(after end of source)"));
// by the upper bits of an offset, but that does not appear to be
// necessary.)
+class AllSources;
+
class Provenance {
public:
Provenance() {}
void Put(ProvenanceRange);
void Put(const OffsetToProvenanceMappings &);
ProvenanceRange Map(std::size_t at) const;
- std::optional<std::size_t> ReverseMap(Provenance) const;
void RemoveLastBytes(std::size_t);
ProvenanceRangeToOffsetMappings Invert(const AllSources &) const;
std::ostream &Dump(std::ostream &) const;
const SourceFile *GetSourceFile(
Provenance, std::size_t *offset = nullptr) const;
std::optional<SourcePosition> GetSourcePosition(Provenance) const;
- std::optional<ProvenanceRange> GetFirstFileProvenance();
+ std::optional<ProvenanceRange> GetFirstFileProvenance() const;
std::string GetPath(Provenance) const; // __FILE__
int GetLineNumber(Provenance) const; // __LINE__
Provenance CompilerInsertionProvenance(char ch);
bool IsValid(ProvenanceRange r) const { return allSources_.IsValid(r); }
std::optional<ProvenanceRange> GetProvenanceRange(CharBlock) const;
- std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
std::optional<CharBlock> GetCharBlockFromLineAndColumns(
int line, int startColumn, int endColumn) const;
std::optional<std::pair<SourcePosition, SourcePosition>>
GetSourcePositionRange(CharBlock) const;
+ std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
// The result of a Put() is the offset that the new data
// will have in the eventually marshaled contiguous buffer.
class SourceFile;
struct SourcePosition {
- SourcePosition(const SourceFile &file, int line, int column)
- : file{file}, line{line}, column{column} {}
- SourcePosition(const SourceFile &file, std::pair<int, int> pos)
- : file{file}, line{pos.first}, column{pos.second} {}
-
const SourceFile &file;
int line, column;
};
GetSymbolNames(context_.globalScope(), symbols);
for (const auto pair : symbols) {
const Symbol &symbol{*pair.second};
- auto sourceInfo{cooked_.GetSourcePositionRange(symbol.name())};
- if (sourceInfo) {
+ if (auto sourceInfo{cooked_.GetSourcePositionRange(symbol.name())}) {
os << symbol.name().ToString() << ": " << sourceInfo->first.file.path()
<< ", " << sourceInfo->first.line << ", " << sourceInfo->first.column
<< "-" << sourceInfo->second.column << "\n";
}
struct GetDefinitionArgs {
- GetDefinitionArgs(int line, int startColumn, int endColumn)
- : line{line}, startColumn{startColumn}, endColumn{endColumn} {}
int line, startColumn, endColumn;
};
return {};
}
if (driver.getDefinition) {
- std::string notFoundText{"Symbol not found.\n"};
- auto cb{parsing.cooked().GetCharBlockFromLineAndColumns(
- driver.getDefinitionArgs.line, driver.getDefinitionArgs.startColumn,
- driver.getDefinitionArgs.endColumn)};
- if (!cb) {
- std::cerr << notFoundText;
- exitStatus = EXIT_FAILURE;
- return {};
- }
- std::cerr << "String range: >" << std::string(cb->begin(), cb->size())
- << "<\n";
- auto &scope{semanticsContext.FindScope(*cb)};
- auto symbol{scope.FindSymbol(*cb)};
- if (!symbol) {
- std::cerr << notFoundText;
- exitStatus = EXIT_FAILURE;
- return {};
- }
- std::cerr << "Found symbol name: "
- << std::string(symbol->name().begin(), symbol->name().size())
- << "\n";
- auto sourceInfo{parsing.cooked().GetSourcePositionRange(symbol->name())};
- if (!sourceInfo) {
- std::cerr << notFoundText;
- exitStatus = EXIT_FAILURE;
- return {};
+ if (auto cb{parsing.cooked().GetCharBlockFromLineAndColumns(
+ driver.getDefinitionArgs.line,
+ driver.getDefinitionArgs.startColumn,
+ driver.getDefinitionArgs.endColumn)}) {
+ std::cerr << "String range: >" << cb->ToString() << "<\n";
+ if (auto symbol{semanticsContext.FindScope(*cb).FindSymbol(*cb)}) {
+ std::cerr << "Found symbol name: " << symbol->name().ToString()
+ << "\n";
+ if (auto sourceInfo{
+ parsing.cooked().GetSourcePositionRange(symbol->name())}) {
+ std::cout << symbol->name().ToString() << ": "
+ << sourceInfo->first.file.path() << ", "
+ << sourceInfo->first.line << ", "
+ << sourceInfo->first.column << "-"
+ << sourceInfo->second.column << "\n";
+ exitStatus = EXIT_SUCCESS;
+ return {};
+ }
+ }
}
- std::cout << symbol->name().ToString() << ": "
- << sourceInfo->first.file.path() << ", "
- << sourceInfo->first.line << ", " << sourceInfo->first.column
- << "-" << sourceInfo->second.column << "\n";
- exitStatus = EXIT_SUCCESS;
+ std::cerr << "Symbol not found.\n";
+ exitStatus = EXIT_FAILURE;
return {};
}
}
driver.encoding = Fortran::parser::Encoding::LATIN_1;
} else if (arg == "-fget-definition") {
// Receives 3 arguments: line, startColumn, endColumn.
+ options.needProvenanceRangeToCharBlockMappings = true;
driver.getDefinition = true;
char *endptr;
int arguments[3];