brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.0 KiB · e9a86f3 Raw
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