[K/N][stdlib] Fixed lookaround regexes (KT-45932)

This commit is contained in:
Elena Lepilkina
2021-04-23 12:12:49 +03:00
committed by Space
parent d7a87a8552
commit 18462445b7
5 changed files with 120 additions and 13 deletions
@@ -56,6 +56,26 @@ constructor (internal val input: CharSequence,
var previousMatch = -1
var mode = Regex.Mode.MATCH
private data class MatchResultState(val groupBounds: IntArray, val consumers: IntArray, val enterCounters: IntArray,
val startIndex: Int, val previousMatch: Int)
private var state: MatchResultState? = null
internal fun saveState() {
state = MatchResultState(groupBounds.copyOf(), consumers.copyOf(), enterCounters.copyOf(), startIndex, previousMatch)
}
internal fun rollbackState(): Boolean {
return state?.let {
it.groupBounds.copyInto(groupBounds)
it.consumers.copyInto(consumers)
it.enterCounters.copyInto(enterCounters)
startIndex = it.startIndex
previousMatch = it.previousMatch
true
} ?: false
}
// MatchResult interface ===========================================================================================
/** The range of indices in the original string where match was captured. */
override val range: IntRange
@@ -25,10 +25,10 @@ package kotlin.text.regex
/**
* Positive lookahead node.
*/
internal class PositiveLookAheadSet(children: List<AbstractSet>, fSet: FSet) : AtomicJointSet(children, fSet) {
internal class PositiveLookAheadSet(children: List<AbstractSet>, fSet: FSet) : LookAroundSet(children, fSet) {
/** Returns startIndex+shift, the next position to match */
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
children.forEach {
val shift = it.matches(startIndex, testString, matchResult)
if (shift >= 0) {
@@ -39,7 +39,6 @@ internal class PositiveLookAheadSet(children: List<AbstractSet>, fSet: FSet) : A
return -1
}
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String
get() = "PositiveLookaheadJointSet"
}
@@ -47,10 +46,10 @@ internal class PositiveLookAheadSet(children: List<AbstractSet>, fSet: FSet) : A
/**
* Negative look ahead node.
*/
internal class NegativeLookAheadSet(children: List<AbstractSet>, fSet: FSet) : AtomicJointSet(children, fSet) {
internal class NegativeLookAheadSet(children: List<AbstractSet>, fSet: FSet) : LookAroundSet(children, fSet) {
/** Returns startIndex+shift, the next position to match */
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
children.forEach {
if (it.matches(startIndex, testString, matchResult) >= 0) {
return -1
@@ -60,7 +59,6 @@ internal class NegativeLookAheadSet(children: List<AbstractSet>, fSet: FSet) : A
return next.matches(startIndex, testString, matchResult)
}
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String
get() = "NegativeLookaheadJointSet"
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.text.regex
/**
* Abstract class for lookahead and lookbehind nodes.
*/
internal abstract class LookAroundSet(children: List<AbstractSet>, fSet: FSet) : AtomicJointSet(children, fSet) {
protected abstract fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int
/** Returns startIndex+shift, the next position to match */
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
matchResult.saveState()
return tryToMatch(startIndex, testString, matchResult).also { if (it < 0) matchResult.rollbackState() }
}
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
}
@@ -25,11 +25,10 @@ package kotlin.text.regex
/**
* Positive lookbehind node.
*/
internal class PositiveLookBehindSet(children: List<AbstractSet>, fSet: FSet) : AtomicJointSet(children, fSet) {
internal class PositiveLookBehindSet(children: List<AbstractSet>, fSet: FSet) : LookAroundSet(children, fSet) {
/** Returns startIndex+shift, the next position to match */
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
matchResult.setConsumed(groupIndex, startIndex)
children.forEach {
if (it.findBack(0, startIndex, testString, matchResult) >= 0) {
@@ -41,7 +40,6 @@ internal class PositiveLookBehindSet(children: List<AbstractSet>, fSet: FSet) :
return -1
}
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String
get() = "PositiveBehindJointSet"
}
@@ -49,10 +47,10 @@ internal class PositiveLookBehindSet(children: List<AbstractSet>, fSet: FSet) :
/**
* Negative look behind node.
*/
internal class NegativeLookBehindSet(children: List<AbstractSet>, fSet: FSet) : AtomicJointSet(children, fSet) {
internal class NegativeLookBehindSet(children: List<AbstractSet>, fSet: FSet) : LookAroundSet(children, fSet) {
/** Returns startIndex+shift, the next position to match */
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
override fun tryToMatch(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
matchResult.setConsumed(groupIndex, startIndex)
children.forEach {
@@ -65,7 +63,6 @@ internal class NegativeLookBehindSet(children: List<AbstractSet>, fSet: FSet) :
return next.matches(startIndex, testString, matchResult)
}
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String
get() = "NegativeBehindJointSet"
}