// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_ #define CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_ #include #include "common/enum_mask_base.h" #include "toolchain/sem_ir/name_scope.h" namespace Carbon::Check { // The order of modifiers. Each of these corresponds to a group on // KeywordModifierSet, and can be used as an array index. enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Evaluation, Last = Evaluation }; // A single X-macro to cover modifier groups. These are split out to make groups // clearer. #define CARBON_KEYWORD_MODIFIER_SET(X) \ /* At most one of these access modifiers allowed for a given declaration, \ * and if present it must be first. */ \ X(Private) \ X(Protected) \ \ /* Extern is standalone. */ \ X(Extern) \ \ /* Extend can be combined with Final, but no others in the group below. */ \ X(Extend) \ \ /* At most one of these declaration modifiers allowed for a given \ * declaration. */ \ X(Abstract) \ X(Base) \ X(Default) \ X(Export) \ X(Final) \ X(Impl) \ X(Override) \ X(Returned) \ X(Virtual) \ \ /* Eval and MustEval are mutually exclusive. */ \ X(Eval) \ X(MustEval) // We expect this to grow, so are using a bigger size than needed. CARBON_DEFINE_RAW_ENUM_MASK(KeywordModifierSet, uint32_t) { CARBON_KEYWORD_MODIFIER_SET(CARBON_RAW_ENUM_MASK_ENUMERATOR) }; // Represents a set of keyword modifiers, using a separate bit per modifier. class KeywordModifierSet : public CARBON_ENUM_MASK_BASE(KeywordModifierSet) { public: CARBON_KEYWORD_MODIFIER_SET(CARBON_ENUM_MASK_CONSTANT_DECL) // Sets of modifiers. static const KeywordModifierSet Access; static const KeywordModifierSet Class; static const KeywordModifierSet Method; static const KeywordModifierSet ImplDecl; static const KeywordModifierSet Interface; static const KeywordModifierSet Evaluation; static const KeywordModifierSet Decl; // Return a builder that returns the new enumeration type once a series of // mapping `Case`s and a final `Default` are provided. For example: // ``` // auto e = set.ToEnum() // .Case(KeywordModifierSet::A, SomeEnum::A) // .Case(KeywordModifierSet::B, SomeEnum::B) // .Default(SomeEnum::DefaultValue); // ``` template auto ToEnum() const -> auto { class Converter { public: explicit Converter(const KeywordModifierSet& set) : set_(set) {} auto Case(KeywordModifierSet other, T result) -> Converter& { if (set_.HasAnyOf(other)) { result_ = result; } return *this; } auto Default(T default_value) -> T { if (result_) { return *result_; } return default_value; } private: const KeywordModifierSet& set_; std::optional result_; }; return Converter(*this); } // Returns the access kind from modifiers. auto GetAccessKind() const -> SemIR::AccessKind { if (HasAnyOf(KeywordModifierSet::Protected)) { return SemIR::AccessKind::Protected; } if (HasAnyOf(KeywordModifierSet::Private)) { return SemIR::AccessKind::Private; } return SemIR::AccessKind::Public; } }; #define CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE(X) \ CARBON_ENUM_MASK_CONSTANT_DEFINITION(KeywordModifierSet, X) CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE) #undef CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE inline constexpr KeywordModifierSet KeywordModifierSet::Access(Private | Protected); inline constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base); inline constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Override | Virtual); inline constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend | Final); inline constexpr KeywordModifierSet KeywordModifierSet::Interface(Default | Final); inline constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method | Impl | Interface | Export | Returned); inline constexpr KeywordModifierSet KeywordModifierSet::Evaluation(Eval | MustEval); // TODO: This and the ordering checking logic in handle_modifiers.cpp are // becoming unwieldy. Find a better representation. static_assert( !KeywordModifierSet::Access.HasAnyOf(KeywordModifierSet::Extern) && !(KeywordModifierSet::Access | KeywordModifierSet::Extern | KeywordModifierSet::Extend) .HasAnyOf(KeywordModifierSet::Decl) && !(KeywordModifierSet::Access | KeywordModifierSet::Extern | KeywordModifierSet::Decl) .HasAnyOf(KeywordModifierSet::Evaluation), "Order-related sets must not overlap"); #define CARBON_KEYWORD_MODIFIER_SET_IN_GROUP(Modifier) \ static_assert((KeywordModifierSet::Access | KeywordModifierSet::Extern | \ KeywordModifierSet::Extend | KeywordModifierSet::Decl | \ KeywordModifierSet::Evaluation) \ .HasAnyOf(KeywordModifierSet::Modifier), \ "Modifier missing from all modifier sets: " #Modifier); CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_IN_GROUP) #undef CARBON_KEYWORD_MODIFIER_SET_IN_GROUP } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_