if (!symbol) {
const auto pair = CurrScope().try_emplace(name, attrs, details);
CHECK(pair.second); // name was not found, so must be able to add
- return pair.first->second;
+ return *pair.first->second;
}
symbol->add_occurrence(name);
if (symbol->CanReplaceDetails(details)) {
Symbol &MakeSymbol(const parser::Name &name, D &&details) {
return MakeSymbol(name, Attrs(), details);
}
+ template<typename D>
+ Symbol &MakeSymbol(const SourceName &name, D &&details) {
+ return MakeSymbol(name, Attrs(), details);
+ }
Symbol &MakeSymbol(const SourceName &name, Attrs attrs = Attrs{}) {
return MakeSymbol(name, attrs, UnknownDetails());
}
void AddToGeneric(const parser::Name &name, bool expectModuleProc = false);
void AddToGeneric(const Symbol &symbol);
// Add to generic the symbol for the subprogram with the same name
- void SetSpecificInGeneric(Symbol &&symbol);
+ void SetSpecificInGeneric(Symbol *symbol);
private:
bool inInterfaceBlock_{false}; // set when in interface block
if (it == CurrScope().end()) {
return nullptr;
} else {
- return &it->second;
+ return it->second;
}
}
void ScopeHandler::EraseSymbol(const SourceName &name) {
if (!isImplicitNoneType()) {
implicitRules().AddDefaultRules();
for (auto &pair : CurrScope()) {
- Symbol &symbol = pair.second;
+ Symbol &symbol = *pair.second;
if (symbol.has<UnknownDetails>()) {
symbol.set_details(ObjectEntityDetails{});
} else if (auto *details = symbol.detailsIf<EntityDetails>()) {
Say(x.moduleName, "Module '%s' not found"_err_en_US);
return false;
}
- const auto *details = it->second.detailsIf<ModuleDetails>();
+ const auto *details = it->second->detailsIf<ModuleDetails>();
if (!details) {
Say(x.moduleName, "'%s' is not a module"_err_en_US);
return false;
}
const SourceName &moduleName{x.moduleName.source};
for (const auto &pair : *useModuleScope_) {
- const Symbol &symbol{pair.second};
+ const Symbol &symbol{*pair.second};
if (symbol.attrs().test(Attr::PUBLIC) &&
!symbol.detailsIf<ModuleDetails>()) {
const SourceName &name{symbol.name()};
useModuleScope_->name());
return;
}
- const Symbol &useSymbol{it->second};
+ const Symbol &useSymbol{*it->second};
if (useSymbol.attrs().test(Attr::PRIVATE)) {
Say(useName, "'%s' is PRIVATE in '%s'"_err_en_US, useName,
useModuleScope_->name());
void ModuleVisitor::ApplyDefaultAccess() {
for (auto &pair : CurrScope()) {
- Symbol &symbol = pair.second;
+ Symbol &symbol = *pair.second;
if (!symbol.attrs().HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
symbol.attrs().set(defaultAccess_);
}
} else {
CHECK(!"can't happen");
}
- Symbol symbol{CurrScope(), genericSymbol_->name(), genericSymbol_->attrs(),
- std::move(details)};
+ GenericDetails genericDetails;
+ genericDetails.set_specific(genericSymbol_);
EraseSymbol(*genericName);
- genericSymbol_ = &MakeSymbol(*genericName);
- genericSymbol_->set_details(GenericDetails{std::move(symbol)});
+ genericSymbol_ = &MakeSymbol(*genericName, genericDetails);
}
CHECK(genericSymbol_->has<GenericDetails>());
return false;
return;
}
if (symbol == genericSymbol_) {
- if (auto *specific =
- genericSymbol_->details<GenericDetails>().specific().get()) {
+ if (auto *specific = genericSymbol_->details<GenericDetails>().specific()) {
symbol = specific;
}
}
void InterfaceVisitor::AddToGeneric(const Symbol &symbol) {
genericSymbol_->details<GenericDetails>().add_specificProc(&symbol);
}
-void InterfaceVisitor::SetSpecificInGeneric(Symbol &&symbol) {
- genericSymbol_->details<GenericDetails>().set_specific(std::move(symbol));
+void InterfaceVisitor::SetSpecificInGeneric(Symbol *symbol) {
+ genericSymbol_->details<GenericDetails>().set_specific(symbol);
}
// SubprogramVisitor implementation
EntityDetails dummyDetails{true};
auto it = CurrScope().parent().find(dummyName.source);
if (it != CurrScope().parent().end()) {
- if (auto *d = it->second.detailsIf<EntityDetails>()) {
+ if (auto *d = it->second->detailsIf<EntityDetails>()) {
if (d->type()) {
dummyDetails.set_type(*d->type());
}
if (Symbol *symbol = FindSymbol(name.source)) {
if (auto *details = symbol->detailsIf<GenericDetails>()) {
// found generic, want subprogram
- auto *specific = details->specific().get();
+ auto *specific = details->specific();
if (isGeneric()) {
if (specific) {
SayAlreadyDeclared(name.source, *specific);
} else {
- SetSpecificInGeneric(
- Symbol{CurrScope(), name.source, Attrs{}, SubprogramDetails{}});
- specific = details->specific().get();
+ specific = &CurrScope().MakeSymbol(
+ name.source, Attrs{}, SubprogramDetails{});
+ SetSpecificInGeneric(specific);
}
}
if (specific) {
const auto pair = CurrScope().try_emplace(name.source, Attrs{attr});
if (!pair.second) {
// symbol was already there: set attribute on it
- Symbol &symbol{pair.first->second};
+ Symbol &symbol{*pair.first->second};
if (attr != Attr::ASYNCHRONOUS && attr != Attr::VOLATILE &&
symbol.has<UseDetails>()) {
Say(*currStmtSource(),
// Check that every name referenced has an explicit type
for (const auto &pair : CurrScope()) {
const auto &name = pair.first;
- const auto &symbol = pair.second;
+ const auto &symbol = *pair.second;
if (NeedsExplicitType(symbol)) {
Say(name, "No explicit type declared for '%s'"_err_en_US);
}
++indent;
for (const auto &symbol : scope) {
PutIndent(os, indent);
- os << symbol.second << "\n";
+ os << *symbol.second << "\n";
}
for (const auto &child : scope.children()) {
DumpSymbols(os, child, indent);
namespace Fortran::semantics {
class Scope {
- using mapType = std::map<SourceName, Symbol>;
+ using mapType = std::map<SourceName, Symbol *>;
public:
// root of the scope tree; contains intrinsics:
template<typename D>
std::pair<iterator, bool> try_emplace(
const SourceName &name, Attrs attrs, D &&details) {
- return symbols_.try_emplace(name, *this, name, attrs, details);
+ Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
+ return symbols_.insert(std::make_pair(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_; }
std::list<Scope> children_;
mapType symbols_;
+ // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
+ // or Symbol& points to one in there.
+ static Symbols<1024> allSymbols;
+
friend std::ostream &operator<<(std::ostream &, const Scope &);
};
using listType = std::list<const Symbol *>;
GenericDetails() {}
GenericDetails(const listType &specificProcs);
- GenericDetails(Symbol &&specific) { set_specific(std::move(specific)); }
+ GenericDetails(Symbol *specific) : specific_{specific} {}
const listType specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol *proc) { specificProcs_.push_back(proc); }
- std::unique_ptr<Symbol> &specific() { return specific_; }
- void set_specific(Symbol &&specific);
+ Symbol *specific() { return specific_; }
+ void set_specific(Symbol *specific);
// Check that specific is one of the specificProcs. If not, return the
// specific as a raw pointer.
// all of the specific procedures for this generic
listType specificProcs_;
// a specific procedure with the same name as this generic, if any
- std::unique_ptr<Symbol> specific_;
+ Symbol *specific_{nullptr};
};
class UnknownDetails {};
ENUM_CLASS(Flag, Function, Subroutine);
using Flags = common::EnumSet<Flag, Flag_enumSize>;
- Symbol(const Scope &owner, const SourceName &name, const Attrs &attrs,
- Details &&details)
- : owner_{owner}, attrs_{attrs}, details_{std::move(details)} {
- add_occurrence(name);
- }
- const Scope &owner() const { return owner_; }
+ const Scope &owner() const { return *owner_; }
const SourceName &name() const { return occurrences_.front(); }
Attrs &attrs() { return attrs_; }
const Attrs &attrs() const { return attrs_; }
bool operator!=(const Symbol &that) const { return this != &that; }
private:
- const Scope &owner_;
+ const Scope *owner_;
std::list<SourceName> occurrences_;
Attrs attrs_;
Flags flags_;
Details details_;
+ Symbol() {} // only created in class Symbols
const std::string GetDetailsName() const;
friend std::ostream &operator<<(std::ostream &, const Symbol &);
+ template<std::size_t> friend class Symbols;
+ template<class, std::size_t> friend class std::array;
};
std::ostream &operator<<(std::ostream &, Symbol::Flag);
+// Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
+// Make() returns a reference to the next available one. They are never
+// deleted.
+template<std::size_t BLOCK_SIZE> class Symbols {
+public:
+ Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
+ Details &&details) {
+ Symbol &symbol = Get();
+ symbol.owner_ = &owner;
+ symbol.occurrences_.push_back(name);
+ symbol.attrs_ = attrs;
+ symbol.details_ = std::move(details);
+ return symbol;
+ }
+
+private:
+ using blockType = std::array<Symbol, BLOCK_SIZE>;
+ std::list<blockType *> blocks_;
+ std::size_t nextIndex_{0};
+ blockType *currBlock_{nullptr};
+
+ Symbol &Get() {
+ if (nextIndex_ == 0) {
+ blocks_.push_back(new blockType());
+ currBlock_ = blocks_.back();
+ }
+ Symbol &result = (*currBlock_)[nextIndex_];
+ if (++nextIndex_ >= BLOCK_SIZE) {
+ nextIndex_ = 0; // allocate a new block next time
+ }
+ return result;
+ }
+};
+
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_SYMBOL_H_