diff --git a/Sources/SwiftParser/ParseSourceFile.swift b/Sources/SwiftParser/ParseSourceFile.swift index a19e9c0c651..04f5a8d92af 100644 --- a/Sources/SwiftParser/ParseSourceFile.swift +++ b/Sources/SwiftParser/ParseSourceFile.swift @@ -13,6 +13,14 @@ @_spi(RawSyntax) import SwiftSyntax extension Parser { + public struct IncrementalParseResult { + /// The parsed tree. + public let tree: SourceFileSyntax + /// ``LookaheadRanges`` that describe how far the parser looked ahead while parsing a node, + /// which is necessary to construct an ``IncrementalParseTransition`` for a subsequent incremental parse. + public let lookaheadRanges: LookaheadRanges + } + /// Parse the source code in the given string as Swift source file. See /// `Parser.init` for more details. public static func parse( @@ -62,12 +70,42 @@ extension Parser { /// how far the parser looked ahead while parsing a node, which is /// necessary to construct an ``IncrementalParseTransition`` for a /// subsequent incremental parse + @available(*, deprecated, message: "Use the new version that returns a struct instead.") public static func parseIncrementally( source: String, parseTransition: IncrementalParseTransition? ) -> (tree: SourceFileSyntax, lookaheadRanges: LookaheadRanges) { + let result: IncrementalParseResult = parseIncrementally(source: source, parseTransition: parseTransition) + return (result.tree, result.lookaheadRanges) + } + + /// Parse the source code in the given string as Swift source file with support + /// for incremental parsing. + /// + /// When parsing a source file for the first time, invoke `parseIncrementally` + /// with `parseTransition: nil`. This returns the initial tree as well as + /// ``LookaheadRanges``. If an edit is made to the source file, an + /// ``IncrementalParseTransition`` can be constructed from the initial tree + /// and its ``LookaheadRanges``. When invoking `parseIncrementally` again with + /// the post-edit source and that parse transition, the parser will re-use + /// nodes that haven’t changed. + /// + /// - Parameters: + /// - source: The source code to parse + /// - parseTransition: If a similar source file has already been parsed, the + /// ``IncrementalParseTransition`` that contains the previous tree as well + /// as the edits that were performed to it. + /// - Returns: The ``IncrementalParseResult``. + public static func parseIncrementally( + source: String, + parseTransition: IncrementalParseTransition? + ) -> IncrementalParseResult { var parser = Parser(source, parseTransition: parseTransition) - return (SourceFileSyntax.parse(from: &parser), parser.lookaheadRanges) + + return IncrementalParseResult( + tree: SourceFileSyntax.parse(from: &parser), + lookaheadRanges: parser.lookaheadRanges + ) } /// Parse the source code in the given buffer as Swift source file with support diff --git a/Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift b/Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift index d3bba1e5b4a..bfafb4f3a75 100644 --- a/Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift +++ b/Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift @@ -44,35 +44,35 @@ public func assertIncrementalParse( let originalString = String(originalSource) let editedString = String(editedSource) - let (originalTree, lookaheadRanges) = Parser.parseIncrementally(source: originalString, parseTransition: nil) + let originalResult: Parser.IncrementalParseResult = Parser.parseIncrementally(source: originalString, parseTransition: nil) var reusedNodes: [Syntax] = [] let transition = IncrementalParseTransition( - previousTree: originalTree, + previousTree: originalResult.tree, edits: concurrentEdits, - lookaheadRanges: lookaheadRanges, + lookaheadRanges: originalResult.lookaheadRanges, reusedNodeCallback: { reusedNodes.append($0) } ) let newTree = Parser.parse(source: editedString) - let (incrementallyParsedNewTree, _) = Parser.parseIncrementally(source: editedString, parseTransition: transition) + let incrementalParseResult: Parser.IncrementalParseResult = Parser.parseIncrementally(source: editedString, parseTransition: transition) // Round-trip assertStringsEqualWithDiff( editedString, - "\(incrementallyParsedNewTree)", + "\(incrementalParseResult.tree)", additionalInfo: """ Source failed to round-trip when parsing incrementally Actual syntax tree: - \(incrementallyParsedNewTree.debugDescription) + \(incrementalParseResult.tree.debugDescription) """, file: file, line: line ) // Substructure - let subtreeMatcher = SubtreeMatcher(incrementallyParsedNewTree, markers: [:]) + let subtreeMatcher = SubtreeMatcher(incrementalParseResult.tree, markers: [:]) do { try subtreeMatcher.assertSameStructure(newTree, includeTrivia: true, file: file, line: line) } catch {