[K/N and WASM] Support back references to groups with multi-digit index #KT-51776
This commit is contained in:
committed by
Space
parent
9c4c1ed557
commit
d500d03baa
@@ -36,7 +36,7 @@ constructor (internal val input: CharSequence,
|
|||||||
|
|
||||||
// Harmony's implementation ========================================================================================
|
// Harmony's implementation ========================================================================================
|
||||||
private val nativePattern = regex.nativePattern
|
private val nativePattern = regex.nativePattern
|
||||||
private val groupCount = nativePattern.capturingGroupCount
|
private val groupCount = nativePattern.capturingGroups.size
|
||||||
private val groupBounds = IntArray(groupCount * 2) { -1 }
|
private val groupBounds = IntArray(groupCount * 2) { -1 }
|
||||||
|
|
||||||
private val consumers = IntArray(nativePattern.consumersCount + 1) { -1 }
|
private val consumers = IntArray(nativePattern.consumersCount + 1) { -1 }
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
/** A lexer instance used to get tokens from the pattern. */
|
/** A lexer instance used to get tokens from the pattern. */
|
||||||
private val lexemes = Lexer(pattern, flags)
|
private val lexemes = Lexer(pattern, flags)
|
||||||
|
|
||||||
/** All back references that may be used in pattern. */
|
/** List of all capturing groups in the pattern. Primarily used for handling back references. */
|
||||||
private val backRefs = arrayOfNulls<FSet>(BACK_REF_NUMBER)
|
val capturingGroups = mutableListOf<FSet>()
|
||||||
|
|
||||||
/** Mapping from group name to its index */
|
/** Mapping from group name to its index */
|
||||||
val groupNameToIndex = hashMapOf<String, Int>()
|
val groupNameToIndex = hashMapOf<String, Int>()
|
||||||
@@ -41,17 +41,13 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
/** Is true if back referenced sets replacement by second compilation pass is needed.*/
|
/** Is true if back referenced sets replacement by second compilation pass is needed.*/
|
||||||
private var needsBackRefReplacement = false
|
private var needsBackRefReplacement = false
|
||||||
|
|
||||||
/** Global count of found capturing groups. */
|
|
||||||
var capturingGroupCount = 0
|
|
||||||
private set
|
|
||||||
|
|
||||||
/** A number of group quantifiers in the pattern */
|
/** A number of group quantifiers in the pattern */
|
||||||
var groupQuantifierCount = 0
|
var groupQuantifierCount = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A number of consumers found in the pattern.
|
* A number of consumers found in the pattern.
|
||||||
* Consumer is any expression ending with an FSet except capturing groups (they are counted by [capturingGroupCount])
|
* Consumer is any expression ending with an FSet except capturing groups (they are counted by [capturingGroups])
|
||||||
*/
|
*/
|
||||||
var consumersCount = 0
|
var consumersCount = 0
|
||||||
private set
|
private set
|
||||||
@@ -127,16 +123,15 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
fSet = FinalSet()
|
fSet = FinalSet()
|
||||||
saveChangedFlags = true
|
saveChangedFlags = true
|
||||||
} else {
|
} else {
|
||||||
fSet = FSet(capturingGroupCount)
|
fSet = FSet(capturingGroups.size)
|
||||||
}
|
|
||||||
if (capturingGroupCount < BACK_REF_NUMBER) {
|
|
||||||
backRefs[capturingGroupCount] = fSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capturingGroups.add(fSet)
|
||||||
|
|
||||||
if (ch == Lexer.CHAR_NAMED_GROUP) {
|
if (ch == Lexer.CHAR_NAMED_GROUP) {
|
||||||
val name = (lexemes.curSpecialToken as NamedGroup).name
|
val name = (lexemes.curSpecialToken as NamedGroup).name
|
||||||
groupNameToIndex[name] = capturingGroupCount
|
groupNameToIndex[name] = fSet.groupIndex
|
||||||
}
|
}
|
||||||
capturingGroupCount++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,7 +574,16 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
0x80000000.toInt() or '7'.toInt(),
|
0x80000000.toInt() or '7'.toInt(),
|
||||||
0x80000000.toInt() or '8'.toInt(),
|
0x80000000.toInt() or '8'.toInt(),
|
||||||
0x80000000.toInt() or '9'.toInt() -> {
|
0x80000000.toInt() or '9'.toInt() -> {
|
||||||
val groupIndex = (char and 0x7FFFFFFF) - '0'.toInt()
|
var groupIndex = (char and 0x7FFFFFFF) - '0'.code
|
||||||
|
while (lexemes.lookAhead in '0'.code..'9'.code) {
|
||||||
|
val newGroupIndex = (groupIndex * 10) + (lexemes.lookAhead - '0'.code)
|
||||||
|
if (newGroupIndex in 0 until capturingGroups.size) {
|
||||||
|
groupIndex = newGroupIndex
|
||||||
|
lexemes.next()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
term = createBackReference(groupIndex)
|
term = createBackReference(groupIndex)
|
||||||
lexemes.next()
|
lexemes.next()
|
||||||
}
|
}
|
||||||
@@ -636,9 +640,8 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
|
|
||||||
/** Creates a back reference to the group with specified [groupIndex], or throws if the group doesn't exist yet. */
|
/** Creates a back reference to the group with specified [groupIndex], or throws if the group doesn't exist yet. */
|
||||||
private fun createBackReference(groupIndex: Int): BackReferenceSet {
|
private fun createBackReference(groupIndex: Int): BackReferenceSet {
|
||||||
if (groupIndex >= 0 && groupIndex < capturingGroupCount) { // All is ok - the group exists.
|
if (groupIndex >= 0 && groupIndex < capturingGroups.size) {
|
||||||
// backRefs[groupIndex] is proved to be not null because the group is already created (groupIndex < capturingGroupCount)
|
capturingGroups[groupIndex].isBackReferenced = true
|
||||||
backRefs[groupIndex]!!.isBackReferenced = true
|
|
||||||
needsBackRefReplacement = true // And process back references in the second pass.
|
needsBackRefReplacement = true // And process back references in the second pass.
|
||||||
return BackReferenceSet(groupIndex, consumersCount++, hasFlag(CASE_INSENSITIVE))
|
return BackReferenceSet(groupIndex, consumersCount++, hasFlag(CASE_INSENSITIVE))
|
||||||
} else {
|
} else {
|
||||||
@@ -888,9 +891,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|
|||||||
*/
|
*/
|
||||||
val CANON_EQ = 1 shl 6
|
val CANON_EQ = 1 shl 6
|
||||||
|
|
||||||
/** Max number of back references supported. */
|
|
||||||
internal val BACK_REF_NUMBER = 10
|
|
||||||
|
|
||||||
/** A bit mask that includes all defined match flags */
|
/** A bit mask that includes all defined match flags */
|
||||||
internal val flagsBitMask = Pattern.UNIX_LINES or
|
internal val flagsBitMask = Pattern.UNIX_LINES or
|
||||||
Pattern.CASE_INSENSITIVE or
|
Pattern.CASE_INSENSITIVE or
|
||||||
|
|||||||
Reference in New Issue
Block a user