Skip to content

Commit 70dd884

Browse files
authored
libSyntax: add a factory method to create meaningful nodes with a generic syntax list. (swiftlang#12332)
1 parent 192b523 commit 70dd884

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

include/swift/Syntax/Syntax.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class Syntax {
152152
/// Returns true if the node is "present" in the source.
153153
bool isPresent() const;
154154

155+
156+
bool isToken() const;
157+
155158
/// Print the syntax node with full fidelity to the given output stream.
156159
void print(llvm::raw_ostream &OS) const;
157160

@@ -166,6 +169,10 @@ class Syntax {
166169
return Root == Other.Root && Data == Other.Data;
167170
}
168171

172+
static bool classof(const Syntax *S) {
173+
// Trivially true.
174+
return true;
175+
}
169176
// TODO: hasSameStructureAs ?
170177
};
171178

include/swift/Syntax/SyntaxFactory.h.gyb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ struct SyntaxFactory {
5151
static UnknownSyntax
5252
makeUnknownSyntax(llvm::ArrayRef<TokenSyntax> Tokens);
5353

54+
static Optional<Syntax>
55+
createSyntax(SyntaxKind Kind, llvm::ArrayRef<Syntax> Elements);
56+
5457
% for node in SYNTAX_NODES:
5558
% if node.children:
5659
% child_params = []

include/swift/Syntax/TokenSyntax.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ class TokenSyntax final : public Syntax {
8989
StringRef getText() const {
9090
return getRawToken()->getText();
9191
}
92+
93+
static bool classof(const Syntax *S) {
94+
return S->isToken();
95+
}
9296
};
9397

9498
} // end namespace syntax

lib/Syntax/Syntax.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ bool Syntax::isMissing() const {
6868
return getRaw()->isMissing();
6969
}
7070

71+
bool Syntax::isToken() const {
72+
return getRaw()->isToken();
73+
}
74+
75+
7176
llvm::Optional<Syntax> Syntax::getParent() const {
7277
auto ParentData = getData().Parent;
7378
if (ParentData == nullptr) return llvm::None;

lib/Syntax/SyntaxFactory.cpp.gyb

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,109 @@ SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef<TokenSyntax> Tokens) {
5757
return make<UnknownSyntax>(Raw);
5858
}
5959

60+
Optional<Syntax>
61+
SyntaxFactory::createSyntax(SyntaxKind Kind, llvm::ArrayRef<Syntax> Elements) {
62+
switch(Kind) {
63+
% for node in SYNTAX_NODES:
64+
case SyntaxKind::${node.syntax_kind}: {
65+
% if node.children:
66+
% child_count = len(node.children)
67+
static std::pair<bool, std::function<bool(const Syntax&)>>
68+
ChildrenConditions[${child_count}] = {
69+
% for child in node.children:
70+
% if child.is_optional:
71+
% option = "true"
72+
% else:
73+
% option = "false"
74+
% if child.token_choices:
75+
{ ${option},
76+
[](const Syntax &S) {
77+
// check ${child.name}.
78+
if (auto Tok = S.getAs<TokenSyntax>()) {
79+
auto Kind = Tok->getTokenKind();
80+
% tok_checks = []
81+
% for choice in child.token_choices:
82+
% tok_checks.append("Kind == tok::%s" % choice.kind)
83+
% end
84+
% all_checks = ' || '.join(tok_checks)
85+
return ${all_checks};
86+
}
87+
return false;
88+
}
89+
},
90+
% else:
91+
{ ${option},
92+
[](const Syntax &S) {
93+
// check ${child.name}.
94+
return S.getAs<${child.type_name}>().hasValue();
95+
}
96+
},
97+
% end
98+
% end
99+
};
100+
Optional<Syntax> Parameters[${child_count}];
101+
unsigned CurCond = 0;
102+
for (unsigned I = 0, N = Elements.size(); I < N; ) {
103+
// We should use all elements.
104+
if (CurCond == ${child_count}) {
105+
return None;
106+
}
107+
if (ChildrenConditions[CurCond].second(Elements[I])) {
108+
// we find a node that satisfies the condition.
109+
Parameters[CurCond].emplace(Elements[I]);
110+
CurCond ++;
111+
I ++;
112+
} else if (ChildrenConditions[CurCond].first) {
113+
// If the unsatisfied condition is optional, move on to the next condition.
114+
CurCond ++;
115+
} else {
116+
// Mandatory condition is not satisfied.
117+
return None;
118+
}
119+
}
120+
for (; CurCond < ${child_count}; CurCond ++) {
121+
if (!ChildrenConditions[CurCond].first) {
122+
// if the remaining condition is mandatory, we cannot create.
123+
return None;
124+
}
125+
}
126+
assert(CurCond == ${child_count});
127+
return make${node.syntax_kind}(
128+
% params = []
129+
% for i, child in enumerate(node.children):
130+
% child = node.children[i]
131+
% if child.is_optional:
132+
% params.append("/*Optional %s*/ Parameters[%s].hasValue() ?" \
133+
% "(*Parameters[%s]).getAs<%s>().getValue() : (Optional<%s>) None" %
134+
% (child.name, i, i, child.type_name, child.type_name))
135+
% else:
136+
% params.append("/*%s*/ (*Parameters[%s]).getAs<%s>().getValue()" %
137+
% (child.name, i, child.type_name))
138+
% end
139+
% end
140+
% child_parms = '\n, '.join(params)
141+
${child_parms}
142+
);
143+
% elif node.is_syntax_collection():
144+
std::vector<${node.collection_element_type}> Parts;
145+
for (auto &E: Elements) {
146+
if (auto P = E.getAs<${node.collection_element_type}>()) {
147+
Parts.emplace_back(make<${node.collection_element_type}>(P->getRaw()));
148+
} else {
149+
return None;
150+
}
151+
}
152+
return make${node.syntax_kind}(Parts);
153+
% else:
154+
return None;
155+
% end
156+
}
157+
% end
158+
default:
159+
return None;
160+
}
161+
}
162+
60163
% for node in SYNTAX_NODES:
61164
% if node.children:
62165
% child_params = []
@@ -110,7 +213,7 @@ SyntaxFactory::makeBlank${node.syntax_kind}() {
110213
TokenSyntax
111214
SyntaxFactory::make${token.name}Keyword(const Trivia &LeadingTrivia,
112215
const Trivia &TrailingTrivia) {
113-
return makeToken(tok::${token.kind}, "${token.text}",
216+
return makeToken(tok::${token.kind}, "${token.text}",
114217
SourcePresence::Present,
115218
LeadingTrivia, TrailingTrivia);
116219
}
@@ -168,7 +271,7 @@ TypeIdentifierSyntax SyntaxFactory::makeAnyTypeIdentifier(
168271
const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) {
169272
return makeTypeIdentifier("Any", LeadingTrivia, TrailingTrivia);
170273
}
171-
274+
172275
TypeIdentifierSyntax SyntaxFactory::makeSelfTypeIdentifier(
173276
const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) {
174277
return makeTypeIdentifier("Self", LeadingTrivia, TrailingTrivia);

0 commit comments

Comments
 (0)