Skip to content

Commit d339985

Browse files
committed
Hold on to the SwiftSyntax source file parsed by ASTGen.
Rework the ASTGen interface to split apart parsing a source file, turning the top-level declarations from that source file into C++ AST nodes, and then deallocating that source file. Hold on to the source file in the C++ SourceFile abstraction so we can query it later if we need to. And we will need to.
1 parent 1ebcd13 commit d339985

File tree

3 files changed

+106
-20
lines changed

3 files changed

+106
-20
lines changed

include/swift/AST/SourceFile.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ class SourceFile final : public FileUnit {
316316
/// this source file.
317317
llvm::SmallVector<Located<StringRef>, 0> VirtualFilePaths;
318318

319+
/// The \c ExportedSourceFile instance produced by ASTGen, which includes
320+
/// the SourceFileSyntax node corresponding to this source file.
321+
void *exportedSourceFile = nullptr;
322+
319323
/// Returns information about the file paths used for diagnostics and magic
320324
/// identifiers in this source file, including virtual filenames introduced by
321325
/// \c #sourceLocation(file:) declarations.

lib/ASTGen/Sources/ASTGen/ASTGen.swift

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ extension UnsafePointer {
1717
}
1818
}
1919

20-
/// Little utility wrapper that lets us
20+
/// Little utility wrapper that lets us have some mutable state within
21+
/// immutable structs, and is therefore pretty evil.
2122
@propertyWrapper
2223
class Boxed<Value> {
2324
var wrappedValue: Value
@@ -29,7 +30,7 @@ class Boxed<Value> {
2930

3031
struct ASTGenVisitor: SyntaxTransformVisitor {
3132
let ctx: UnsafeMutableRawPointer
32-
let base: UnsafePointer<CChar>
33+
let base: UnsafePointer<UInt8>
3334

3435
@Boxed var declContext: UnsafeMutableRawPointer
3536

@@ -68,15 +69,65 @@ struct ASTGenVisitor: SyntaxTransformVisitor {
6869
}
6970
}
7071

71-
@_cdecl("parseTopLevelSwift")
72-
public func parseTopLevelSwift(
73-
buffer: UnsafePointer<CChar>, dc: UnsafeMutableRawPointer,
74-
ctx: UnsafeMutableRawPointer,
75-
outputContext: UnsafeMutableRawPointer,
76-
callback: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Void
72+
/// Describes a source file that has been "exported" to the C++ part of the
73+
/// compiler, with enough information to interface with the C++ layer.
74+
struct ExportedSourceFile {
75+
/// The underlying buffer within the C++ SourceManager, which is used
76+
/// for computations of source locations.
77+
let buffer: UnsafeBufferPointer<UInt8>
78+
79+
/// The name of the enclosing module.
80+
let moduleName: String
81+
82+
/// The name of the source file being parsed.
83+
let fileName: String
84+
85+
/// The syntax tree for the complete source file.
86+
let syntax: SourceFileSyntax
87+
}
88+
89+
/// Parses the given source file and produces a pointer to a new
90+
/// ExportedSourceFile instance.
91+
@_cdecl("swift_ASTGen_parseSourceFile")
92+
public func parseSourceFile(
93+
buffer: UnsafePointer<UInt8>, bufferLength: Int,
94+
moduleName: UnsafePointer<UInt8>, filename: UnsafePointer<UInt8>
95+
) -> UnsafeRawPointer {
96+
let buffer = UnsafeBufferPointer(start: buffer, count: bufferLength)
97+
let sourceFile = Parser.parse(source: buffer)
98+
99+
let exportedPtr = UnsafeMutablePointer<ExportedSourceFile>.allocate(capacity: 1)
100+
exportedPtr.initialize(to: .init(
101+
buffer: buffer, moduleName: String(cString: moduleName),
102+
fileName: String(cString: filename), syntax: sourceFile)
103+
)
104+
105+
return UnsafeRawPointer(exportedPtr)
106+
}
107+
108+
/// Deallocate a parsed source file.
109+
@_cdecl("swift_ASTGen_destroySourceFile")
110+
public func destroySourceFile(
111+
sourceFilePtr: UnsafeMutableRawPointer
77112
) {
78-
let syntax = try! Parser.parse(source: String(cString: buffer))
79-
ASTGenVisitor(ctx: ctx, base: buffer, declContext: dc)
80-
.visit(syntax)
81-
.forEach { callback($0, outputContext) }
113+
sourceFilePtr.withMemoryRebound(to: ExportedSourceFile.self, capacity: 1) { sourceFile in
114+
sourceFile.deinitialize(count: 1)
115+
sourceFile.deallocate()
116+
}
117+
}
118+
119+
/// Generate AST nodes for all top-level entities in the given source file.
120+
@_cdecl("swift_ASTGen_buildTopLevelASTNodes")
121+
public func buildTopLevelASTNodes(
122+
sourceFilePtr: UnsafeRawPointer,
123+
dc: UnsafeMutableRawPointer,
124+
ctx: UnsafeMutableRawPointer,
125+
outputContext: UnsafeMutableRawPointer,
126+
callback: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Void
127+
) {
128+
sourceFilePtr.withMemoryRebound(to: ExportedSourceFile.self, capacity: 1) { sourceFile in
129+
ASTGenVisitor(ctx: ctx, base: sourceFile.pointee.buffer.baseAddress!, declContext: dc)
130+
.visit(sourceFile.pointee.syntax)
131+
.forEach { callback($0, outputContext) }
132+
}
82133
}

lib/Parse/ParseDecl.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ static void appendToVector(void *declPtr, void *vecPtr) {
173173
vec->push_back(decl);
174174
}
175175

176+
/// Parse a source file.
177+
extern "C" void *swift_ASTGen_parseSourceFile(const char *buffer,
178+
size_t bufferLength,
179+
const char *moduleName,
180+
const char *filename);
181+
182+
/// Destroy a source file parsed with swift_ASTGen_parseSourceFile.
183+
extern "C" void swift_ASTGen_destroySourceFile(void *sourceFile);
184+
185+
// Build AST nodes for the top-level entities in the syntax.
186+
extern "C" void swift_ASTGen_buildTopLevelASTNodes(void *sourceFile,
187+
void *declContext,
188+
void *astContext,
189+
void *outputContext,
190+
void (*)(void *, void *));
191+
176192
/// Main entrypoint for the parser.
177193
///
178194
/// \verbatim
@@ -182,20 +198,35 @@ static void appendToVector(void *declPtr, void *vecPtr) {
182198
/// decl-sil-stage [[only in SIL mode]
183199
/// \endverbatim
184200
void Parser::parseTopLevel(SmallVectorImpl<Decl *> &decls) {
185-
StringRef contents =
186-
SourceMgr.extractText(SourceMgr.getRangeForBuffer(L->getBufferID()));
187-
188201
#ifdef SWIFT_SWIFT_PARSER
189202
if (Context.LangOpts.hasFeature(Feature::ParserASTGen) &&
190203
!SourceMgr.hasCodeCompletionBuffer() &&
191204
SF.Kind != SourceFileKind::SIL) {
192-
parseTopLevelSwift(contents.data(), CurDeclContext, &Context, &decls, appendToVector);
205+
StringRef contents =
206+
SourceMgr.extractText(SourceMgr.getRangeForBuffer(L->getBufferID()));
207+
208+
// Parse the source file.
209+
auto exportedSourceFile = swift_ASTGen_parseSourceFile(
210+
contents.begin(), contents.size(),
211+
SF.getParentModule()->getName().str().str().c_str(),
212+
SF.getFilename().str().c_str());
213+
SF.exportedSourceFile = exportedSourceFile;
214+
Context.addCleanup([exportedSourceFile] {
215+
swift_ASTGen_destroySourceFile(exportedSourceFile);
216+
});
193217

194-
// Spin the C++ parser to the end; we won't be using it.
195-
while (!Tok.is(tok::eof)) {
196-
consumeToken();
218+
// If we want to do ASTGen, do so now.
219+
if (Context.LangOpts.hasFeature(Feature::ParserASTGen)) {
220+
swift_ASTGen_buildTopLevelASTNodes(
221+
exportedSourceFile, CurDeclContext, &Context, &decls, appendToVector);
222+
223+
// Spin the C++ parser to the end; we won't be using it.
224+
while (!Tok.is(tok::eof)) {
225+
consumeToken();
226+
}
227+
228+
return;
197229
}
198-
return;
199230
}
200231
#endif
201232

0 commit comments

Comments
 (0)