diff --git a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift index 2f48e8f78fc..f29fdb18103 100644 --- a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift @@ -2270,4 +2270,21 @@ public let DECL_NODES: [Node] = [ ), ] ), + + Node( + kind: .skippedDecl, + base: .decl, + nameForDiagnostics: "skipped body", + documentation: """ + Represent skipped portion of the source. + """, + traits: [], + children: [ + Child( + name: "text", + kind: .token(choices: [.token(.unknown)]), + nameForDiagnostics: "text" + ), + ] + ), ] diff --git a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift index 6b36c0b76cf..25095ff2702 100644 --- a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift +++ b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift @@ -252,6 +252,7 @@ public enum SyntaxNodeKind: String, CaseIterable { case stmt case simpleStringLiteralExpr case simpleStringLiteralSegmentList + case skippedDecl case stringLiteralExpr case stringLiteralSegmentList case stringSegment diff --git a/Sources/SwiftParser/CMakeLists.txt b/Sources/SwiftParser/CMakeLists.txt index ea9b7e7bb0f..54d24220926 100644 --- a/Sources/SwiftParser/CMakeLists.txt +++ b/Sources/SwiftParser/CMakeLists.txt @@ -12,6 +12,7 @@ add_swift_syntax_library(SwiftParser CharacterInfo.swift CollectionNodes+Parsable.swift Declarations.swift + DelayedParsing.swift Directives.swift Expressions.swift IncrementalParseTransition.swift diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 6cd0a74cb34..4bf7ec12b71 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -383,7 +383,7 @@ extension Parser { } else { whereClause = nil } - let memberBlock = self.parseMemberBlock(introducer: extensionKeyword) + let memberBlock = self.parseMemberBlock(introducer: extensionKeyword, allowSkip: true) return RawExtensionDeclSyntax( attributes: attrs.attributes, modifiers: attrs.modifiers, @@ -777,9 +777,19 @@ extension Parser { /// `introducer` is the `struct`, `class`, ... keyword that is the cause that the member decl block is being parsed. /// If the left brace is missing, its indentation will be used to judge whether a following `}` was /// indented to close this code block or a surrounding context. See `expectRightBrace`. - mutating func parseMemberBlock(introducer: RawTokenSyntax? = nil) -> RawMemberBlockSyntax { + mutating func parseMemberBlock(introducer: RawTokenSyntax? = nil, allowSkip: Bool = false) -> RawMemberBlockSyntax { let (unexpectedBeforeLBrace, lbrace) = self.expect(.leftBrace) - let members = parseMemberDeclList() + + let members: RawMemberBlockItemListSyntax + if allowSkip, + self.options.contains(.bodySkipping), + let skipped = self.skippedMemberBody() { + let member = RawMemberBlockItemSyntax(decl: .init(skipped), semicolon: nil, arena: self.arena) + members = RawMemberBlockItemListSyntax(elements: [member], arena: self.arena) + } else { + members = parseMemberDeclList() + } + let (unexpectedBeforeRBrace, rbrace) = self.expectRightBrace(leftBrace: lbrace, introducer: introducer) return RawMemberBlockSyntax( diff --git a/Sources/SwiftParser/DelayedParsing.swift b/Sources/SwiftParser/DelayedParsing.swift new file mode 100644 index 00000000000..11fa2e7d252 --- /dev/null +++ b/Sources/SwiftParser/DelayedParsing.swift @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@_spi(RawSyntax) import SwiftSyntax + +extension Parser { + mutating func skippedFunctionBody() -> RawSkippedDeclSyntax? { + return self.skippedBraceBody(while: { tokenKind, tokenText in + // If the function body contains a type decl, don't skip. + if tokenKind == .keyword && ( + tokenText == "enum" || + tokenText == "struct" || + tokenText == "class" || + tokenText == "actor" + ) { + return false + } + return true + }) + } + + mutating func skippedMemberBody() -> RawSkippedDeclSyntax? { + var lastTokenWasFunc: Bool = false + return self.skippedBraceBody(while: { tokenKind, tokenText in + + // '#' directives. + if tokenKind == .poundIf || tokenKind == .poundSourceLocation { + return false + } + + // Nested class. Because? + if tokenKind == .keyword && tokenText == "class" { + return false + } + + // Operator functions. Because they're visible from top-level. + if lastTokenWasFunc && ( + tokenKind == .binaryOperator || tokenKind == .prefixOperator || tokenKind == .postfixOperator + ) { + return false + } + lastTokenWasFunc = tokenKind == .keyword && tokenText == "func" + + return true + }) + } + + fileprivate mutating func skippedBraceBody(while condition: (_ tokenKind: RawTokenKind, _ tokenText: SyntaxText) -> Bool) -> RawSkippedDeclSyntax? { + return self.withLookahead { lookahead in + guard lookahead.advanceUntilMatchingRightBrace(while: condition) == .reachedToEnd else { + return nil + } + + // Skipped region as a single SyntaxText. + let wholeText = SyntaxText( + baseAddress: self.currentToken.start, + count: self.currentToken.start.distance(to: lookahead.currentToken.start) + ) + + // Advance the Lexer to skipped position. + self.currentToken = lookahead.currentToken + self.lexemes = lookahead.lexemes + + // Represent the skipped range with a single .unknown token. + let tok = RawTokenSyntax( + kind: .unknown, + wholeText: wholeText, + textRange: wholeText.startIndex.. Bool) -> SkipBodyResult { + var openBraces = 1 + + while self.currentToken.rawTokenKind != .endOfFile { + let tokenKind = currentToken.rawTokenKind + let tokenText = currentToken.tokenText + + guard condition(tokenKind, tokenText) else { + return .aborted + } + + if tokenKind == .leftBrace { + openBraces += 1 + } else if tokenKind == .rightBrace { + openBraces -= 1 + if openBraces == 0 { + break + } + } + self.consumeAnyToken() + } + + return .reachedToEnd + } +} diff --git a/Sources/SwiftParser/Nominals.swift b/Sources/SwiftParser/Nominals.swift index 7e65bea5068..7ce5de2a4c9 100644 --- a/Sources/SwiftParser/Nominals.swift +++ b/Sources/SwiftParser/Nominals.swift @@ -254,7 +254,7 @@ extension Parser { whereClause = nil } - let memberBlock = self.parseMemberBlock(introducer: introducerKeyword) + let memberBlock = self.parseMemberBlock(introducer: introducerKeyword, allowSkip: true) return T.init( attributes: attrs.attributes, modifiers: attrs.modifiers, diff --git a/Sources/SwiftParser/ParseSourceFile.swift b/Sources/SwiftParser/ParseSourceFile.swift index 6b0a2149fa2..42b0dd6161b 100644 --- a/Sources/SwiftParser/ParseSourceFile.swift +++ b/Sources/SwiftParser/ParseSourceFile.swift @@ -16,9 +16,10 @@ extension Parser { /// Parse the source code in the given string as Swift source file. See /// `Parser.init` for more details. public static func parse( - source: String + source: String, + options: ParsingOptions = [] ) -> SourceFileSyntax { - var parser = Parser(source) + var parser = Parser(source, options: options) return SourceFileSyntax.parse(from: &parser) } @@ -26,9 +27,10 @@ extension Parser { @_spi(ExperimentalLanguageFeatures) public static func parse( source: UnsafeBufferPointer, - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + options: ParsingOptions = [] ) -> SourceFileSyntax { - var parser = Parser(source, experimentalFeatures: experimentalFeatures) + var parser = Parser(source, experimentalFeatures: experimentalFeatures, options: options) return SourceFileSyntax.parse(from: &parser) } @@ -36,9 +38,10 @@ extension Parser { /// `Parser.init` for more details. public static func parse( source: UnsafeBufferPointer, - maximumNestingLevel: Int? = nil + maximumNestingLevel: Int? = nil, + options: ParsingOptions = [] ) -> SourceFileSyntax { - var parser = Parser(source, maximumNestingLevel: maximumNestingLevel) + var parser = Parser(source, maximumNestingLevel: maximumNestingLevel, options: options) return SourceFileSyntax.parse(from: &parser) } diff --git a/Sources/SwiftParser/Parser.swift b/Sources/SwiftParser/Parser.swift index e92d0e31e2f..8e62d494c6c 100644 --- a/Sources/SwiftParser/Parser.swift +++ b/Sources/SwiftParser/Parser.swift @@ -87,6 +87,17 @@ /// tokens as needed to disambiguate a parse. However, because lookahead /// operates on a copy of the lexical stream, no input tokens are lost.. public struct Parser { + public struct ParsingOptions: OptionSet { + public let rawValue: UInt8 + public init(rawValue: UInt8) { + self.rawValue = rawValue + } + + public static let bodySkipping = Self(rawValue: 1 << 0) + } + + var options: ParsingOptions + var arena: ParsingSyntaxArena /// A view of the sequence of lexemes in the input. @@ -168,7 +179,7 @@ public struct Parser { return _emptyRawAttributeListSyntax! } - /// The delegated initializer for the parser. + /// The designated initializer for the parser. /// /// - Parameters /// - input: An input buffer containing Swift source text. If a non-`nil` @@ -193,8 +204,10 @@ public struct Parser { maximumNestingLevel: Int?, parseTransition: IncrementalParseTransition?, arena: ParsingSyntaxArena?, - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + options: ParsingOptions ) { + self.options = options var input = input if let arena { self.arena = arena @@ -224,7 +237,8 @@ public struct Parser { string input: String, maximumNestingLevel: Int?, parseTransition: IncrementalParseTransition?, - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + options: ParsingOptions ) { var input = input input.makeContiguousUTF8() @@ -234,7 +248,8 @@ public struct Parser { maximumNestingLevel: maximumNestingLevel, parseTransition: parseTransition, arena: nil, - experimentalFeatures: experimentalFeatures + experimentalFeatures: experimentalFeatures, + options: options ) } } @@ -243,14 +258,16 @@ public struct Parser { public init( _ input: String, maximumNestingLevel: Int? = nil, - parseTransition: IncrementalParseTransition? = nil + parseTransition: IncrementalParseTransition? = nil, + options: ParsingOptions = [] ) { // Chain to the private String initializer. self.init( string: input, maximumNestingLevel: maximumNestingLevel, parseTransition: parseTransition, - experimentalFeatures: [] + experimentalFeatures: [], + options: options ) } @@ -277,7 +294,8 @@ public struct Parser { _ input: UnsafeBufferPointer, maximumNestingLevel: Int? = nil, parseTransition: IncrementalParseTransition? = nil, - arena: ParsingSyntaxArena? = nil + arena: ParsingSyntaxArena? = nil, + options: ParsingOptions = [] ) { // Chain to the private buffer initializer. self.init( @@ -285,7 +303,8 @@ public struct Parser { maximumNestingLevel: maximumNestingLevel, parseTransition: parseTransition, arena: arena, - experimentalFeatures: [] + experimentalFeatures: [], + options: options ) } @@ -296,14 +315,16 @@ public struct Parser { _ input: String, maximumNestingLevel: Int? = nil, parseTransition: IncrementalParseTransition? = nil, - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + options: ParsingOptions = [] ) { // Chain to the private String initializer. self.init( string: input, maximumNestingLevel: maximumNestingLevel, parseTransition: parseTransition, - experimentalFeatures: experimentalFeatures + experimentalFeatures: experimentalFeatures, + options: options ) } @@ -315,7 +336,8 @@ public struct Parser { maximumNestingLevel: Int? = nil, parseTransition: IncrementalParseTransition? = nil, arena: ParsingSyntaxArena? = nil, - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + options: ParsingOptions = [] ) { // Chain to the private buffer initializer. self.init( @@ -323,7 +345,8 @@ public struct Parser { maximumNestingLevel: maximumNestingLevel, parseTransition: parseTransition, arena: arena, - experimentalFeatures: experimentalFeatures + experimentalFeatures: experimentalFeatures, + options: options ) } diff --git a/Sources/SwiftParser/TopLevel.swift b/Sources/SwiftParser/TopLevel.swift index 0b87638dd40..b00b72bc729 100644 --- a/Sources/SwiftParser/TopLevel.swift +++ b/Sources/SwiftParser/TopLevel.swift @@ -96,7 +96,7 @@ extension Parser { guard self.at(.leftBrace) || self.canRecoverTo(TokenSpec(.leftBrace, allowAtStartOfLine: false)) != nil else { return nil } - return self.parseCodeBlock(allowInitDecl: allowInitDecl) + return self.parseCodeBlock(allowInitDecl: allowInitDecl, allowSkip: true) } /// Parse a code block. @@ -104,9 +104,19 @@ extension Parser { /// `introducer` is the `while`, `if`, ... keyword that is the cause that the code block is being parsed. /// If the left brace is missing, its indentation will be used to judge whether a following `}` was /// indented to close this code block or a surrounding context. See `expectRightBrace`. - mutating func parseCodeBlock(introducer: RawTokenSyntax? = nil, allowInitDecl: Bool = true) -> RawCodeBlockSyntax { + mutating func parseCodeBlock(introducer: RawTokenSyntax? = nil, allowInitDecl: Bool = true, allowSkip: Bool = false) -> RawCodeBlockSyntax { let (unexpectedBeforeLBrace, lbrace) = self.expect(.leftBrace) - let itemList = parseCodeBlockItemList(allowInitDecl: allowInitDecl, until: { $0.at(.rightBrace) }) + + let itemList: RawCodeBlockItemListSyntax + if allowSkip, + options.contains(.bodySkipping), + let skipped = self.skippedFunctionBody() { + let item = RawCodeBlockItemSyntax(item: .decl(.init(skipped)), semicolon: nil, arena: self.arena) + itemList = RawCodeBlockItemListSyntax(elements: [item], arena: self.arena) + } else { + itemList = parseCodeBlockItemList(allowInitDecl: allowInitDecl, until: { $0.at(.rightBrace) }) + } + let (unexpectedBeforeRBrace, rbrace) = self.expectRightBrace(leftBrace: lbrace, introducer: introducer) return .init( diff --git a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift index d0545bdd0d8..797e1ae615b 100644 --- a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift @@ -294,6 +294,8 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? { return "left-hand type" case \SameTypeRequirementSyntax.rightType: return "right-hand type" + case \SkippedDeclSyntax.text: + return "text" case \SpecializeAvailabilityArgumentSyntax.availabilityLabel: return "label" case \SpecializeTargetFunctionArgumentSyntax.targetLabel: diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index 93aa8b3955a..d93e3752647 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -333,6 +333,8 @@ extension SyntaxKind { return "same type requirement" case .simpleStringLiteralExpr: return "simple string literal" + case .skippedDecl: + return "skipped body" case .someOrAnyType: return "type" case .sourceFile: diff --git a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md index 02a10fe376c..f0a19f78106 100644 --- a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md +++ b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md @@ -84,6 +84,7 @@ These articles are intended for developers wishing to contribute to SwiftSyntax - - - +- - - - diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index e87cebaf991..c598ee58616 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -2791,6 +2791,12 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "closingQuote" case \SimpleStringLiteralExprSyntax.unexpectedAfterClosingQuote: return "unexpectedAfterClosingQuote" + case \SkippedDeclSyntax.unexpectedBeforeText: + return "unexpectedBeforeText" + case \SkippedDeclSyntax.text: + return "text" + case \SkippedDeclSyntax.unexpectedAfterText: + return "unexpectedAfterText" case \SomeOrAnyTypeSyntax.unexpectedBeforeSomeOrAnySpecifier: return "unexpectedBeforeSomeOrAnySpecifier" case \SomeOrAnyTypeSyntax.someOrAnySpecifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift index 7734160b505..bd295fd9b23 100644 --- a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift @@ -1846,6 +1846,14 @@ open class SyntaxAnyVisitor: SyntaxVisitor { visitAnyPost(node._syntaxNode) } + override open func visit(_ node: SkippedDeclSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: SkippedDeclSyntax) { + visitAnyPost(node._syntaxNode) + } + override open func visit(_ node: SomeOrAnyTypeSyntax) -> SyntaxVisitorContinueKind { return visitAny(node._syntaxNode) } diff --git a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift index 50479429881..1e955d83e22 100644 --- a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift +++ b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift @@ -176,6 +176,7 @@ public extension Syntax { /// - ``PoundSourceLocationSyntax`` /// - ``PrecedenceGroupDeclSyntax`` /// - ``ProtocolDeclSyntax`` +/// - ``SkippedDeclSyntax`` /// - ``StructDeclSyntax`` /// - ``SubscriptDeclSyntax`` /// - ``TypeAliasDeclSyntax`` @@ -216,7 +217,7 @@ public struct DeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public init?(_ node: some SyntaxProtocol) { switch node.raw.kind { - case .accessorDecl, .actorDecl, .associatedTypeDecl, .classDecl, .deinitializerDecl, .editorPlaceholderDecl, .enumCaseDecl, .enumDecl, .extensionDecl, .functionDecl, .ifConfigDecl, .importDecl, .initializerDecl, .macroDecl, .macroExpansionDecl, .missingDecl, .operatorDecl, .poundSourceLocation, .precedenceGroupDecl, .protocolDecl, .structDecl, .subscriptDecl, .typeAliasDecl, .variableDecl: + case .accessorDecl, .actorDecl, .associatedTypeDecl, .classDecl, .deinitializerDecl, .editorPlaceholderDecl, .enumCaseDecl, .enumDecl, .extensionDecl, .functionDecl, .ifConfigDecl, .importDecl, .initializerDecl, .macroDecl, .macroExpansionDecl, .missingDecl, .operatorDecl, .poundSourceLocation, .precedenceGroupDecl, .protocolDecl, .skippedDecl, .structDecl, .subscriptDecl, .typeAliasDecl, .variableDecl: self._syntaxNode = node._syntaxNode default: return nil @@ -261,6 +262,7 @@ public struct DeclSyntax: DeclSyntaxProtocol, SyntaxHashable { .node(PoundSourceLocationSyntax.self), .node(PrecedenceGroupDeclSyntax.self), .node(ProtocolDeclSyntax.self), + .node(SkippedDeclSyntax.self), .node(StructDeclSyntax.self), .node(SubscriptDeclSyntax.self), .node(TypeAliasDeclSyntax.self), @@ -1747,6 +1749,7 @@ extension Syntax { .node(SequenceExprSyntax.self), .node(SimpleStringLiteralExprSyntax.self), .node(SimpleStringLiteralSegmentListSyntax.self), + .node(SkippedDeclSyntax.self), .node(SomeOrAnyTypeSyntax.self), .node(SourceFileSyntax.self), .node(SpecializeAttributeArgumentListSyntax.self), diff --git a/Sources/SwiftSyntax/generated/SyntaxEnum.swift b/Sources/SwiftSyntax/generated/SyntaxEnum.swift index 3026e006fd2..979081fa689 100644 --- a/Sources/SwiftSyntax/generated/SyntaxEnum.swift +++ b/Sources/SwiftSyntax/generated/SyntaxEnum.swift @@ -241,6 +241,7 @@ public enum SyntaxEnum { case sequenceExpr(SequenceExprSyntax) case simpleStringLiteralExpr(SimpleStringLiteralExprSyntax) case simpleStringLiteralSegmentList(SimpleStringLiteralSegmentListSyntax) + case skippedDecl(SkippedDeclSyntax) case someOrAnyType(SomeOrAnyTypeSyntax) case sourceFile(SourceFileSyntax) case specializeAttributeArgumentList(SpecializeAttributeArgumentListSyntax) @@ -753,6 +754,8 @@ public extension Syntax { return .simpleStringLiteralExpr(SimpleStringLiteralExprSyntax(self)!) case .simpleStringLiteralSegmentList: return .simpleStringLiteralSegmentList(SimpleStringLiteralSegmentListSyntax(self)!) + case .skippedDecl: + return .skippedDecl(SkippedDeclSyntax(self)!) case .someOrAnyType: return .someOrAnyType(SomeOrAnyTypeSyntax(self)!) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxKind.swift b/Sources/SwiftSyntax/generated/SyntaxKind.swift index 92931b634f0..21acf519430 100644 --- a/Sources/SwiftSyntax/generated/SyntaxKind.swift +++ b/Sources/SwiftSyntax/generated/SyntaxKind.swift @@ -241,6 +241,7 @@ public enum SyntaxKind { case sequenceExpr case simpleStringLiteralExpr case simpleStringLiteralSegmentList + case skippedDecl case someOrAnyType case sourceFile case specializeAttributeArgumentList @@ -874,6 +875,8 @@ public enum SyntaxKind { return SimpleStringLiteralExprSyntax.self case .simpleStringLiteralSegmentList: return SimpleStringLiteralSegmentListSyntax.self + case .skippedDecl: + return SkippedDeclSyntax.self case .someOrAnyType: return SomeOrAnyTypeSyntax.self case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index 929a7b0fa54..e9c4106bf83 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -1644,6 +1644,13 @@ open class SyntaxRewriter { return visitChildren(node) } + /// Visit a ``SkippedDeclSyntax``. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: SkippedDeclSyntax) -> DeclSyntax { + return DeclSyntax(visitChildren(node)) + } + /// Visit a ``SomeOrAnyTypeSyntax``. /// - Parameter node: the node that is being visited /// - Returns: the rewritten node @@ -3008,6 +3015,10 @@ open class SyntaxRewriter { return { self.visitImpl($0, SimpleStringLiteralSegmentListSyntax.self, self.visit) } + case .skippedDecl: + return { + self.visitImpl($0, SkippedDeclSyntax.self, self.visit) + } case .someOrAnyType: return { self.visitImpl($0, SomeOrAnyTypeSyntax.self, self.visit) @@ -3684,6 +3695,8 @@ open class SyntaxRewriter { return visitImpl(node, SimpleStringLiteralExprSyntax.self, visit) case .simpleStringLiteralSegmentList: return visitImpl(node, SimpleStringLiteralSegmentListSyntax.self, visit) + case .skippedDecl: + return visitImpl(node, SkippedDeclSyntax.self, visit) case .someOrAnyType: return visitImpl(node, SomeOrAnyTypeSyntax.self, visit) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift index b7505bdf2c9..a396aca0e58 100644 --- a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift @@ -2716,6 +2716,18 @@ open class SyntaxVisitor { open func visitPost(_ node: SimpleStringLiteralSegmentListSyntax) { } + /// Visiting ``SkippedDeclSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: SkippedDeclSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting ``SkippedDeclSyntax`` and its descendants. + /// - node: the node we just finished visiting. + open func visitPost(_ node: SkippedDeclSyntax) { + } + /// Visiting ``SomeOrAnyTypeSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: how should we continue visiting. @@ -4336,6 +4348,10 @@ open class SyntaxVisitor { return { self.visitImpl($0, SimpleStringLiteralSegmentListSyntax.self, self.visit, self.visitPost) } + case .skippedDecl: + return { + self.visitImpl($0, SkippedDeclSyntax.self, self.visit, self.visitPost) + } case .someOrAnyType: return { self.visitImpl($0, SomeOrAnyTypeSyntax.self, self.visit, self.visitPost) @@ -5015,6 +5031,8 @@ open class SyntaxVisitor { visitImpl(node, SimpleStringLiteralExprSyntax.self, visit, visitPost) case .simpleStringLiteralSegmentList: visitImpl(node, SimpleStringLiteralSegmentListSyntax.self, visit, visitPost) + case .skippedDecl: + visitImpl(node, SkippedDeclSyntax.self, visit, visitPost) case .someOrAnyType: visitImpl(node, SomeOrAnyTypeSyntax.self, visit, visitPost) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesD.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesD.swift index 94fe65da6c6..ea019561539 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesD.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesD.swift @@ -484,7 +484,7 @@ public struct RawDeclSyntax: RawDeclSyntaxNodeProtocol { public static func isKindOf(_ raw: RawSyntax) -> Bool { switch raw.kind { - case .accessorDecl, .actorDecl, .associatedTypeDecl, .classDecl, .deinitializerDecl, .editorPlaceholderDecl, .enumCaseDecl, .enumDecl, .extensionDecl, .functionDecl, .ifConfigDecl, .importDecl, .initializerDecl, .macroDecl, .macroExpansionDecl, .missingDecl, .operatorDecl, .poundSourceLocation, .precedenceGroupDecl, .protocolDecl, .structDecl, .subscriptDecl, .typeAliasDecl, .variableDecl: + case .accessorDecl, .actorDecl, .associatedTypeDecl, .classDecl, .deinitializerDecl, .editorPlaceholderDecl, .enumCaseDecl, .enumDecl, .extensionDecl, .functionDecl, .ifConfigDecl, .importDecl, .initializerDecl, .macroDecl, .macroExpansionDecl, .missingDecl, .operatorDecl, .poundSourceLocation, .precedenceGroupDecl, .protocolDecl, .skippedDecl, .structDecl, .subscriptDecl, .typeAliasDecl, .variableDecl: return true default: return false diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift index a2f062d7d02..7046dba0a23 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift @@ -613,6 +613,64 @@ public struct RawSimpleStringLiteralSegmentListSyntax: RawSyntaxNodeProtocol { } } +@_spi(RawSyntax) +public struct RawSkippedDeclSyntax: RawDeclSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .skippedDecl + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init( + _ unexpectedBeforeText: RawUnexpectedNodesSyntax? = nil, + text: RawTokenSyntax, + _ unexpectedAfterText: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .skippedDecl, uninitializedCount: 3, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeText?.raw + layout[1] = text.raw + layout[2] = unexpectedAfterText?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeText: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var text: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterText: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } +} + @_spi(RawSyntax) public struct RawSomeOrAnyTypeSyntax: RawTypeSyntaxNodeProtocol { @_spi(RawSyntax) diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index 68a9dadabaf..2ae9559c491 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -2261,6 +2261,11 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { for (index, element) in layout.enumerated() { assertNoError(kind, index, verify(element, as: RawStringSegmentSyntax.self)) } + case .skippedDecl: + assert(layout.count == 3) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.unknown)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .someOrAnyType: assert(layout.count == 5) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift index bf00274d194..44c66555064 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift @@ -1084,6 +1084,85 @@ public struct SimpleStringLiteralExprSyntax: ExprSyntaxProtocol, SyntaxHashable, } } +// MARK: - SkippedDeclSyntax + +/// Represent skipped portion of the source. +/// +/// ### Children +/// +/// - `text`: `` +public struct SkippedDeclSyntax: DeclSyntaxProtocol, SyntaxHashable, _LeafDeclSyntaxNodeProtocol { + public let _syntaxNode: Syntax + + public init?(_ node: some SyntaxProtocol) { + guard node.raw.kind == .skippedDecl else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + /// - Parameters: + /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeText: UnexpectedNodesSyntax? = nil, + text: TokenSyntax, + _ unexpectedAfterText: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + + ) { + // Extend the lifetime of all parameters so their arenas don't get destroyed + // before they can be added as children of the new arena. + self = withExtendedLifetime((SyntaxArena(), (unexpectedBeforeText, text, unexpectedAfterText))) { (arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforeText?.raw, text.raw, unexpectedAfterText?.raw] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.skippedDecl, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + + ) + return Syntax.forRoot(raw, rawNodeArena: arena).cast(Self.self) + } + } + + public var unexpectedBeforeText: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 0)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 0, with: Syntax(value), arena: SyntaxArena()).cast(SkippedDeclSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be ``. + public var text: TokenSyntax { + get { + return Syntax(self).child(at: 1)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 1, with: Syntax(value), arena: SyntaxArena()).cast(SkippedDeclSyntax.self) + } + } + + public var unexpectedAfterText: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 2)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 2, with: Syntax(value), arena: SyntaxArena()).cast(SkippedDeclSyntax.self) + } + } + + public static var structure: SyntaxNodeStructure { + return .layout([\Self.unexpectedBeforeText, \Self.text, \Self.unexpectedAfterText]) + } +} + // MARK: - SomeOrAnyTypeSyntax /// ### Children