@@ -351,6 +351,59 @@ fileprivate extension Compiler.ByteCodeGen {
351351 }
352352 }
353353
354+ func _guaranteesForwardProgressImpl( _ list: ArraySlice < DSLTree . Node > , position: inout Int ) -> Bool {
355+ guard position < list. endIndex else { return false }
356+ let node = list [ position]
357+ position += 1
358+ switch node {
359+ case . orderedChoice( let children) :
360+ return ( 0 ..< children. count) . allSatisfy { _ in
361+ _guaranteesForwardProgressImpl ( list, position: & position)
362+ }
363+ case . concatenation( let children) :
364+ return ( 0 ..< children. count) . contains { _ in
365+ _guaranteesForwardProgressImpl ( list, position: & position)
366+ }
367+ case . capture( _, _, _, _) :
368+ return _guaranteesForwardProgressImpl ( list, position: & position)
369+ case . nonCapturingGroup( let kind, _) :
370+ switch kind. ast {
371+ case . lookahead, . negativeLookahead, . lookbehind, . negativeLookbehind:
372+ return false
373+ default :
374+ return _guaranteesForwardProgressImpl ( list, position: & position)
375+ }
376+ case . atom( let atom) :
377+ switch atom {
378+ case . changeMatchingOptions, . assertion: return false
379+ // Captures may be nil so backreferences may be zero length matches
380+ case . backreference: return false
381+ default : return true
382+ }
383+ case . trivia, . empty:
384+ return false
385+ case . quotedLiteral( let string) :
386+ return !string. isEmpty
387+ case . consumer, . matcher:
388+ // Allow zero width consumers and matchers
389+ return false
390+ case . customCharacterClass( let ccc) :
391+ return ccc. guaranteesForwardProgress
392+ case . quantification( let amount, _, _) :
393+ let ( atLeast, _) = amount. ast. bounds
394+ guard let atLeast, atLeast > 0 else { return false }
395+ return _guaranteesForwardProgressImpl ( list, position: & position)
396+ case . limitCaptureNesting, . ignoreCapturesInTypedOutput:
397+ return _guaranteesForwardProgressImpl ( list, position: & position)
398+ default : return false
399+ }
400+ }
401+
402+ func guaranteesForwardProgress( _ list: ArraySlice < DSLTree . Node > ) -> Bool {
403+ var pos = list. startIndex
404+ return _guaranteesForwardProgressImpl ( list, position: & pos)
405+ }
406+
354407 mutating func emitQuantification(
355408 _ amount: AST . Quantification . Amount ,
356409 _ kind: DSLTree . QuantificationKind ,
@@ -526,8 +579,8 @@ fileprivate extension Compiler.ByteCodeGen {
526579 let startPosition : PositionRegister ?
527580 // FIXME: forward progress check?!
528581 let emitPositionChecking =
529- ( !optimizationsEnabled || ( list. first ? . guaranteesForwardProgress != true ) ) &&
530- maxExtraTrips == nil
582+ ( !optimizationsEnabled || !guaranteesForwardProgress ( list) )
583+ && maxExtraTrips == nil
531584
532585 if emitPositionChecking {
533586 startPosition = builder. makePositionRegister ( )
0 commit comments