Skip to content

Commit

Permalink
[Syntax] Tablegen Sequence classes. NFC
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sam-mccall committed Nov 11, 2020
1 parent 418f18c commit ea4d24c
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 151 deletions.
67 changes: 0 additions & 67 deletions clang/include/clang/Tooling/Syntax/Nodes.h
Expand Up @@ -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 {
Expand All @@ -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, ',')
Expand All @@ -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:
Expand Down
89 changes: 76 additions & 13 deletions clang/include/clang/Tooling/Syntax/Nodes.td
Expand Up @@ -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,
Expand All @@ -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> {}
Expand All @@ -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> {}
Expand Down Expand Up @@ -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 {
Expand Down
31 changes: 29 additions & 2 deletions clang/include/clang/Tooling/Syntax/Syntax.td
Expand Up @@ -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.
Expand All @@ -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.
69 changes: 0 additions & 69 deletions clang/lib/Tooling/Syntax/Nodes.cpp
Expand Up @@ -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));
}
Expand All @@ -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));
Expand Down
32 changes: 32 additions & 0 deletions clang/utils/TableGen/ClangSyntaxEmitter.cpp
Expand Up @@ -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,
Expand Down Expand Up @@ -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";

Expand Down

0 comments on commit ea4d24c

Please sign in to comment.