505 lines · c
1//=== ASTTableGen.h - Common definitions for AST node tablegen --*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef CLANG_AST_TABLEGEN_H10#define CLANG_AST_TABLEGEN_H11 12#include "llvm/TableGen/Record.h"13#include "llvm/ADT/STLExtras.h"14#include <optional>15 16// These are spellings in the tblgen files.17 18#define HasPropertiesClassName "HasProperties"19 20// ASTNodes and their common fields. `Base` is actually defined21// in subclasses, but it's still common across the hierarchies.22#define ASTNodeClassName "ASTNode"23#define BaseFieldName "Base"24#define AbstractFieldName "Abstract"25 26// Comment node hierarchy.27#define CommentNodeClassName "CommentNode"28 29// Decl node hierarchy.30#define DeclNodeClassName "DeclNode"31#define DeclContextNodeClassName "DeclContext"32 33// Stmt node hierarchy.34#define StmtNodeClassName "StmtNode"35 36// Type node hierarchy.37#define TypeNodeClassName "TypeNode"38#define AlwaysDependentClassName "AlwaysDependent"39#define NeverCanonicalClassName "NeverCanonical"40#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"41#define AlwaysCanonicalTypeClassName "AlwaysCanonical"42 43// Cases of various non-ASTNode structured types like DeclarationName.44#define TypeKindClassName "PropertyTypeKind"45#define KindTypeFieldName "KindType"46#define KindPropertyNameFieldName "KindPropertyName"47#define TypeCaseClassName "PropertyTypeCase"48 49// Properties of AST nodes.50#define PropertyClassName "Property"51#define ClassFieldName "Class"52#define NameFieldName "Name"53#define TypeFieldName "Type"54#define ReadFieldName "Read"55 56// Types of properties.57#define PropertyTypeClassName "PropertyType"58#define CXXTypeNameFieldName "CXXName"59#define PassByReferenceFieldName "PassByReference"60#define ConstWhenWritingFieldName "ConstWhenWriting"61#define ConditionalCodeFieldName "Conditional"62#define PackOptionalCodeFieldName "PackOptional"63#define UnpackOptionalCodeFieldName "UnpackOptional"64#define BufferElementTypesFieldName "BufferElementTypes"65#define ArrayTypeClassName "Array"66#define ArrayElementTypeFieldName "Element"67#define OptionalTypeClassName "Optional"68#define OptionalElementTypeFieldName "Element"69#define SubclassPropertyTypeClassName "SubclassPropertyType"70#define SubclassBaseTypeFieldName "Base"71#define SubclassClassNameFieldName "SubclassName"72#define EnumPropertyTypeClassName "EnumPropertyType"73 74// Write helper rules.75#define ReadHelperRuleClassName "ReadHelper"76#define HelperCodeFieldName "Code"77 78// Creation rules.79#define CreationRuleClassName "Creator"80#define CreateFieldName "Create"81 82// Override rules.83#define OverrideRuleClassName "Override"84#define IgnoredPropertiesFieldName "IgnoredProperties"85 86namespace clang {87namespace tblgen {88 89class WrappedRecord {90 const llvm::Record *Record;91 92protected:93 WrappedRecord(const llvm::Record *record = nullptr) : Record(record) {}94 95 const llvm::Record *get() const {96 assert(Record && "accessing null record");97 return Record;98 }99 100public:101 const llvm::Record *getRecord() const { return Record; }102 103 explicit operator bool() const { return Record != nullptr; }104 105 llvm::ArrayRef<llvm::SMLoc> getLoc() const {106 return get()->getLoc();107 }108 109 /// Does the node inherit from the given TableGen class?110 bool isSubClassOf(llvm::StringRef className) const {111 return get()->isSubClassOf(className);112 }113 114 template <class NodeClass>115 NodeClass getAs() const {116 return (isSubClassOf(NodeClass::getTableGenNodeClassName())117 ? NodeClass(get()) : NodeClass());118 }119 120 friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) {121 assert(lhs && rhs && "sorting null nodes");122 return lhs.get()->getName() < rhs.get()->getName();123 }124 friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) {125 return rhs < lhs;126 }127 friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) {128 return !(rhs < lhs);129 }130 friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) {131 return !(lhs < rhs);132 }133 friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) {134 // This should handle null nodes.135 return lhs.getRecord() == rhs.getRecord();136 }137 friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) {138 return !(lhs == rhs);139 }140};141 142/// Anything in the AST that has properties.143class HasProperties : public WrappedRecord {144public:145 static constexpr llvm::StringRef ClassName = HasPropertiesClassName;146 147 HasProperties(const llvm::Record *record = nullptr) : WrappedRecord(record) {}148 149 llvm::StringRef getName() const;150 151 static llvm::StringRef getTableGenNodeClassName() {152 return HasPropertiesClassName;153 }154};155 156/// An (optional) reference to a TableGen node representing a class157/// in one of Clang's AST hierarchies.158class ASTNode : public HasProperties {159public:160 ASTNode(const llvm::Record *record = nullptr) : HasProperties(record) {}161 162 llvm::StringRef getName() const {163 return get()->getName();164 }165 166 /// Return the node for the base, if there is one.167 ASTNode getBase() const {168 return get()->getValueAsOptionalDef(BaseFieldName);169 }170 171 /// Is the corresponding class abstract?172 bool isAbstract() const {173 return get()->getValueAsBit(AbstractFieldName);174 }175 176 static llvm::StringRef getTableGenNodeClassName() {177 return ASTNodeClassName;178 }179};180 181class DeclNode : public ASTNode {182public:183 DeclNode(const llvm::Record *record = nullptr) : ASTNode(record) {}184 185 llvm::StringRef getId() const;186 std::string getClassName() const;187 DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); }188 189 static llvm::StringRef getASTHierarchyName() {190 return "Decl";191 }192 static llvm::StringRef getASTIdTypeName() {193 return "Decl::Kind";194 }195 static llvm::StringRef getASTIdAccessorName() {196 return "getKind";197 }198 static llvm::StringRef getTableGenNodeClassName() {199 return DeclNodeClassName;200 }201};202 203class TypeNode : public ASTNode {204public:205 TypeNode(const llvm::Record *record = nullptr) : ASTNode(record) {}206 207 llvm::StringRef getId() const;208 llvm::StringRef getClassName() const;209 TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); }210 211 static llvm::StringRef getASTHierarchyName() {212 return "Type";213 }214 static llvm::StringRef getASTIdTypeName() {215 return "Type::TypeClass";216 }217 static llvm::StringRef getASTIdAccessorName() {218 return "getTypeClass";219 }220 static llvm::StringRef getTableGenNodeClassName() {221 return TypeNodeClassName;222 }223};224 225class StmtNode : public ASTNode {226public:227 StmtNode(const llvm::Record *record = nullptr) : ASTNode(record) {}228 229 std::string getId() const;230 llvm::StringRef getClassName() const;231 StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); }232 233 static llvm::StringRef getASTHierarchyName() {234 return "Stmt";235 }236 static llvm::StringRef getASTIdTypeName() {237 return "Stmt::StmtClass";238 }239 static llvm::StringRef getASTIdAccessorName() {240 return "getStmtClass";241 }242 static llvm::StringRef getTableGenNodeClassName() {243 return StmtNodeClassName;244 }245};246 247/// The type of a property.248class PropertyType : public WrappedRecord {249public:250 PropertyType(const llvm::Record *record = nullptr) : WrappedRecord(record) {}251 252 /// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)?253 bool isGenericSpecialization() const {254 return get()->isAnonymous();255 }256 257 /// The abstract type name of the property. Doesn't work for generic258 /// specializations.259 llvm::StringRef getAbstractTypeName() const {260 return get()->getName();261 }262 263 /// The C++ type name of the property. Doesn't work for generic264 /// specializations.265 llvm::StringRef getCXXTypeName() const {266 return get()->getValueAsString(CXXTypeNameFieldName);267 }268 void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const;269 270 /// Whether the C++ type should be passed around by reference.271 bool shouldPassByReference() const {272 return get()->getValueAsBit(PassByReferenceFieldName);273 }274 275 /// Whether the C++ type should have 'const' prepended when working with276 /// a value of the type being written.277 bool isConstWhenWriting() const {278 return get()->getValueAsBit(ConstWhenWritingFieldName);279 }280 281 /// If this is `Array<T>`, return `T`; otherwise return null.282 PropertyType getArrayElementType() const {283 if (isSubClassOf(ArrayTypeClassName))284 return get()->getValueAsDef(ArrayElementTypeFieldName);285 return nullptr;286 }287 288 /// If this is `Optional<T>`, return `T`; otherwise return null.289 PropertyType getOptionalElementType() const {290 if (isSubClassOf(OptionalTypeClassName))291 return get()->getValueAsDef(OptionalElementTypeFieldName);292 return nullptr;293 }294 295 /// If this is a subclass type, return its superclass type.296 PropertyType getSuperclassType() const {297 if (isSubClassOf(SubclassPropertyTypeClassName))298 return get()->getValueAsDef(SubclassBaseTypeFieldName);299 return nullptr;300 }301 302 // Given that this is a subclass type, return the C++ name of its303 // subclass type. This is just the bare class name, suitable for304 // use in `cast<>`.305 llvm::StringRef getSubclassClassName() const {306 return get()->getValueAsString(SubclassClassNameFieldName);307 }308 309 /// Does this represent an enum type?310 bool isEnum() const {311 return isSubClassOf(EnumPropertyTypeClassName);312 }313 314 llvm::StringRef getPackOptionalCode() const {315 return get()->getValueAsString(PackOptionalCodeFieldName);316 }317 318 llvm::StringRef getUnpackOptionalCode() const {319 return get()->getValueAsString(UnpackOptionalCodeFieldName);320 }321 322 std::vector<const llvm::Record *> getBufferElementTypes() const {323 return get()->getValueAsListOfDefs(BufferElementTypesFieldName);324 }325 326 static llvm::StringRef getTableGenNodeClassName() {327 return PropertyTypeClassName;328 }329};330 331/// A rule for returning the kind of a type.332class TypeKindRule : public WrappedRecord {333public:334 TypeKindRule(const llvm::Record *record = nullptr) : WrappedRecord(record) {}335 336 /// Return the type to which this applies.337 PropertyType getParentType() const {338 return get()->getValueAsDef(TypeFieldName);339 }340 341 /// Return the type of the kind.342 PropertyType getKindType() const {343 return get()->getValueAsDef(KindTypeFieldName);344 }345 346 /// Return the name to use for the kind property.347 llvm::StringRef getKindPropertyName() const {348 return get()->getValueAsString(KindPropertyNameFieldName);349 }350 351 /// Return the code for reading the kind value.352 llvm::StringRef getReadCode() const {353 return get()->getValueAsString(ReadFieldName);354 }355 356 static llvm::StringRef getTableGenNodeClassName() {357 return TypeKindClassName;358 }359};360 361/// An implementation case of a property type.362class TypeCase : public HasProperties {363public:364 TypeCase(const llvm::Record *record = nullptr) : HasProperties(record) {}365 366 /// Return the name of this case.367 llvm::StringRef getCaseName() const {368 return get()->getValueAsString(NameFieldName);369 }370 371 /// Return the type of which this is a case.372 PropertyType getParentType() const {373 return get()->getValueAsDef(TypeFieldName);374 }375 376 static llvm::StringRef getTableGenNodeClassName() {377 return TypeCaseClassName;378 }379};380 381/// A property of an AST node.382class Property : public WrappedRecord {383public:384 Property(const llvm::Record *record = nullptr) : WrappedRecord(record) {}385 386 /// Return the name of this property.387 llvm::StringRef getName() const {388 return get()->getValueAsString(NameFieldName);389 }390 391 /// Return the type of this property.392 PropertyType getType() const {393 return get()->getValueAsDef(TypeFieldName);394 }395 396 /// Return the class of which this is a property.397 HasProperties getClass() const {398 return get()->getValueAsDef(ClassFieldName);399 }400 401 /// Return the code for reading this property.402 llvm::StringRef getReadCode() const {403 return get()->getValueAsString(ReadFieldName);404 }405 406 /// Return the code for determining whether to add this property.407 llvm::StringRef getCondition() const {408 return get()->getValueAsString(ConditionalCodeFieldName);409 }410 411 static llvm::StringRef getTableGenNodeClassName() {412 return PropertyClassName;413 }414};415 416/// A rule for running some helper code for reading properties from417/// a value (which is actually done when writing the value out).418class ReadHelperRule : public WrappedRecord {419public:420 ReadHelperRule(const llvm::Record *record = nullptr)421 : WrappedRecord(record) {}422 423 /// Return the class for which this is a creation rule.424 /// Should never be abstract.425 HasProperties getClass() const {426 return get()->getValueAsDef(ClassFieldName);427 }428 429 llvm::StringRef getHelperCode() const {430 return get()->getValueAsString(HelperCodeFieldName);431 }432 433 static llvm::StringRef getTableGenNodeClassName() {434 return ReadHelperRuleClassName;435 }436};437 438/// A rule for how to create an AST node from its properties.439class CreationRule : public WrappedRecord {440public:441 CreationRule(const llvm::Record *record = nullptr) : WrappedRecord(record) {}442 443 /// Return the class for which this is a creation rule.444 /// Should never be abstract.445 HasProperties getClass() const {446 return get()->getValueAsDef(ClassFieldName);447 }448 449 llvm::StringRef getCreationCode() const {450 return get()->getValueAsString(CreateFieldName);451 }452 453 static llvm::StringRef getTableGenNodeClassName() {454 return CreationRuleClassName;455 }456};457 458/// A rule which overrides the standard rules for serializing an AST node.459class OverrideRule : public WrappedRecord {460public:461 OverrideRule(const llvm::Record *record = nullptr) : WrappedRecord(record) {}462 463 /// Return the class for which this is an override rule.464 /// Should never be abstract.465 HasProperties getClass() const {466 return get()->getValueAsDef(ClassFieldName);467 }468 469 /// Return a set of properties that are unnecessary when serializing470 /// this AST node. Generally this is used for inherited properties471 /// that are derived for this subclass.472 std::vector<llvm::StringRef> getIgnoredProperties() const {473 return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);474 }475 476 static llvm::StringRef getTableGenNodeClassName() {477 return OverrideRuleClassName;478 }479};480 481/// A visitor for an AST node hierarchy. Note that `base` can be null for482/// the root class.483template <class NodeClass>484using ASTNodeHierarchyVisitor =485 llvm::function_ref<void(NodeClass node, NodeClass base)>;486 487void visitASTNodeHierarchyImpl(const llvm::RecordKeeper &records,488 llvm::StringRef nodeClassName,489 ASTNodeHierarchyVisitor<ASTNode> visit);490 491template <class NodeClass>492void visitASTNodeHierarchy(const llvm::RecordKeeper &records,493 ASTNodeHierarchyVisitor<NodeClass> visit) {494 visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(),495 [visit](ASTNode node, ASTNode base) {496 visit(NodeClass(node.getRecord()),497 NodeClass(base.getRecord()));498 });499}500 501} // end namespace clang::tblgen502} // end namespace clang503 504#endif505