//=== ASTTableGen.h - Common definitions for AST node tablegen --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef CLANG_AST_TABLEGEN_H #define CLANG_AST_TABLEGEN_H #include "llvm/TableGen/Record.h" #include "llvm/ADT/STLExtras.h" // These are spellings in the tblgen files. #define HasPropertiesClassName "HasProperties" // ASTNodes and their common fields. `Base` is actually defined // in subclasses, but it's still common across the hierarchies. #define ASTNodeClassName "ASTNode" #define BaseFieldName "Base" #define AbstractFieldName "Abstract" // Comment node hierarchy. #define CommentNodeClassName "CommentNode" // Decl node hierarchy. #define DeclNodeClassName "DeclNode" #define DeclContextNodeClassName "DeclContext" // Stmt node hierarchy. #define StmtNodeClassName "StmtNode" // Type node hierarchy. #define TypeNodeClassName "TypeNode" #define AlwaysDependentClassName "AlwaysDependent" #define NeverCanonicalClassName "NeverCanonical" #define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" #define LeafTypeClassName "LeafType" // Cases of various non-ASTNode structured types like DeclarationName. #define TypeKindClassName "PropertyTypeKind" #define KindTypeFieldName "KindType" #define KindPropertyNameFieldName "KindPropertyName" #define TypeCaseClassName "PropertyTypeCase" // Properties of AST nodes. #define PropertyClassName "Property" #define ClassFieldName "Class" #define NameFieldName "Name" #define TypeFieldName "Type" #define ReadFieldName "Read" // Types of properties. #define PropertyTypeClassName "PropertyType" #define CXXTypeNameFieldName "CXXName" #define PassByReferenceFieldName "PassByReference" #define ConstWhenWritingFieldName "ConstWhenWriting" #define ConditionalCodeFieldName "Conditional" #define PackOptionalCodeFieldName "PackOptional" #define UnpackOptionalCodeFieldName "UnpackOptional" #define BufferElementTypesFieldName "BufferElementTypes" #define ArrayTypeClassName "Array" #define ArrayElementTypeFieldName "Element" #define OptionalTypeClassName "Optional" #define OptionalElementTypeFieldName "Element" #define SubclassPropertyTypeClassName "SubclassPropertyType" #define SubclassBaseTypeFieldName "Base" #define SubclassClassNameFieldName "SubclassName" #define EnumPropertyTypeClassName "EnumPropertyType" // Write helper rules. #define ReadHelperRuleClassName "ReadHelper" #define HelperCodeFieldName "Code" // Creation rules. #define CreationRuleClassName "Creator" #define CreateFieldName "Create" // Override rules. #define OverrideRuleClassName "Override" #define IgnoredPropertiesFieldName "IgnoredProperties" namespace clang { namespace tblgen { class WrappedRecord { llvm::Record *Record; protected: WrappedRecord(llvm::Record *record = nullptr) : Record(record) {} llvm::Record *get() const { assert(Record && "accessing null record"); return Record; } public: llvm::Record *getRecord() const { return Record; } explicit operator bool() const { return Record != nullptr; } llvm::ArrayRef getLoc() const { return get()->getLoc(); } /// Does the node inherit from the given TableGen class? bool isSubClassOf(llvm::StringRef className) const { return get()->isSubClassOf(className); } template NodeClass getAs() const { return (isSubClassOf(NodeClass::getTableGenNodeClassName()) ? NodeClass(get()) : NodeClass()); } friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) { assert(lhs && rhs && "sorting null nodes"); return lhs.get()->getName() < rhs.get()->getName(); } friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) { return rhs < lhs; } friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) { return !(rhs < lhs); } friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) { return !(lhs < rhs); } friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) { // This should handle null nodes. return lhs.getRecord() == rhs.getRecord(); } friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) { return !(lhs == rhs); } }; /// Anything in the AST that has properties. class HasProperties : public WrappedRecord { public: static constexpr llvm::StringRef ClassName = HasPropertiesClassName; HasProperties(llvm::Record *record = nullptr) : WrappedRecord(record) {} llvm::StringRef getName() const; static llvm::StringRef getTableGenNodeClassName() { return HasPropertiesClassName; } }; /// An (optional) reference to a TableGen node representing a class /// in one of Clang's AST hierarchies. class ASTNode : public HasProperties { public: ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {} llvm::StringRef getName() const { return get()->getName(); } /// Return the node for the base, if there is one. ASTNode getBase() const { return get()->getValueAsOptionalDef(BaseFieldName); } /// Is the corresponding class abstract? bool isAbstract() const { return get()->getValueAsBit(AbstractFieldName); } static llvm::StringRef getTableGenNodeClassName() { return ASTNodeClassName; } }; class DeclNode : public ASTNode { public: DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {} llvm::StringRef getId() const; std::string getClassName() const; DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); } static llvm::StringRef getASTHierarchyName() { return "Decl"; } static llvm::StringRef getASTIdTypeName() { return "Decl::Kind"; } static llvm::StringRef getASTIdAccessorName() { return "getKind"; } static llvm::StringRef getTableGenNodeClassName() { return DeclNodeClassName; } }; class TypeNode : public ASTNode { public: TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {} llvm::StringRef getId() const; llvm::StringRef getClassName() const; TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); } static llvm::StringRef getASTHierarchyName() { return "Type"; } static llvm::StringRef getASTIdTypeName() { return "Type::TypeClass"; } static llvm::StringRef getASTIdAccessorName() { return "getTypeClass"; } static llvm::StringRef getTableGenNodeClassName() { return TypeNodeClassName; } }; class StmtNode : public ASTNode { public: StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {} std::string getId() const; llvm::StringRef getClassName() const; StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); } static llvm::StringRef getASTHierarchyName() { return "Stmt"; } static llvm::StringRef getASTIdTypeName() { return "Stmt::StmtClass"; } static llvm::StringRef getASTIdAccessorName() { return "getStmtClass"; } static llvm::StringRef getTableGenNodeClassName() { return StmtNodeClassName; } }; /// The type of a property. class PropertyType : public WrappedRecord { public: PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Is this a generic specialization (i.e. `Array` or `Optional`)? bool isGenericSpecialization() const { return get()->isAnonymous(); } /// The abstract type name of the property. Doesn't work for generic /// specializations. llvm::StringRef getAbstractTypeName() const { return get()->getName(); } /// The C++ type name of the property. Doesn't work for generic /// specializations. llvm::StringRef getCXXTypeName() const { return get()->getValueAsString(CXXTypeNameFieldName); } void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const; /// Whether the C++ type should be passed around by reference. bool shouldPassByReference() const { return get()->getValueAsBit(PassByReferenceFieldName); } /// Whether the C++ type should have 'const' prepended when working with /// a value of the type being written. bool isConstWhenWriting() const { return get()->getValueAsBit(ConstWhenWritingFieldName); } /// If this is `Array`, return `T`; otherwise return null. PropertyType getArrayElementType() const { if (isSubClassOf(ArrayTypeClassName)) return get()->getValueAsDef(ArrayElementTypeFieldName); return nullptr; } /// If this is `Optional`, return `T`; otherwise return null. PropertyType getOptionalElementType() const { if (isSubClassOf(OptionalTypeClassName)) return get()->getValueAsDef(OptionalElementTypeFieldName); return nullptr; } /// If this is a subclass type, return its superclass type. PropertyType getSuperclassType() const { if (isSubClassOf(SubclassPropertyTypeClassName)) return get()->getValueAsDef(SubclassBaseTypeFieldName); return nullptr; } // Given that this is a subclass type, return the C++ name of its // subclass type. This is just the bare class name, suitable for // use in `cast<>`. llvm::StringRef getSubclassClassName() const { return get()->getValueAsString(SubclassClassNameFieldName); } /// Does this represent an enum type? bool isEnum() const { return isSubClassOf(EnumPropertyTypeClassName); } llvm::StringRef getPackOptionalCode() const { return get()->getValueAsString(PackOptionalCodeFieldName); } llvm::StringRef getUnpackOptionalCode() const { return get()->getValueAsString(UnpackOptionalCodeFieldName); } std::vector getBufferElementTypes() const { return get()->getValueAsListOfDefs(BufferElementTypesFieldName); } static llvm::StringRef getTableGenNodeClassName() { return PropertyTypeClassName; } }; /// A rule for returning the kind of a type. class TypeKindRule : public WrappedRecord { public: TypeKindRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Return the type to which this applies. PropertyType getParentType() const { return get()->getValueAsDef(TypeFieldName); } /// Return the type of the kind. PropertyType getKindType() const { return get()->getValueAsDef(KindTypeFieldName); } /// Return the name to use for the kind property. llvm::StringRef getKindPropertyName() const { return get()->getValueAsString(KindPropertyNameFieldName); } /// Return the code for reading the kind value. llvm::StringRef getReadCode() const { return get()->getValueAsString(ReadFieldName); } static llvm::StringRef getTableGenNodeClassName() { return TypeKindClassName; } }; /// An implementation case of a property type. class TypeCase : public HasProperties { public: TypeCase(llvm::Record *record = nullptr) : HasProperties(record) {} /// Return the name of this case. llvm::StringRef getCaseName() const { return get()->getValueAsString(NameFieldName); } /// Return the type of which this is a case. PropertyType getParentType() const { return get()->getValueAsDef(TypeFieldName); } static llvm::StringRef getTableGenNodeClassName() { return TypeCaseClassName; } }; /// A property of an AST node. class Property : public WrappedRecord { public: Property(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Return the name of this property. llvm::StringRef getName() const { return get()->getValueAsString(NameFieldName); } /// Return the type of this property. PropertyType getType() const { return get()->getValueAsDef(TypeFieldName); } /// Return the class of which this is a property. HasProperties getClass() const { return get()->getValueAsDef(ClassFieldName); } /// Return the code for reading this property. llvm::StringRef getReadCode() const { return get()->getValueAsString(ReadFieldName); } /// Return the code for determining whether to add this property. llvm::StringRef getCondition() const { return get()->getValueAsString(ConditionalCodeFieldName); } static llvm::StringRef getTableGenNodeClassName() { return PropertyClassName; } }; /// A rule for running some helper code for reading properties from /// a value (which is actually done when writing the value out). class ReadHelperRule : public WrappedRecord { public: ReadHelperRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Return the class for which this is a creation rule. /// Should never be abstract. HasProperties getClass() const { return get()->getValueAsDef(ClassFieldName); } llvm::StringRef getHelperCode() const { return get()->getValueAsString(HelperCodeFieldName); } static llvm::StringRef getTableGenNodeClassName() { return ReadHelperRuleClassName; } }; /// A rule for how to create an AST node from its properties. class CreationRule : public WrappedRecord { public: CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Return the class for which this is a creation rule. /// Should never be abstract. HasProperties getClass() const { return get()->getValueAsDef(ClassFieldName); } llvm::StringRef getCreationCode() const { return get()->getValueAsString(CreateFieldName); } static llvm::StringRef getTableGenNodeClassName() { return CreationRuleClassName; } }; /// A rule which overrides the standard rules for serializing an AST node. class OverrideRule : public WrappedRecord { public: OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} /// Return the class for which this is an override rule. /// Should never be abstract. HasProperties getClass() const { return get()->getValueAsDef(ClassFieldName); } /// Return a set of properties that are unnecessary when serializing /// this AST node. Generally this is used for inherited properties /// that are derived for this subclass. std::vector getIgnoredProperties() const { return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName); } static llvm::StringRef getTableGenNodeClassName() { return OverrideRuleClassName; } }; /// A visitor for an AST node hierarchy. Note that `base` can be null for /// the root class. template using ASTNodeHierarchyVisitor = llvm::function_ref; void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records, llvm::StringRef nodeClassName, ASTNodeHierarchyVisitor visit); template void visitASTNodeHierarchy(llvm::RecordKeeper &records, ASTNodeHierarchyVisitor visit) { visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(), [visit](ASTNode node, ASTNode base) { visit(NodeClass(node.getRecord()), NodeClass(base.getRecord())); }); } } // end namespace clang::tblgen } // end namespace clang #endif