Skip to content

Commit ea4d24c

Browse files
committed
[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
1 parent 418f18c commit ea4d24c

File tree

5 files changed

+137
-151
lines changed

5 files changed

+137
-151
lines changed

clang/include/clang/Tooling/Syntax/Nodes.h

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -135,22 +135,6 @@ class UnqualifiedId final : public Tree {
135135
static bool classof(const Node *N);
136136
};
137137

138-
/// Models an `id-expression`, e.g. `std::vector<int>::size`.
139-
/// C++ [expr.prim.id]
140-
/// id-expression:
141-
/// unqualified-id
142-
/// qualified-id
143-
/// qualified-id:
144-
/// nested-name-specifier template_opt unqualified-id
145-
class IdExpression final : public Expression {
146-
public:
147-
IdExpression() : Expression(NodeKind::IdExpression) {}
148-
static bool classof(const Node *N);
149-
NestedNameSpecifier *getQualifier();
150-
Leaf *getTemplateKeyword();
151-
UnqualifiedId *getUnqualifiedId();
152-
};
153-
154138
/// An expression of an unknown kind, i.e. one not currently handled by the
155139
/// syntax tree.
156140
class UnknownExpression final : public Expression {
@@ -159,14 +143,6 @@ class UnknownExpression final : public Expression {
159143
static bool classof(const Node *N);
160144
};
161145

162-
/// Models a this expression `this`. C++ [expr.prim.this]
163-
class ThisExpression final : public Expression {
164-
public:
165-
ThisExpression() : Expression(NodeKind::ThisExpression) {}
166-
static bool classof(const Node *N);
167-
Leaf *getThisKeyword();
168-
};
169-
170146
/// Models arguments of a function call.
171147
/// call-arguments:
172148
/// delimited_list(expression, ',')
@@ -180,49 +156,6 @@ class CallArguments final : public List {
180156
std::vector<List::ElementAndDelimiter<Expression>> getArgumentsAndCommas();
181157
};
182158

183-
/// A function call. C++ [expr.call]
184-
/// call-expression:
185-
/// expression '(' call-arguments ')'
186-
/// e.g `f(1, '2')` or `this->Base::f()`
187-
class CallExpression final : public Expression {
188-
public:
189-
CallExpression() : Expression(NodeKind::CallExpression) {}
190-
static bool classof(const Node *N);
191-
Expression *getCallee();
192-
Leaf *getOpenParen();
193-
CallArguments *getArguments();
194-
Leaf *getCloseParen();
195-
};
196-
197-
/// Models a parenthesized expression `(E)`. C++ [expr.prim.paren]
198-
/// e.g. `(3 + 2)` in `a = 1 + (3 + 2);`
199-
class ParenExpression final : public Expression {
200-
public:
201-
ParenExpression() : Expression(NodeKind::ParenExpression) {}
202-
static bool classof(const Node *N);
203-
Leaf *getOpenParen();
204-
Expression *getSubExpression();
205-
Leaf *getCloseParen();
206-
};
207-
208-
/// Models a class member access. C++ [expr.ref]
209-
/// member-expression:
210-
/// expression -> template_opt id-expression
211-
/// expression . template_opt id-expression
212-
/// e.g. `x.a`, `xp->a`
213-
///
214-
/// Note: An implicit member access inside a class, i.e. `a` instead of
215-
/// `this->a`, is an `id-expression`.
216-
class MemberExpression final : public Expression {
217-
public:
218-
MemberExpression() : Expression(NodeKind::MemberExpression) {}
219-
static bool classof(const Node *N);
220-
Expression *getObject();
221-
Leaf *getAccessToken();
222-
Leaf *getTemplateKeyword();
223-
IdExpression *getMember();
224-
};
225-
226159
/// Expression for literals. C++ [lex.literal]
227160
class LiteralExpression : public Expression {
228161
public:

clang/include/clang/Tooling/Syntax/Nodes.td

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ def TranslationUnit : Unconstrained {
2323
}];
2424
}
2525

26+
def UnqualifiedId : External<Tree> {}
27+
28+
// Lists
29+
def List : External<Tree> {}
30+
def DeclaratorList : External<List> {}
31+
def ParameterDeclarationList : External<List> {}
32+
def CallArguments : External<List> {}
33+
def NestedNameSpecifier : External<List> {}
34+
2635
def Expression : Alternatives {
2736
let documentation = [{
2837
A base class for all expressions. Note that expressions are not statements,
@@ -34,7 +43,17 @@ def UnaryOperatorExpression : External<Tree> {}
3443
def PrefixUnaryOperatorExpression : External<UnaryOperatorExpression> {}
3544
def PostfixUnaryOperatorExpression : External<UnaryOperatorExpression> {}
3645
def BinaryOperatorExpression : External<Expression> {}
37-
def ParenExpression : External<Expression> {}
46+
def ParenExpression : Sequence<Expression> {
47+
let documentation = [{
48+
Models a parenthesized expression `(E)`. C++ [expr.prim.paren]
49+
e.g. `(3 + 2)` in `a = 1 + (3 + 2);`
50+
}];
51+
let children = [
52+
Role<"OpenParen", Token<"l_paren">>,
53+
Role<"SubExpression", Expression>,
54+
Role<"CloseParen", Token<"r_paren">>,
55+
];
56+
}
3857
def LiteralExpression : External<Expression> {}
3958
def IntegerLiteralExpression : External<LiteralExpression> {}
4059
def CharacterLiteralExpression : External<LiteralExpression> {}
@@ -47,10 +66,62 @@ def IntegerUserDefinedLiteralExpression : External<UserDefinedLiteralExpression>
4766
def FloatUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
4867
def CharUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
4968
def StringUserDefinedLiteralExpression : External<UserDefinedLiteralExpression> {}
50-
def IdExpression : External<Expression> {}
51-
def MemberExpression : External<Expression> {}
52-
def ThisExpression : External<Expression> {}
53-
def CallExpression : External<Expression> {}
69+
def IdExpression : Sequence<Expression> {
70+
let documentation = [{
71+
Models an `id-expression`, e.g. `std::vector<int>::size`.
72+
C++ [expr.prim.id]
73+
id-expression:
74+
unqualified-id
75+
qualified-id
76+
qualified-id:
77+
nested-name-specifier template_opt unqualified-id
78+
}];
79+
let children = [
80+
Role<"Qualifier", Optional<NestedNameSpecifier>>,
81+
Role<"TemplateKeyword", Optional<Keyword<"template">>>,
82+
Role<"UnqualifiedId", UnqualifiedId>,
83+
];
84+
}
85+
def MemberExpression : Sequence<Expression> {
86+
let documentation = [{
87+
Models a class member access. C++ [expr.ref]
88+
member-expression:
89+
expression -> template_opt id-expression
90+
expression . template_opt id-expression
91+
e.g. `x.a`, `xp->a`
92+
93+
Note: An implicit member access inside a class, i.e. `a` instead of
94+
`this->a`, is an `id-expression`.
95+
}];
96+
let children = [
97+
Role<"Object", Expression>,
98+
Role<"AccessToken", AnyToken<["period","arrow"]>>,
99+
Role<"TemplateKeyword", Optional<Keyword<"template">>>,
100+
Role<"Member", IdExpression>,
101+
];
102+
}
103+
def ThisExpression : Sequence<Expression> {
104+
let documentation = [{
105+
Models a this expression `this`. C++ [expr.prim.this]
106+
}];
107+
let children = [
108+
Role<"IntroducerKeyword", Keyword<"this">>,
109+
];
110+
}
111+
def CallExpression : Sequence<Expression> {
112+
let documentation = [{
113+
A function call. C++ [expr.call]
114+
call-expression:
115+
expression '(' call-arguments ')'
116+
e.g `f(1, '2')` or `this->Base::f()`
117+
}];
118+
let children = [
119+
Role<"Callee", Expression>,
120+
Role<"OpenParen", Token<"l_paren">>,
121+
Role<"Arguments", CallArguments>,
122+
Role<"CloseParen", Token<"r_paren">>,
123+
];
124+
}
54125

55126
// Statements.
56127
def Statement : External<Tree> {}
@@ -94,14 +165,6 @@ def ArraySubscript : External<Tree> {}
94165
def TrailingReturnType : External<Tree> {}
95166
def ParametersAndQualifiers : External<Tree> {}
96167
def MemberPointer : External<Tree> {}
97-
def UnqualifiedId : External<Tree> {}
98-
99-
// Lists
100-
def List : External<Tree> {}
101-
def DeclaratorList : External<List> {}
102-
def ParameterDeclarationList : External<List> {}
103-
def CallArguments : External<List> {}
104-
def NestedNameSpecifier : External<List> {}
105168

106169
// Name Specifiers.
107170
def NameSpecifier : Alternatives {

clang/include/clang/Tooling/Syntax/Syntax.td

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,16 @@
2727
//
2828
//===----------------------------------------------------------------------===//
2929

30+
// Syntax is any constraint on constructs that can appear somewhere.
31+
class Syntax;
32+
class Optional<Syntax inner_> : Syntax { Syntax inner = inner_; }
33+
class AnyToken<list<string> kinds_> : Syntax { list<string> kinds = kinds_; }
34+
class Token<string kind_> : AnyToken<[kind_]>;
35+
class Keyword<string kw> : Token<!strconcat("kw_", kw)>;
36+
3037
// Defs derived from NodeType correspond to syntax tree node types.
31-
class NodeType {
38+
// NodeType is also a syntax constraint: one node of this type.
39+
class NodeType : Syntax {
3240
// The NodeType that this node is derived from in the Node class hierarchy.
3341
NodeType base = ?;
3442
// Documentation for this Node subclass.
@@ -55,4 +63,23 @@ class Alternatives<NodeType base_ = Tree> : NodeType { let base = base_; }
5563
// These are generally placeholders for a more precise implementation.
5664
class Unconstrained<NodeType base_ = Tree> : NodeType { let base = base_; }
5765

58-
// FIXME: add sequence and list archetypes.
66+
class Role<string role_, Syntax syntax_> {
67+
string role = role_;
68+
Syntax syntax = syntax_;
69+
}
70+
71+
// A node which contains a fixed sequence of children in a particular order.
72+
//
73+
// Each child is characterized by a role (unique within the sequence), and
74+
// has an allowed base type for the node.
75+
// The role sequence and role/type match are enforced invariants of the class.
76+
//
77+
// We also record whether the child is required to be present, and which tokens
78+
// are permitted (for Leaf nodes). These invariants are not enforced.
79+
class Sequence<NodeType base_ = Tree> : NodeType {
80+
let base = base_;
81+
// Children must be Role or have a default role derived from the NodeType.
82+
list<Role> children;
83+
}
84+
85+
// FIXME: add list archetype.

clang/lib/Tooling/Syntax/Nodes.cpp

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -196,58 +196,6 @@ syntax::DeclaratorList::getDeclaratorsAndCommas() {
196196
return Children;
197197
}
198198

199-
syntax::Expression *syntax::MemberExpression::getObject() {
200-
return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Object));
201-
}
202-
203-
syntax::Leaf *syntax::MemberExpression::getTemplateKeyword() {
204-
return llvm::cast_or_null<syntax::Leaf>(
205-
findChild(syntax::NodeRole::TemplateKeyword));
206-
}
207-
208-
syntax::Leaf *syntax::MemberExpression::getAccessToken() {
209-
return llvm::cast_or_null<syntax::Leaf>(
210-
findChild(syntax::NodeRole::AccessToken));
211-
}
212-
213-
syntax::IdExpression *syntax::MemberExpression::getMember() {
214-
return cast_or_null<syntax::IdExpression>(
215-
findChild(syntax::NodeRole::Member));
216-
}
217-
218-
syntax::NestedNameSpecifier *syntax::IdExpression::getQualifier() {
219-
return cast_or_null<syntax::NestedNameSpecifier>(
220-
findChild(syntax::NodeRole::Qualifier));
221-
}
222-
223-
syntax::Leaf *syntax::IdExpression::getTemplateKeyword() {
224-
return llvm::cast_or_null<syntax::Leaf>(
225-
findChild(syntax::NodeRole::TemplateKeyword));
226-
}
227-
228-
syntax::UnqualifiedId *syntax::IdExpression::getUnqualifiedId() {
229-
return cast_or_null<syntax::UnqualifiedId>(
230-
findChild(syntax::NodeRole::UnqualifiedId));
231-
}
232-
233-
syntax::Leaf *syntax::ParenExpression::getOpenParen() {
234-
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
235-
}
236-
237-
syntax::Expression *syntax::ParenExpression::getSubExpression() {
238-
return cast_or_null<syntax::Expression>(
239-
findChild(syntax::NodeRole::SubExpression));
240-
}
241-
242-
syntax::Leaf *syntax::ParenExpression::getCloseParen() {
243-
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
244-
}
245-
246-
syntax::Leaf *syntax::ThisExpression::getThisKeyword() {
247-
return cast_or_null<syntax::Leaf>(
248-
findChild(syntax::NodeRole::IntroducerKeyword));
249-
}
250-
251199
syntax::Leaf *syntax::LiteralExpression::getLiteralToken() {
252200
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::LiteralToken));
253201
}
@@ -274,23 +222,6 @@ syntax::Expression *syntax::BinaryOperatorExpression::getRhs() {
274222
findChild(syntax::NodeRole::RightHandSide));
275223
}
276224

277-
syntax::Expression *syntax::CallExpression::getCallee() {
278-
return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Callee));
279-
}
280-
281-
syntax::Leaf *syntax::CallExpression::getOpenParen() {
282-
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
283-
}
284-
285-
syntax::CallArguments *syntax::CallExpression::getArguments() {
286-
return cast_or_null<syntax::CallArguments>(
287-
findChild(syntax::NodeRole::Arguments));
288-
}
289-
290-
syntax::Leaf *syntax::CallExpression::getCloseParen() {
291-
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
292-
}
293-
294225
syntax::Leaf *syntax::SwitchStatement::getSwitchKeyword() {
295226
return cast_or_null<syntax::Leaf>(
296227
findChild(syntax::NodeRole::IntroducerKeyword));

clang/utils/TableGen/ClangSyntaxEmitter.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,23 @@ const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {
108108
return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());
109109
}
110110

