Skip to content

Commit e45cdc5

Browse files
committed
Add API to enable or disable bare slash regex parsing
Add a parameter to the `SyntaxParser.parse` functions to enable or disable bare slash regex parsing. rdar://93750821
1 parent 510ddc9 commit e45cdc5

File tree

3 files changed

+77
-14
lines changed

3 files changed

+77
-14
lines changed

Sources/SwiftSyntaxParser/SyntaxParser.swift

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ public enum SyntaxParser {
5858
/// - source: The source string to parse.
5959
/// - parseTransition: Optional mechanism for incremental re-parsing.
6060
/// - filenameForDiagnostics: Optional file name used for SourceLocation.
61+
/// - languageVersion: Interpret input according to a specific Swift
62+
/// language version number. If `nil`, this inherits the default from
63+
/// the syntax parser library.
64+
/// - enableBareSlashRegexLiteral: Enable or disable the use of forward
65+
/// slash regular-expression literal syntax. If `nil`, this inherits the
66+
/// default from the syntax parser library.
6167
/// - diagnosticHandler: Optional callback that will be called for all
6268
/// diagnostics the parser emits
6369
/// - Returns: A top-level Syntax node representing the contents of the tree,
@@ -67,6 +73,8 @@ public enum SyntaxParser {
6773
source: String,
6874
parseTransition: IncrementalParseTransition? = nil,
6975
filenameForDiagnostics: String = "",
76+
languageVersion: String? = nil,
77+
enableBareSlashRegexLiteral: Bool? = nil,
7078
diagnosticHandler: ((Diagnostic) -> Void)? = nil
7179
) throws -> SourceFileSyntax {
7280
guard nodeHashVerifyResult && cnodeLayoutHashVerifyResult else {
@@ -78,8 +86,12 @@ public enum SyntaxParser {
7886
var utf8Source = source
7987
utf8Source.makeContiguousUTF8()
8088

81-
let rawSyntax = parseRaw(utf8Source, parseTransition, filenameForDiagnostics,
82-
diagnosticHandler)
89+
let rawSyntax = parseRaw(source: utf8Source,
90+
parseTransition: parseTransition,
91+
filenameForDiagnostics: filenameForDiagnostics,
92+
languageVersion: languageVersion,
93+
enableBareSlashRegexLiteral: enableBareSlashRegexLiteral,
94+
diagnosticHandler: diagnosticHandler)
8395

8496
let base = _SyntaxParserInterop.nodeFromRetainedOpaqueRawSyntax(rawSyntax)
8597
guard let file = base.as(SourceFileSyntax.self) else {
@@ -92,33 +104,55 @@ public enum SyntaxParser {
92104
///
93105
/// - Parameters:
94106
/// - url: The file URL to parse.
107+
/// - languageVersion: Interpret input according to a specific Swift
108+
/// language version number. If `nil`, this inherits the default from
109+
/// the syntax parser library.
110+
/// - enableBareSlashRegexLiteral: Enable or disable the use of forward
111+
/// slash regular-expression literal syntax. If `nil`, this inherits the
112+
/// default from the syntax parser library.
95113
/// - diagnosticHandler: Optional callback that will be called for all
96114
/// diagnostics the parser emits
97115
/// - Returns: A top-level Syntax node representing the contents of the tree,
98116
/// if the parse was successful.
99117
/// - Throws: `ParserError`
100-
public static func parse(_ url: URL,
101-
diagnosticHandler: ((Diagnostic) -> Void)? = nil) throws -> SourceFileSyntax {
118+
public static func parse(
119+
_ url: URL,
120+
languageVersion: String? = nil,
121+
enableBareSlashRegexLiteral: Bool? = nil,
122+
diagnosticHandler: ((Diagnostic) -> Void)? = nil
123+
) throws -> SourceFileSyntax {
102124
// Avoid using `String(contentsOf:)` because it creates a wrapped NSString.
103125
let fileData = try Data(contentsOf: url)
104126
let source = fileData.withUnsafeBytes { buf in
105127
return String(decoding: buf.bindMemory(to: UInt8.self), as: UTF8.self)
106128
}
107129
return try parse(source: source, filenameForDiagnostics: url.path,
130+
languageVersion: languageVersion,
131+
enableBareSlashRegexLiteral: enableBareSlashRegexLiteral,
108132
diagnosticHandler: diagnosticHandler)
109133
}
110134

111135
private static func parseRaw(
112-
_ source: String,
113-
_ parseTransition: IncrementalParseTransition?,
114-
_ filenameForDiagnostics: String,
115-
_ diagnosticHandler: ((Diagnostic) -> Void)?
136+
source: String,
137+
parseTransition: IncrementalParseTransition?,
138+
filenameForDiagnostics: String,
139+
languageVersion: String?,
140+
enableBareSlashRegexLiteral: Bool?,
141+
diagnosticHandler: ((Diagnostic) -> Void)?
116142
) -> CClientNode {
117143
precondition(source.isContiguousUTF8)
118144
let c_parser = swiftparse_parser_create()
119145
defer {
120146
swiftparse_parser_dispose(c_parser)
121147
}
148+
if let languageVersion = languageVersion {
149+
languageVersion.withCString { languageVersionCString in
150+
swiftparse_parser_set_language_version(c_parser, languageVersionCString)
151+
}
152+
}
153+
if let enableBareSlashRegexLiteral = enableBareSlashRegexLiteral {
154+
swiftparse_parser_set_enable_bare_slash_regex_literal(c_parser, enableBareSlashRegexLiteral)
155+
}
122156

123157
let nodeHandler = { (cnode: CSyntaxNodePtr!) -> UnsafeMutableRawPointer in
124158
return _SyntaxParserInterop.getRetainedOpaqueRawSyntax(cnode: cnode, source: source)

Sources/lit-test-helper/main.swift

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ func printHelp() {
6767
-out FILENAME
6868
The file to which the source representation of the post-edit syntax
6969
tree shall be written.
70+
-swift-version
71+
Interpret input according to a specific Swift language version
72+
number
73+
-enable-bare-slash-regex [0|1]
74+
Enable or disable the use of forward slash regular-expression
75+
literal syntax
7076
""")
7177
}
7278

@@ -195,6 +201,13 @@ struct IncrementalEdit {
195201
let replacement: String
196202
}
197203

204+
func getSwiftLanguageVersionInfo(args: CommandLineArguments) -> (languageVersion: String?, enableBareSlashRegexLiteral: Bool?) {
205+
return (
206+
args["-swift-version"],
207+
args["-enable-bare-slash-regex"].map({ $0 == "1" })
208+
)
209+
}
210+
198211
/// Rewrites a parsed tree with all constructed nodes.
199212
class TreeReconstructor : SyntaxRewriter {
200213
override func visit(_ token: TokenSyntax) -> Syntax {
@@ -207,8 +220,9 @@ class TreeReconstructor : SyntaxRewriter {
207220

208221
func performClassifySyntax(args: CommandLineArguments) throws {
209222
let treeURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
223+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
210224

211-
let tree = try SyntaxParser.parse(treeURL)
225+
let tree = try SyntaxParser.parse(treeURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral)
212226
let result = ClassifiedSyntaxTreePrinter.print(Syntax(tree))
213227
do {
214228
// Sanity check that we get the same result if the tree has constructed nodes.
@@ -286,8 +300,9 @@ func performParseIncremental(args: CommandLineArguments) throws {
286300
URL(fileURLWithPath: try args.getRequired("-old-source-file"))
287301
let postEditURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
288302
let expectedReparseRegions = try args.getReparseRegions()
303+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
289304

290-
let preEditTree = try SyntaxParser.parse(preEditURL)
305+
let preEditTree = try SyntaxParser.parse(preEditURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral)
291306
let edits = try parseIncrementalEditArguments(args: args)
292307
let regionCollector = IncrementalParseReusedNodeCollector()
293308
let editTransition = IncrementalParseTransition(
@@ -390,7 +405,8 @@ func verifyReusedRegions(expectedReparseRegions: [SourceRegion],
390405

391406
func performRoundtrip(args: CommandLineArguments) throws {
392407
let sourceURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
393-
let tree = try SyntaxParser.parse(sourceURL)
408+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
409+
let tree = try SyntaxParser.parse(sourceURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral)
394410
let treeText = tree.description
395411

396412
if let outURL = args["-out"].map(URL.init(fileURLWithPath:)) {
@@ -418,13 +434,15 @@ class NodePrinter: SyntaxAnyVisitor {
418434

419435
func printSyntaxTree(args: CommandLineArguments) throws {
420436
let treeURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
421-
let tree = try SyntaxParser.parse(treeURL)
437+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
438+
let tree = try SyntaxParser.parse(treeURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral)
422439
let printer = NodePrinter()
423440
printer.walk(tree)
424441
}
425442

426443
func printParserDiags(args: CommandLineArguments) throws {
427444
let treeURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
445+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
428446

429447
var diagCounter : (error: Int, warning: Int, note: Int) = (0, 0, 0)
430448

@@ -442,7 +460,7 @@ func printParserDiags(args: CommandLineArguments) throws {
442460
print(diagnostic.debugDescription)
443461
}
444462

445-
_ = try SyntaxParser.parse(treeURL, diagnosticHandler: handleDiagnostic)
463+
_ = try SyntaxParser.parse(treeURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral, diagnosticHandler: handleDiagnostic)
446464

447465
print("\(diagCounter.error) error(s) \(diagCounter.warning) warnings(s) \(diagCounter.note) note(s)")
448466
}
@@ -473,8 +491,9 @@ func diagnose(args: CommandLineArguments) throws {
473491
}
474492

475493
let treeURL = URL(fileURLWithPath: try args.getRequired("-source-file"))
494+
let versionInfo = getSwiftLanguageVersionInfo(args: args)
476495

477-
let tree = try SyntaxParser.parse(treeURL, diagnosticHandler: printDiagnostic)
496+
let tree = try SyntaxParser.parse(treeURL, languageVersion: versionInfo.languageVersion, enableBareSlashRegexLiteral: versionInfo.enableBareSlashRegexLiteral, diagnosticHandler: printDiagnostic)
478497

479498
class DiagnoseUnknown: SyntaxAnyVisitor {
480499
let diagnosticHandler: ((Diagnostic) -> Void)

lit_tests/print_regex.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %lit-test-helper -print-tree -source-file %s | %FileCheck %s --check-prefix REGEX_DISABLED
3+
// RUN: %lit-test-helper -print-tree -source-file %s -enable-bare-slash-regex 1 -swift-version 5 | %FileCheck %s --check-prefix REGEX_ENABLED
4+
5+
_ = /abc/
6+
// REGEX_DISABLED: _ </TokenSyntax></DiscardAssignmentExprSyntax><AssignmentExprSyntax><TokenSyntax>= </TokenSyntax></AssignmentExprSyntax><PrefixOperatorExprSyntax><TokenSyntax>/</TokenSyntax><PostfixUnaryExprSyntax><IdentifierExprSyntax><TokenSyntax>abc</TokenSyntax></IdentifierExprSyntax><TokenSyntax>/</TokenSyntax></PostfixUnaryExprSyntax></PrefixOperatorExprSyntax></ExprListSyntax></SequenceExprSyntax></CodeBlockItemSyntax></CodeBlockItemListSyntax><TokenSyntax>
7+
// REGEX_DISABLED: </TokenSyntax></SourceFileSyntax>
8+
9+
// REGEX_ENABLED: _ </TokenSyntax></DiscardAssignmentExprSyntax><AssignmentExprSyntax><TokenSyntax>= </TokenSyntax></AssignmentExprSyntax><RegexLiteralExprSyntax><TokenSyntax>/abc/</TokenSyntax></RegexLiteralExprSyntax></ExprListSyntax></SequenceExprSyntax></CodeBlockItemSyntax></CodeBlockItemListSyntax><TokenSyntax>
10+
// REGEX_ENABLED: </TokenSyntax></SourceFileSyntax>

0 commit comments

Comments
 (0)