Skip to content

Commit beadd4a

Browse files
authored
Merge pull request #36277 from ahoppen/pr/deferred-nodes-in-syntax-parse-actions
[libSyntax] Create deferred nodes in SyntaxParseActions
2 parents cdc5ddf + bf6aff9 commit beadd4a

16 files changed

+533
-232
lines changed

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 73 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/Basic/Debug.h"
1717
#include "swift/Basic/SourceLoc.h"
1818
#include "swift/Parse/ParsedTrivia.h"
19+
#include "swift/Parse/SyntaxParseActions.h"
1920
#include "swift/Parse/Token.h"
2021
#include "swift/Syntax/SyntaxKind.h"
2122
#include "llvm/Support/Debug.h"
@@ -41,76 +42,40 @@ class SyntaxParsingContext;
4142
/// in the current parsing context.
4243
class ParsedRawSyntaxNode {
4344
friend class ParsedRawSyntaxRecorder;
44-
enum class DataKind: uint8_t {
45-
Null,
46-
Recorded,
47-
DeferredLayout,
48-
DeferredToken,
49-
};
50-
51-
struct RecordedSyntaxNode {
52-
OpaqueSyntaxNode OpaqueNode;
53-
};
54-
struct DeferredLayoutNode {
55-
MutableArrayRef<ParsedRawSyntaxNode> Children;
56-
};
57-
struct DeferredTokenNode {
58-
SourceLoc TokLoc;
59-
unsigned TokLength;
60-
StringRef LeadingTrivia;
61-
StringRef TrailingTrivia;
62-
};
63-
64-
union {
65-
RecordedSyntaxNode RecordedData;
66-
DeferredLayoutNode DeferredLayout;
67-
DeferredTokenNode DeferredToken;
68-
};
45+
using DataKind = RecordedOrDeferredNode::Kind;
46+
47+
/// The opaque data of this node. Needs to be interpreted by the \c
48+
/// SyntaxParseActions, which created it.
49+
RecordedOrDeferredNode Data;
50+
6951
/// The range of this node, including trivia.
7052
CharSourceRange Range;
7153
uint16_t SynKind;
7254
uint16_t TokKind;
73-
DataKind DK;
7455
/// Primary used for capturing a deferred missing token.
7556
bool IsMissing = false;
7657

77-
ParsedRawSyntaxNode(syntax::SyntaxKind k, CharSourceRange r,
78-
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes)
79-
: DeferredLayout({deferredNodes}), Range(r), SynKind(uint16_t(k)),
80-
TokKind(uint16_t(tok::unknown)), DK(DataKind::DeferredLayout) {
81-
assert(getKind() == k && "Syntax kind with too large value!");
82-
}
83-
84-
ParsedRawSyntaxNode(tok tokKind, SourceLoc tokLoc, unsigned tokLength,
85-
StringRef leadingTrivia, StringRef trailingTrivia)
86-
: DeferredToken{tokLoc, tokLength, leadingTrivia, trailingTrivia},
87-
Range{tokLoc.getAdvancedLoc(-leadingTrivia.size()),
88-
(unsigned)leadingTrivia.size() + tokLength +
89-
(unsigned)trailingTrivia.size()},
90-
SynKind(uint16_t(syntax::SyntaxKind::Token)),
91-
TokKind(uint16_t(tokKind)), DK(DataKind::DeferredToken) {
92-
assert(getTokenKind() == tokKind && "Token kind is too large value!");
93-
}
9458
ParsedRawSyntaxNode(const ParsedRawSyntaxNode &other) = delete;
9559
ParsedRawSyntaxNode &operator=(const ParsedRawSyntaxNode &other) = delete;
9660

9761
public:
9862
ParsedRawSyntaxNode()
99-
: RecordedData{}, Range(), SynKind(uint16_t(syntax::SyntaxKind::Unknown)),
100-
TokKind(uint16_t(tok::unknown)), DK(DataKind::Null) {}
101-
102-
ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind, CharSourceRange r,
103-
OpaqueSyntaxNode n, bool IsMissing = false)
104-
: RecordedData{n}, Range(r), SynKind(uint16_t(k)),
105-
TokKind(uint16_t(tokKind)), DK(DataKind::Recorded),
106-
IsMissing(IsMissing) {
107-
assert(getKind() == k && "Syntax kind with too large value!");
108-
assert(getTokenKind() == tokKind && "Token kind with too large value!");
63+
: Data(nullptr, DataKind::Null), Range(),
64+
SynKind(uint16_t(syntax::SyntaxKind::Unknown)),
65+
TokKind(uint16_t(tok::unknown)) {}
66+
67+
ParsedRawSyntaxNode(OpaqueSyntaxNode Opaque, CharSourceRange Range,
68+
syntax::SyntaxKind SynKind, tok TokKind, DataKind DK,
69+
bool IsMissing)
70+
: Data(Opaque, DK), Range(Range), SynKind(uint16_t(SynKind)),
71+
TokKind(uint16_t(TokKind)), IsMissing(IsMissing) {
72+
assert(getKind() == SynKind && "Syntax kind with too large value!");
73+
assert(getTokenKind() == TokKind && "Token kind with too large value!");
10974
}
11075

11176
#ifndef NDEBUG
11277
bool ensureDataIsNotRecorded() {
113-
if (DK != DataKind::Recorded)
78+
if (getDataKind() != DataKind::Recorded)
11479
return true;
11580
llvm::dbgs() << "Leaking node: ";
11681
dump(llvm::dbgs());
@@ -122,23 +87,10 @@ class ParsedRawSyntaxNode {
12287
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) {
12388
assert(ensureDataIsNotRecorded() &&
12489
"recorded data is being destroyed by assignment");
125-
switch (other.DK) {
126-
case DataKind::Null:
127-
break;
128-
case DataKind::Recorded:
129-
RecordedData = std::move(other.RecordedData);
130-
break;
131-
case DataKind::DeferredLayout:
132-
DeferredLayout = std::move(other.DeferredLayout);
133-
break;
134-
case DataKind::DeferredToken:
135-
DeferredToken = std::move(other.DeferredToken);
136-
break;
137-
}
90+
Data = std::move(other.Data);
13891
Range = std::move(other.Range);
13992
SynKind = std::move(other.SynKind);
14093
TokKind = std::move(other.TokKind);
141-
DK = std::move(other.DK);
14294
IsMissing = std::move(other.IsMissing);
14395
other.reset();
14496
return *this;
@@ -150,6 +102,33 @@ class ParsedRawSyntaxNode {
150102
assert(ensureDataIsNotRecorded() && "recorded data is being destructed");
151103
}
152104

105+
/// Returns the type of this node (recorded, deferred layout, deferred token,
106+
/// null).
107+
DataKind getDataKind() const { return Data.getKind(); }
108+
109+
/// Returns the opaque data of this node, assuming that it is deferred. This
110+
/// must be interpreted by the \c SyntaxParseAction, which likely also needs
111+
/// the node type (layout or token) to interpret the data.
112+
/// The data opaque data returned by this function *must not* be used to
113+
/// record the node, only to insepect it.
114+
OpaqueSyntaxNode getUnsafeDeferredOpaqueData() const {
115+
assert(isDeferredLayout() || isDeferredToken());
116+
return Data.getOpaque();
117+
}
118+
119+
RecordedOrDeferredNode takeRecordedOrDeferredNode() {
120+
RecordedOrDeferredNode Data = this->Data;
121+
reset();
122+
return Data;
123+
}
124+
125+
/// Return the opaque data of this node and reset it.
126+
OpaqueSyntaxNode takeData() {
127+
OpaqueSyntaxNode Data = this->Data.getOpaque();
128+
reset();
129+
return Data;
130+
}
131+
153132
syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); }
154133
tok getTokenKind() const { return tok(TokKind); }
155134

@@ -160,118 +139,73 @@ class ParsedRawSyntaxNode {
160139
return getTokenKind() == tokKind;
161140
}
162141

163-
bool isNull() const {
164-
return DK == DataKind::Null;
165-
}
142+
bool isNull() const { return getDataKind() == DataKind::Null; }
166143

167-
bool isRecorded() const { return DK == DataKind::Recorded; }
168-
bool isDeferredLayout() const { return DK == DataKind::DeferredLayout; }
169-
bool isDeferredToken() const { return DK == DataKind::DeferredToken; }
144+
bool isRecorded() const { return getDataKind() == DataKind::Recorded; }
145+
bool isDeferredLayout() const {
146+
return getDataKind() == DataKind::DeferredLayout;
147+
}
148+
bool isDeferredToken() const {
149+
return getDataKind() == DataKind::DeferredToken;
150+
}
170151

171152
/// Primary used for a deferred missing token.
172153
bool isMissing() const { return IsMissing; }
173154

174155
void reset() {
175-
RecordedData = {};
156+
Data = RecordedOrDeferredNode(nullptr, DataKind::Null);
176157
SynKind = uint16_t(syntax::SyntaxKind::Unknown);
177158
TokKind = uint16_t(tok::unknown);
178-
DK = DataKind::Null;
179159
IsMissing = false;
180160
}
181161

182162
ParsedRawSyntaxNode unsafeCopy() const {
183163
ParsedRawSyntaxNode copy;
184-
switch (DK) {
185-
case DataKind::DeferredLayout:
186-
copy.DeferredLayout = DeferredLayout;
187-
break;
188-
case DataKind::DeferredToken:
189-
copy.DeferredToken = DeferredToken;
190-
break;
191-
case DataKind::Recorded:
192-
copy.RecordedData = RecordedData;
193-
break;
194-
case DataKind::Null:
195-
break;
196-
}
164+
copy.Data = Data;
197165
copy.Range = Range;
198166
copy.SynKind = SynKind;
199167
copy.TokKind = TokKind;
200-
copy.DK = DK;
201168
copy.IsMissing = IsMissing;
202169
return copy;
203170
}
204171

205172
/// Returns the range of this node including leading and trailing trivia.
206173
CharSourceRange getRange() const { return Range; }
207174

208-
// Recorded Data ===========================================================//
209-
210-
const OpaqueSyntaxNode &getOpaqueNode() const {
211-
assert(isRecorded());
212-
return RecordedData.OpaqueNode;
213-
}
214-
OpaqueSyntaxNode takeOpaqueNode() {
215-
assert(isRecorded());
216-
auto opaque = RecordedData.OpaqueNode;
217-
reset();
218-
return opaque;
219-
}
220-
221175
// Deferred Layout Data ====================================================//
222176

223-
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {
224-
assert(DK == DataKind::DeferredLayout);
225-
return DeferredLayout.Children;
226-
}
177+
/// If this node is a deferred layout node, return the child at index \p
178+
/// ChildIndex.
179+
/// Note that this may be an expensive operation since the \c
180+
/// SyntaxParseAction, which created the node (implicitly passed via the
181+
/// \p SyntaxContext) needs to be consulted to retrieve the child.
182+
ParsedRawSyntaxNode
183+
getDeferredChild(size_t ChildIndex,
184+
const SyntaxParsingContext *SyntaxContext) const;
227185

228-
MutableArrayRef<ParsedRawSyntaxNode> getDeferredChildren() {
229-
assert(DK == DataKind::DeferredLayout);
230-
return DeferredLayout.Children;
231-
}
186+
size_t
187+
getDeferredNumChildren(const SyntaxParsingContext *SyntaxContext) const;
232188

233189
ParsedRawSyntaxNode copyDeferred() const {
190+
assert(isDeferredLayout() || isDeferredToken() && "node not deferred");
234191
ParsedRawSyntaxNode copy;
235-
switch (DK) {
236-
case DataKind::DeferredLayout:
237-
copy.DeferredLayout = DeferredLayout;
238-
break;
239-
case DataKind::DeferredToken:
240-
copy.DeferredToken = DeferredToken;
241-
break;
242-
default:
243-
llvm_unreachable("node not deferred");
244-
}
192+
copy.Data = Data;
245193
copy.Range = Range;
246194
copy.SynKind = SynKind;
247195
copy.TokKind = TokKind;
248-
copy.DK = DK;
249196
copy.IsMissing = IsMissing;
250197
return copy;
251198
}
252199

253-
// Deferred Token Data =====================================================//
254-
255-
CharSourceRange getDeferredTokenRange() const {
256-
assert(DK == DataKind::DeferredToken);
257-
return CharSourceRange{DeferredToken.TokLoc, DeferredToken.TokLength};
258-
}
259-
StringRef getDeferredLeadingTrivia() const {
260-
assert(DK == DataKind::DeferredToken);
261-
return DeferredToken.LeadingTrivia;
262-
}
263-
StringRef getDeferredTrailingTrivia() const {
264-
assert(DK == DataKind::DeferredToken);
265-
return DeferredToken.TrailingTrivia;
266-
}
267-
268200
//==========================================================================//
269201

270202
/// Dump this piece of syntax recursively for debugging or testing.
271203
SWIFT_DEBUG_DUMP;
272204

273-
/// Dump this piece of syntax recursively.
274-
void dump(raw_ostream &OS, unsigned Indent = 0) const;
205+
/// Dump this piece of syntax recursively. If \p Context is passed, this
206+
/// method is also able to traverse its children and dump them.
207+
void dump(raw_ostream &OS, const SyntaxParsingContext *Context = nullptr,
208+
unsigned Indent = 0) const;
275209

276210
static ParsedRawSyntaxNode null() {
277211
return ParsedRawSyntaxNode{};

include/swift/Parse/ParsedRawSyntaxRecorder.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ namespace syntax {
4141
class ParsedRawSyntaxRecorder final {
4242
std::shared_ptr<SyntaxParseActions> SPActions;
4343

44+
/// Assuming that \p node is a deferred layout or token node, record it and
45+
/// return the recorded node.
46+
/// This consumes the data from \c node, which is unusable after it has been
47+
/// recorded. The returned node should be used afterwards instead.
48+
ParsedRawSyntaxNode recordDeferredNode(ParsedRawSyntaxNode &node);
49+
4450
public:
4551
explicit ParsedRawSyntaxRecorder(std::shared_ptr<SyntaxParseActions> spActions)
4652
: SPActions(std::move(spActions)) {}
@@ -69,6 +75,10 @@ class ParsedRawSyntaxRecorder final {
6975
SourceLoc loc);
7076

7177
/// Form a deferred syntax layout node.
78+
/// All nodes in \p deferred nodes must be deferred. Otherwise, we'd have a
79+
/// deferred layout node with recorded child nodes. Should we decide to
80+
/// discard the deferred layout node, we would also need to discard its
81+
/// recorded children, which cannot be done.
7282
ParsedRawSyntaxNode
7383
makeDeferred(syntax::SyntaxKind k,
7484
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
@@ -85,9 +95,17 @@ class ParsedRawSyntaxRecorder final {
8595
ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc,
8696
syntax::SyntaxKind kind);
8797

88-
#ifndef NDEBUG
98+
/// For a deferred layout node \p parent, retrieve the deferred child node
99+
/// at \p ChildIndex.
100+
ParsedRawSyntaxNode getDeferredChild(const ParsedRawSyntaxNode &parent,
101+
size_t ChildIndex) const;
102+
103+
/// For a deferred layout node \p node, retrieve the number of children.
104+
size_t getDeferredNumChildren(const ParsedRawSyntaxNode &node) const;
105+
106+
#ifndef NDEBUG
89107
static void verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements);
90-
#endif
108+
#endif
91109
};
92110

93111
} // end namespace swift

include/swift/Parse/ParsedSyntaxNodes.h.gyb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,13 @@ public:
6262
/// ${line}
6363
% end
6464
% if child.is_optional:
65-
llvm::Optional<Parsed${child.type_name}> getDeferred${child.name}();
65+
llvm::Optional<Parsed${child.type_name}> getDeferred${child.name}(
66+
const SyntaxParsingContext *SyntaxContext
67+
);
6668
% else:
67-
Parsed${child.type_name} getDeferred${child.name}();
69+
Parsed${child.type_name} getDeferred${child.name}(
70+
const SyntaxParsingContext *SyntaxContext
71+
);
6872
% end
6973
% end
7074

0 commit comments

Comments
 (0)