llvm/flang/lib/semantics/scope.h
Tim Keith 7edb7ec69b [flang] Add top-level Semantics class
Refactor to create the Semantics class that is responsible for holding
state during semantics (the scope tree and messages) and managing the
logic of the various phases of semantic processing. Eliminate static
Scope::globalScope.

The messages generated during semantic processing are accumulated in a
Messages data member of Semantics so that individual phases don't need
to emit them to std::cerr. This is now done by the driver so that it has
control over where they go and eliminates other includes of iostream.
To do this, the messages object is passed in to the various semantics
operations.

Move DumpSymbols into semantics.cc: it doesn't belong in resolve-names.cc
and it depends on the global scope, so it's as good a place as any.
The call to RewriteParseTree is also moved to Semantics.

Original-commit: flang-compiler/f18@771d0e1293
Reviewed-on: https://github.com/flang-compiler/f18/pull/186
Tree-same-pre-rewrite: false
2018-09-14 15:04:50 -07:00

162 lines
5.4 KiB
C++

// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_SEMANTICS_SCOPE_H_
#define FORTRAN_SEMANTICS_SCOPE_H_
#include "attr.h"
#include "symbol.h"
#include "../common/fortran.h"
#include "../common/idioms.h"
#include "../parser/message.h"
#include <list>
#include <map>
#include <set>
#include <string>
namespace Fortran::semantics {
using namespace parser::literals;
class Scope {
using mapType = std::map<SourceName, Symbol *>;
public:
ENUM_CLASS(
Kind, System, Global, Module, MainProgram, Subprogram, DerivedType, Block)
using ImportKind = common::ImportKind;
// Create the Global scope -- the root of the scope tree
Scope() : Scope{*this, Kind::Global, nullptr} {}
Scope(Scope &parent, Kind kind, Symbol *symbol)
: parent_{parent}, kind_{kind}, symbol_{symbol} {
if (symbol) {
symbol->set_scope(this);
}
}
bool operator==(const Scope &that) const { return this == &that; }
bool operator!=(const Scope &that) const { return this != &that; }
Scope &parent() {
CHECK(kind_ != Kind::System);
return parent_;
}
const Scope &parent() const {
CHECK(kind_ != Kind::System);
return parent_;
}
Kind kind() const { return kind_; }
bool IsModule() const; // only module, not submodule
Symbol *symbol() { return symbol_; }
const Symbol *symbol() const { return symbol_; }
const SourceName &name() const {
CHECK(symbol_); // must only be called for Scopes known to have a symbol
return symbol_->name();
}
/// Make a scope nested in this one
Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
using size_type = mapType::size_type;
using iterator = mapType::iterator;
using const_iterator = mapType::const_iterator;
iterator begin() { return symbols_.begin(); }
iterator end() { return symbols_.end(); }
const_iterator begin() const { return symbols_.begin(); }
const_iterator end() const { return symbols_.end(); }
const_iterator cbegin() const { return symbols_.cbegin(); }
const_iterator cend() const { return symbols_.cend(); }
iterator find(const SourceName &name);
const_iterator find(const SourceName &name) const;
size_type erase(const SourceName &);
size_type size() const { return symbols_.size(); }
// Look for symbol by name in this scope and host (depending on imports).
Symbol *FindSymbol(const SourceName &);
/// Make a Symbol with unknown details.
std::pair<iterator, bool> try_emplace(
const SourceName &name, Attrs attrs = Attrs()) {
return try_emplace(name, attrs, UnknownDetails());
}
/// Make a Symbol with provided details.
template<typename D>
std::pair<iterator, bool> try_emplace(const SourceName &name, D &&details) {
return try_emplace(name, Attrs(), details);
}
/// Make a Symbol with attrs and details
template<typename D>
std::pair<iterator, bool> try_emplace(
const SourceName &name, Attrs attrs, D &&details) {
Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
return symbols_.emplace(name, &symbol);
}
/// Make a Symbol but don't add it to the scope.
template<typename D>
Symbol &MakeSymbol(const SourceName &name, Attrs attrs, D &&details) {
return allSymbols.Make(*this, name, attrs, std::move(details));
}
std::list<Scope> &children() { return children_; }
const std::list<Scope> &children() const { return children_; }
// For Module scope, maintain a mapping of all submodule scopes with this
// module as its ancestor module. AddSubmodule returns false if already there.
Scope *FindSubmodule(const SourceName &) const;
bool AddSubmodule(const SourceName &, Scope &);
DerivedTypeSpec &MakeDerivedTypeSpec(const SourceName &);
// For modules read from module files, this is the stream of characters
// that are referenced by SourceName objects.
void set_chars(std::string &&chars) { chars_ = std::move(chars); }
ImportKind GetImportKind() const;
// Names appearing in IMPORT statements in this scope
std::set<SourceName> importNames() const { return importNames_; }
// Set the kind of imports from host into this scope.
// Return an error message for incompatible kinds.
std::optional<parser::MessageFixedText> SetImportKind(ImportKind);
bool add_importName(const SourceName &);
private:
Scope &parent_;
const Kind kind_;
Symbol *const symbol_;
std::list<Scope> children_;
mapType symbols_;
std::map<SourceName, Scope *> submodules_;
std::list<DerivedTypeSpec> derivedTypeSpecs_;
std::string chars_;
std::optional<ImportKind> importKind_;
std::set<SourceName> importNames_;
// Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
// or Symbol& points to one in there.
static Symbols<1024> allSymbols;
bool CanImport(const SourceName &) const;
friend std::ostream &operator<<(std::ostream &, const Scope &);
};
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_SCOPE_H_