[clang] ea4d24c - [Syntax] Tablegen Sequence classes. NFC

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 11 07:29:35 PST 2020


Author: Sam McCall
Date: 2020-11-11T16:29:19+01:00
New Revision: ea4d24c899ea17ee6bd4a84eff0192503c12a5b6

URL: https://github.com/llvm/llvm-project/commit/ea4d24c899ea17ee6bd4a84eff0192503c12a5b6
DIFF: https://github.com/llvm/llvm-project/commit/ea4d24c899ea17ee6bd4a84eff0192503c12a5b6.diff

LOG: [Syntax] Tablegen Sequence classes. NFC

Similar to the previous patch, this doesn't convert *all* the classes that
could be converted. It also doesn't enforce any new invariants etc.

It *does* include some data we don't use yet: specific token types that are
allowed and optional/required status of sequence items. (Similar to Dmitri's
prototype). I think these are easier to add as we go than later, and serve
a useful documentation purpose.

Differential Revision: https://reviews.llvm.org/D90659

Added: 
    

Modified: 
    clang/include/clang/Tooling/Syntax/Nodes.h
    clang/include/clang/Tooling/Syntax/Nodes.td
    clang/include/clang/Tooling/Syntax/Syntax.td
    clang/lib/Tooling/Syntax/Nodes.cpp
    clang/utils/TableGen/ClangSyntaxEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h
index 54b8c33199ff..6f3436691cc8 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.h
+++ b/clang/include/clang/Tooling/Syntax/Nodes.h
@@ -135,22 +135,6 @@ class UnqualifiedId final : public Tree {
   static bool classof(const Node *N);
 };
 
-/// Models an `id-expression`, e.g. `std::vector<int>::size`.
-/// C++ [expr.prim.id]
-/// id-expression:
-///   unqualified-id
-///   qualified-id
-/// qualified-id:
-///   nested-name-specifier template_opt unqualified-id
-class IdExpression final : public Expression {
-public:
-  IdExpression() : Expression(NodeKind::IdExpression) {}
-  static bool classof(const Node *N);
-  NestedNameSpecifier *getQualifier();
-  Leaf *getTemplateKeyword();
-  UnqualifiedId *getUnqualifiedId();
-};
-
 /// An expression of an unknown kind, i.e. one not currently handled by the
 /// syntax tree.
 class UnknownExpression final : public Expression {
@@ -159,14 +143,6 @@ class UnknownExpression final : public Expression {
   static bool classof(const Node *N);
 };
 
-/// Models a this expression `this`. C++ [expr.prim.this]
-class ThisExpression final : public Expression {
-public:
-  ThisExpression() : Expression(NodeKind::ThisExpression) {}
-  static bool classof(const Node *N);
-  Leaf *getThisKeyword();
-};
-
 /// Models arguments of a function call.
 ///   call-arguments:
 ///     delimited_list(expression, ',')
@@ -180,49 +156,6 @@ class CallArguments final : public List {
   std::vector<List::ElementAndDelimiter<Expression>> getArgumentsAndCommas();
 };
 
-/// A function call. C++ [expr.call]
-/// call-expression:
-///   expression '(' call-arguments ')'
-/// e.g `f(1, '2')` or `this->Base::f()`
-class CallExpression final : public Expression {
-public:
-  CallExpression() : Expression(NodeKind::CallExpression) {}
-  static bool classof(const Node *N);
-  Expression *getCallee();
-  Leaf *getOpenParen();
-  CallArguments *getArguments();
-  Leaf *getCloseParen();
-};
-
-/// Models a parenthesized expression `(E)`. C++ [expr.prim.paren]
-/// e.g. `(3 + 2)` in `a = 1 + (3 + 2);`
-class ParenExpression final : public Expression {
-public:
-  ParenExpression() : Expression(NodeKind::ParenExpression) {}
-  static bool classof(const Node *N);
-  Leaf *getOpenParen();
-  Expression *getSubExpression();
-  Leaf *getCloseParen();
-};
-
-/// Models a class member access. C++ [expr.ref]
-/// member-expression:
-///   expression -> template_opt id-expression
-///   expression .  template_opt id-expression
-/// e.g. `x.a`, `xp->a`
-///
-/// Note: An implicit member access inside a class, i.e. `a` instead of
-/// `this->a`, is an `id-expression`.
-class MemberExpression final : public Expression {
-public:
-  MemberExpression() : Expression(NodeKind::MemberExpression) {}
-  static bool classof(const Node *N);
-  Expression *getObject();
-  Leaf *getAccessToken();
-  Leaf *getTemplateKeyword();
-  IdExpression *getMember();
-};
-
 /// Expression for literals. C++ [lex.literal]
 class LiteralExpression : public Expression {
 public:

diff  --git a/clang/include/clang/Tooling/Syntax/Nodes.td b/clang/include/clang/Tooling/Syntax/Nodes.td
index 821e78e1dba5..8f3d1e8f182f 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.td
+++ b/clang/include/clang/Tooling/Syntax/Nodes.td
@@ -23,6 +23,15 @@ def TranslationUnit : Unconstrained {
   }];
 }
 
