[flang] Add ENUM_CLASS to define enum class with ToString function.

This replaces DEFINE_NESTED_ENUM_CLASS in parse-tree.h but works
similarly. "ENUM_CLASS(Foo, A, B, C)" defined enum class Foo with
enumerators A, B, C. It also defines an overloading of EnumToString
that converts enumerators to their string representation.

Change unparse.cc to adapt to this change.

Make use of ENUM_CLASS in attr.h and attr.cc.

Original-commit: flang-compiler/f18@c45b8f172a
Reviewed-on: https://github.com/flang-compiler/f18/pull/31
This commit is contained in:
Tim Keith
2018-03-23 14:31:14 -07:00
parent 43ac92e696
commit 9f755666fb
6 changed files with 79 additions and 127 deletions

View File

@@ -15,5 +15,24 @@ namespace parser {
fputc('\n', stderr);
std::abort();
}
// Convert the int index of an enumerator to a string.
// enumNames is a list of the names, separated by commas with optional spaces.
// This is intended for use from the expansion of ENUM_CLASS.
std::string EnumIndexToString(int index, const char *enumNames) {
const char *p{enumNames};
for (; index > 0; --index, ++p) {
for (; *p && *p != ','; ++p) {
}
}
for (; *p == ' '; ++p) {
}
CHECK(*p != '\0');
const char *q = p;
for (; *q && *q != ' ' && *q != ','; ++q) {
}
return std::string(p, q - p);
}
} // namespace parser
} // namespace Fortran

View File

