protected:
std::optional<Attrs> attrs_;
std::string langBindingName_{""};
+
+ Attr AccessSpecToAttr(const parser::AccessSpec &x) {
+ switch (x.v) {
+ case parser::AccessSpec::Kind::Public: return Attr::PUBLIC;
+ case parser::AccessSpec::Kind::Private: return Attr::PRIVATE;
+ default: CRASH_NO_CASE;
+ }
+ }
};
// Find and create types from declaration-type-spec nodes.
void Post(const parser::EndFunctionStmt &);
bool Pre(const parser::MainProgram &);
void Post(const parser::EndProgramStmt &);
+ bool Pre(const parser::ModuleStmt &);
+ void Post(const parser::EndModuleStmt &);
void Post(const parser::Program &);
bool Pre(const parser::AllocatableStmt &) {
}
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
void Post(const parser::DimensionStmt::Declaration &);
-
- const parser::Name *GetVariableName(const parser::DataRef &x) {
- return std::get_if<parser::Name>(&x.u);
- }
- const parser::Name *GetVariableName(const parser::Designator &x) {
- return std::visit(
- parser::visitors{
- [&](const parser::ObjectName &x) { return &x; },
- [&](const parser::DataRef &x) { return GetVariableName(x); },
- [&](const auto &) {
- return static_cast<const parser::Name *>(nullptr);
- },
- },
- x.u);
- }
- const parser::Name *GetVariableName(const parser::Expr &x) {
- if (const auto *designator =
- std::get_if<parser::Indirection<parser::Designator>>(&x.u)) {
- return GetVariableName(**designator);
- } else {
- return nullptr;
- }
- }
- const parser::Name *GetVariableName(const parser::Variable &x) {
- if (const auto *designator =
- std::get_if<parser::Indirection<parser::Designator>>(&x.u)) {
- return GetVariableName(**designator);
- } else {
- return nullptr;
- }
- }
+ bool Pre(const parser::AccessStmt &);
void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
void Post(const parser::Variable &x) {
CheckImplicitSymbol(GetVariableName(x));
}
- // If implicit types are allowed, ensure name is in the symbol table
- void CheckImplicitSymbol(const parser::Name *name) {
- if (name) {
- if (!isImplicitNoneType()) {
- // ensure this name is in symbol table:
- CurrScope().try_emplace(name->source);
- } else {
- const auto &it = CurrScope().find(name->source);
- if (it == CurrScope().end() || it->second.has<UnknownDetails>()) {
- Say(*name, "No explicit type declared for '%s'"_err_en_US);
- }
- }
- }
- }
-
void Post(const parser::ProcedureDesignator &x) {
if (const auto *name = std::get_if<parser::Name>(&x.u)) {
Symbol &symbol{MakeSymbol(*name)};
std::optional<Attr> objectDeclAttr_;
// Set when we see a stmt function that is really an array element assignment
bool badStmtFuncFound_{false};
+ // The location of the last AccessStmt seen, if any.
+ const parser::CharBlock *prevAccessStmt_{nullptr};
+ // The default access spec for this module.
+ Attr defaultAccess_{Attr::PUBLIC};
// Create a subprogram symbol in the current scope and push a new scope.
Symbol &PushSubprogramScope(const parser::Name &);
return MakeSymbol(name, attrs, UnknownDetails());
}
void DeclareEntity(const parser::Name &, Attrs);
+ void SetAccess(const parser::Name &, Attr);
+ void ApplyDefaultAccess();
+ const parser::Name *GetVariableName(const parser::DataRef &);
+ const parser::Name *GetVariableName(const parser::Designator &);
+ const parser::Name *GetVariableName(const parser::Expr &);
+ const parser::Name *GetVariableName(const parser::Variable &);
+ void CheckImplicitSymbol(const parser::Name *);
};
// ImplicitRules implementation
}
}
bool AttrsVisitor::Pre(const parser::AccessSpec &x) {
- switch (x.v) {
- case parser::AccessSpec::Kind::Public: attrs_->set(Attr::PUBLIC); break;
- case parser::AccessSpec::Kind::Private: attrs_->set(Attr::PRIVATE); break;
- default: CRASH_NO_CASE;
- }
+ attrs_->set(AccessSpecToAttr(x));
return false;
}
bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
void MessageHandler::Say(
const parser::CharBlock &source, parser::MessageFixedText &&msg) {
- Say(parser::Message{
+ Say(Message{
source, parser::MessageFormattedText{msg, source.ToString().c_str()}});
}
void MessageHandler::Say(
}
}
+bool ResolveNamesVisitor::Pre(const parser::AccessStmt &x) {
+ Attr accessAttr = AccessSpecToAttr(std::get<parser::AccessSpec>(x.t));
+ const auto &accessIds = std::get<std::list<parser::AccessId>>(x.t);
+ if (accessIds.empty()) {
+ if (prevAccessStmt_) {
+ Say("The default accessibility of this module has already "
+ "been declared"_err_en_US);
+ Say(*prevAccessStmt_, "Previous declaration"_en_US);
+ }
+ prevAccessStmt_ = currStmtSource();
+ defaultAccess_ = accessAttr;
+ } else {
+ for (const auto &accessId : accessIds) {
+ std::visit(
+ parser::visitors{
+ [=](const parser::Name &y) { SetAccess(y, accessAttr); },
+ [=](const parser::Indirection<parser::GenericSpec> &y) {
+ std::visit(
+ parser::visitors{
+ [=](const parser::Name &z) {
+ SetAccess(z, accessAttr);
+ },
+ [](const auto &) { parser::die("TODO: GenericSpec"); },
+ },
+ y->u);
+ },
+ },
+ accessId.u);
+ }
+ }
+ return false;
+}
+
+// Set the access specification for this name.
+void ResolveNamesVisitor::SetAccess(const parser::Name &name, Attr attr) {
+ Symbol &symbol{MakeSymbol(name)};
+ if (symbol.attrs().HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
+ Say(name, "The accessibility of '%s' has already been specified"_err_en_US);
+ } else {
+ symbol.attrs().set(attr);
+ }
+}
+
void ResolveNamesVisitor::Post(const parser::SpecificationPart &s) {
badStmtFuncFound_ = false;
if (isImplicitNoneType()) {
PopScope();
}
+bool ResolveNamesVisitor::Pre(const parser::ModuleStmt &stmt) {
+ const auto &name = stmt.v;
+ auto &symbol = MakeSymbol(name, ModuleDetails());
+ Scope &modScope = CurrScope().MakeScope(Scope::Kind::Module, &symbol);
+ PushScope(modScope);
+ MakeSymbol(name, ModuleDetails(symbol.details<ModuleDetails>()));
+ return false;
+}
+void ResolveNamesVisitor::Post(const parser::EndModuleStmt &) {
+ ApplyDefaultAccess();
+ ApplyImplicitRules();
+ PopScope();
+}
+
+void ResolveNamesVisitor::ApplyDefaultAccess() {
+ for (auto &pair : CurrScope()) {
+ Symbol &symbol = pair.second;
+ if (!symbol.attrs().HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
+ symbol.attrs().set(defaultAccess_);
+ }
+ }
+}
+
+const parser::Name *ResolveNamesVisitor::GetVariableName(
+ const parser::DataRef &x) {
+ return std::get_if<parser::Name>(&x.u);
+}
+const parser::Name *ResolveNamesVisitor::GetVariableName(
+ const parser::Designator &x) {
+ return std::visit(
+ parser::visitors{
+ [&](const parser::ObjectName &x) { return &x; },
+ [&](const parser::DataRef &x) { return GetVariableName(x); },
+ [&](const auto &) {
+ return static_cast<const parser::Name *>(nullptr);
+ },
+ },
+ x.u);
+}
+const parser::Name *ResolveNamesVisitor::GetVariableName(
+ const parser::Expr &x) {
+ if (const auto *designator =
+ std::get_if<parser::Indirection<parser::Designator>>(&x.u)) {
+ return GetVariableName(**designator);
+ } else {
+ return nullptr;
+ }
+}
+const parser::Name *ResolveNamesVisitor::GetVariableName(
+ const parser::Variable &x) {
+ if (const auto *designator =
+ std::get_if<parser::Indirection<parser::Designator>>(&x.u)) {
+ return GetVariableName(**designator);
+ } else {
+ return nullptr;
+ }
+}
+
+// If implicit types are allowed, ensure name is in the symbol table
+void ResolveNamesVisitor::CheckImplicitSymbol(const parser::Name *name) {
+ if (name) {
+ if (!isImplicitNoneType()) {
+ // ensure this name is in symbol table:
+ CurrScope().try_emplace(name->source);
+ } else {
+ const auto &it = CurrScope().find(name->source);
+ if (it == CurrScope().end() || it->second.has<UnknownDetails>()) {
+ Say(*name, "No explicit type declared for '%s'"_err_en_US);
+ }
+ }
+ }
+}
+
void ResolveNamesVisitor::Post(const parser::Program &) {
// ensure that all temps were deallocated
CHECK(!attrs_);