111+
struct SyntaxConstraint {
112+
SyntaxConstraint(const llvm::Record &R) {
113+
if (R.isSubClassOf("Optional")) {
114+
*this = SyntaxConstraint(*R.getValueAsDef("inner"));
115+
} else if (R.isSubClassOf("AnyToken")) {
116+
NodeType = "Leaf";
117+
} else if (R.isSubClassOf("NodeType")) {
118+
NodeType = R.getName().str();
119+
} else {
120+
assert(false && "Unhandled Syntax kind");
121+
}
122+
}
123+
124+
std::string NodeType;
125+
// optional and leaf types also go here, once we want to use them.
126+
};
127+
111128
} // namespace
112129

113130
void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
@@ -196,6 +213,21 @@ void clang::EmitClangSyntaxNodeClasses(llvm::RecordKeeper &Records,
196213
OS << formatv("protected:\n {0}(NodeKind K) : {1}(K) {{}\npublic:\n",
197214
N.name(), N.Base->name());
198215

216+
if (N.Record->isSubClassOf("Sequence")) {
217+
// Getters for sequence elements.
218+
for (const auto &C : N.Record->getValueAsListOfDefs("children")) {
219+
assert(C->isSubClassOf("Role"));
220+
llvm::StringRef Role = C->getValueAsString("role");
221+
SyntaxConstraint Constraint(*C->getValueAsDef("syntax"));
222+
for (const char *Const : {"", "const "})
223+
OS << formatv(
224+
" {2}{1} *get{0}() {2} {{\n"
225+
" return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"
226+
" }\n",
227+
Role, Constraint.NodeType, Const);
228+
}
229+
}
230+
199231
// classof. FIXME: move definition inline once ~all nodes are generated.
200232
OS << " static bool classof(const Node *N);\n";
201233

0 commit comments

Comments
 (0)