From d500d03baaac4ae7c43865ad9188eeecb3f3ae1b Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Thu, 17 Feb 2022 20:05:12 +0300 Subject: [PATCH] [K/N and WASM] Support back references to groups with multi-digit index #KT-51776 --- .../src/kotlin/text/regex/MatchResultImpl.kt | 2 +- .../src/kotlin/text/regex/Pattern.kt | 40 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/MatchResultImpl.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/MatchResultImpl.kt index e552647626f..14cadb63e8c 100644 --- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/MatchResultImpl.kt +++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/MatchResultImpl.kt @@ -36,7 +36,7 @@ constructor (internal val input: CharSequence, // Harmony's implementation ======================================================================================== 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 consumers = IntArray(nativePattern.consumersCount + 1) { -1 } diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/regex/Pattern.kt b/libraries/stdlib/native-wasm/src/kotlin/text/regex/Pattern.kt index f5e874c63dd..1ecf690e2dd 100644 --- a/libraries/stdlib/native-wasm/src/kotlin/text/regex/Pattern.kt +++ b/libraries/stdlib/native-wasm/src/kotlin/text/regex/Pattern.kt @@ -32,8 +32,8 @@ internal class Pattern(val pattern: String, flags: Int = 0) { /** A lexer instance used to get tokens from the pattern. */ private val lexemes = Lexer(pattern, flags) - /** All back references that may be used in pattern. */ - private val backRefs = arrayOfNulls(BACK_REF_NUMBER) + /** List of all capturing groups in the pattern. Primarily used for handling back references. */ + val capturingGroups = mutableListOf() /** Mapping from group name to its index */ val groupNameToIndex = hashMapOf() @@ -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.*/ private var needsBackRefReplacement = false - /** Global count of found capturing groups. */ - var capturingGroupCount = 0 - private set - /** A number of group quantifiers in the pattern */ var groupQuantifierCount = 0 private set /** * 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 private set @@ -127,16 +123,15 @@ internal class Pattern(val pattern: String, flags: Int = 0) { fSet = FinalSet() saveChangedFlags = true } else { - fSet = FSet(capturingGroupCount) - } - if (capturingGroupCount < BACK_REF_NUMBER) { - backRefs[capturingGroupCount] = fSet + fSet = FSet(capturingGroups.size) } + + capturingGroups.add(fSet) + if (ch == Lexer.CHAR_NAMED_GROUP) { 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 '8'.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) 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. */ private fun createBackReference(groupIndex: Int): BackReferenceSet { - if (groupIndex >= 0 && groupIndex < capturingGroupCount) { // All is ok - the group exists. - // backRefs[groupIndex] is proved to be not null because the group is already created (groupIndex < capturingGroupCount) - backRefs[groupIndex]!!.isBackReferenced = true + if (groupIndex >= 0 && groupIndex < capturingGroups.size) { + capturingGroups[groupIndex].isBackReferenced = true needsBackRefReplacement = true // And process back references in the second pass. return BackReferenceSet(groupIndex, consumersCount++, hasFlag(CASE_INSENSITIVE)) } else { @@ -888,9 +891,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) { */ 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 */ internal val flagsBitMask = Pattern.UNIX_LINES or Pattern.CASE_INSENSITIVE or