@@ -24,9 +24,12 @@ func _firstMatch(
24
24
_ regexStr: String ,
25
25
input: String ,
26
26
validateOptimizations: Bool ,
27
- syntax: SyntaxOptions = . traditional
27
+ semanticLevel: RegexSemanticLevel = . graphemeCluster,
28
+ syntax: SyntaxOptions = . traditional,
29
+ file: StaticString ,
30
+ line: UInt
28
31
) throws -> ( String , [ String ? ] ) {
29
- var regex = try Regex ( regexStr, syntax: syntax)
32
+ var regex = try Regex ( regexStr, syntax: syntax) . matchingSemantics ( semanticLevel )
30
33
guard let result = try regex. firstMatch ( in: input) else {
31
34
throw MatchError ( " match not found for \( regexStr) in \( input) " )
32
35
}
@@ -35,13 +38,15 @@ func _firstMatch(
35
38
if validateOptimizations {
36
39
regex. _setCompilerOptionsForTesting ( . disableOptimizations)
37
40
guard let unoptResult = try regex. firstMatch ( in: input) else {
38
- XCTFail ( " Optimized regex for \( regexStr) matched on \( input) when unoptimized regex did not " )
41
+ XCTFail ( " Optimized regex for \( regexStr) matched on \( input) when unoptimized regex did not " , file : file , line : line )
39
42
throw MatchError ( " match not found for unoptimized \( regexStr) in \( input) " )
40
43
}
41
44
XCTAssertEqual (
42
45
String ( input [ result. range] ) ,
43
46
String ( input [ unoptResult. range] ) ,
44
- " Unoptimized regex returned a different result " )
47
+ " Unoptimized regex returned a different result " ,
48
+ file: file,
49
+ line: line)
45
50
}
46
51
return ( String ( input [ result. range] ) , caps. map { $0. map ( String . init) } )
47
52
}
@@ -55,6 +60,7 @@ func flatCaptureTest(
55
60
dumpAST: Bool = false ,
56
61
xfail: Bool = false ,
57
62
validateOptimizations: Bool = true ,
63
+ semanticLevel: RegexSemanticLevel = . graphemeCluster,
58
64
file: StaticString = #file,
59
65
line: UInt = #line
60
66
) {
@@ -64,7 +70,10 @@ func flatCaptureTest(
64
70
regex,
65
71
input: test,
66
72
validateOptimizations: validateOptimizations,
67
- syntax: syntax
73
+ semanticLevel: semanticLevel,
74
+ syntax: syntax,
75
+ file: file,
76
+ line: line
68
77
) else {
69
78
if expect == nil {
70
79
continue
@@ -114,6 +123,7 @@ func matchTest(
114
123
dumpAST: Bool = false ,
115
124
xfail: Bool = false ,
116
125
validateOptimizations: Bool = true ,
126
+ semanticLevel: RegexSemanticLevel = . graphemeCluster,
117
127
file: StaticString = #file,
118
128
line: UInt = #line
119
129
) {
@@ -127,6 +137,7 @@ func matchTest(
127
137
dumpAST: dumpAST,
128
138
xfail: xfail,
129
139
validateOptimizations: validateOptimizations,
140
+ semanticLevel: semanticLevel,
130
141
file: file,
131
142
line: line)
132
143
}
@@ -144,6 +155,7 @@ func firstMatchTest(
144
155
dumpAST: Bool = false ,
145
156
xfail: Bool = false ,
146
157
validateOptimizations: Bool = true ,
158
+ semanticLevel: RegexSemanticLevel = . graphemeCluster,
147
159
file: StaticString = #filePath,
148
160
line: UInt = #line
149
161
) {
@@ -152,12 +164,15 @@ func firstMatchTest(
152
164
regex,
153
165
input: input,
154
166
validateOptimizations: validateOptimizations,
155
- syntax: syntax)
167
+ semanticLevel: semanticLevel,
168
+ syntax: syntax,
169
+ file: file,
170
+ line: line)
156
171
157
172
if xfail {
158
173
XCTAssertNotEqual ( found, match, file: file, line: line)
159
174
} else {
160
- XCTAssertEqual ( found, match, file: file, line: line)
175
+ XCTAssertEqual ( found, match, " Incorrect match " , file: file, line: line)
161
176
}
162
177
} catch {
163
178
// FIXME: This allows non-matches to succeed even when xfail'd
@@ -618,14 +633,12 @@ extension RegexTests {
618
633
// interpreted as matching the scalars "\r" or "\n".
619
634
// It does not fully match the character "\r\n" because the character class
620
635
// in scalar mode will only match one scalar
621
- do {
622
- let regex = try Regex ( " [ \r \n ] " ) . matchingSemantics ( . unicodeScalar)
623
- XCTAssertEqual ( " \r " , try regex. wholeMatch ( in: " \r " ) ? . 0 )
624
- XCTAssertEqual ( " \n " , try regex. wholeMatch ( in: " \n " ) ? . 0 )
625
- XCTAssertEqual ( nil , try regex. wholeMatch ( in: " \r \n " ) ? . 0 )
626
- } catch {
627
- XCTFail ( " \( error) " , file: #filePath, line: #line)
628
- }
636
+ matchTest (
637
+ " ^[ \r \n ]$ " ,
638
+ ( " \r " , true ) ,
639
+ ( " \n " , true ) ,
640
+ ( " \r \n " , false ) ,
641
+ semanticLevel: . unicodeScalar)
629
642
630
643
matchTest ( " [^ \r \n ] " ,
631
644
( " \r \n " , false ) ,
@@ -635,26 +648,15 @@ extension RegexTests {
635
648
( " \n " , true ) ,
636
649
( " \r " , true ) ,
637
650
( " \r \n " , false ) )
638
-
639
- do {
640
- let r = #"[a]\u0301"#
641
- var regex = try Regex ( r) . matchingSemantics ( . unicodeScalar)
642
- let input : String = " a \u{301} "
643
- // Should match in unicode semantic mode because the character class
644
- // should consume the a and then matchScalar should match the \u{301}
645
- regex. _debug ( )
646
- XCTAssertEqual ( " a \u{301} " , try regex. wholeMatch ( in: input) ? . 0 )
647
- // validate this is the same in unoptimized mode
648
- regex. _setCompilerOptionsForTesting ( . disableOptimizations)
649
- XCTAssertEqual ( " a \u{301} " , try regex. wholeMatch ( in: input) ? . 0 )
650
-
651
- // Should not match in grapheme semantic mode because a\u{301} is
652
- // a single character
653
- matchTest ( r,
654
- ( input, false ) )
655
- } catch {
656
- XCTFail ( " \( error) " , file: #filePath, line: #line)
657
- }
651
+
652
+ matchTest (
653
+ #"[a]\u0301"# ,
654
+ ( " a \u{301} " , false ) ,
655
+ semanticLevel: . graphemeCluster)
656
+ matchTest (
657
+ #"[a]\u0301"# ,
658
+ ( " a \u{301} " , true ) ,
659
+ semanticLevel: . unicodeScalar)
658
660
659
661
firstMatchTest ( " [-] " , input: " 123-abcxyz " , match: " - " )
660
662
@@ -1853,13 +1855,14 @@ extension RegexTests {
1853
1855
1854
1856
// TODO: Add test for grapheme boundaries at start/end of match
1855
1857
1858
+ // Testing the matchScalar optimization for ascii quoted literals and characters
1856
1859
func testScalarOptimization( ) throws {
1857
1860
// check that we are correctly doing the boundary check after matchScalar
1858
1861
firstMatchTest ( " a " , input: " a \u{301} " , match: nil )
1859
1862
firstMatchTest ( " aa " , input: " aa \u{301} " , match: nil )
1860
- // let regex = "aa"
1861
- // let input = "aa \u{301}"
1862
- // XCTAssertEqual(regex.firstMatch(of: input), nil )
1863
+
1864
+ firstMatchTest ( " a " , input: " a \u{301} " , match : " a " , semanticLevel : . unicodeScalar )
1865
+ firstMatchTest ( " aa " , input: " aa \u{301} " , match : " aa " , semanticLevel : . unicodeScalar )
1863
1866
}
1864
1867
1865
1868
func testCase( ) {
0 commit comments