Skip to content

Commit 44d7769

Browse files
author
Jan Svoboda
committed
[Parser] Decouple the parser from AST creation (part 1)
Instead of creating the AST directly in the parser (and libSyntax or SwiftSyntax via SyntaxParsingContext), make Parser to explicitly create a tree of ParsedSyntaxNodes. Their OpaqueSyntaxNodes can be either libSyntax or SwiftSyntax. If AST is needed, it can be generated from the libSyntax tree.
1 parent b2fd31d commit 44d7769

23 files changed

+903
-307
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//===--- HiddenLibSyntaxAction.h ------------------------------------------===//
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_HIDDENLIBSYNTAXACTION_H
14+
#define SWIFT_PARSE_HIDDENLIBSYNTAXACTION_H
15+
16+
#include "swift/Parse/SyntaxParseActions.h"
17+
#include "swift/SyntaxParse/SyntaxTreeCreator.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
20+
namespace swift {
21+
/// Holds an explicitly provided action and uses it to handle all function
22+
/// calls. Also hides an implicit SyntaxTreeCreator and ensures libSyntax nodes
23+
/// are always created. Provides an interface to map results of the explicitly
24+
/// provided action to the hidden libSyntax action.
25+
// todo [gsoc]: remove when possible
26+
class HiddenLibSyntaxAction : public SyntaxParseActions {
27+
std::shared_ptr<SyntaxParseActions> ExplicitAction;
28+
std::shared_ptr<SyntaxTreeCreator> LibSyntaxAction;
29+
llvm::DenseMap<OpaqueSyntaxNode, OpaqueSyntaxNode> OpaqueNodeMap;
30+
31+
bool areBothLibSyntax() {
32+
return ExplicitAction->getOpaqueKind() == OpaqueSyntaxNodeKind::LibSyntax;
33+
}
34+
35+
public:
36+
HiddenLibSyntaxAction(
37+
const std::shared_ptr<SyntaxParseActions> &SPActions,
38+
const std::shared_ptr<SyntaxTreeCreator> &LibSyntaxAction)
39+
: ExplicitAction(SPActions != nullptr ? SPActions : LibSyntaxAction),
40+
LibSyntaxAction(LibSyntaxAction){};
41+
42+
OpaqueSyntaxNode recordToken(tok tokenKind,
43+
ArrayRef<ParsedTriviaPiece> leadingTrivia,
44+
ArrayRef<ParsedTriviaPiece> trailingTrivia,
45+
CharSourceRange range) override;
46+
47+
OpaqueSyntaxNode recordMissingToken(tok tokenKind, SourceLoc loc) override;
48+
49+
OpaqueSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
50+
ArrayRef<OpaqueSyntaxNode> elements,
51+
CharSourceRange range) override;
52+
53+
std::pair<size_t, OpaqueSyntaxNode>
54+
lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) override;
55+
56+
OpaqueSyntaxNodeKind getOpaqueKind() override {
57+
return ExplicitAction->getOpaqueKind();
58+
}
59+
60+
/// Returns the libSyntax node corresponding to the provided node that has
61+
/// been created by the explicit action.
62+
OpaqueSyntaxNode getLibSyntaxNodeFor(OpaqueSyntaxNode explicitNode);
63+
64+
/// Returns the underlying libSyntax SyntaxTreeCreator.
65+
std::shared_ptr<SyntaxTreeCreator> getLibSyntaxAction() {
66+
return LibSyntaxAction;
67+
}
68+
};
69+
} // namespace swift
70+
71+
#endif // SWIFT_PARSE_HIDDENLIBSYNTAXACTION_H
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===----------- LibSyntaxGenerator.h -------------------------------------===//
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_LIBSYNTAXGENERATOR_H
14+
#define SWIFT_PARSE_LIBSYNTAXGENERATOR_H
15+
16+
#include "swift/Parse/HiddenLibSyntaxAction.h"
17+
#include "swift/Parse/ParsedRawSyntaxNode.h"
18+
#include "swift/Parse/ParsedRawSyntaxRecorder.h"
19+
#include "swift/Parse/SyntaxParsingCache.h"
20+
#include "swift/Syntax/RawSyntax.h"
21+
#include "swift/SyntaxParse/SyntaxTreeCreator.h"
22+
23+
namespace swift {
24+
/// Generates libSyntax nodes either by looking them up using
25+
/// HiddenLibSyntaxAction (based on provided OpaqueSyntaxNode) or by recording
26+
/// them with ParsedRawSyntaxRecorder.
27+
// todo [gsoc]: remove when possible
28+
class LibSyntaxGenerator {
29+
std::shared_ptr<HiddenLibSyntaxAction> Actions;
30+
ParsedRawSyntaxRecorder Recorder;
31+
32+
public:
33+
explicit LibSyntaxGenerator(std::shared_ptr<HiddenLibSyntaxAction> TwoActions)
34+
: Actions(std::move(TwoActions)),
35+
Recorder(Actions->getLibSyntaxAction()) {}
36+
37+
TokenSyntax createToken(ParsedRawSyntaxNode Node) {
38+
assert(Node.isDeferredToken());
39+
40+
auto Kind = Node.getTokenKind();
41+
auto Range = Node.getDeferredTokenRangeWithTrivia();
42+
auto LeadingTriviaPieces = Node.getDeferredLeadingTriviaPieces();
43+
auto TrailingTriviaPieces = Node.getDeferredTrailingTriviaPieces();
44+
45+
auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces,
46+
TrailingTriviaPieces);
47+
auto Raw = static_cast<RawSyntax *>(Recorded.getOpaqueNode());
48+
return make<TokenSyntax>(Raw);
49+
}
50+
51+
template <typename SyntaxNode>
52+
SyntaxNode createNode(ParsedRawSyntaxNode Node) {
53+
assert(Node.isDeferredLayout());
54+
auto Kind = Node.getKind();
55+
auto Children = Node.getDeferredChildren();
56+
57+
auto Recorded = Recorder.recordRawSyntax(Kind, Children);
58+
auto Raw = static_cast<RawSyntax *>(Recorded.getOpaqueNode());
59+
return make<SyntaxNode>(Raw);
60+
}
61+
62+
TokenSyntax getLibSyntaxTokenFor(OpaqueSyntaxNode Node) {
63+
return getLibSyntaxNodeFor<TokenSyntax>(Node);
64+
}
65+
66+
template <typename SyntaxNode>
67+
SyntaxNode getLibSyntaxNodeFor(OpaqueSyntaxNode Node) {
68+
auto Raw = static_cast<RawSyntax *>(Actions->getLibSyntaxNodeFor(Node));
69+
return make<SyntaxNode>(Raw);
70+
}
71+
};
72+
} // namespace swift
73+
74+
#endif // SWIFT_PARSE_LIBSYNTAXGENERATOR_H

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,19 @@ class ParsedRawSyntaxNode {
156156

157157
// Deferred Token Data =====================================================//
158158

159+
CharSourceRange getDeferredTokenRangeWithTrivia() const {
160+
assert(DK == DataKind::DeferredToken);
161+
auto leadTriviaPieces = getDeferredLeadingTriviaPieces();
162+
auto trailTriviaPieces = getDeferredTrailingTriviaPieces();
163+
164+
auto leadTriviaLen = ParsedTriviaPiece::getTotalLength(leadTriviaPieces);
165+
auto trailTriviaLen = ParsedTriviaPiece::getTotalLength(trailTriviaPieces);
166+
167+
SourceLoc begin = DeferredToken.TokLoc.getAdvancedLoc(-leadTriviaLen);
168+
unsigned len = leadTriviaLen + DeferredToken.TokLength + trailTriviaLen;
169+
170+
return CharSourceRange{begin, len};
171+
}
159172
CharSourceRange getDeferredTokenRangeWithoutBackticks() const {
160173
assert(DK == DataKind::DeferredToken);
161174
return CharSourceRange{DeferredToken.TokLoc, DeferredToken.TokLength};

include/swift/Parse/ParsedSyntaxRecorder.h.gyb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,31 @@ public:
6666

6767
static Parsed${node.name} makeBlank${node.syntax_kind}(SourceLoc loc,
6868
SyntaxParsingContext &SPCtx);
69+
% elif node.is_unknown():
70+
private:
71+
static Parsed${node.name} record${node.syntax_kind}(
72+
ArrayRef<ParsedSyntax> elts,
73+
ParsedRawSyntaxRecorder &rec);
74+
75+
public:
76+
static Parsed${node.name} defer${node.syntax_kind}(
77+
ArrayRef<ParsedSyntax> elts,
78+
SyntaxParsingContext &SPCtx);
79+
80+
static Parsed${node.name} make${node.syntax_kind}(
81+
ArrayRef<ParsedSyntax> elts,
82+
SyntaxParsingContext &SPCtx);
6983
% end
7084
% end
7185

7286
#pragma mark - Convenience APIs
7387

88+
public:
89+
static ParsedTokenSyntax makeToken(const Token &Tok,
90+
const ParsedTrivia &LeadingTrivia,
91+
const ParsedTrivia &TrailingTrivia,
92+
SyntaxParsingContext &SPCtx);
93+
7494
/// Records an unlabelled TupleTypeElementSyntax with the provided type and
7595
/// optional trailing comma.
7696
static ParsedTupleTypeElementSyntax

include/swift/Parse/Parser.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
#include "swift/Parse/LocalContext.h"
3030
#include "swift/Parse/PersistentParserState.h"
3131
#include "swift/Parse/Token.h"
32+
#include "swift/Parse/ParsedSyntaxNodes.h"
3233
#include "swift/Parse/ParserPosition.h"
3334
#include "swift/Parse/ParserResult.h"
3435
#include "swift/Parse/SyntaxParserResult.h"
3536
#include "swift/Parse/SyntaxParsingContext.h"
37+
#include "swift/Parse/SyntaxTransformer.h"
3638
#include "swift/Syntax/References.h"
3739
#include "swift/Config.h"
3840
#include "llvm/ADT/SetVector.h"
@@ -376,6 +378,9 @@ class Parser {
376378
/// Current syntax parsing context where call backs should be directed to.
377379
SyntaxParsingContext *SyntaxContext;
378380

381+
/// The libSyntax to AST transformer.
382+
SyntaxTransformer Transformer;
383+
379384
public:
380385
Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
381386
SILParserTUStateBase *SIL,
@@ -518,6 +523,12 @@ class Parser {
518523
assert(Tok.is(K) && "Consuming wrong token kind");
519524
return consumeToken();
520525
}
526+
/// Consume a token without providing it to the SyntaxParsingContext.
527+
ParsedTokenSyntax consumeTokenSyntax();
528+
ParsedTokenSyntax consumeTokenSyntax(tok K) {
529+
assert(Tok.is(K) && "Consuming wrong token kind");
530+
return consumeTokenSyntax();
531+
}
521532

522533
SourceLoc consumeIdentifier(Identifier *Result = nullptr,
523534
bool allowDollarIdentifier = false) {
@@ -1321,6 +1332,15 @@ class Parser {
13211332
ParserResult<Expr> parseExprSuper();
13221333
ParserResult<Expr> parseExprStringLiteral();
13231334

1335+
// todo [gsoc]: create new result type for ParsedSyntax
1336+
// todo [gsoc]: turn into proper non-templated methods later
1337+
template <typename SyntaxNode>
1338+
ParsedExprSyntax parseExprSyntax();
1339+
1340+
// todo [gsoc]: remove when possible
1341+
template <typename SyntaxNode>
1342+
ParserResult<Expr> parseExprAST();
1343+
13241344
StringRef copyAndStripUnderscores(StringRef text);
13251345

13261346
ParserStatus parseStringSegments(SmallVectorImpl<Lexer::StringSegment> &Segments,

include/swift/Parse/SyntaxParseActions.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ namespace syntax {
3333

3434
typedef void *OpaqueSyntaxNode;
3535

36+
// todo [gsoc]: remove when possible
37+
enum class OpaqueSyntaxNodeKind {
38+
SwiftSyntax,
39+
LibSyntax,
40+
};
41+
3642
class SyntaxParseActions {
3743
virtual void _anchor();
3844

@@ -60,6 +66,9 @@ class SyntaxParseActions {
6066
lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) {
6167
return std::make_pair(0, nullptr);
6268
}
69+
70+
/// Returns what kind of OpaqueSyntaxNode is created by `recordXXX` methods.
71+
virtual OpaqueSyntaxNodeKind getOpaqueKind() = 0;
6372
};
6473

6574
} // end namespace swift

include/swift/Parse/SyntaxParsingContext.h

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515

1616
#include "llvm/ADT/PointerUnion.h"
1717
#include "swift/Basic/SourceLoc.h"
18+
#include "swift/Parse/HiddenLibSyntaxAction.h"
19+
#include "swift/Parse/LibSyntaxGenerator.h"
1820
#include "swift/Parse/ParsedRawSyntaxNode.h"
1921
#include "swift/Parse/ParsedRawSyntaxRecorder.h"
22+
#include "swift/Parse/ParsedSyntaxNodes.h"
2023

2124
namespace swift {
2225

@@ -74,6 +77,7 @@ constexpr size_t SyntaxAlignInBits = 3;
7477
/// // Now the context holds { '(' Expr ')' }.
7578
/// // From these parts, it creates ParenExpr node and add it to the parent.
7679
/// }
80+
// todo [gsoc]: remove when/if possible
7781
class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
7882
public:
7983
/// The shared data for all syntax parsing contexts with the same root.
@@ -94,13 +98,15 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
9498

9599
ParsedRawSyntaxRecorder Recorder;
96100

101+
LibSyntaxGenerator LibSyntaxCreator;
102+
97103
llvm::BumpPtrAllocator ScratchAlloc;
98104

99105
RootContextData(SourceFile &SF, DiagnosticEngine &Diags,
100106
SourceManager &SourceMgr, unsigned BufferID,
101-
std::shared_ptr<SyntaxParseActions> spActions)
107+
const std::shared_ptr<HiddenLibSyntaxAction>& TwoActions)
102108
: SF(SF), Diags(Diags), SourceMgr(SourceMgr), BufferID(BufferID),
103-
Recorder(std::move(spActions)) {}
109+
Recorder(TwoActions), LibSyntaxCreator(TwoActions) {}
104110
};
105111

106112
private:
@@ -162,9 +168,6 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
162168
/// true if it's in backtracking context.
163169
bool IsBacktracking = false;
164170

165-
// If false, context does nothing.
166-
bool Enabled;
167-
168171
/// Create a syntax node using the tail \c N elements of collected parts and
169172
/// replace those parts with the single result.
170173
void createNodeInPlace(SyntaxKind Kind, size_t N,
@@ -182,18 +185,19 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
182185
Optional<ParsedRawSyntaxNode> bridgeAs(SyntaxContextKind Kind,
183186
ArrayRef<ParsedRawSyntaxNode> Parts);
184187

188+
ParsedRawSyntaxNode finalizeSourceFile();
189+
185190
public:
186191
/// Construct root context.
187192
SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder, SourceFile &SF,
188193
unsigned BufferID,
189-
std::shared_ptr<SyntaxParseActions> SPActions);
194+
std::shared_ptr<HiddenLibSyntaxAction> SPActions);
190195

191196
/// Designated constructor for child context.
192197
SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder)
193198
: RootDataOrParent(CtxtHolder), CtxtHolder(CtxtHolder),
194199
RootData(CtxtHolder->RootData), Offset(RootData->Storage.size()),
195-
IsBacktracking(CtxtHolder->IsBacktracking),
196-
Enabled(CtxtHolder->isEnabled()) {
200+
IsBacktracking(CtxtHolder->IsBacktracking) {
197201
assert(CtxtHolder->isTopOfContextStack() &&
198202
"SyntaxParsingContext cannot have multiple children");
199203
assert(CtxtHolder->Mode != AccumulationMode::SkippedForIncrementalUpdate &&
@@ -221,8 +225,6 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
221225
/// offset. If nothing is found \c 0 is returned.
222226
size_t lookupNode(size_t LexerOffset, SourceLoc Loc);
223227

224-
void disable() { Enabled = false; }
225-
bool isEnabled() const { return Enabled; }
226228
bool isRoot() const { return RootDataOrParent.is<RootContextData*>(); }
227229
bool isTopOfContextStack() const { return this == CtxtHolder; }
228230

@@ -240,6 +242,10 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
240242
return getRootData()->Storage;
241243
}
242244

245+
LibSyntaxGenerator &getSyntaxCreator() {
246+
return getRootData()->LibSyntaxCreator;
247+
}
248+
243249
const SyntaxParsingContext *getRoot() const;
244250

245251
ParsedRawSyntaxRecorder &getRecorder() { return getRootData()->Recorder; }
@@ -258,6 +264,21 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
258264
/// Add Syntax to the parts.
259265
void addSyntax(ParsedSyntax Node);
260266

267+
template <SyntaxKind Kind>
268+
bool isTopNode() {
269+
return getStorage().back().getKind() == Kind;
270+
}
271+
272+
/// Returns the topmost Syntax node.
273+
template <typename SyntaxNode> SyntaxNode topNode() {
274+
ParsedRawSyntaxNode TopNode = getStorage().back();
275+
276+
if (IsBacktracking)
277+
return getSyntaxCreator().createNode<SyntaxNode>(TopNode);
278+
279+
OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode();
280+
return getSyntaxCreator().getLibSyntaxNodeFor<SyntaxNode>(OpaqueNode);
281+
}
261282

262283
template<typename SyntaxNode>
263284
llvm::Optional<SyntaxNode> popIf() {
@@ -300,6 +321,11 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext {
300321
SynKind = Kind;
301322
}
302323

324+
/// On destruction, do not attempt to finalize the root node.
325+
void setDiscard() {
326+
Mode = AccumulationMode::Discard;
327+
}
328+
303329
/// On destruction, if the parts size is 1 and it's kind of \c Kind, just
304330
/// append it to the parent context. Otherwise, create Unknown{Kind} node from
305331
/// the collected parts.

0 commit comments

Comments
 (0)