+def UnqualifiedId : External<Tree> {}
+
+// Lists
+def List : External<Tree> {}
+def DeclaratorList : External<List> {}
+def ParameterDeclarationList : External<List> {}
+def CallArguments : External<List> {}
+def NestedNameSpecifier : External<List> {}
+
 def Expression : Alternatives {
   let documentation = [{
     A base class for all expressions. Note that expressions are not statements,
@@ -34,7 +43,17 @@ def UnaryOperatorExpression : External<Tree> {}
 def PrefixUnaryOperatorExpression : External<UnaryOperatorExpression> {}
 def PostfixUnaryOperatorExpression : External<UnaryOperatorExpression> {}
 def BinaryOperatorExpression : External<Expression> {}
-def ParenExpression : External<Expression> {}
+def ParenExpression : Sequence<Expression> {
+  let documentation = [{
+    Models a parenthesized expression `(E)`. C++ [expr.prim.paren]
+    e.g. `(3 + 2)` in `a = 1 + (3 + 2);`
+  }];
+  let children = [
+    Role<"OpenParen", Token<"l_paren">>,
+    Role<"SubExpression", Expression>,
+    Role<"CloseParen", Token<"r_paren">>,
+  ];
+}
 def LiteralExpression : External<Expression> {}
 def IntegerLiteralExpression : External<LiteralExpression> {}
 def CharacterLiteralExpression : External<LiteralExpression> {}
@@ -47,10 +66,62 @@ def IntegerUserDefinedLiteralExpression : External<UserDefinedLiteralExpression>
 def FloatUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
 def CharUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
 def StringUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
-def IdExpression : External<Expression> {}
-def MemberExpression : External<Expression> {}
-def ThisExpression : External<Expression> {}
-def CallExpression : External<Expression> {}
+def IdExpression : Sequence<Expression> {
+  let documentation = [{
+    Models an `id-expression`, e.g. `std::vector<int>::size`.
+    C++ [expr.prim.id]
+    id-expression:
+      unqualified-id
+      qualified-id
+    qualified-id:
+      nested-name-specifier template_opt unqualified-id
+  }];
+  let children = [
+    Role<"Qualifier", Optional<NestedNameSpecifier>>,
+    Role<"TemplateKeyword", Optional<Keyword<"template">>>,
+    Role<"UnqualifiedId", UnqualifiedId>,
+  ];
+}
+def MemberExpression : Sequence<Expression> {
+  let documentation = [{
+    Models a class member access. C++ [expr.ref]
+    member-expression:
+      expression -> template_opt id-expression
+      expression .  template_opt id-expression
+    e.g. `x.a`, `xp->a`
+
+    Note: An implicit member access inside a class, i.e. `a` instead of
+    `this->a`, is an `id-expression`.
+  }];
+  let children = [
+    Role<"Object", Expression>,
+    Role<"AccessToken", AnyToken<["period","arrow"]>>,
+    Role<"TemplateKeyword", Optional<Keyword<"template">>>,
+    Role<"Member", IdExpression>,
+  ];
+}
+def ThisExpression : Sequence<Expression> {
+  let documentation = [{
+    Models a this expression `this`. C++ [expr.prim.this]
+  }];
+  let children = [
+    Role<"IntroducerKeyword", Keyword<"this">>,
+  ];
+}
+def CallExpression : Sequence<Expression> {
+  let documentation = [{
+    A function call. C++ [expr.call]
+    call-expression:
+      expression '(' call-arguments ')'
+    e.g `f(1, '2')` or `this->Base::f()`
+  }];
+  let children = [
+    Role<"Callee", Expression>,
+    Role<"OpenParen", Token<"l_paren">>,
+    Role<"Arguments", CallArguments>,
+    Role<"CloseParen", Token<"r_paren">>,
+  ];
+}
 
 // Statements.
 def Statement : External<Tree> {}
@@ -94,14 +165,6 @@ def ArraySubscript : External<Tree> {}
 def TrailingReturnType : External<Tree> {}
 def ParametersAndQualifiers : External<Tree> {}
 def MemberPointer : External<Tree> {}
-def UnqualifiedId : External<Tree> {}
-
-// Lists
-def List : External<Tree> {}
-def DeclaratorList : External<List> {}
-def ParameterDeclarationList : External<List> {}
-def CallArguments : External<List> {}
-def NestedNameSpecifier : External<List> {}
 
 // Name Specifiers.
 def NameSpecifier : Alternatives {

diff  --git a/clang/include/clang/Tooling/Syntax/Syntax.td b/clang/include/clang/Tooling/Syntax/Syntax.td
index 3decceae85f2..2da0c1452b86 100644
--- a/clang/include/clang/Tooling/Syntax/Syntax.td
+++ b/clang/include/clang/Tooling/Syntax/Syntax.td
@@ -27,8 +27,16 @@
 //
 //===----------------------------------------------------------------------===//
 
+// Syntax is any constraint on constructs that can appear somewhere.
+class Syntax;
+class Optional<Syntax inner_> : Syntax { Syntax inner = inner_; }
+class AnyToken<list<string> kinds_> : Syntax { list<string> kinds = kinds_; }
+class Token<string kind_> : AnyToken<[kind_]>;
+class Keyword<string kw> : Token<!strconcat("kw_", kw)>;
+
 // Defs derived from NodeType correspond to syntax tree node types.
-class NodeType {
+// NodeType is also a syntax constraint: one node of this type.
+class NodeType : Syntax {
   // The NodeType that this node is derived from in the Node class hierarchy.
   NodeType base = ?;
   // Documentation for this Node subclass.
@@ -55,4 +63,23 @@ class Alternatives<NodeType base_ = Tree> : NodeType { let base = base_; }
 // These are generally placeholders for a more precise implementation.
 class Unconstrained<NodeType base_ = Tree> : NodeType { let base = base_; }
 
-// FIXME: add sequence and list archetypes.
+class Role<string role_, Syntax syntax_> {
+  string role = role_;
+  Syntax syntax = syntax_;
+}
+
+// A node which contains a fixed sequence of children in a particular order.
+//
+// Each child is characterized by a role (unique within the sequence), and
+// has an allowed base type for the node.
+// The role sequence and role/type match are enforced invariants of the class.
+//
+// We also record whether the child is required to be present, and which tokens
+// are permitted (for Leaf nodes). These invariants are not enforced.
+class Sequence<NodeType base_ = Tree> : NodeType {
+  let base = base_;
+  // Children must be Role or have a default role derived from the NodeType.
+  list<Role> children;
+}
+
+// FIXME: add list archetype.

diff  --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp
index e9e216af5754..bbf880c8f4ea 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -196,58 +196,6 @@ syntax::DeclaratorList::getDeclaratorsAndCommas() {
   return Children;
 }
 
-syntax::Expression *syntax::MemberExpression::getObject() {
-  return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Object));
-}
-
-syntax::Leaf *syntax::MemberExpression::getTemplateKeyword() {
-  return llvm::cast_or_null<syntax::Leaf>(
-      findChild(syntax::NodeRole::TemplateKeyword));
-}
-
-syntax::Leaf *syntax::MemberExpression::getAccessToken() {
-  return llvm::cast_or_null<syntax::Leaf>(
-      findChild(syntax::NodeRole::AccessToken));
-}
-
-syntax::IdExpression *syntax::MemberExpression::getMember() {
-  return cast_or_null<syntax::IdExpression>(
-      findChild(syntax::NodeRole::Member));
-}
-
-syntax::NestedNameSpecifier *syntax::IdExpression::getQualifier() {
-  return cast_or_null<syntax::NestedNameSpecifier>(
-      findChild(syntax::NodeRole::Qualifier));
-}
-
-syntax::Leaf *syntax::IdExpression::getTemplateKeyword() {
-  return llvm::cast_or_null<syntax::Leaf>(
-      findChild(syntax::NodeRole::TemplateKeyword));
-}
-
-syntax::UnqualifiedId *syntax::IdExpression::getUnqualifiedId() {
-  return cast_or_null<syntax::UnqualifiedId>(
-      findChild(syntax::NodeRole::UnqualifiedId));
-}
-
-syntax::Leaf *syntax::ParenExpression::getOpenParen() {
-  return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
-}
-
-syntax::Expression *syntax::ParenExpression::getSubExpression() {
-  return cast_or_null<syntax::Expression>(
-      findChild(syntax::NodeRole::SubExpression));
-}
-
-syntax::Leaf *syntax::ParenExpression::getCloseParen() {
-  return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
-}
-
-syntax::Leaf *syntax::ThisExpression::getThisKeyword() {
-  return cast_or_null<syntax::Leaf>(
-      findChild(syntax::NodeRole::IntroducerKeyword));
-}
-
 syntax::Leaf *syntax::LiteralExpression::getLiteralToken() {
   return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::LiteralToken));
 }
@@ -274,23 +222,6 @@ syntax::Expression *syntax::BinaryOperatorExpression::getRhs() {
       findChild(syntax::NodeRole::RightHandSide));
 }
 
-syntax::Expression *syntax::CallExpression::getCallee() {
-  return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Callee));
-}
-
-syntax::Leaf *syntax::CallExpression::getOpenParen() {
-  return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
-}
-
-syntax::CallArguments *syntax::CallExpression::getArguments() {
-  return cast_or_null<syntax::CallArguments>(
-      findChild(syntax::NodeRole::Arguments));
-}
-
-syntax::Leaf *syntax::CallExpression::getCloseParen() {
-  return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
-}
-
 syntax::Leaf *syntax::SwitchStatement::getSwitchKeyword() {
   return cast_or_null<syntax::Leaf>(
       findChild(syntax::NodeRole::IntroducerKeyword));

diff  --git a/clang/utils/TableGen/ClangSyntaxEmitter.cpp b/clang/utils/TableGen/ClangSyntaxEmitter.cpp
index c0b09220dc73..a940edbb1d24 100644
--- a/clang/utils/TableGen/ClangSyntaxEmitter.cpp
+++ b/clang/utils/TableGen/ClangSyntaxEmitter.cpp
@@ -108,6 +108,23 @@ const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {
   return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());
 }
 
