Skip to content

Commit efb91f7

Browse files
committed
[libSyntax] Handle deferred node data in SyntaxParseActions
By now ParsedRawSyntaxNode does not have any knowledge about deferred node data anymore, which frees up SyntaxParseActions (and, in particular its sublass SyntaxTreeCreator) to perform optimisations to more efficiently create and record deferred nodes.
1 parent a5632b4 commit efb91f7

15 files changed

+419
-160
lines changed

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 26 additions & 66 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"
@@ -24,17 +25,6 @@ namespace swift {
2425

2526
typedef const void *OpaqueSyntaxNode;
2627
class SyntaxParsingContext;
27-
class ParsedRawSyntaxNode;
28-
29-
struct DeferredLayoutNode {
30-
MutableArrayRef<ParsedRawSyntaxNode> Children;
31-
};
32-
struct DeferredTokenNode {
33-
SourceLoc TokLoc;
34-
unsigned TokLength;
35-
StringRef LeadingTrivia;
36-
StringRef TrailingTrivia;
37-
};
3828

3929
/// Represents a raw syntax node formed by the parser.
4030
///
@@ -52,12 +42,7 @@ struct DeferredTokenNode {
5242
/// in the current parsing context.
5343
class ParsedRawSyntaxNode {
5444
friend class ParsedRawSyntaxRecorder;
55-
enum class DataKind: uint8_t {
56-
Null,
57-
Recorded,
58-
DeferredLayout,
59-
DeferredToken,
60-
};
45+
using DataKind = RecordedOrDeferredNode::Kind;
6146

6247
OpaqueSyntaxNode Data;
6348
/// The range of this node, including trivia.
@@ -83,28 +68,6 @@ class ParsedRawSyntaxNode {
8368
TokKind(uint16_t(TokKind)), DK(DK), IsMissing(IsMissing) {
8469
assert(getKind() == SynKind && "Syntax kind with too large value!");
8570
assert(getTokenKind() == TokKind && "Token kind with too large value!");
86-
assert(DK == DataKind::Recorded);
87-
}
88-
89-
ParsedRawSyntaxNode(const DeferredLayoutNode *Layout, CharSourceRange Range,
90-
syntax::SyntaxKind SynKind, tok TokKind, DataKind DK,
91-
bool IsMissing)
92-
: Data(Layout), Range(Range), SynKind(uint16_t(SynKind)),
93-
TokKind(uint16_t(TokKind)), DK(DK), IsMissing(IsMissing) {
94-
assert(getKind() == SynKind && "Syntax kind with too large value!");
95-
assert(getTokenKind() == TokKind && "Token kind with too large value!");
96-
assert(DK == DataKind::DeferredLayout);
97-
}
98-
99-
ParsedRawSyntaxNode(const DeferredTokenNode *Token, CharSourceRange Range,
100-
syntax::SyntaxKind SynKind, tok TokKind, DataKind DK,
101-
bool IsMissing)
102-
: Data(Token), Range(Range), SynKind(uint16_t(SynKind)),
103-
TokKind(uint16_t(TokKind)), DK(DK), IsMissing(IsMissing) {
104-
assert(getKind() == SynKind && "Syntax kind with too large value!");
105-
assert(getTokenKind() == TokKind && "Token kind with too large value!");
106-
assert(getKind() == syntax::SyntaxKind::Token);
107-
assert(DK == DataKind::DeferredToken);
10871
}
10972

11073
#ifndef NDEBUG
@@ -137,6 +100,22 @@ class ParsedRawSyntaxNode {
137100
assert(ensureDataIsNotRecorded() && "recorded data is being destructed");
138101
}
139102

103+
/// Returns the type of this node (recorded, deferred layout, deferred token,
104+
/// null).
105+
DataKind getDataKind() const { return DK; }
106+
107+
/// Returns the opaque data of this node. This must be interpreted by the
108+
/// \c SyntaxParseAction, which likely also needs the node type to know
109+
/// what type of node the data represents.
110+
OpaqueSyntaxNode getData() const { return Data; }
111+
112+
/// Return the opaque data of this node and reset it.
113+
OpaqueSyntaxNode takeData() {
114+
OpaqueSyntaxNode Data = this->getData();
115+
reset();
116+
return Data;
117+
}
118+
140119
syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); }
141120
tok getTokenKind() const { return tok(TokKind); }
142121

@@ -195,15 +174,14 @@ class ParsedRawSyntaxNode {
195174

196175
// Deferred Layout Data ====================================================//
197176

198-
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {
199-
assert(DK == DataKind::DeferredLayout);
200-
return static_cast<const DeferredLayoutNode *>(Data)->Children;
201-
}
202-
203-
MutableArrayRef<ParsedRawSyntaxNode> getDeferredChildren() {
204-
assert(DK == DataKind::DeferredLayout);
205-
return static_cast<const DeferredLayoutNode *>(Data)->Children;
206-
}
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;
207185

208186
ParsedRawSyntaxNode copyDeferred() const {
209187
assert(DK == DataKind::DeferredLayout ||
@@ -218,24 +196,6 @@ class ParsedRawSyntaxNode {
218196
return copy;
219197
}
220198

221-
// Deferred Token Data =====================================================//
222-
223-
CharSourceRange getDeferredTokenRange() const {
224-
assert(DK == DataKind::DeferredToken);
225-
auto DeferredToken = static_cast<const DeferredTokenNode *>(Data);
226-
return CharSourceRange{DeferredToken->TokLoc, DeferredToken->TokLength};
227-
}
228-
StringRef getDeferredLeadingTrivia() const {
229-
assert(DK == DataKind::DeferredToken);
230-
auto DeferredToken = static_cast<const DeferredTokenNode *>(Data);
231-
return DeferredToken->LeadingTrivia;
232-
}
233-
StringRef getDeferredTrailingTrivia() const {
234-
assert(DK == DataKind::DeferredToken);
235-
auto DeferredToken = static_cast<const DeferredTokenNode *>(Data);
236-
return DeferredToken->TrailingTrivia;
237-
}
238-
239199
//==========================================================================//
240200

241201
/// Dump this piece of syntax recursively for debugging or testing.

include/swift/Parse/ParsedRawSyntaxRecorder.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ 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+
ParsedRawSyntaxNode recordDeferredNode(const ParsedRawSyntaxNode &node);
47+
4448
public:
4549
explicit ParsedRawSyntaxRecorder(std::shared_ptr<SyntaxParseActions> spActions)
4650
: SPActions(std::move(spActions)) {}
@@ -69,6 +73,10 @@ class ParsedRawSyntaxRecorder final {
6973
SourceLoc loc);
7074

7175
/// Form a deferred syntax layout node.
76+
/// All nodes in \p deferred nodes must be deferred. Otherwise, we'd have a
77+
/// deferred layout node with recorded child nodes. Should we decide to
78+
/// discard the deferred layout node, we would also need to discard its
79+
/// recorded children, which cannot be done.
7280
ParsedRawSyntaxNode
7381
makeDeferred(syntax::SyntaxKind k,
7482
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
@@ -85,9 +93,14 @@ class ParsedRawSyntaxRecorder final {
8593
ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc,
8694
syntax::SyntaxKind kind);
8795

88-
#ifndef NDEBUG
96+
/// For a deferred layout node \p parent, retrieve the deferred child node
97+
/// at \p ChildIndex.
98+
ParsedRawSyntaxNode getDeferredChild(const ParsedRawSyntaxNode &parent,
99+
size_t ChildIndex) const;
100+
101+
#ifndef NDEBUG
89102
static void verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements);
90-
#endif
103+
#endif
91104
};
92105

93106
} // 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

include/swift/Parse/SyntaxParseActions.h

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
#define SWIFT_PARSE_SYNTAXPARSEACTIONS_H
2020

2121
#include "swift/Basic/LLVM.h"
22+
#include "swift/Basic/SourceLoc.h"
23+
#include "llvm/Support/Allocator.h"
2224

2325
namespace swift {
2426

25-
class CharSourceRange;
2627
class ParsedTriviaPiece;
2728
class SourceFile;
2829
class SourceLoc;
@@ -35,7 +36,54 @@ enum class SyntaxKind;
3536

3637
typedef const void *OpaqueSyntaxNode;
3738

39+
// MARK: - Helper types
40+
41+
/// A syntax node that can either be deferred or recorded. The actual data is
42+
/// opaque and needs to be interpreted by the \c SyntaxParseAction which created
43+
/// it.
44+
class RecordedOrDeferredNode {
45+
public:
46+
enum class Kind : uint8_t {
47+
Null,
48+
Recorded,
49+
DeferredLayout,
50+
DeferredToken,
51+
};
52+
53+
private:
54+
OpaqueSyntaxNode Opaque;
55+
Kind NodeKind;
56+
57+
public:
58+
RecordedOrDeferredNode(OpaqueSyntaxNode Node, Kind NodeKind)
59+
: Opaque(Node), NodeKind(NodeKind) {}
60+
61+
OpaqueSyntaxNode getOpaque() const { return Opaque; }
62+
Kind getKind() const { return NodeKind; }
63+
};
64+
65+
/// Data returned from \c getDeferredChild. This is enough data to construct
66+
/// a \c ParsedRawSyntaxNode. We don't return \c ParsedRawSyntaxNodes from
67+
/// \c getDeferredChild to maintain a clean dependency relationship of
68+
/// \c ParsedRawSyntaxNode being on a higher level than \c SyntaxParseActions.
69+
struct DeferredNodeInfo {
70+
OpaqueSyntaxNode Data;
71+
syntax::SyntaxKind SyntaxKind;
72+
tok TokenKind;
73+
bool IsMissing;
74+
CharSourceRange Range;
75+
76+
DeferredNodeInfo(OpaqueSyntaxNode Data, syntax::SyntaxKind SyntaxKind,
77+
tok TokenKind, bool IsMissing, CharSourceRange Range)
78+
: Data(Data), SyntaxKind(SyntaxKind), TokenKind(TokenKind),
79+
IsMissing(IsMissing), Range(Range) {}
80+
};
81+
82+
// MARK: - SyntaxParseActions
83+
3884
class SyntaxParseActions {
85+
llvm::BumpPtrAllocator DeferredNodeAllocator;
86+
3987
virtual void _anchor();
4088

4189
public:
@@ -52,9 +100,47 @@ class SyntaxParseActions {
52100
/// The provided \c elements are an exact layout appropriate for the syntax
53101
/// \c kind. Missing optional elements are represented with a null
54102
/// OpaqueSyntaxNode object.
55-
virtual OpaqueSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
56-
ArrayRef<OpaqueSyntaxNode> elements,
57-
CharSourceRange range) = 0;
103+
virtual OpaqueSyntaxNode
104+
recordRawSyntax(syntax::SyntaxKind kind,
105+
ArrayRef<OpaqueSyntaxNode> elements) = 0;
106+
107+
/// Create a deferred token node that may or may not be recorded later using
108+
/// \c recordDeferredToken. The \c SyntaxParseAction is responsible for
109+
/// keeping the deferred token alive until the action is destructed.
110+
virtual OpaqueSyntaxNode makeDeferredToken(tok tokenKind,
111+
StringRef leadingTrivia,
112+
StringRef trailingTrivia,
113+
CharSourceRange range,
114+
bool isMissing);
115+
116+
/// Create a deferred layout node that may or may not be recorded later using
117+
/// \c recordDeferredLayout. The \c SyntaxParseAction is responsible for
118+
/// keeping the deferred token alive until it is destructed.
119+
virtual OpaqueSyntaxNode
120+
makeDeferredLayout(syntax::SyntaxKind k, bool isMissing,
121+
const ArrayRef<RecordedOrDeferredNode> &children);
122+
123+
/// Record a deferred token node that was previously created using \c
124+
/// makeDeferredToken. The deferred data will never be used again, so it can
125+
/// be destroyed by this method. Note that not all deferred nodes will be
126+
/// recorded and that pending deferred nodes need to be freed when the \c
127+
/// SyntaxParseActions is destructed.
128+
virtual OpaqueSyntaxNode recordDeferredToken(OpaqueSyntaxNode deferred);
129+
130+
/// Record a deferred layout node. See recordDeferredToken.
131+
virtual OpaqueSyntaxNode recordDeferredLayout(OpaqueSyntaxNode deferred);
132+
133+
/// Since most data of \c ParsedRawSyntax is described as opaque data, the
134+
/// \c ParsedRawSyntax node needs to reach out to the \c SyntaxParseAction,
135+
/// which created it, to retrieve children.
136+
/// This method assumes that \p node represents a *deferred* layout node.
137+
/// This methods returns all information needed to construct a \c
138+
/// ParsedRawSyntaxNode of a child node. \p node is the parent node for which
139+
/// the child at position \p ChildIndex should be retrieved. Furthmore, \p
140+
/// node starts at \p StartLoc.
141+
virtual DeferredNodeInfo getDeferredChild(OpaqueSyntaxNode node,
142+
size_t childIndex,
143+
SourceLoc startLoc);
58144

59145
/// Attempt to realize an opaque raw syntax node for a source file into a
60146
/// SourceFileSyntax node. This will return \c None if the parsing action

include/swift/Parse/SyntaxParsingContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
255255
const SyntaxParsingContext *getRoot() const;
256256

257257
ParsedRawSyntaxRecorder &getRecorder() { return getRootData()->Recorder; }
258+
const ParsedRawSyntaxRecorder &getRecorder() const {
259+
return getRootData()->Recorder;
260+
}
258261

259262
llvm::BumpPtrAllocator &getScratchAlloc() {
260263
return getRootData()->ScratchAlloc;

include/swift/SyntaxParse/SyntaxTreeCreator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ class SyntaxTreeCreator: public SyntaxParseActions {
6464

6565
OpaqueSyntaxNode recordMissingToken(tok tokenKind, SourceLoc loc) override;
6666

67-
OpaqueSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
68-
ArrayRef<OpaqueSyntaxNode> elements,
69-
CharSourceRange range) override;
67+
OpaqueSyntaxNode
68+
recordRawSyntax(syntax::SyntaxKind kind,
69+
ArrayRef<OpaqueSyntaxNode> elements) override;
7070

7171
std::pair<size_t, OpaqueSyntaxNode>
7272
lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override;

lib/Parse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_swift_host_library(swiftParse STATIC
2222
ParseStmt.cpp
2323
ParseType.cpp
2424
PersistentParserState.cpp
25+
SyntaxParseActions.cpp
2526
SyntaxParsingCache.cpp
2627
SyntaxParsingContext.cpp)
2728
_swift_gyb_target_sources(swiftParse PRIVATE

lib/Parse/ParsePattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,7 +1263,7 @@ ParserResult<Pattern> Parser::parseMatchingPattern(bool isExprBasic) {
12631263

12641264
if (SyntaxContext->isEnabled()) {
12651265
if (auto UPES = PatternCtx.popIf<ParsedUnresolvedPatternExprSyntax>()) {
1266-
PatternCtx.addSyntax(UPES->getDeferredPattern());
1266+
PatternCtx.addSyntax(UPES->getDeferredPattern(SyntaxContext));
12671267
} else {
12681268
PatternCtx.setCreateSyntax(SyntaxKind::ExpressionPattern);
12691269
}

lib/Parse/ParseType.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,9 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
406406
if (InputNode.is<ParsedTupleTypeSyntax>()) {
407407
auto TupleTypeNode = std::move(InputNode).castTo<ParsedTupleTypeSyntax>();
408408
// Decompose TupleTypeSyntax and repack into FunctionType.
409-
auto LeftParen = TupleTypeNode.getDeferredLeftParen();
410-
auto Arguments = TupleTypeNode.getDeferredElements();
411-
auto RightParen = TupleTypeNode.getDeferredRightParen();
409+
auto LeftParen = TupleTypeNode.getDeferredLeftParen(SyntaxContext);
410+
auto Arguments = TupleTypeNode.getDeferredElements(SyntaxContext);
411+
auto RightParen = TupleTypeNode.getDeferredRightParen(SyntaxContext);
412412
Builder
413413
.useLeftParen(std::move(LeftParen))
414414
.useArguments(std::move(Arguments))

lib/Parse/ParsedRawSyntaxNode.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ using namespace swift;
1717
using namespace swift::syntax;
1818
using namespace llvm;
1919

20+
ParsedRawSyntaxNode ParsedRawSyntaxNode::getDeferredChild(
21+
size_t ChildIndex, const SyntaxParsingContext *SyntaxContext) const {
22+
assert(isDeferredLayout());
23+
return SyntaxContext->getRecorder().getDeferredChild(*this, ChildIndex);
24+
}
25+
2026
void ParsedRawSyntaxNode::dump() const {
2127
dump(llvm::errs(), /*Indent*/ 0);
2228
llvm::errs() << '\n';
@@ -42,11 +48,7 @@ void ParsedRawSyntaxNode::dump(llvm::raw_ostream &OS, unsigned Indent) const {
4248
break;
4349
case DataKind::DeferredLayout:
4450
dumpSyntaxKind(OS, getKind());
45-
OS << " [deferred]";
46-
for (const auto &child : getDeferredChildren()) {
47-
OS << "\n";
48-
child.dump(OS, Indent + 2);
49-
}
51+
OS << " [deferred layout]";
5052
break;
5153
case DataKind::DeferredToken:
5254
dumpSyntaxKind(OS, getKind());

0 commit comments

Comments
 (0)