diff --git a/Sources/_RegexParser/Regex/AST/AST.swift b/Sources/_RegexParser/Regex/AST/AST.swift index a7dcd2015..be1548b72 100644 --- a/Sources/_RegexParser/Regex/AST/AST.swift +++ b/Sources/_RegexParser/Regex/AST/AST.swift @@ -125,7 +125,9 @@ extension AST.Node { switch self { case .atom(let a): return a.isQuantifiable - case .group, .conditional, .customCharacterClass, .absentFunction: + case .group(let g): + return g.isQuantifiable + case .conditional, .customCharacterClass, .absentFunction: return true case .alternation, .concatenation, .quantification, .quote, .trivia, .empty: diff --git a/Sources/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 9b0f1cb2e..8e4e76fa1 100644 --- a/Sources/_RegexParser/Regex/AST/Atom.swift +++ b/Sources/_RegexParser/Regex/AST/Atom.swift @@ -768,6 +768,8 @@ extension AST.Atom { // TODO: Are callouts quantifiable? case .escaped(let esc): return esc.isQuantifiable + case .startOfLine, .endOfLine: + return false default: return true } diff --git a/Sources/_RegexParser/Regex/AST/Group.swift b/Sources/_RegexParser/Regex/AST/Group.swift index 8ecaadeda..6fd46abe7 100644 --- a/Sources/_RegexParser/Regex/AST/Group.swift +++ b/Sources/_RegexParser/Regex/AST/Group.swift @@ -136,3 +136,18 @@ extension AST.Group { } } } + +extension AST.Group { + var isQuantifiable: Bool { + switch kind.value { + case .capture, .namedCapture, .balancedCapture, .nonCapture, + .nonCaptureReset, .atomicNonCapturing, .scriptRun, .atomicScriptRun, + .changeMatchingOptions: + return true + + case .lookahead, .negativeLookahead, .nonAtomicLookahead, + .lookbehind, .negativeLookbehind, .nonAtomicLookbehind: + return false + } + } +} diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index 9dfcff99e..f5e98b1fc 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -2569,6 +2569,10 @@ extension RegexTests { diagnosticTest(#"\Z??"#, .notQuantifiable) diagnosticTest(#"\G*?"#, .notQuantifiable) diagnosticTest(#"\z+?"#, .notQuantifiable) + diagnosticTest(#"^*"#, .notQuantifiable) + diagnosticTest(#"$?"#, .notQuantifiable) + diagnosticTest(#"(?=a)+"#, .notQuantifiable) + diagnosticTest(#"(?i)*"#, .notQuantifiable) diagnosticTest(#"\K{1}"#, .unsupported(#"'\K'"#)) diagnosticTest(#"\y{2,5}"#, .notQuantifiable) diagnosticTest(#"\Y{3,}"#, .notQuantifiable)