Skip to content

Commit 4508479

Browse files
committed
DSLList generation fixes
Was missing the AST-sourced indicator node plus a DSLList-based implementation of `guaranteesForwardProgress`.
1 parent a8f7ee9 commit 4508479

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

Sources/_StringProcessing/ByteCodeGen+DSLList.swift

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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()

Sources/_StringProcessing/Regex/DSLList.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct DSLList {
3434
}
3535

3636
init(ast: AST) {
37-
self.nodes = []
37+
self.nodes = [.limitCaptureNesting(TEMP_FAKE_NODE)]
3838
try! ast.root.convert(into: &nodes)
3939
}
4040

0 commit comments

Comments
 (0)