Skip to content

Conversation

@natecook1000
Copy link
Member

This fixes an issue where capture groups inside a positive lookahead were being reset even upon successful matching of the lookahead. For example, with the pattern /(?=(\d))/, matching against a string like "abc1" should result in the output ("", "1"). However, accessing the output traps instead, since the range data for capture 1 is missing even on success.

This change resolves the issue by adding a boolean payload to the fail instruction that indicates whether to preserve captures when resetting the matching state, which allows any captures inside a lookahead to persist after success.

Fixes #713.

This fixes an issue where capture groups inside a positive lookahead
were being reset even upon successful matching of the lookahead. For
example, with the pattern `/(?=(\d))/`, matching against a string like
`"abc1"` should result in the output `("", "1")`. However, accessing
the output traps instead, since the range data for capture 1 is
missing even on success.

This change resolves the issue by adding a boolean payload to the
`fail` instruction that indicates whether to preserve captures when
resetting the matching state, which allows any captures inside a
lookahead to persist after success.

Fixes #713.
Comment on lines -214 to +218
init(bool: BoolRegister) {
self.init(bool)
init(bool: Bool) {
self.init(bool ? 1 : 0, 0)
}
var bool: BoolRegister {
interpret()
var boolPayload: Bool {
interpret(as: TypedInt<Bool>.self) == 1
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay to switch this to a payload access? It doesn't look like we actually have a Boolean register.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, if there's no need to have a value that's stored and updated

Comment on lines +145 to +146
mutating func buildFail(preservingCaptures: Bool = false) {
instructions.append(.init(.fail, .init(bool: preservingCaptures)))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you think about renaming fail to backtrack or something similar? I always have to remember that the fail instruction isn't an overall failure, just a failure of the immediate execution track.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, if we can do it pervasively and consistently

Copy link
Member

@milseman milseman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM, with some comments

Comment on lines -214 to +218
init(bool: BoolRegister) {
self.init(bool)
init(bool: Bool) {
self.init(bool ? 1 : 0, 0)
}
var bool: BoolRegister {
interpret()
var boolPayload: Bool {
interpret(as: TypedInt<Bool>.self) == 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, if there's no need to have a value that's stored and updated

Comment on lines +145 to +146
mutating func buildFail(preservingCaptures: Bool = false) {
instructions.append(.init(.fail, .init(bool: preservingCaptures)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, if we can do it pervasively and consistently

@natecook1000
Copy link
Member Author

@swift-ci Please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regex with positive lookahead crashes at runtime when accessing match.output

3 participants