@@ -102,6 +102,16 @@ template<typename A> struct BadType : std::false_type {};
} \
} \
template<typename A> constexpr bool T { class_trait_ns_##T::trait_value<A>() }
// Define enum class NAME with the given enumerators, and also a
// static function EnumToString that maps enumerators to std::string.
std::string EnumIndexToString(int index, const char *names);
#define ENUM_CLASS(NAME, ...) \
enum class NAME { __VA_ARGS__ }; \
static inline std::string EnumToString(NAME e) \
{ return Fortran::parser::EnumIndexToString( \
static_cast<int>(e), #__VA_ARGS__); }
} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PARSER_IDIOMS_H_

View File

@@ -94,14 +94,6 @@ CLASS_TRAIT(TupleTrait);
WRAPPER_CLASS_BOILERPLATE(classname, type); \
}
// Enumeration types in classes can be defined with this macro,
// which also captures the names of the enums for formatting.
// Invocations an be followed by declarators and must be followed by
// a semicolon.
#define DEFINE_NESTED_ENUM_CLASS(ENUMTYPE, ...) \
static constexpr const char *ENUMTYPE##AsString{#__VA_ARGS__}; \
enum class ENUMTYPE { __VA_ARGS__ }
namespace Fortran {
namespace parser {
@@ -517,8 +509,8 @@ WRAPPER_CLASS(DefinedOpName, Name);
// R610 extended-intrinsic-op -> intrinsic-operator
struct DefinedOperator {
UNION_CLASS_BOILERPLATE(DefinedOperator);
DEFINE_NESTED_ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add,
Subtract, Concat, LT, LE, EQ, NE, GE, GT, NOT, AND, OR, XOR, EQV, NEQV);
ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat,
LT, LE, EQ, NE, GE, GT, NOT, AND, OR, XOR, EQV, NEQV)
std::variant<DefinedOpName, IntrinsicOperator> u;
};
@@ -530,10 +522,11 @@ using ObjectName = Name;
// IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
struct ImportStmt {
BOILERPLATE(ImportStmt);
DEFINE_NESTED_ENUM_CLASS(Kind, Default, Only, None, All) kind{Kind::Default};
ENUM_CLASS(Kind, Default, Only, None, All)
ImportStmt(Kind &&k) : kind{k} {}
ImportStmt(std::list<Name> &&n) : names(std::move(n)) {}
ImportStmt(Kind &&, std::list<Name> &&);
Kind kind{Kind::Default};
std::list<Name> names;
};
@@ -802,7 +795,7 @@ struct ConstantValue {
// R807 access-spec -> PUBLIC | PRIVATE
struct AccessSpec {
DEFINE_NESTED_ENUM_CLASS(Kind, Public, Private);
ENUM_CLASS(Kind, Public, Private)
WRAPPER_CLASS_BOILERPLATE(AccessSpec, Kind);
};
@@ -846,7 +839,7 @@ struct TypeParamDecl {
// integer-type-spec , type-param-attr-spec :: type-param-decl-list
// R734 type-param-attr-spec -> KIND | LEN
struct TypeParamDefStmt {
DEFINE_NESTED_ENUM_CLASS(KindOrLen, Kind, Len); // R734
ENUM_CLASS(KindOrLen, Kind, Len) // R734
TUPLE_CLASS_BOILERPLATE(TypeParamDefStmt);
std::tuple<IntegerTypeSpec, KindOrLen, std::list<TypeParamDecl>> t;
};
@@ -1226,7 +1219,7 @@ struct ArraySpec {
// R826 intent-spec -> IN | OUT | INOUT
struct IntentSpec {
DEFINE_NESTED_ENUM_CLASS(Intent, In, Out, InOut);
ENUM_CLASS(Intent, In, Out, InOut)
WRAPPER_CLASS_BOILERPLATE(IntentSpec, Intent);
};
@@ -1303,7 +1296,7 @@ WRAPPER_CLASS(AsynchronousStmt, std::list<ObjectName>);
// R833 bind-entity -> entity-name | / common-block-name /
struct BindEntity {
TUPLE_CLASS_BOILERPLATE(BindEntity);
DEFINE_NESTED_ENUM_CLASS(Kind, Object, Common);
ENUM_CLASS(Kind, Object, Common)
std::tuple<Kind, Name> t;
};
@@ -1430,7 +1423,7 @@ WRAPPER_CLASS(ProtectedStmt, std::list<Name>);
// R858 proc-pointer-name -> name
struct SavedEntity {
TUPLE_CLASS_BOILERPLATE(SavedEntity);
DEFINE_NESTED_ENUM_CLASS(Kind, Object, ProcPointer, Common);
ENUM_CLASS(Kind, Object, ProcPointer, Common)
std::tuple<Kind, Name> t;
};
@@ -1464,7 +1457,7 @@ struct ImplicitSpec {
// R866 implicit-name-spec -> EXTERNAL | TYPE
struct ImplicitStmt {
UNION_CLASS_BOILERPLATE(ImplicitStmt);
DEFINE_NESTED_ENUM_CLASS(ImplicitNoneNameSpec, External, Type); // R866
ENUM_CLASS(ImplicitNoneNameSpec, External, Type) // R866
std::variant<std::list<ImplicitSpec>, std::list<ImplicitNoneNameSpec>> u;
};
@@ -2353,7 +2346,7 @@ struct StopCode {
// R1161 error-stop-stmt ->
// ERROR STOP [stop-code] [, QUIET = scalar-logical-expr]
struct StopStmt {
DEFINE_NESTED_ENUM_CLASS(Kind, Stop, ErrorStop);
ENUM_CLASS(Kind, Stop, ErrorStop)
TUPLE_CLASS_BOILERPLATE(StopStmt);
std::tuple<Kind, std::optional<StopCode>, std::optional<ScalarLogicalExpr>> t;
};
@@ -2469,9 +2462,8 @@ WRAPPER_CLASS(ErrLabel, Label);
struct ConnectSpec {
UNION_CLASS_BOILERPLATE(ConnectSpec);
struct CharExpr {
DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal,
Delim, Encoding, Form, Pad, Position, Round, Sign,
Dispose /*extension*/);
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
Encoding, Form, Pad, Position, Round, Sign, Dispose /*extension*/)
TUPLE_CLASS_BOILERPLATE(CharExpr);
std::tuple<Kind, ScalarDefaultCharExpr> t;
};
@@ -2526,8 +2518,7 @@ WRAPPER_CLASS(EorLabel, Label);
struct IoControlSpec {
UNION_CLASS_BOILERPLATE(IoControlSpec);
struct CharExpr {
DEFINE_NESTED_ENUM_CLASS(
Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign);
ENUM_CLASS(Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign)
TUPLE_CLASS_BOILERPLATE(CharExpr);
std::tuple<Kind, ScalarDefaultCharExpr> t;
};
@@ -2680,20 +2671,19 @@ WRAPPER_CLASS(FlushStmt, std::list<PositionOrFlushSpec>);
struct InquireSpec {
UNION_CLASS_BOILERPLATE(InquireSpec);
struct CharVar {
DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal,
Delim, Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position,
Read, Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted,
Write);
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read,
Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, Write)
TUPLE_CLASS_BOILERPLATE(CharVar);
std::tuple<Kind, ScalarDefaultCharVariable> t;
};
struct IntVar {
DEFINE_NESTED_ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size);
ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size)
TUPLE_CLASS_BOILERPLATE(IntVar);
std::tuple<Kind, ScalarIntVariable> t;
};
struct LogVar {
DEFINE_NESTED_ENUM_CLASS(Kind, Exist, Named, Opened, Pending);
ENUM_CLASS(Kind, Exist, Named, Opened, Pending)
TUPLE_CLASS_BOILERPLATE(LogVar);
std::tuple<Kind, Scalar<Logical<Variable>>> t;
};
@@ -2866,7 +2856,7 @@ struct Only {
// R1410 module-nature -> INTRINSIC | NON_INTRINSIC
struct UseStmt {
BOILERPLATE(UseStmt);
DEFINE_NESTED_ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic); // R1410
ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic) // R1410
template<typename A>
UseStmt(std::optional<ModuleNature> &&nat, Name &&n, std::list<A> &&x)
: nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {}
@@ -2979,7 +2969,7 @@ struct InterfaceBody {
// R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
struct ProcedureStmt {
DEFINE_NESTED_ENUM_CLASS(Kind, ModuleProcedure, Procedure);
ENUM_CLASS(Kind, ModuleProcedure, Procedure)
TUPLE_CLASS_BOILERPLATE(ProcedureStmt);
std::tuple<Kind, std::list<Name>> t;
};

View File

@@ -82,7 +82,7 @@ public:
case DefinedOperator::IntrinsicOperator::GT: Put('>'); break;
default:
Put('.');
PutEnum(static_cast<int>(x), DefinedOperator::IntrinsicOperatorAsString);
Word(DefinedOperator::EnumToString(x));
Put('.');
}
return false;
@@ -1994,22 +1994,22 @@ public:
return false;
}
#define WALK_NESTED_ENUM(ENUMTYPE) \
bool Pre(const ENUMTYPE &x) { \
PutEnum(static_cast<int>(x), ENUMTYPE##AsString); \
#define WALK_NESTED_ENUM(CLASS, ENUM) \
bool Pre(const CLASS::ENUM &x) { \
Word(CLASS::EnumToString(x)); \
return false; \
}
WALK_NESTED_ENUM(AccessSpec::Kind) // R807
WALK_NESTED_ENUM(TypeParamDefStmt::KindOrLen) // R734
WALK_NESTED_ENUM(IntentSpec::Intent) // R826
WALK_NESTED_ENUM(ImplicitStmt::ImplicitNoneNameSpec) // R866
WALK_NESTED_ENUM(ConnectSpec::CharExpr::Kind) // R1205
WALK_NESTED_ENUM(IoControlSpec::CharExpr::Kind)
WALK_NESTED_ENUM(InquireSpec::CharVar::Kind)
WALK_NESTED_ENUM(InquireSpec::IntVar::Kind)
WALK_NESTED_ENUM(InquireSpec::LogVar::Kind)
WALK_NESTED_ENUM(ProcedureStmt::Kind) // R1506
WALK_NESTED_ENUM(UseStmt::ModuleNature) // R1410
WALK_NESTED_ENUM(AccessSpec, Kind) // R807
WALK_NESTED_ENUM(TypeParamDefStmt, KindOrLen) // R734
WALK_NESTED_ENUM(IntentSpec, Intent) // R826
WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
#undef WALK_NESTED_ENUM
void Done() const { CHECK(indent_ == 0); }
@@ -2020,8 +2020,8 @@ private:
void Put(const std::string &);
void PutKeywordLetter(char);
void PutQuoted(const std::string &);
void PutEnum(int, const char *);
void Word(const char *);
void Word(const std::string &);
void Indent() { indent_ += indentationAmount_; }
void Outdent() {
CHECK(indent_ >= indentationAmount_);
@@ -2144,27 +2144,16 @@ void UnparseVisitor::PutQuoted(const std::string &str) {
Put('"');
}
void UnparseVisitor::PutEnum(int n, const char *enumNames) {
const char *p{enumNames};
for (; n > 0; --n, ++p) {
for (; *p && *p != ','; ++p) {
}
}
while (*p == ' ') {
++p;
}
CHECK(*p != '\0');
for (; *p && *p != ' ' && *p != ','; ++p) {
PutKeywordLetter(*p);
}
}
void UnparseVisitor::Word(const char *str) {
for (; *str != '\0'; ++str) {
PutKeywordLetter(*str);
}
}
void UnparseVisitor::Word(const std::string &str) {
Word(str.c_str());
}
void Unparse(std::ostream &out, const Program &program, Encoding encoding,
bool capitalizeKeywords) {
UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords};

View File

@@ -7,38 +7,6 @@ namespace semantics {
constexpr static size_t toInt(Attr attr) { return static_cast<size_t>(attr); }
static const char *attrToString[] = {
[toInt(Attr::ABSTRACT)] = "ABSTRACT",
[toInt(Attr::ALLOCATABLE)] = "ALLOCATABLE",
[toInt(Attr::ASYNCHRONOUS)] = "ASYNCHRONOUS",
[toInt(Attr::BIND_C)] = "BIND_C",
[toInt(Attr::CONTIGUOUS)] = "CONTIGUOUS",
[toInt(Attr::DEFERRED)] = "DEFERRED",
[toInt(Attr::ELEMENTAL)] = "ELEMENTAL",
[toInt(Attr::EXTERNAL)] = "EXTERNAL",
[toInt(Attr::IMPURE)] = "IMPURE",
[toInt(Attr::INTENT_IN)] = "INTENT_IN",
[toInt(Attr::INTENT_OUT)] = "INTENT_OUT",
[toInt(Attr::INTRINSIC)] = "INTRINSIC",
[toInt(Attr::MODULE)] = "MODULE",
[toInt(Attr::NON_OVERRIDABLE)] = "NON_OVERRIDABLE",
[toInt(Attr::NON_RECURSIVE)] = "NON_RECURSIVE",
[toInt(Attr::NOPASS)] = "NOPASS",
[toInt(Attr::OPTIONAL)] = "OPTIONAL",
[toInt(Attr::PARAMETER)] = "PARAMETER",
[toInt(Attr::PASS)] = "PASS",
[toInt(Attr::POINTER)] = "POINTER",
[toInt(Attr::PRIVATE)] = "PRIVATE",
[toInt(Attr::PROTECTED)] = "PROTECTED",
[toInt(Attr::PUBLIC)] = "PUBLIC",
[toInt(Attr::PURE)] = "PURE",
[toInt(Attr::RECURSIVE)] = "RECURSIVE",
[toInt(Attr::SAVE)] = "SAVE",
[toInt(Attr::TARGET)] = "TARGET",
[toInt(Attr::VALUE)] = "VALUE",
[toInt(Attr::VOLATILE)] = "VOLATILE",
};
const Attrs Attrs::EMPTY;
Attrs::Attrs(std::initializer_list<Attr> attrs) {
@@ -74,7 +42,7 @@ void Attrs::CheckValid(const Attrs &allowed) const {
}
std::ostream &operator<<(std::ostream &o, Attr attr) {
return o << attrToString[toInt(attr)];
return o << EnumToString(attr);
}
std::ostream &operator<<(std::ostream &o, const Attrs &attrs) {
@@ -84,7 +52,7 @@ std::ostream &operator<<(std::ostream &o, const Attrs &attrs) {
if (n++) {
o << ", ";
}
o << attrToString[i];
o << EnumToString(static_cast<Attr>(i));
}
}
return o;

View File

@@ -1,6 +1,7 @@
#ifndef FORTRAN_ATTR_H_
#define FORTRAN_ATTR_H_
#include "../parser/idioms.h"
#include <cinttypes>
#include <iostream>
#include <string>
@@ -8,38 +9,13 @@
namespace Fortran {
namespace semantics {
// All available attributes.
enum class Attr {
ABSTRACT,
ALLOCATABLE,
ASYNCHRONOUS,
BIND_C,
CONTIGUOUS,
DEFERRED,
ELEMENTAL,
EXTERNAL,
IMPURE,
INTENT_IN,
INTENT_OUT,
INTRINSIC,
MODULE,
NON_OVERRIDABLE,
NON_RECURSIVE,
NOPASS,
OPTIONAL,
PARAMETER,
PASS,
POINTER,
PRIVATE,
PROTECTED,
PUBLIC,
PURE,
RECURSIVE,
SAVE,
TARGET,
VALUE,
VOLATILE,
};
ENUM_CLASS(Attr, ABSTRACT, ALLOCATABLE, ASYNCHRONOUS, BIND_C, CONTIGUOUS,
DEFERRED, ELEMENTAL, EXTERNAL, IMPURE, INTENT_IN, INTENT_OUT, INTRINSIC,
MODULE, NON_OVERRIDABLE, NON_RECURSIVE, NOPASS, OPTIONAL, PARAMETER, PASS,
POINTER, PRIVATE, PROTECTED, PUBLIC, PURE, RECURSIVE, SAVE, TARGET, VALUE,
VOLATILE)
// Set of attributes
class Attrs {