+struct SyntaxConstraint {
+  SyntaxConstraint(const llvm::Record &R) {
+    if (R.isSubClassOf("Optional")) {
+      *this = SyntaxConstraint(*R.getValueAsDef("inner"));
+    } else if (R.isSubClassOf("AnyToken")) {
+      NodeType = "Leaf";
+    } else if (R.isSubClassOf("NodeType")) {
+      NodeType = R.getName().str();
+    } else {
+      assert(false && "Unhandled Syntax kind");
+    }
+  }
+
+  std::string NodeType;
+  // optional and leaf types also go here, once we want to use them.
+};
+
 } // namespace
 
 void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
@@ -196,6 +213,21 @@ void clang::EmitClangSyntaxNodeClasses(llvm::RecordKeeper &Records,
       OS << formatv("protected:\n  {0}(NodeKind K) : {1}(K) {{}\npublic:\n",
                     N.name(), N.Base->name());
 
+    if (N.Record->isSubClassOf("Sequence")) {
+      // Getters for sequence elements.
+      for (const auto &C : N.Record->getValueAsListOfDefs("children")) {
+        assert(C->isSubClassOf("Role"));
+        llvm::StringRef Role = C->getValueAsString("role");
+        SyntaxConstraint Constraint(*C->getValueAsDef("syntax"));
+        for (const char *Const : {"", "const "})
+          OS << formatv(
+              "  {2}{1} *get{0}() {2} {{\n"
+              "    return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"
+              "  }\n",
+              Role, Constraint.NodeType, Const);
+      }
+    }
+
     // classof. FIXME: move definition inline once ~all nodes are generated.
     OS << "  static bool classof(const Node *N);\n";
 


        


More information about the cfe-commits mailing list