forked from OSchip/llvm-project
[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
This commit is contained in:
parent
418f18c6cd
commit
ea4d24c899
clang
include/clang/Tooling/Syntax
lib/Tooling/Syntax
utils/TableGen
|
@ -135,22 +135,6 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
Loading…
Reference in New Issue