Skip to content

Commit b55c1e2

Browse files
authored
Merge pull request #21368 from akyrtzi/syntax-parser-decoupling
[Parse/Syntax] Refactoring to decouple the parser from syntax tree creation
2 parents bd16513 + c929511 commit b55c1e2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2132
-467
lines changed

include/swift/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if(SWIFT_INCLUDE_TOOLS)
88
configure_file(Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/Config.h
99
ESCAPE_QUOTES @ONLY)
1010
add_subdirectory(Option)
11+
add_subdirectory(Parse)
1112
add_subdirectory(Syntax)
1213
endif()
1314

include/swift/Parse/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
2+
set(SWIFT_GYB_FLAGS --line-directive "^\"#line %(line)d \\\"%(file)s\\\"^\"")
3+
else()
4+
set(SWIFT_GYB_FLAGS --line-directive "\'#line" "%(line)d" "\"%(file)s\"\'")
5+
endif()
6+
7+
set(generated_include_sources
8+
ParsedSyntaxBuilders.h.gyb
9+
ParsedSyntaxNodes.h.gyb
10+
ParsedSyntaxRecorder.h.gyb
11+
)
12+
13+
add_gyb_target(swift-parse-syntax-generated-headers
14+
"${generated_include_sources}")
15+
set_property(TARGET swift-parse-syntax-generated-headers
16+
PROPERTY FOLDER "Miscellaneous")
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
//===--- ParsedRawSyntaxNode.h - Parsed Raw Syntax Node ---------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PARSE_PARSEDRAWSYNTAXNODE_H
14+
#define SWIFT_PARSE_PARSEDRAWSYNTAXNODE_H
15+
16+
#include "swift/Basic/SourceLoc.h"
17+
#include "swift/Parse/Token.h"
18+
#include "swift/Syntax/SyntaxKind.h"
19+
#include "swift/Syntax/Trivia.h"
20+
#include <vector>
21+
22+
namespace swift {
23+
24+
typedef void *OpaqueSyntaxNode;
25+
26+
/// Represents a raw syntax node formed by the parser.
27+
///
28+
/// It can be either 'recorded', in which case it encapsulates an
29+
/// \c OpaqueSyntaxNode that was returned from a \c SyntaxParseActions
30+
/// invocation, or 'deferred' which captures the data for a
31+
/// \c SyntaxParseActions invocation to occur later.
32+
///
33+
/// An \c OpaqueSyntaxNode can represent both the result of 'recording' a token
34+
/// as well as 'recording' a syntax layout, so there's only one
35+
/// \c RecordedSyntaxNode structure that can represent both.
36+
///
37+
/// The 'deferred' form is used for when the parser is backtracking and when
38+
/// there are instances that it's not clear what will be the final syntax node
39+
/// in the current parsing context.
40+
class ParsedRawSyntaxNode {
41+
enum class DataKind: uint8_t {
42+
Null,
43+
Recorded,
44+
DeferredLayout,
45+
DeferredToken,
46+
};
47+
48+
struct RecordedSyntaxNode {
49+
OpaqueSyntaxNode OpaqueNode;
50+
CharSourceRange Range;
51+
};
52+
struct DeferredLayoutNode {
53+
std::vector<ParsedRawSyntaxNode> Children;
54+
};
55+
struct DeferredTokenNode {
56+
Token Tok;
57+
syntax::Trivia LeadingTrivia;
58+
syntax::Trivia TrailingTrivia;
59+
};
60+
61+
union {
62+
RecordedSyntaxNode RecordedData;
63+
DeferredLayoutNode DeferredLayout;
64+
DeferredTokenNode DeferredToken;
65+
};
66+
uint16_t SynKind;
67+
uint16_t TokKind;
68+
DataKind DK;
69+
/// Primary used for capturing a deferred missing token.
70+
bool IsMissing = false;
71+
72+
ParsedRawSyntaxNode(syntax::SyntaxKind k,
73+
ArrayRef<ParsedRawSyntaxNode> deferredNodes)
74+
: DeferredLayout{deferredNodes},
75+
SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)),
76+
DK(DataKind::DeferredLayout) {
77+
assert(getKind() == k && "Syntax kind with too large value!");
78+
}
79+
80+
ParsedRawSyntaxNode(Token tok,
81+
syntax::Trivia leadingTrivia,
82+
syntax::Trivia trailingTrivia)
83+
: DeferredToken{std::move(tok),
84+
std::move(leadingTrivia),
85+
std::move(trailingTrivia)},
86+
SynKind(uint16_t(syntax::SyntaxKind::Token)),
87+
TokKind(uint16_t(tok.getKind())),
88+
DK(DataKind::DeferredToken) {
89+
assert(getTokenKind() == tok.getKind() && "Token kind is too large value!");
90+
}
91+
92+
public:
93+
ParsedRawSyntaxNode()
94+
: RecordedData{},
95+
SynKind(uint16_t(syntax::SyntaxKind::Unknown)),
96+
TokKind(uint16_t(tok::unknown)),
97+
DK(DataKind::Null) {
98+
}
99+
100+
ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind,
101+
CharSourceRange r, OpaqueSyntaxNode n)
102+
: RecordedData{n, r},
103+
SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)),
104+
DK(DataKind::Recorded) {
105+
assert(getKind() == k && "Syntax kind with too large value!");
106+
assert(getTokenKind() == tokKind && "Token kind with too large value!");
107+
}
108+
109+
ParsedRawSyntaxNode(const ParsedRawSyntaxNode &other) {
110+
switch (other.DK) {
111+
case DataKind::Null:
112+
break;
113+
case DataKind::Recorded:
114+
new(&this->RecordedData)RecordedSyntaxNode(other.RecordedData);
115+
break;
116+
case DataKind::DeferredLayout:
117+
new(&this->DeferredLayout)DeferredLayoutNode(other.DeferredLayout);
118+
break;
119+
case DataKind::DeferredToken:
120+
new(&this->DeferredToken)DeferredTokenNode(other.DeferredToken);
121+
break;
122+
}
123+
this->SynKind = other.SynKind;
124+
this->TokKind = other.TokKind;
125+
this->DK = other.DK;
126+
}
127+
128+
ParsedRawSyntaxNode(ParsedRawSyntaxNode &&other) {
129+
switch (other.DK) {
130+
case DataKind::Null:
131+
break;
132+
case DataKind::Recorded:
133+
new(&this->RecordedData)RecordedSyntaxNode(
134+
std::move(other.RecordedData));
135+
break;
136+
case DataKind::DeferredLayout:
137+
new(&this->DeferredLayout)DeferredLayoutNode(
138+
std::move(other.DeferredLayout));
139+
break;
140+
case DataKind::DeferredToken:
141+
new(&this->DeferredToken)DeferredTokenNode(
142+
std::move(other.DeferredToken));
143+
break;
144+
}
145+
this->SynKind = other.SynKind;
146+
this->TokKind = other.TokKind;
147+
this->DK = other.DK;
148+
}
149+
150+
~ParsedRawSyntaxNode() {
151+
releaseMemory();
152+
}
153+
154+
ParsedRawSyntaxNode &operator=(const ParsedRawSyntaxNode &other) {
155+
releaseMemory();
156+
new (this)ParsedRawSyntaxNode(other);
157+
return *this;
158+
}
159+
160+
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) {
161+
releaseMemory();
162+
new (this)ParsedRawSyntaxNode(std::move(other));
163+
return *this;
164+
}
165+
166+
syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); }
167+
tok getTokenKind() const { return tok(TokKind); }
168+
169+
bool isToken() const {
170+
return getKind() == syntax::SyntaxKind::Token;
171+
}
172+
bool isToken(tok tokKind) const {
173+
return getTokenKind() == tokKind;
174+
}
175+
176+
bool isNull() const {
177+
return DK == DataKind::Null;
178+
}
179+
180+
bool isRecorded() const { return DK == DataKind::Recorded; }
181+
bool isDeferredLayout() const { return DK == DataKind::DeferredLayout; }
182+
bool isDeferredToken() const { return DK == DataKind::DeferredToken; }
183+
184+
/// Primary used for a deferred missing token.
185+
bool isMissing() const { return IsMissing; }
186+
187+
// Recorded Data ===========================================================//
188+
189+
CharSourceRange getRange() const {
190+
assert(isRecorded());
191+
return RecordedData.Range;
192+
}
193+
OpaqueSyntaxNode getOpaqueNode() const {
194+
assert(isRecorded());
195+
return RecordedData.OpaqueNode;
196+
}
197+
198+
// Deferred Layout Data ====================================================//
199+
200+
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {
201+
assert(DK == DataKind::DeferredLayout);
202+
return DeferredLayout.Children;
203+
}
204+
void addDeferredChild(ParsedRawSyntaxNode subnode) {
205+
assert(DK == DataKind::DeferredLayout);
206+
DeferredLayout.Children.push_back(std::move(subnode));
207+
}
208+
209+
// Deferred Token Data =====================================================//
210+
211+
const Token &getToken() const {
212+
assert(DK == DataKind::DeferredToken);
213+
return DeferredToken.Tok;
214+
}
215+
const syntax::Trivia &getLeadingTrivia() const {
216+
assert(DK == DataKind::DeferredToken);
217+
return DeferredToken.LeadingTrivia;
218+
}
219+
const syntax::Trivia &getTrailingTrivia() const {
220+
assert(DK == DataKind::DeferredToken);
221+
return DeferredToken.TrailingTrivia;
222+
}
223+
224+
//==========================================================================//
225+
226+
/// Form a deferred syntax layout node.
227+
static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k,
228+
ArrayRef<ParsedRawSyntaxNode> deferredNodes) {
229+
return ParsedRawSyntaxNode{k, deferredNodes};
230+
}
231+
232+
/// Form a deferred token node.
233+
static ParsedRawSyntaxNode makeDeferred(Token tok,
234+
syntax::Trivia leadingTrivia,
235+
syntax::Trivia trailingTrivia) {
236+
return ParsedRawSyntaxNode{std::move(tok), std::move(leadingTrivia),
237+
std::move(trailingTrivia)};
238+
}
239+
240+
/// Form a deferred missing token node.
241+
static ParsedRawSyntaxNode makeDeferredMissing(tok tokKind, SourceLoc loc);
242+
243+
/// Dump this piece of syntax recursively for debugging or testing.
244+
LLVM_ATTRIBUTE_DEPRECATED(
245+
void dump() const LLVM_ATTRIBUTE_USED,
246+
"only for use within the debugger");
247+
248+
/// Dump this piece of syntax recursively.
249+
void dump(raw_ostream &OS, unsigned Indent = 0) const;
250+
251+
static ParsedRawSyntaxNode null() {
252+
return ParsedRawSyntaxNode{};
253+
}
254+
255+
private:
256+
void releaseMemory() {
257+
switch (DK) {
258+
case DataKind::Null:
259+
break;
260+
case DataKind::Recorded:
261+
RecordedData.~RecordedSyntaxNode(); break;
262+
case DataKind::DeferredLayout:
263+
DeferredLayout.~DeferredLayoutNode(); break;
264+
case DataKind::DeferredToken:
265+
DeferredToken.~DeferredTokenNode(); break;
266+
}
267+
}
268+
};
269+
270+
} // end namespace swift
271+
272+
#endif
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===--- ParsedRawSyntaxRecorder.h - Raw Syntax Parsing Recorder ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the ParsedRawSyntaxRecorder, which is the interface the
14+
// parser is using to pass parsed syntactic elements to a SyntaxParseActions
15+
// receiver and get a ParsedRawSyntaxNode object back.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_PARSE_PARSEDRAWSYNTAXRECORDER_H
20+
#define SWIFT_PARSE_PARSEDRAWSYNTAXRECORDER_H
21+
22+
#include "swift/Basic/LLVM.h"
23+
#include <memory>
24+
25+
namespace swift {
26+
27+
class ParsedRawSyntaxNode;
28+
class SyntaxParseActions;
29+
class SourceLoc;
30+
class Token;
31+
enum class tok;
32+
33+
namespace syntax {
34+
enum class SyntaxKind;
35+
struct Trivia;
36+
}
37+
38+
class ParsedRawSyntaxRecorder {
39+
std::shared_ptr<SyntaxParseActions> SPActions;
40+
41+
public:
42+
explicit ParsedRawSyntaxRecorder(std::shared_ptr<SyntaxParseActions> spActions)
43+
: SPActions(std::move(spActions)) {}
44+
45+
ParsedRawSyntaxNode recordToken(const Token &tok,
46+
const syntax::Trivia &leadingTrivia,
47+
const syntax::Trivia &trailingTrivia);
48+
49+
/// Record a missing token. \p loc can be invalid or an approximate location
50+
/// of where the token would be if not missing.
51+
ParsedRawSyntaxNode recordMissingToken(tok tokenKind, SourceLoc loc);
52+
53+
/// The provided \p elements are an exact layout appropriate for the syntax
54+
/// \p kind. Missing optional elements are represented with a null
55+
/// ParsedRawSyntaxNode object.
56+
ParsedRawSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
57+
ArrayRef<ParsedRawSyntaxNode> elements);
58+
59+
/// Record a raw syntax collecton without eny elements. \p loc can be invalid
60+
/// or an approximate location of where an element of the collection would be
61+
/// if not missing.
62+
ParsedRawSyntaxNode recordEmptyRawSyntaxCollection(syntax::SyntaxKind kind,
63+
SourceLoc loc);
64+
65+
/// Used for incremental re-parsing.
66+
ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc,
67+
syntax::SyntaxKind kind);
68+
};
69+
70+
} // end namespace swift
71+
72+
#endif // SWIFT_PARSE_PARSEDRAWSYNTAXRECORDER_H

0 commit comments

Comments
 (0)