static bool IsIntrinsicOp(const Symbol &symbol) {
if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) {
- GenericKind kind{details->kind()};
- return kind >= GenericKind::OpPower && kind <= GenericKind::OpNEQV;
+ return details->kind().IsIntrinsicOperator();
} else {
return false;
}
using common::LanguageFeature;
using common::LogicalOperator;
+using common::NumericOperator;
using common::RelationalOperator;
using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
}
return result;
}};
- switch (kind_) {
- case GenericKind::OpGE: return getNames(RelationalOperator::GE);
- case GenericKind::OpGT: return getNames(RelationalOperator::GT);
- case GenericKind::OpLE: return getNames(RelationalOperator::LE);
- case GenericKind::OpLT: return getNames(RelationalOperator::LT);
- case GenericKind::OpEQ: return getNames(RelationalOperator::EQ);
- case GenericKind::OpNE: return getNames(RelationalOperator::NE);
- case GenericKind::OpAND: return getNames(LogicalOperator::And);
- case GenericKind::OpOR: return getNames(LogicalOperator::Or);
- case GenericKind::OpEQV: return getNames(LogicalOperator::Eqv);
- case GenericKind::OpNEQV: return getNames(LogicalOperator::Neqv);
- case GenericKind::OpNOT: return getNames(LogicalOperator::Not);
- default: return {symbolName_.value().ToString()};
- }
+ return std::visit(
+ common::visitors{[&](const LogicalOperator &x) { return getNames(x); },
+ [&](const RelationalOperator &x) { return getNames(x); },
+ [&](const auto &) -> std::forward_list<std::string> {
+ return {symbolName_.value().ToString()};
+ }},
+ kind_.u);
}
Symbol *GenericSpecInfo::FindInScope(
}
void GenericSpecInfo::Analyze(const parser::DefinedOpName &name) {
- kind_ = GenericKind::DefinedOp;
+ kind_ = GenericKind::OtherKind::DefinedOp;
parseName_ = &name.v;
symbolName_ = name.v.source;
}
symbolName_ = x.source;
kind_ = std::visit(
common::visitors{
- [&](const parser::Name &y) {
+ [&](const parser::Name &y) -> GenericKind {
parseName_ = &y;
symbolName_ = y.source;
- return GenericKind::Name;
+ return GenericKind::OtherKind::Name;
},
[&](const parser::DefinedOperator &y) {
return std::visit(
common::visitors{
- [&](const parser::DefinedOpName &z) {
+ [&](const parser::DefinedOpName &z) -> GenericKind {
Analyze(z);
- return GenericKind::DefinedOp;
+ return GenericKind::OtherKind::DefinedOp;
},
[&](const IntrinsicOperator &z) {
return MapIntrinsicOperator(z);
},
y.u);
},
- [&](const parser::GenericSpec::Assignment &) {
- return GenericKind::Assignment;
+ [&](const parser::GenericSpec::Assignment &) -> GenericKind {
+ return GenericKind::OtherKind::Assignment;
},
- [&](const parser::GenericSpec::ReadFormatted &) {
- return GenericKind::ReadFormatted;
+ [&](const parser::GenericSpec::ReadFormatted &) -> GenericKind {
+ return GenericKind::DefinedIo::ReadFormatted;
},
- [&](const parser::GenericSpec::ReadUnformatted &) {
- return GenericKind::ReadUnformatted;
+ [&](const parser::GenericSpec::ReadUnformatted &) -> GenericKind {
+ return GenericKind::DefinedIo::ReadUnformatted;
},
- [&](const parser::GenericSpec::WriteFormatted &) {
- return GenericKind::WriteFormatted;
+ [&](const parser::GenericSpec::WriteFormatted &) -> GenericKind {
+ return GenericKind::DefinedIo::WriteFormatted;
},
- [&](const parser::GenericSpec::WriteUnformatted &) {
- return GenericKind::WriteUnformatted;
+ [&](const parser::GenericSpec::WriteUnformatted &) -> GenericKind {
+ return GenericKind::DefinedIo::WriteUnformatted;
},
},
x.u);
static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
switch (op) {
SWITCH_COVERS_ALL_CASES
- case IntrinsicOperator::Power: return GenericKind::OpPower;
- case IntrinsicOperator::Multiply: return GenericKind::OpMultiply;
- case IntrinsicOperator::Divide: return GenericKind::OpDivide;
- case IntrinsicOperator::Add: return GenericKind::OpAdd;
- case IntrinsicOperator::Subtract: return GenericKind::OpSubtract;
- case IntrinsicOperator::Concat: return GenericKind::OpConcat;
- case IntrinsicOperator::LT: return GenericKind::OpLT;
- case IntrinsicOperator::LE: return GenericKind::OpLE;
- case IntrinsicOperator::EQ: return GenericKind::OpEQ;
- case IntrinsicOperator::NE: return GenericKind::OpNE;
- case IntrinsicOperator::GE: return GenericKind::OpGE;
- case IntrinsicOperator::GT: return GenericKind::OpGT;
- case IntrinsicOperator::NOT: return GenericKind::OpNOT;
- case IntrinsicOperator::AND: return GenericKind::OpAND;
- case IntrinsicOperator::OR: return GenericKind::OpOR;
- case IntrinsicOperator::EQV: return GenericKind::OpEQV;
- case IntrinsicOperator::NEQV: return GenericKind::OpNEQV;
+ case IntrinsicOperator::Concat: return GenericKind::OtherKind::Concat;
+ case IntrinsicOperator::Power: return NumericOperator::Power;
+ case IntrinsicOperator::Multiply: return NumericOperator::Multiply;
+ case IntrinsicOperator::Divide: return NumericOperator::Divide;
+ case IntrinsicOperator::Add: return NumericOperator::Add;
+ case IntrinsicOperator::Subtract: return NumericOperator::Subtract;
+ case IntrinsicOperator::AND: return LogicalOperator::And;
+ case IntrinsicOperator::OR: return LogicalOperator::Or;
+ case IntrinsicOperator::EQV: return LogicalOperator::Eqv;
+ case IntrinsicOperator::NEQV: return LogicalOperator::Neqv;
+ case IntrinsicOperator::NOT: return LogicalOperator::Not;
+ case IntrinsicOperator::LT: return RelationalOperator::LT;
+ case IntrinsicOperator::LE: return RelationalOperator::LE;
+ case IntrinsicOperator::EQ: return RelationalOperator::EQ;
+ case IntrinsicOperator::NE: return RelationalOperator::NE;
+ case IntrinsicOperator::GE: return RelationalOperator::GE;
+ case IntrinsicOperator::GT: return RelationalOperator::GT;
}
}
}
if (!namesSeen.insert(name->source).second) {
Say(*name,
- IsDefinedOperator(generic.name())
+ details.kind().IsDefinedOperator()
? "Procedure '%s' is already specified in generic operator '%s'"_err_en_US
: "Procedure '%s' is already specified in generic '%s'"_err_en_US,
name->source, generic.name());
generic.details());
}
-static bool IsOperatorOrAssignment(const Symbol &generic) {
- auto kind{GetGenericKind(generic)};
- return kind == GenericKind::DefinedOp || kind == GenericKind::Assignment ||
- (kind >= GenericKind::OpPower && kind <= GenericKind::OpNEQV);
-}
-
// Check that the specifics of this generic are distinguishable from each other
void InterfaceVisitor::CheckSpecificsAreDistinguishable(
Symbol &generic, const SymbolVector &specifics) {
if (specifics.size() < 2) {
return;
}
- auto distinguishable{IsOperatorOrAssignment(generic)
+ auto kind{GetGenericKind(generic)};
+ auto distinguishable{kind.IsAssignment() || kind.IsOperator()
? evaluate::characteristics::DistinguishableOpOrAssign
: evaluate::characteristics::Distinguishable};
using evaluate::characteristics::Procedure;
const auto &symbolName{info.symbolName()};
if (auto *symbol{info.FindInScope(context(), currScope())}) {
info.Resolve(&SetAccess(symbolName, accessAttr, symbol));
- } else if (info.kind() == GenericKind::Name) {
+ } else if (info.kind().IsName()) {
info.Resolve(&SetAccess(symbolName, accessAttr));
} else {
Say(symbolName, "Generic spec '%s' not found"_err_en_US);
},
[](const HostAssocDetails &) {},
[&](const GenericDetails &x) {
- os << ' ' << EnumToString(x.kind());
+ os << ' ' << x.kind().ToString();
DumpBool(os, "(specific)", x.specific() != nullptr);
DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
os << " procs:";
type_ = &type;
}
+bool GenericKind::IsIntrinsicOperator() const {
+ return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
+ Has<common::NumericOperator>() || Has<common::RelationalOperator>();
+}
+
+bool GenericKind::IsOperator() const {
+ return IsDefinedOperator() || IsIntrinsicOperator();
+}
+
+std::string GenericKind::ToString() const {
+ return std::visit(
+ common::visitors{
+ [](const OtherKind &x) { return EnumToString(x); },
+ [](const DefinedIo &x) { return EnumToString(x); },
+ [](const auto &x) { return common::EnumToString(x); },
+ },
+ u);
+}
+
+bool GenericKind::Is(GenericKind::OtherKind x) const {
+ const OtherKind *y{std::get_if<OtherKind>(&u)};
+ return y && *y == x;
+}
+
}
SymbolRef symbol_; // procedure bound to; may be forward
};
-ENUM_CLASS(GenericKind, // Kinds of generic-spec
- Name, DefinedOp, // these have a Name associated with them
- Assignment, // user-defined assignment
- OpPower, OpMultiply, OpDivide, OpAdd, OpSubtract, OpConcat, OpLT, OpLE,
- OpEQ, OpNE, OpGE, OpGT, OpNOT, OpAND, OpOR, OpEQV, OpNEQV, //
- ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
+// A GenericKind is one of: generic name, defined operator,
+// defined assignment, intrinsic operator, or defined I/O.
+struct GenericKind {
+ ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
+ ENUM_CLASS(DefinedIo, // defined io
+ ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
+ GenericKind() : u{OtherKind::Name} {}
+ template<typename T> GenericKind(const T &x) { u = x; }
+ bool IsName() const { return Is(OtherKind::Name); }
+ bool IsAssignment() const { return Is(OtherKind::Assignment); }
+ bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
+ bool IsIntrinsicOperator() const;
+ bool IsOperator() const;
+ std::string ToString() const;
+ std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
+ common::RelationalOperator, DefinedIo>
+ u;
+
+private:
+ template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
+ bool Is(OtherKind) const;
+};
class GenericBindingDetails {
public:
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
private:
- GenericKind kind_{GenericKind::Name};
+ GenericKind kind_;
SymbolVector specificProcs_;
};
void set_useDetails(const UseDetails &details) { useDetails_ = details; }
private:
- GenericKind kind_{GenericKind::Name};
+ GenericKind kind_;
// all of the specific procedures for this generic
SymbolVector specificProcs_;
// a specific procedure with the same name as this generic, if any
bool IsGenericDefinedOp(const Symbol &symbol) {
const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()};
- return details && details->kind() == GenericKind::DefinedOp;
+ return details && details->kind().IsDefinedOperator();
}
bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) {