[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