diff --git a/Sources/_MatchingEngine/Regex/Parse/Mocking.swift b/Sources/_MatchingEngine/Regex/Parse/Mocking.swift index b2bd6902..e3a178a1 100644 --- a/Sources/_MatchingEngine/Regex/Parse/Mocking.swift +++ b/Sources/_MatchingEngine/Regex/Parse/Mocking.swift @@ -15,11 +15,13 @@ enum Delimiter: Hashable, CaseIterable { case traditional case experimental + case reSingleQuote var openingAndClosing: (opening: String, closing: String) { switch self { - case .traditional: return ("'/", "/'") - case .experimental: return ("'|", "|'") + case .traditional: return ("#/", "/#") + case .experimental: return ("#|", "|#") + case .reSingleQuote: return ("re'", "'") } } var opening: String { openingAndClosing.opening } @@ -28,8 +30,10 @@ enum Delimiter: Hashable, CaseIterable { /// The default set of syntax options that the delimiter indicates. var defaultSyntaxOptions: SyntaxOptions { switch self { - case .traditional: return .traditional - case .experimental: return .experimental + case .traditional, .reSingleQuote: + return .traditional + case .experimental: + return .experimental } } } diff --git a/Tests/RegexTests/LexTests.swift b/Tests/RegexTests/LexTests.swift index ce82f8b8..25ced92c 100644 --- a/Tests/RegexTests/LexTests.swift +++ b/Tests/RegexTests/LexTests.swift @@ -102,23 +102,26 @@ extension RegexTests { func testCompilerInterface() { let testCases: [(String, (String, Delimiter)?)] = [ - ("'/abc/'", ("abc", .traditional)), - ("'|abc|'", ("abc", .experimental)), + ("#/abc/#", ("abc", .traditional)), + ("#|abc|#", ("abc", .experimental)), // TODO: Null characters are lexically valid, similar to string literals, // but we ought to warn the user about them. - ("'|ab\0c|'", ("ab\0c", .experimental)), + ("#|ab\0c|#", ("ab\0c", .experimental)), ("'abc'", nil), - ("'/abc/def/'", ("abc/def", .traditional)), - ("'|abc|def|'", ("abc|def", .experimental)), - ("'/abc\\/'def/'", ("abc\\/'def", .traditional)), - ("'|abc\\|'def|'", ("abc\\|'def", .experimental)), - ("'/abc|'def/'", ("abc|'def", .traditional)), - ("'|abc/'def|'", ("abc/'def", .experimental)), - ("'/abc|'def/", nil), - ("'|abc/'def'", nil), - ("'/abc\n/'", nil), - ("'/abc\r/'", nil), + ("#/abc/def/#", ("abc/def", .traditional)), + ("#|abc|def|#", ("abc|def", .experimental)), + ("#/abc\\/#def/#", ("abc\\/#def", .traditional)), + ("#|abc\\|#def|#", ("abc\\|#def", .experimental)), + ("#/abc|#def/#", ("abc|#def", .traditional)), + ("#|abc/#def|#", ("abc/#def", .experimental)), + ("#/abc|#def/", nil), + ("#|abc/#def#", nil), + ("#/abc\n/#", nil), + ("#/abc\r/#", nil), + + (#"re'abcre\''"#, (#"abcre\'"#, .reSingleQuote)), + (#"re'\'"#, nil) ] for (input, expected) in testCases { diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index ac062111..4872e256 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -1436,31 +1436,33 @@ extension RegexTests { // MARK: Parse with delimiters - parseWithDelimitersTest("'/a b/'", concat("a", " ", "b")) - parseWithDelimitersTest("'|a b|'", concat("a", "b")) + parseWithDelimitersTest("#/a b/#", concat("a", " ", "b")) + parseWithDelimitersTest("#|a b|#", concat("a", "b")) - parseWithDelimitersTest("'|[a b]|'", charClass("a", "b")) + parseWithDelimitersTest("#|[a b]|#", charClass("a", "b")) parseWithDelimitersTest( - "'|(?-x)[a b]|'", changeMatchingOptions( + "#|(?-x)[a b]|#", changeMatchingOptions( matchingOptions(removing: .extended), isIsolated: true, charClass("a", " ", "b")) ) - parseWithDelimitersTest("'|[[a ] b]|'", charClass(charClass("a"), "b")) + parseWithDelimitersTest("#|[[a ] b]|#", charClass(charClass("a"), "b")) // Non-semantic whitespace between quantifier characters for consistency // with PCRE. - parseWithDelimitersTest("'|a * ?|'", zeroOrMore(.reluctant, of: "a")) + parseWithDelimitersTest("#|a * ?|#", zeroOrMore(.reluctant, of: "a")) // End-of-line comments aren't enabled by default in experimental syntax. - parseWithDelimitersTest("'|#abc|'", concat("#", "a", "b", "c")) - parseWithDelimitersTest("'|(?x)#abc|'", changeMatchingOptions( + parseWithDelimitersTest("#|#abc|#", concat("#", "a", "b", "c")) + parseWithDelimitersTest("#|(?x)#abc|#", changeMatchingOptions( matchingOptions(adding: .extended), isIsolated: true, empty()) ) - parseWithDelimitersTest("'|||'", alt(empty(), empty())) - parseWithDelimitersTest("'||||'", alt(empty(), empty(), empty())) - parseWithDelimitersTest("'|a||'", alt("a", empty())) + parseWithDelimitersTest("#|||#", alt(empty(), empty())) + parseWithDelimitersTest("#||||#", alt(empty(), empty(), empty())) + parseWithDelimitersTest("#|a||#", alt("a", empty())) + + parseWithDelimitersTest("re'x*'", zeroOrMore(of: "x")) // MARK: Parse not-equal @@ -1878,6 +1880,6 @@ extension RegexTests { func testlibswiftDiagnostics() { libswiftDiagnosticMessageTest( - "'/[x*/'", "cannot parse regular expression: expected ']'") + "#/[x*/#", "cannot parse regular expression: expected ']'") } }