[flang] Add mapping of source location to Scope

Each Scope now tracks the source locations that it and its nested scopes
span. This is achieved by extending the source range of a scope for each
statement encountered while it is the current scope.

Semantics::FindScope maps a source location (from the cooked character
stream) to the narrowest scope that contains it.

Original-commit: flang-compiler/f18@7b4d2bb113
Reviewed-on: https://github.com/flang-compiler/f18/pull/230
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2018-11-28 15:55:55 -08:00
parent a640a8f0dd
commit cef802b1b4
6 changed files with 57 additions and 11 deletions

View File

@ -48,6 +48,10 @@ public:
return interval_.start()[j];
}
bool Contains(const CharBlock &that) const {
return interval_.Contains(that.interval_);
}
bool IsBlank() const {
for (char ch : *this) {
if (ch != ' ' && ch != '\t') {

View File

@ -199,15 +199,8 @@ public:
void set_messages(parser::Messages &messages) { messages_ = &messages; }
template<typename T> bool Pre(const parser::Statement<T> &x) {
currStmtSource_ = &x.source;
return true;
}
template<typename T> void Post(const parser::Statement<T> &) {
currStmtSource_ = nullptr;
}
const SourceName *currStmtSource() { return currStmtSource_; }
void set_currStmtSource(const SourceName *x) { currStmtSource_ = x; }
// Add a message to the messages to be emitted.
Message &Say(Message &&);
@ -240,8 +233,6 @@ class ImplicitRulesVisitor : public DeclTypeSpecVisitor, public MessageHandler {
public:
using DeclTypeSpecVisitor::Post;
using DeclTypeSpecVisitor::Pre;
using MessageHandler::Post;
using MessageHandler::Pre;
using ImplicitNoneNameSpec = parser::ImplicitStmt::ImplicitNoneNameSpec;
void Post(const parser::ParameterStmt &);
@ -338,6 +329,15 @@ public:
ImplicitRulesVisitor::ClearScopes();
}
template<typename T> bool Pre(const parser::Statement<T> &x) {
set_currStmtSource(&x.source);
currScope_->AddSourceRange(x.source);
return true;
}
template<typename T> void Post(const parser::Statement<T> &) {
set_currStmtSource(nullptr);
}
Symbol *FindSymbol(const SourceName &name);
void EraseSymbol(const SourceName &name);
@ -765,6 +765,8 @@ public:
using InterfaceVisitor::Pre;
using ModuleVisitor::Post;
using ModuleVisitor::Pre;
using ScopeHandler::Post;
using ScopeHandler::Pre;
using SubprogramVisitor::Post;
using SubprogramVisitor::Pre;

View File

@ -134,6 +134,28 @@ bool Scope::CanImport(const SourceName &name) const {
}
}
const Scope *Scope::FindScope(const parser::CharBlock &source) const {
if (!sourceRange_.Contains(source)) {
return nullptr;
}
for (const auto &child : children_) {
if (const auto *scope{child.FindScope(source)}) {
return scope;
}
}
return this;
}
void Scope::AddSourceRange(const parser::CharBlock &source) {
if (sourceRange_.empty()) {
sourceRange_ = source;
} else if (!source.empty()) {
sourceRange_ =
parser::CharBlock(std::min(sourceRange_.begin(), source.begin()),
std::max(sourceRange_.end(), source.end()));
}
}
std::ostream &operator<<(std::ostream &os, const Scope &scope) {
os << Scope::EnumToString(scope.kind()) << " scope: ";
if (auto *symbol{scope.symbol()}) {

View File

@ -137,9 +137,16 @@ public:
bool add_importName(const SourceName &);
// The range of the source of this and nested scopes.
const parser::CharBlock &sourceRange() const { return sourceRange_; }
void AddSourceRange(const parser::CharBlock &);
// Find the smallest scope under this one that contains source
const Scope *FindScope(const parser::CharBlock &) const;
private:
Scope &parent_;
const Kind kind_;
parser::CharBlock sourceRange_;
Symbol *const symbol_;
std::list<Scope> children_;
mapType symbols_;

View File

@ -74,6 +74,14 @@ bool Semantics::Perform() {
return !AnyFatalError();
}
const Scope &Semantics::FindScope(const parser::CharBlock &source) const {
if (const auto *scope{context_.globalScope().FindScope(source)}) {
return *scope;
} else {
common::die("invalid source location");
}
}
void Semantics::EmitMessages(std::ostream &os) const {
context_.messages().Emit(os, cooked_);
}

View File

@ -89,10 +89,13 @@ class Semantics {
public:
explicit Semantics(SemanticsContext &context, parser::Program &program,
parser::CookedSource &cooked)
: context_{context}, program_{program}, cooked_{cooked} {}
: context_{context}, program_{program}, cooked_{cooked} {
context.globalScope().AddSourceRange(parser::CharBlock{cooked.data()});
}
SemanticsContext &context() const { return context_; }
bool Perform();
const Scope &FindScope(const parser::CharBlock &) const;
bool AnyFatalError() const { return context_.AnyFatalError(); }
void EmitMessages(std::ostream &) const;
void DumpSymbols(std::ostream &);