}
protected:
- void PushScope();
+ void PushScope(bool copyImplicitRules);
void PopScope();
private:
return !arraySpec_.empty() ? arraySpec_ : attrArraySpec_;
}
- void BeginArraySpec() {
- CHECK(attrArraySpec_.empty());
- }
- void EndArraySpec() {
- attrArraySpec_.clear();
- }
- void ClearArraySpec() {
- arraySpec_.clear();
- }
+ void BeginArraySpec() { CHECK(attrArraySpec_.empty()); }
+ void EndArraySpec() { attrArraySpec_.clear(); }
+ void ClearArraySpec() { arraySpec_.clear(); }
bool Pre(const parser::ArraySpec &x) {
CHECK(arraySpec_.empty());
class ResolveNamesVisitor : public ImplicitRulesVisitor,
public ArraySpecVisitor {
public:
- using ImplicitRulesVisitor::Pre;
- using ImplicitRulesVisitor::Post;
- using ArraySpecVisitor::Pre;
using ArraySpecVisitor::Post;
+ using ArraySpecVisitor::Pre;
+ using ImplicitRulesVisitor::Post;
+ using ImplicitRulesVisitor::Pre;
ResolveNamesVisitor(parser::Messages &messages)
: ImplicitRulesVisitor(messages) {
}
Scope &CurrScope() { return *scopes_.top(); }
- void PushScope(Scope &scope) {
+ void PushScope(Scope &scope, bool copyImplicitRules = false) {
scopes_.push(&scope);
- ImplicitRulesVisitor::PushScope();
+ ImplicitRulesVisitor::PushScope(copyImplicitRules);
}
void PopScope() {
scopes_.pop();
bool Pre(const parser::ValueStmt &);
bool Pre(const parser::VolatileStmt &);
void Post(const parser::SpecificationPart &);
- void Post(const parser::EndSubroutineStmt &);
- void Post(const parser::EndFunctionStmt &);
bool Pre(const parser::Suffix &);
+ bool Pre(const parser::StmtFunctionStmt &);
+ void Post(const parser::StmtFunctionStmt &);
bool Pre(const parser::SubroutineStmt &);
void Post(const parser::SubroutineStmt &);
+ void Post(const parser::EndSubroutineStmt &);
bool Pre(const parser::FunctionStmt &);
void Post(const parser::FunctionStmt &);
+ void Post(const parser::EndFunctionStmt &);
bool Pre(const parser::MainProgram &);
void Post(const parser::EndProgramStmt &);
void Post(const parser::Program &);
objectDeclAttr_ = Attr::ALLOCATABLE;
return true;
}
- void Post(const parser::AllocatableStmt &) {
- objectDeclAttr_ = std::nullopt;
- }
+ void Post(const parser::AllocatableStmt &) { objectDeclAttr_ = std::nullopt; }
bool Pre(const parser::TargetStmt &x) {
objectDeclAttr_ = Attr::TARGET;
return true;
}
- void Post(const parser::TargetStmt &) {
- objectDeclAttr_ = std::nullopt;
- }
+ void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
void Post(const parser::DimensionStmt::Declaration &);
const parser::Name *GetVariableName(const parser::DataRef &x) {
}
}
- void Post(const parser::Expr &x) {
- CheckImplicitSymbol(GetVariableName(x));
- }
+ void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
void Post(const parser::Variable &x) {
CheckImplicitSymbol(GetVariableName(x));
}
std::optional<Attr> objectDeclAttr_;
// Create a subprogram symbol in the current scope and push a new scope.
- void PushSubprogramScope(const parser::Name &, SubprogramDetails &);
+ Symbol &PushSubprogramScope(
+ const parser::Name &, bool copyImplicitRules = false);
// On leaving a scope, add implicit types if appropriate.
void ApplyImplicitRules();
template<typename D>
Symbol &MakeSymbol(
const parser::Name &name, const Attrs &attrs, D &&details) {
- const auto pair = CurrScope().try_emplace(name.source, attrs, details);
- Symbol &symbol = pair.first->second;
- if (!pair.second) {
+ const auto &it = CurrScope().find(name.source);
+ auto &symbol = it->second;
+ if (it == CurrScope().end()) {
+ const auto pair = CurrScope().try_emplace(name.source, attrs, details);
+ CHECK(pair.second); // name was not found, so must be able to add
+ return pair.first->second;
+ } else if (symbol.has<UnknownDetails>()) {
+ // update the existing symbol
symbol.attrs() |= attrs;
- if (!std::is_same<UnknownDetails, D>::value) {
- if (symbol.has<UnknownDetails>()) {
- symbol.set_details(details);
- } else {
- Say(name, "'%s' is already declared in this scoping unit"_err_en_US);
- Say(symbol.name(), "Previous declaration of '%s'"_en_US);
- }
- }
+ symbol.set_details(details);
+ return symbol;
+ } else if (std::is_same<UnknownDetails, D>::value) {
+ symbol.attrs() |= attrs;
+ return symbol;
+ } else {
+ Say(name, "'%s' is already declared in this scoping unit"_err_en_US);
+ Say(symbol.name(), "Previous declaration of '%s'"_en_US);
+ // replace the old symbols with a new one with correct details
+ CurrScope().erase(symbol.name());
+ return MakeSymbol(name, attrs, details);
}
- return symbol;
}
template<typename D>
Symbol &MakeSymbol(const parser::Name &name, D &&details) {
EndDeclTypeSpec();
}
-void ImplicitRulesVisitor::PushScope() {
- implicitRules_.push(ImplicitRules(*this));
+void ImplicitRulesVisitor::PushScope(bool copyImplicitRules) {
+ implicitRules_.push(copyImplicitRules ? ImplicitRules(implicitRules_.top())
+ : ImplicitRules(*this));
prevImplicit_ = nullptr;
prevImplicitNone_ = nullptr;
prevImplicitNoneType_ = nullptr;
return true;
}
+bool ResolveNamesVisitor::Pre(const parser::StmtFunctionStmt &x) {
+ const auto &name = std::get<parser::Name>(x.t);
+ std::optional<SourceName> occurrence;
+ std::optional<DeclTypeSpec> resultType;
+ // Look up name: provides return type or tells us if it's an array
+ auto it = CurrScope().find(name.source);
+ if (it != CurrScope().end()) {
+ Symbol &symbol{it->second};
+ if (auto *details = symbol.detailsIf<EntityDetails>()) {
+ if (details->isArray()) {
+ // not a stmt-func at all but an array; do nothing
+ symbol.add_occurrence(name.source);
+ return true;
+ }
+ // TODO: check that attrs are compatible with stmt func
+ resultType = details->type();
+ occurrence = symbol.name();
+ CurrScope().erase(symbol.name());
+ }
+ }
+ BeginAttrs(); // no attrs to collect, but PushSubprogramScope expects this
+ auto &symbol = PushSubprogramScope(name, /*copyImplicitRules=*/true);
+ if (occurrence) {
+ symbol.add_occurrence(*occurrence);
+ }
+ auto &details = symbol.details<SubprogramDetails>();
+ for (const auto &dummyName : std::get<std::list<parser::Name>>(x.t)) {
+ EntityDetails dummyDetails{true};
+ auto it = CurrScope().parent().find(dummyName.source);
+ if (it != CurrScope().parent().end()) {
+ if (auto *d = it->second.detailsIf<EntityDetails>()) {
+ if (d->type()) {
+ dummyDetails.set_type(*d->type());
+ }
+ }
+ }
+ details.add_dummyArg(MakeSymbol(dummyName, std::move(dummyDetails)));
+ }
+ CurrScope().erase(name.source); // added by PushSubprogramScope
+ EntityDetails resultDetails;
+ if (resultType) {
+ resultDetails.set_type(*resultType);
+ }
+ details.set_result(MakeSymbol(name, resultDetails));
+ return true;
+}
+
+void ResolveNamesVisitor::Post(const parser::StmtFunctionStmt &x) {
+ ApplyImplicitRules();
+ std::cout << "End of stmt func scope\n";
+ std::cout << CurrScope();
+ PopScope();
+}
+
bool ResolveNamesVisitor::Pre(const parser::SubroutineStmt &stmt) {
BeginAttrs();
return true;
void ResolveNamesVisitor::Post(const parser::SubroutineStmt &stmt) {
const auto &subrName = std::get<parser::Name>(stmt.t);
- SubprogramDetails details;
- PushSubprogramScope(subrName, details);
+ auto &symbol = PushSubprogramScope(subrName);
+ auto &details = symbol.details<SubprogramDetails>();
for (const auto &dummyArg : std::get<std::list<parser::DummyArg>>(stmt.t)) {
const parser::Name *dummyName = std::get_if<parser::Name>(&dummyArg.u);
CHECK(dummyName != nullptr && "TODO: alternate return indicator");
- MakeSymbol(*dummyName, EntityDetails(true));
- details.AddDummyName(dummyName->source);
+ Symbol &dummy{MakeSymbol(*dummyName, EntityDetails(true))};
+ details.add_dummyArg(dummy);
}
}
void ResolveNamesVisitor::Post(const parser::FunctionStmt &stmt) {
const auto &funcName = std::get<parser::Name>(stmt.t);
- const auto &funcResultName = funcResultName_ ? *funcResultName_ : funcName;
- funcResultName_ = nullptr;
- SubprogramDetails details(funcResultName.source);
- PushSubprogramScope(funcName, details);
+ auto &symbol = PushSubprogramScope(funcName);
+ auto &details = symbol.details<SubprogramDetails>();
for (const auto &dummyName : std::get<std::list<parser::Name>>(stmt.t)) {
- MakeSymbol(dummyName, EntityDetails(true));
- details.AddDummyName(dummyName.source);
+ Symbol &dummy{MakeSymbol(dummyName, EntityDetails(true))};
+ details.add_dummyArg(dummy);
}
// add function result to function scope
EntityDetails funcResultDetails;
funcResultDetails.set_type(*declTypeSpec_);
}
EndDeclTypeSpec();
- if (funcResultName.source != funcName.source) {
- MakeSymbol(funcResultName, funcResultDetails);
+
+ const parser::Name *funcResultName;
+ if (funcResultName_ && funcResultName_->source != funcName.source) {
+ funcResultName = funcResultName_;
+ funcResultName_ = nullptr;
} else {
CurrScope().erase(funcName.source); // was added by PushSubprogramScope
- MakeSymbol(funcName, funcResultDetails);
+ funcResultName = &funcName;
}
+ details.set_result(MakeSymbol(*funcResultName, funcResultDetails));
}
-void ResolveNamesVisitor::PushSubprogramScope(
- const parser::Name &name, SubprogramDetails &details) {
- MakeSymbol(name, EndAttrs(), details);
+Symbol &ResolveNamesVisitor::PushSubprogramScope(
+ const parser::Name &name, bool copyImplicitRules) {
+ auto &symbol = MakeSymbol(name, EndAttrs(), SubprogramDetails());
Scope &subpScope = CurrScope().MakeScope(Scope::Kind::Subprogram);
- PushScope(subpScope);
- MakeSymbol(name, details); // can't reused this name inside subprogram
+ PushScope(subpScope, copyImplicitRules);
+ auto &details = symbol.details<SubprogramDetails>();
+ // can't reused this name inside subprogram:
+ MakeSymbol(name, SubprogramDetails(details));
+ return symbol;
}
bool ResolveNamesVisitor::Pre(const parser::MainProgram &x) {
/// *Details classes.
class Scope;
+class Symbol;
class ModuleDetails {
public:
class SubprogramDetails {
public:
- // Subroutine:
SubprogramDetails() {}
- // Function:
- SubprogramDetails(const SourceName &resultName) : resultName_{resultName} {}
-
- bool isFunction() const { return resultName_.has_value(); }
- const std::list<SourceName> &dummyNames() const { return dummyNames_; }
- const std::optional<SourceName> &resultName() const { return resultName_; }
- void AddDummyName(const SourceName &name) { dummyNames_.push_back(name); }
+ SubprogramDetails(const SubprogramDetails &that)
+ : dummyArgs_{that.dummyArgs_}, result_{that.result_} {}
+
+ bool isFunction() const { return result_.has_value(); }
+ const Symbol &result() const { CHECK(isFunction()); return **result_; }
+ void set_result(Symbol &result) {
+ CHECK(!result_.has_value());
+ result_ = &result;
+ }
+ const std::list<Symbol *> &dummyArgs() const { return dummyArgs_; }
+ void add_dummyArg(Symbol &symbol) { dummyArgs_.push_back(&symbol); }
private:
- std::list<SourceName> dummyNames_;
- std::optional<SourceName> resultName_;
+ std::list<Symbol *> dummyArgs_;
+ std::optional<Symbol *> result_;
friend std::ostream &operator<<(std::ostream &, const SubprogramDetails &);
};
const ArraySpec &shape() const { return shape_; }
void set_shape(const ArraySpec &shape);
bool isDummy() const { return isDummy_; }
+ bool isArray() const { return !shape_.empty(); }
private:
bool isDummy_;
Symbol(const Scope &owner, const SourceName &name, const Attrs &attrs,
Details &&details)
- : owner_{owner}, name_{name}, attrs_{attrs},
- details_{std::move(details)} {}
+ : owner_{owner}, attrs_{attrs}, details_{std::move(details)} {
+ add_occurrence(name);
+ }
const Scope &owner() const { return owner_; }
- const SourceName &name() const { return name_; }
+ const SourceName &name() const { return occurrences_.front(); }
Attrs &attrs() { return attrs_; }
const Attrs &attrs() const { return attrs_; }
// Return a reference to the details which must be of type D.
template<typename D> D &details() {
- auto p = detailsIf<D>();
- CHECK(p && "unexpected type");
- return *p;
+ return const_cast<D &>(static_cast<const Symbol *>(this)->details<D>());
}
template<typename D> const D &details() const {
- const auto p = detailsIf<D>();
- CHECK(p && "unexpected type");
- return *p;
+ if (const auto p = detailsIf<D>()) {
+ return *p;
+ } else {
+ Fortran::parser::die("unexpected %s details at %s(%d)",
+ GetDetailsName().c_str(), __FILE__, __LINE__);
+ }
}
// Assign the details of the symbol from one of the variants.
details_.swap(details);
}
+ const std::list<SourceName> &occurrences() const {
+ return occurrences_;
+ }
+ void add_occurrence(const SourceName &name) {
+ occurrences_.push_back(name);
+ }
+
private:
const Scope &owner_;
- const SourceName name_;
+ std::list<SourceName> occurrences_;
Attrs attrs_;
Details details_;
+
+ const std::string GetDetailsName() const;
friend std::ostream &operator<<(std::ostream &, const Symbol &);
};