Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ let experimentalFeaturesFile = SourceFileSyntax(leadingTrivia: copyrightHeader)
DeclSyntax(
"""
extension Parser {
@_spi(ExperimentalLanguageFeatures)
/// The type is public so it can appear in the (non-SPI) parser API, but
/// the individual features are `@_spi(ExperimentalLanguageFeatures)` since
/// they are unstable. Clients that don't enable experimental features only
/// ever use the empty set.
public struct ExperimentalFeatures: OptionSet, Hashable, Sendable {
public let rawValue: UInt
public init(rawValue: UInt) {
Expand All @@ -35,6 +38,7 @@ let experimentalFeaturesFile = SourceFileSyntax(leadingTrivia: copyrightHeader)
DeclSyntax(
"""
/// Whether to enable the parsing of \(raw: feature.documentationDescription).
@_spi(ExperimentalLanguageFeatures)
public static let \(feature.token) = Self(rawValue: 1 << \(raw: i))
"""
)
Expand All @@ -44,6 +48,7 @@ let experimentalFeaturesFile = SourceFileSyntax(leadingTrivia: copyrightHeader)
"""
/// Creates a new value representing the experimental feature with the
/// given name, or returns nil if the name is not recognized.
@_spi(ExperimentalLanguageFeatures)
public init?(name: String)
"""
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
internal import SwiftDiagnostics
internal import SwiftIfConfig
internal import SwiftOperators
@_spi(ExperimentalLanguageFeatures) internal import SwiftParser
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) internal import SwiftParser
internal import SwiftSyntax
internal import SwiftSyntaxMacros
#else
import SwiftDiagnostics
import SwiftIfConfig
import SwiftOperators
@_spi(ExperimentalLanguageFeatures) import SwiftParser
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftParser
import SwiftSyntax
import SwiftSyntaxMacros
#endif
Expand Down
26 changes: 7 additions & 19 deletions Sources/SwiftParser/ParseSourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,14 @@ 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
) -> SourceFileSyntax {
return withParser(
source: source,
maximumNestingLevel: nil,
parseTransition: nil,
swiftVersion: nil,
experimentalFeatures: []
) { SourceFileSyntax.parse(from: &$0) }
}

/// A compiler interface that allows the enabling of experimental features.
@_spi(ExperimentalLanguageFeatures)
public static func parse(
source: UnsafeBufferPointer<UInt8>,
source: String,
maximumNestingLevel: Int? = nil,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures
experimentalFeatures: ExperimentalFeatures = []
) -> SourceFileSyntax {
return withParser(
source: source,
maximumNestingLevel: nil,
maximumNestingLevel: maximumNestingLevel,
parseTransition: nil,
swiftVersion: swiftVersion,
experimentalFeatures: experimentalFeatures
Expand All @@ -52,14 +39,15 @@ extension Parser {
public static func parse(
source: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
swiftVersion: SwiftVersion? = nil
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures = []
) -> SourceFileSyntax {
return withParser(
source: source,
maximumNestingLevel: maximumNestingLevel,
parseTransition: nil,
swiftVersion: swiftVersion,
experimentalFeatures: []
experimentalFeatures: experimentalFeatures
) { SourceFileSyntax.parse(from: &$0) }
}

Expand Down
137 changes: 41 additions & 96 deletions Sources/SwiftParser/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,25 @@ public struct Parser {
}
}

/// Private initializer for creating a ``Parser`` from the given string.
private init(
string input: String,
maximumNestingLevel: Int?,
parseTransition: IncrementalParseTransition?,
swiftVersion: SwiftVersion?,
experimentalFeatures: ExperimentalFeatures
/// Initializes a ``Parser`` from the given string.
///
/// - Parameters:
/// - input: The source text to parse.
/// - maximumNestingLevel: To avoid overflowing the stack, the parser will
/// stop if a nesting level greater than this value
/// is reached. `defaultMaximumNestingLevel` is used
/// if this is `nil`.
/// - parseTransition: The previously recorded state for an incremental
/// parse, or `nil`.
/// - swiftVersion: The version of Swift to parse as, or `nil` for the
/// default.
/// - experimentalFeatures: The experimental features to enable.
public init(
_ input: String,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures = []
) {
var input = input
input.makeContiguousUTF8()
Expand All @@ -300,90 +312,55 @@ public struct Parser {
}
}

/// Initializes a ``Parser`` from the given string.
public init(
_ input: String,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion? = nil
) {
// Chain to the private String initializer.
self.init(
string: input,
maximumNestingLevel: maximumNestingLevel,
parseTransition: parseTransition,
swiftVersion: swiftVersion,
experimentalFeatures: []
)
}

/// Initializes a ``Parser`` from the given input buffer.
///
/// - Parameters
/// - Parameters:
/// - input: An input buffer containing Swift source text. It is copied into
/// a parser-owned buffer, so it can be freed after the initializer
/// has been called.
/// - maximumNestingLevel: To avoid overflowing the stack, the parser will
/// stop if a nesting level greater than this value
/// is reached. The nesting level is increased
/// whenever a bracketed expression like `(` or `{`
/// is started. `defaultMaximumNestingLevel` is used
/// is reached. `defaultMaximumNestingLevel` is used
/// if this is `nil`.
/// - parseTransition: The previously recorded state for an incremental
/// parse, or `nil`.
/// - swiftVersion: The version of Swift to parse as, or `nil` for the
/// default.
/// - experimentalFeatures: The experimental features to enable.
public init(
_ input: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion? = nil
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures = []
) {
// Chain to the private buffer initializer. Copy the source so the caller may
// free `input` after this initializer returns.
// Copy the source so the caller may free `input` after this initializer
// returns.
self.init(
buffer: input,
maximumNestingLevel: maximumNestingLevel,
parseTransition: parseTransition,
arena: nil,
copySource: true,
swiftVersion: swiftVersion,
experimentalFeatures: []
)
}

/// Initializes a ``Parser`` from the given input string, with a given set
/// of experimental language features.
@_spi(ExperimentalLanguageFeatures)
public init(
_ input: String,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures
) {
// Chain to the private String initializer.
self.init(
string: input,
maximumNestingLevel: maximumNestingLevel,
parseTransition: parseTransition,
swiftVersion: swiftVersion,
experimentalFeatures: experimentalFeatures
)
}

/// Initializes a ``Parser`` from the given input buffer, with a given set
/// of experimental language features.
@_spi(ExperimentalLanguageFeatures)
/// Initializes a ``Parser`` from the given input buffer, allocating the parsed
/// syntax into the given arena.
@_spi(RawSyntax)
public init(
_ input: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
arena: ParsingRawSyntaxArena? = nil,
arena: ParsingRawSyntaxArena,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures
experimentalFeatures: ExperimentalFeatures = []
) {
// Chain to the private buffer initializer. Copy the source so the caller may
// free `input` after this initializer returns, and so the resulting tree
// does not depend on `input` (its tokens are interned into `arena`).
// Copy the source so the caller may free `input` after this initializer
// returns, and so the resulting tree does not depend on `input` (its tokens
// are interned into `arena`).
self.init(
buffer: input,
maximumNestingLevel: maximumNestingLevel,
Expand Down Expand Up @@ -413,38 +390,8 @@ public struct Parser {
source input: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
body: (inout Parser) -> T
) -> T {
return withParser(
source: input,
maximumNestingLevel: maximumNestingLevel,
parseTransition: parseTransition,
swiftVersion: nil,
experimentalFeatures: [],
body: body
)
}

/// Runs `body` with a `Parser` that lexes directly over `input` without
/// copying it into a parser-owned buffer, with a given Swift version and set
/// of experimental language features.
///
/// This is the no-copy fast path: the entire parse runs inside this scope,
/// where `input` is guaranteed valid, and each token's text is interned into
/// the arena so the resulting tree is self-contained once `body` returns.
///
/// - Important: `input` must remain valid for the entire duration of `body`.
/// It is *not* referenced after `body` returns.
/// - Important: The `Parser` passed to `body` must not escape the closure. It
/// lexes directly over `input`, so it is only valid within this scope.
@_spi(RawSyntax)
@_spi(ExperimentalLanguageFeatures)
public static func withParser<T>(
source input: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion?,
experimentalFeatures: ExperimentalFeatures,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures = [],
body: (inout Parser) -> T
) -> T {
var parser = Parser(
Expand All @@ -459,22 +406,20 @@ public struct Parser {
return body(&parser)
}

/// Runs `body` with a no-copy `Parser` over the UTF-8 of `input`, with a given
/// Swift version and set of experimental language features.
/// Runs `body` with a no-copy `Parser` over the UTF-8 of `input`.
///
/// The entire parse runs inside `String.withUTF8`, where the contiguous UTF-8
/// storage is valid, so no copy of the source is needed.
///
/// - Important: The `Parser` passed to `body` must not escape the closure. It
/// lexes directly over `input`, so it is only valid within this scope.
@_spi(RawSyntax)
@_spi(ExperimentalLanguageFeatures)
public static func withParser<T>(
source input: String,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
swiftVersion: SwiftVersion?,
experimentalFeatures: ExperimentalFeatures,
swiftVersion: SwiftVersion? = nil,
experimentalFeatures: ExperimentalFeatures = [],
body: (inout Parser) -> T
) -> T {
var input = input
Expand Down
18 changes: 17 additions & 1 deletion Sources/SwiftParser/generated/ExperimentalFeatures.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading