regex: Clean TODOs

This commit is contained in:
Ilya Matveev
2017-06-16 16:19:23 +07:00
committed by ilmat192
parent bfcc0fc0d0
commit 1e7d132a88
32 changed files with 31 additions and 107 deletions
@@ -47,7 +47,6 @@ internal abstract class AbstractLineTerminator {
} }
} }
// TODO: Replace with property or another Kotlin-way singleton.
fun getInstance(flag: Int): AbstractLineTerminator { fun getInstance(flag: Int): AbstractLineTerminator {
if (flag and Pattern.UNIX_LINES != 0) { if (flag and Pattern.UNIX_LINES != 0) {
return unixLT return unixLT
@@ -55,7 +55,6 @@ internal abstract class SpecialToken {
*/ */
abstract val type: Type abstract val type: Type
// TODO: Replace with an enum?
enum class Type { enum class Type {
CHARCLASS, CHARCLASS,
QUANTIFIER QUANTIFIER
@@ -87,8 +86,6 @@ internal class Lexer(val patternString: String, flags: Int) {
/** When in [Mode.ESCAPE] mode, this field will save the previous one */ /** When in [Mode.ESCAPE] mode, this field will save the previous one */
private var savedMode = Mode.PATTERN private var savedMode = Mode.PATTERN
// TODO: Remove it.
// TODO: Harmony doesn't allow us to set the ESCAPE mode from outside of the lexer. DO we need this limitation?
fun setModeWithReread(value: Mode) { fun setModeWithReread(value: Mode) {
if(value == Mode.PATTERN || value == Mode.RANGE) { if(value == Mode.PATTERN || value == Mode.RANGE) {
mode = value mode = value
@@ -99,7 +96,6 @@ internal class Lexer(val patternString: String, flags: Int) {
} }
// Tokens ========================================================================================================== // Tokens ==========================================================================================================
// TODO: May be add getters.
internal var lookBack: Int = 0 // Previous char read. internal var lookBack: Int = 0 // Previous char read.
private set private set
internal var currentChar: Int = 0 // Current character read. Returns 0 if there is no more characters. internal var currentChar: Int = 0 // Current character read. Returns 0 if there is no more characters.
@@ -107,7 +103,6 @@ internal class Lexer(val patternString: String, flags: Int) {
internal var lookAhead: Int = 0 // Next character. internal var lookAhead: Int = 0 // Next character.
private set private set
// TODO: Investigate if we can make it not nullable or not
internal var curSpecialToken: SpecialToken? = null // Current special token (e.g. quantifier) internal var curSpecialToken: SpecialToken? = null // Current special token (e.g. quantifier)
private set private set
internal var lookAheadSpecialToken: SpecialToken? = null // Next special token internal var lookAheadSpecialToken: SpecialToken? = null // Next special token
@@ -116,7 +111,7 @@ internal class Lexer(val patternString: String, flags: Int) {
// Indices in the pattern. // Indices in the pattern.
private var index = 0 // Current char being processed index. private var index = 0 // Current char being processed index.
private var prevNonWhitespaceIndex = 0 // Previous non-whitespace character index. private var prevNonWhitespaceIndex = 0 // Previous non-whitespace character index.
private var curTokenIndex = 0 // Current token start index. TODO: == index? private var curTokenIndex = 0 // Current token start index.
private var lookAheadTokenIndex = 0 // Next token index. private var lookAheadTokenIndex = 0 // Next token index.
init { init {
@@ -124,7 +119,7 @@ internal class Lexer(val patternString: String, flags: Int) {
if (flags and Pattern.LITERAL > 0) { if (flags and Pattern.LITERAL > 0) {
processedPattern = Pattern.quote(patternString) processedPattern = Pattern.quote(patternString)
} else if (flags and Pattern.CANON_EQ > 0) { } else if (flags and Pattern.CANON_EQ > 0) {
processedPattern = Lexer.normalize(patternString) // TODO: rewrite normalization processedPattern = Lexer.normalize(patternString)
} }
this.pattern = processedPattern.toCharArray().copyOf(processedPattern.length + 2) this.pattern = processedPattern.toCharArray().copyOf(processedPattern.length + 2)
@@ -142,7 +137,6 @@ internal class Lexer(val patternString: String, flags: Int) {
val isQuantifier: Boolean get() = isSpecial && curSpecialToken!!.type == SpecialToken.Type.QUANTIFIER val isQuantifier: Boolean get() = isSpecial && curSpecialToken!!.type == SpecialToken.Type.QUANTIFIER
val isNextSpecial: Boolean get() = lookAheadSpecialToken != null val isNextSpecial: Boolean get() = lookAheadSpecialToken != null
// TODO: May be replace with some already existing.
private fun Int.isSurrogatePair() : Boolean { private fun Int.isSurrogatePair() : Boolean {
val high = (this ushr 16).toChar() val high = (this ushr 16).toChar()
val low = this.toChar() val low = this.toChar()
@@ -152,7 +146,6 @@ internal class Lexer(val patternString: String, flags: Int) {
private fun Char.isLineSeparator(): Boolean = private fun Char.isLineSeparator(): Boolean =
this == '\n' || this == '\r' || this == '\u0085' || this.toInt() or 1 == '\u2029'.toInt() this == '\n' || this == '\r' || this == '\u0085' || this.toInt() or 1 == '\u2029'.toInt()
// TODO: Replace with properties
/** Checks if there are any characters in the pattern. */ /** Checks if there are any characters in the pattern. */
fun isEmpty(): Boolean = fun isEmpty(): Boolean =
currentChar == 0 && lookAhead == 0 && index >= pattern.size && !isSpecial currentChar == 0 && lookAhead == 0 && index >= pattern.size && !isSpecial
@@ -170,7 +163,6 @@ internal class Lexer(val patternString: String, flags: Int) {
* Restores flags for Lexer * Restores flags for Lexer
* @param flags * @param flags
*/ */
// TODO: Refactor.
fun restoreFlags(flags: Int) { fun restoreFlags(flags: Int) {
this.flags = flags this.flags = flags
lookAhead = currentChar lookAhead = currentChar
@@ -221,7 +213,7 @@ internal class Lexer(val patternString: String, flags: Int) {
*/ */
private fun nextIndex(): Int { private fun nextIndex(): Int {
prevNonWhitespaceIndex = index prevNonWhitespaceIndex = index
if (flags and Pattern.COMMENTS != 0) { // TODO: Refactor flags. if (flags and Pattern.COMMENTS != 0) {
skipComments() skipComments()
} else { } else {
index++ index++
@@ -310,7 +302,6 @@ internal class Lexer(val patternString: String, flags: Int) {
if (lookAheadChar == 'E') { if (lookAheadChar == 'E') {
// If \E found - change the mode to the previous one and shift to the next char. // If \E found - change the mode to the previous one and shift to the next char.
mode = savedMode mode = savedMode
// TODO: + we create an array with 2 additional characters but check the index here. May be there is not need to check it?
lookAhead = if (index <= pattern.size - 2) nextCodePoint() else 0 lookAhead = if (index <= pattern.size - 2) nextCodePoint() else 0
} else { } else {
// If \ have no E - make a step back and return. // If \ have no E - make a step back and return.
@@ -332,8 +323,9 @@ internal class Lexer(val patternString: String, flags: Int) {
return processEscapedChar() return processEscapedChar()
} }
// TODO: Look like we can create a quantifier here.
when (lookAheadChar) { when (lookAheadChar) {
// Quantifier (*, +, ?). TODO: May be create a quantifier here. // Quantifier (*, +, ?).
'+', '*', '?' -> { '+', '*', '?' -> {
val mode = if (index < pattern.size) pattern[index] else '*' val mode = if (index < pattern.size) pattern[index] else '*'
// look at the next character to determine if the mode is greedy, reluctant or possessive. // look at the next character to determine if the mode is greedy, reluctant or possessive.
@@ -407,14 +399,6 @@ internal class Lexer(val patternString: String, flags: Int) {
')' -> lookAhead = CHAR_RIGHT_PARENTHESIS ')' -> lookAhead = CHAR_RIGHT_PARENTHESIS
'[' -> { lookAhead = CHAR_LEFT_SQUARE_BRACKET; mode = Mode.RANGE } '[' -> { lookAhead = CHAR_LEFT_SQUARE_BRACKET; mode = Mode.RANGE }
// TODO: No need in this case.
/*']' -> {
assert(mode == Mode.PATTERN)
/* // TODO: Think we cannot meet it here. because we already checked the mode and it is PATTERN, not RANGE. Check it.
if (mode == Lexer.MODE_RANGE) {
lookAhead = CHAR_RIGHT_SQUARE_BRACKET
}*/
}*/
'^' -> lookAhead = CHAR_CARET '^' -> lookAhead = CHAR_CARET
'|' -> lookAhead = CHAR_VERTICAL_BAR '|' -> lookAhead = CHAR_VERTICAL_BAR
'.' -> lookAhead = CHAR_DOT '.' -> lookAhead = CHAR_DOT
@@ -457,15 +441,12 @@ internal class Lexer(val patternString: String, flags: Int) {
val cs = parseCharClassName() val cs = parseCharClassName()
val negative = lookAheadChar == 'P' val negative = lookAheadChar == 'P'
// TODO: Harmony processes errors thrown from the getPredefinedClass
lookAheadSpecialToken = AbstractCharClass.getPredefinedClass(cs, negative) lookAheadSpecialToken = AbstractCharClass.getPredefinedClass(cs, negative)
lookAhead = 0 lookAhead = 0
} }
// Word/whitespace/digit. // Word/whitespace/digit.
'w', 's', 'd', 'W', 'S', 'D' -> { 'w', 's', 'd', 'W', 'S', 'D' -> {
// TODO: Strange string creation. Can we do easily
// TODO: may be use parseCharClassName here?
lookAheadSpecialToken = AbstractCharClass.getPredefinedClass( lookAheadSpecialToken = AbstractCharClass.getPredefinedClass(
fromCharArray(pattern, prevNonWhitespaceIndex, 1), fromCharArray(pattern, prevNonWhitespaceIndex, 1),
false false
@@ -496,7 +477,6 @@ internal class Lexer(val patternString: String, flags: Int) {
} }
// A literal: octal, hex, or hex unicode. // A literal: octal, hex, or hex unicode.
// TODO: May be use standard Kotlin methods here.
'0' -> lookAhead = readOctals() '0' -> lookAhead = readOctals()
'x' -> lookAhead = readHex(2) 'x' -> lookAhead = readHex(2)
'u' -> lookAhead = readHex(4) 'u' -> lookAhead = readHex(4)
@@ -520,7 +500,6 @@ internal class Lexer(val patternString: String, flags: Int) {
} }
} }
// TODO: May be throw an exception in any not supported case?
'C', 'E', 'F', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'R', 'T', 'U', 'V', 'X', 'Y', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'o', 'q', 'y' -> throw PatternSyntaxException() 'C', 'E', 'F', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'R', 'T', 'U', 'V', 'X', 'Y', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'o', 'q', 'y' -> throw PatternSyntaxException()
} }
return false return false
@@ -570,8 +549,7 @@ internal class Lexer(val patternString: String, flags: Int) {
} }
} }
// TODO: Double check this contition. if (min < 0 || max >=0 && max < min) {
if (min < 0 || max >=0 && max - min < 0) {
throw PatternSyntaxException() throw PatternSyntaxException()
} }
@@ -581,7 +559,7 @@ internal class Lexer(val patternString: String, flags: Int) {
'?' -> { lookAhead = Lexer.QUANT_COMP_R; nextIndex() } '?' -> { lookAhead = Lexer.QUANT_COMP_R; nextIndex() }
else -> lookAhead = Lexer.QUANT_COMP else -> lookAhead = Lexer.QUANT_COMP
} }
return Quantifier(min, max) // TODO: Save mode (P, R, G) in the Quantifier return Quantifier(min, max)
} }
// Reading methods for specific tokens ============================================================================= // Reading methods for specific tokens =============================================================================
@@ -652,7 +630,6 @@ internal class Lexer(val patternString: String, flags: Int) {
if (index < pattern.size - 2) { if (index < pattern.size - 2) {
// one symbol family // one symbol family
if (pattern[index] != '{') { if (pattern[index] != '{') {
// TODO: Replace such string formation with something like patter.substring(..)
return "Is${pattern[nextIndex()]}" return "Is${pattern[nextIndex()]}"
} }
@@ -692,11 +669,9 @@ internal class Lexer(val patternString: String, flags: Int) {
} }
/** Process octal integer. */ /** Process octal integer. */
// TODO: Replace with String.toInt(8)
private fun readOctals(): Int { private fun readOctals(): Int {
val length = pattern.size - 2 // TODO: Add a special method for check 'index < pattern.size - 2' val length = pattern.size - 2
var result = 0 var result = 0
// TODO: Add digit conversion.
var digit = digitOf(pattern[index], 8) var digit = digitOf(pattern[index], 8)
if (digit == -1) { if (digit == -1) {
throw PatternSyntaxException() throw PatternSyntaxException()
@@ -758,7 +733,7 @@ internal class Lexer(val patternString: String, flags: Int) {
val QUANT_COMP_P = QMOD_POSSESSIVE or '{'.toInt() val QUANT_COMP_P = QMOD_POSSESSIVE or '{'.toInt()
val QUANT_COMP_R = QMOD_RELUCTANT or '{'.toInt() val QUANT_COMP_R = QMOD_RELUCTANT or '{'.toInt()
/** Returns true if [ch] is a plain token. */ // TODO: May be rename /** Returns true if [ch] is a plain token. */
fun isLetter(ch: Int): Boolean { fun isLetter(ch: Int): Boolean {
// All supplementary codepoints have integer value that is >= 0. // All supplementary codepoints have integer value that is >= 0.
return ch >= 0 return ch >= 0
@@ -22,12 +22,7 @@ package kotlin.text.regex
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: rework defaults.
// TODO: May be we can remove left/rightBound and just create a substring for matching/searching.
// TODO: We don't use right/leftBound in our API now. So this function can be removed.
// TODO: But I think it may be useful to save them for further improvements of the API.
internal class MatchResultImpl internal class MatchResultImpl
// TODO: Refactor the constructor comment.
/** /**
* @param input an input sequence for matching/searching. * @param input an input sequence for matching/searching.
* @param regex a [Regex] instance used for matching/searching. * @param regex a [Regex] instance used for matching/searching.
@@ -37,20 +32,18 @@ constructor (internal val input: CharSequence,
internal val regex: Regex) : MatchResult { internal val regex: Regex) : MatchResult {
// Harmony's implementation ======================================================================================== // Harmony's implementation ========================================================================================
// TODO: Rework number of groups
private val nativePattern = regex.nativePattern private val nativePattern = regex.nativePattern
private val groupCount = nativePattern.capturingGroupCount private val groupCount = nativePattern.capturingGroupCount
private val groupBounds = IntArray(groupCount * 2) { -1 } private val groupBounds = IntArray(groupCount * 2) { -1 }
private val consumers = IntArray(nativePattern.consumersCount + 1) { -1 } // TODO: What is consumers array? private val consumers = IntArray(nativePattern.consumersCount + 1) { -1 }
// Used by quantifiers to store a count of a quantified expression occurrences. // Used by quantifiers to store a count of a quantified expression occurrences.
val enterCounters: IntArray = IntArray( maxOf(nativePattern.groupQuantifierCount, 0) ) // TODO remove maxOf val enterCounters: IntArray = IntArray( maxOf(nativePattern.groupQuantifierCount, 0) )
var startIndex: Int = 0 var startIndex: Int = 0
set (startIndex: Int) { set (startIndex: Int) {
field = startIndex field = startIndex
// TODO: what is it? And do we need it?
if (previousMatch < 0) { if (previousMatch < 0) {
previousMatch = startIndex previousMatch = startIndex
} }
@@ -62,7 +55,7 @@ constructor (internal val input: CharSequence,
// MatchResult interface =========================================================================================== // MatchResult interface ===========================================================================================
/** The range of indices in the original string where match was captured. */ /** The range of indices in the original string where match was captured. */
override val range: IntRange override val range: IntRange
get() = getStart(0) until getEnd(0) // TODO: I don't like these get... set... methods. Rename them or make properties. get() = getStart(0) until getEnd(0)
/** The substring from the input string captured by this match. */ /** The substring from the input string captured by this match. */
override val value: String override val value: String
@@ -136,7 +129,6 @@ constructor (internal val input: CharSequence,
// Harmony's implementation ======================================================================================== // Harmony's implementation ========================================================================================
// TODO: What is it?
fun setConsumed(counter: Int, value: Int) { fun setConsumed(counter: Int, value: Int) {
this.consumers[counter] = value this.consumers[counter] = value
} }
@@ -148,7 +140,6 @@ constructor (internal val input: CharSequence,
fun isCaptured(group: Int): Boolean = getStart(group) >= 0 fun isCaptured(group: Int): Boolean = getStart(group) >= 0
// Setters and getters for starts and ends of groups =============================================================== // Setters and getters for starts and ends of groups ===============================================================
// TODO: Decide what access modifier should we use in this class.
internal fun setStart(group: Int, offset: Int) { internal fun setStart(group: Int, offset: Int) {
checkGroup(group) checkGroup(group)
groupBounds[group * 2] = offset groupBounds[group * 2] = offset
@@ -189,14 +180,12 @@ constructor (internal val input: CharSequence,
* @param group the group, ranging from 0 to groupCount() - 1, with 0 representing the whole pattern. * @param group the group, ranging from 0 to groupCount() - 1, with 0 representing the whole pattern.
* @return the text that matched the group. * @return the text that matched the group.
*/ */
// TODO: Reread and maybe rewrite.
fun group(group: Int = 0): String? { fun group(group: Int = 0): String? {
val start = getStart(group) val start = getStart(group)
val end = getEnd(group) val end = getEnd(group)
if (start < 0) { // TODO: Do we need to check end? if (start < 0 || end < 0) {
return null return null
} }
assert(start <= end && end >= 0 && end <= input.length) // TODO: remove the assert.
return input.subSequence(getStart(group), getEnd(group)).toString() return input.subSequence(getStart(group), getEnd(group)).toString()
} }
@@ -207,7 +196,7 @@ constructor (internal val input: CharSequence,
* @return the number of groups. * @return the number of groups.
*/ */
fun groupCount(): Int { fun groupCount(): Int {
return groupCount - 1 // TODO: Do something with it. These +/-1 are terrible. return groupCount - 1
} }
/* /*
@@ -43,7 +43,9 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
if (flags != 0 && flags or flagsBitMask != flagsBitMask) { if (flags != 0 && flags or flagsBitMask != flagsBitMask) {
throw IllegalArgumentException() throw IllegalArgumentException()
} }
AbstractSet.counter = 1 // TODO: It's for debug purposes.
// It's for debug purposes.
AbstractSet.counter = 1
startNode = processExpression(-1, this.flags, null) startNode = processExpression(-1, this.flags, null)
@@ -108,7 +110,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
fSet = FinalSet() fSet = FinalSet()
saveChangedFlags = true saveChangedFlags = true
} else { } else {
// TODO: Looks like next here is null. Or it is set later.
fSet = FSet(capturingGroupCount) fSet = FSet(capturingGroupCount)
} }
if (capturingGroupCount < BACK_REF_NUMBER) { if (capturingGroupCount < BACK_REF_NUMBER) {
@@ -136,7 +137,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
} }
} }
} }
// TODO: Do we realy need this null check? Looks like child cannot be null.
children.add(child) children.add(child)
} while (!(lexemes.isEmpty() || lexemes.currentChar == Lexer.CHAR_RIGHT_PARENTHESIS)) } while (!(lexemes.isEmpty() || lexemes.currentChar == Lexer.CHAR_RIGHT_PARENTHESIS))
@@ -184,7 +184,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
|| lexemes.lookAhead == Lexer.CHAR_DOLLAR)) { || lexemes.lookAhead == Lexer.CHAR_DOLLAR)) {
val ch = lexemes.next() val ch = lexemes.next()
// TODO: Adapt to our checks.
if (Char.isSupplementaryCodePoint(ch)) { if (Char.isSupplementaryCodePoint(ch)) {
substring.append(Char.toChars(ch)) substring.append(Char.toChars(ch))
} else { } else {
@@ -197,7 +196,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
/** /**
* D->a * D->a
*/ */
// TODO: Refactor
private fun processDecomposedChar(): AbstractSet { private fun processDecomposedChar(): AbstractSet {
val codePoints = IntArray(Lexer.MAX_DECOMPOSITION_LENGTH) val codePoints = IntArray(Lexer.MAX_DECOMPOSITION_LENGTH)
val codePointsHangul: CharArray val codePointsHangul: CharArray
@@ -288,7 +286,7 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
} }
} }
lexemes.isHighSurrogate() || lexemes.isLowSurrogate() -> { lexemes.isHighSurrogate() || lexemes.isLowSurrogate() -> {
val term = processTerminal(last) // TODO: term is not null. val term = processTerminal(last)
cur = processQuantifier(last, term) cur = processQuantifier(last, term)
} }
else -> { else -> {
@@ -479,7 +477,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
if (lexemes.currentChar != Lexer.CHAR_RIGHT_SQUARE_BRACKET) { if (lexemes.currentChar != Lexer.CHAR_RIGHT_SQUARE_BRACKET) {
throw PatternSyntaxException() throw PatternSyntaxException()
} }
// TODO: Set mode lexer as Mode.Range is set.
lexemes.setModeWithReread(Lexer.Mode.PATTERN) lexemes.setModeWithReread(Lexer.Mode.PATTERN)
lexemes.next() lexemes.next()
} }
@@ -598,7 +595,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
/** /**
* Process [...] ranges * Process [...] ranges
*/ */
// TODO: We can merge it with processRangeExpression.
private fun processRange(negative: Boolean, last: AbstractSet): AbstractSet { private fun processRange(negative: Boolean, last: AbstractSet): AbstractSet {
val res = processRangeExpression(negative) val res = processRangeExpression(negative)
val rangeSet = processRangeSet(res) val rangeSet = processRangeSet(res)
@@ -760,7 +756,6 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
return result return result
} }
// TODO: Reread
private fun processRangeSet(charClass: AbstractCharClass): AbstractSet { private fun processRangeSet(charClass: AbstractCharClass): AbstractSet {
if (charClass.hasLowHighSurrogates()) { if (charClass.hasLowHighSurrogates()) {
val lowHighSurrRangeSet = SurrogateRangeSet(charClass.surrogates) val lowHighSurrRangeSet = SurrogateRangeSet(charClass.surrogates)
@@ -10,7 +10,6 @@ import kotlin.IllegalArgumentException
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: May be replace with some other class (Range?).
internal class Quantifier(val min: Int, val max: Int = min) : SpecialToken() { internal class Quantifier(val min: Int, val max: Int = min) : SpecialToken() {
init { init {
@@ -98,7 +98,7 @@ internal abstract class AbstractSet(val type: Int = 0) {
/** /**
* @param leftLimit - an index, to finish search back (left limit, inclusive). * @param leftLimit - an index, to finish search back (left limit, inclusive).
* @param rightLimit - an index to start search from (right limit, exclusive). // TODO: Is it really exclusive * @param rightLimit - an index to start search from (right limit, exclusive).
* @param testString - test string. * @param testString - test string.
* @param matchResult - match result. * @param matchResult - match result.
* @return an index to start back search next time if this search fails(new left bound); * @return an index to start back search next time if this search fails(new left bound);
@@ -128,7 +128,6 @@ internal abstract class AbstractSet(val type: Int = 0) {
* @param set - A node the intersection is checked for. Usually a previous node. * @param set - A node the intersection is checked for. Usually a previous node.
* @return true if the given node intersects with this one, false otherwise. * @return true if the given node intersects with this one, false otherwise.
*/ */
// TODO: May be rename. e.g. intersects for something else.
open fun first(set: AbstractSet): Boolean = true open fun first(set: AbstractSet): Boolean = true
/** /**
@@ -32,8 +32,7 @@ open internal class AtomicJointSet(children: List<AbstractSet>, fSet: FSet) : No
val shift = it.matches(startIndex, testString, matchResult) val shift = it.matches(startIndex, testString, matchResult)
if (shift >= 0) { if (shift >= 0) {
// AtomicFset always returns true, but saves the index to run this next.match() from; // AtomicFset always returns true, but saves the index to run this next.match() from;
// TODO: Try to get rid of this explicit cast to AtomicFSet return next.matches((fSet as AtomicFSet).index, testString, matchResult)
return next.matches((fSet as AtomicFSet).index, testString, matchResult) // TODO: We use next here.
} }
} }
@@ -44,6 +43,5 @@ open internal class AtomicJointSet(children: List<AbstractSet>, fSet: FSet) : No
override val name: String override val name: String
get() = "AtomicJointSet" get() = "AtomicJointSet"
// TODO: looks like we can replace it with just next property.
override var next: AbstractSet = dummyNext override var next: AbstractSet = dummyNext
} }
@@ -22,7 +22,6 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: Process next better - it is non-null in almost all cases.
open internal class CharSet(char: Char, val ignoreCase: Boolean = false) : LeafSet() { open internal class CharSet(char: Char, val ignoreCase: Boolean = false) : LeafSet() {
// We use only low case characters when working in case insensitive mode. // We use only low case characters when working in case insensitive mode.
@@ -87,8 +87,6 @@ package kotlin.text.regex
* the first consisting of these surrogate characters and the second consisting of all others characters * the first consisting of these surrogate characters and the second consisting of all others characters
* from the parent range. This class represents the parent range split in such a manner. * from the parent range. This class represents the parent range split in such a manner.
*/ */
// TODO: May be we can merge sets with surrogates and without them.
// TODO: Use more specific constructor params (e.g. RangeSet)
internal class CompositeRangeSet(/* range without surrogates */ val withoutSurrogates: AbstractSet, internal class CompositeRangeSet(/* range without surrogates */ val withoutSurrogates: AbstractSet,
/* range containing surrogates only */ val surrogates: AbstractSet) : SimpleSet() { /* range containing surrogates only */ val surrogates: AbstractSet) : SimpleSet() {
@@ -18,7 +18,6 @@
package kotlin.text.regex package kotlin.text.regex
/** Represents canonical decomposition of Unicode character. Is used when CANON_EQ flag of Pattern class is specified. */ /** Represents canonical decomposition of Unicode character. Is used when CANON_EQ flag of Pattern class is specified. */
// TODO: Refactor it.
open internal class DecomposedCharSet( open internal class DecomposedCharSet(
/** Decomposition of the Unicode codepoint */ /** Decomposition of the Unicode codepoint */
private val decomposedChar: IntArray, private val decomposedChar: IntArray,
@@ -22,7 +22,6 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: Looks like we can extend AbstractSet instead of JointSet here.
internal class DotSet(val lt: AbstractLineTerminator, val matchLineTerminator: Boolean) internal class DotSet(val lt: AbstractLineTerminator, val matchLineTerminator: Boolean)
: SimpleSet(AbstractSet.TYPE_DOTSET) { : SimpleSet(AbstractSet.TYPE_DOTSET) {
@@ -24,7 +24,7 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: What is consCounter? // TODO: rename consCounter?
internal class EOLSet(val consCounter: Int, val lt: AbstractLineTerminator, val multiline: Boolean = false) : SimpleSet() { internal class EOLSet(val consCounter: Int, val lt: AbstractLineTerminator, val multiline: Boolean = false) : SimpleSet() {
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
@@ -21,7 +21,6 @@ package kotlin.text.regex
* The node which marks end of the particular group. * The node which marks end of the particular group.
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: Rename?
open internal class FSet(val groupIndex: Int) : SimpleSet() { open internal class FSet(val groupIndex: Int) : SimpleSet() {
var isBackReferenced = false var isBackReferenced = false
@@ -96,7 +95,7 @@ internal class FinalSet : FSet(0) {
internal class NonCapFSet(groupIndex: Int) : FSet(groupIndex) { internal class NonCapFSet(groupIndex: Int) : FSet(groupIndex) {
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
matchResult.setConsumed(groupIndex, startIndex - matchResult.getConsumed(groupIndex)) // TODO: Don't understand it. matchResult.setConsumed(groupIndex, startIndex - matchResult.getConsumed(groupIndex))
return next.matches(startIndex, testString, matchResult) return next.matches(startIndex, testString, matchResult)
} }
@@ -43,8 +43,6 @@ open internal class GroupQuantifierSet(
return next.matches(startIndex, testString, matchResult) return next.matches(startIndex, testString, matchResult)
} }
// TODO: We can store an optimized functions for specific cases (like *) in a separate callable reference and
// TODO: call it instead of checks during matching.
// Fast case: '*' or {0, } - no need to count occurrences. // Fast case: '*' or {0, } - no need to count occurrences.
if (min == 0 && max == Quantifier.INF) { if (min == 0 && max == Quantifier.INF) {
val nextIndex = innerSet.matches(startIndex, testString, matchResult) val nextIndex = innerSet.matches(startIndex, testString, matchResult)
@@ -21,7 +21,6 @@ package kotlin.text.regex
* Represents canonical decomposition of Hangul syllable. Is used when * Represents canonical decomposition of Hangul syllable. Is used when
* CANON_EQ flag of Pattern class is specified. * CANON_EQ flag of Pattern class is specified.
*/ */
// TODO: Refactor it.
internal class HangulDecomposedCharSet( internal class HangulDecomposedCharSet(
/** /**
* Decomposed Hangul syllable. * Decomposed Hangul syllable.
@@ -36,7 +36,6 @@ open internal class JointSet(children: List<AbstractSet>, fSet: FSet) : Abstract
/** /**
* Returns startIndex+shift, the next position to match * Returns startIndex+shift, the next position to match
*/ */
// TODO: Why don't we use a next here?
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
if (children.isEmpty()) { if (children.isEmpty()) {
return -1 return -1
@@ -26,11 +26,7 @@ internal abstract class LeafSet : SimpleSet(AbstractSet.TYPE_LEAF) {
open val charCount = 1 open val charCount = 1
/** /** Returns "shift", the number of accepted chars. Commonly internal function, but called by quantifiers. */
* Returns "shift", the number of accepted chars.
* Commonly internal function, but called by quantifiers.
*/
// TODO: Magic function. Use by another way?
abstract fun accepts(startIndex: Int, testString: CharSequence): Int abstract fun accepts(startIndex: Int, testString: CharSequence): Int
/** /**
@@ -36,7 +36,7 @@ internal class PositiveLookAheadSet(children: List<AbstractSet>, fSet: FSet) : A
return -1 return -1
} }
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true // TODO: May be false? override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String override val name: String
get() = "PositiveLookaheadJointSet" get() = "PositiveLookaheadJointSet"
} }
@@ -38,7 +38,7 @@ internal class PositiveLookBehindSet(children: List<AbstractSet>, fSet: FSet) :
return -1 return -1
} }
override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true // TODO: False was here. It's true just for experiment. override fun hasConsumed(matchResult: MatchResultImpl): Boolean = true
override val name: String override val name: String
get() = "PositiveBehindJointSet" get() = "PositiveBehindJointSet"
} }
@@ -31,7 +31,7 @@ internal class PossessiveGroupQuantifierSet(
): GroupQuantifierSet(quantifier, innerSet, next, type, setCounter) { ): GroupQuantifierSet(quantifier, innerSet, next, type, setCounter) {
init { init {
innerSet.next = FSet.possessiveFSet // TODO: Try to use such an approach for other sets. innerSet.next = FSet.possessiveFSet
} }
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
@@ -45,8 +45,7 @@ internal class PossessiveGroupQuantifierSet(
nextIndex = innerSet.matches(index, testString, matchResult) nextIndex = innerSet.matches(index, testString, matchResult)
} }
// TODO: Do we need this check? if (occurrences < quantifier.min) {
if (/* nextIndex < 0 && */ occurrences < quantifier.min) {
return -1 return -1
} else { } else {
return next.matches(index, testString, matchResult) return next.matches(index, testString, matchResult)
@@ -36,7 +36,6 @@ internal class PossessiveLeafQuantifierSet(
var index = startIndex var index = startIndex
var occurrences = 0 var occurrences = 0
// TODO: Create a separate functions for these loops?
while (occurrences < min) { while (occurrences < min) {
if (index + leaf.charCount > testString.length) { if (index + leaf.charCount > testString.length) {
return -1 return -1
@@ -22,11 +22,9 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: check of innerSet must be nullable or not
internal abstract class QuantifierSet(open var innerSet: AbstractSet, override var next: AbstractSet, type: Int) internal abstract class QuantifierSet(open var innerSet: AbstractSet, override var next: AbstractSet, type: Int)
: SimpleSet(type) { : SimpleSet(type) {
// TODO: Looks like we need true by default here.
override fun first(set: AbstractSet): Boolean = override fun first(set: AbstractSet): Boolean =
innerSet.first(set) || next.first(set) innerSet.first(set) || next.first(set)
@@ -18,7 +18,7 @@
package kotlin.text.regex package kotlin.text.regex
/** /**
* Represents node accepting single character from the given char class. (TODO: Not a surrogate character?) * Represents node accepting single character from the given char class.
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
@@ -50,7 +50,7 @@ internal class ReluctantGroupQuantifierSet(
// can't go inner set; // can't go inner set;
if (enterCounter >= max) { if (enterCounter >= max) {
matchResult.enterCounters[groupQuantifierIndex] = 0 // TODO: Do we need it? matchResult.enterCounters[groupQuantifierIndex] = 0
return next.matches(startIndex, testString, matchResult) return next.matches(startIndex, testString, matchResult)
} }
@@ -50,7 +50,6 @@ internal class ReluctantLeafQuantifierSet(
occurrences++ occurrences++
} }
// TODO: May be refactor this loop.
do { do {
var shift = next.matches(index, testString, matchResult) var shift = next.matches(index, testString, matchResult)
if (shift >= 0) { if (shift >= 0) {
@@ -32,8 +32,6 @@ internal class SOLSet(val lt: AbstractLineTerminator, val multiline: Boolean = f
return next.matches(startIndex, testString, matchResult) return next.matches(startIndex, testString, matchResult)
} }
} else { } else {
// TODO: In Kotlin JVM the empty string doesn't match to "^.$" pattern in multiline mode and matches in single-line mode.
// TODO: So do we need to implement this behaviour or we can match to the pattern in the both cases?
if (startIndex != testString.length if (startIndex != testString.length
&& (startIndex == 0 && (startIndex == 0
|| lt.isAfterLineTerminator(testString[startIndex - 1], testString[startIndex]))) { || lt.isAfterLineTerminator(testString[startIndex - 1], testString[startIndex]))) {
@@ -86,7 +86,6 @@ open internal class SequenceSet(substring: CharSequence, val ignoreCase: Boolean
return -1 return -1
} }
// TODO: reread/rewrite
override fun first(set: AbstractSet): Boolean { override fun first(set: AbstractSet): Boolean {
if (ignoreCase) { if (ignoreCase) {
return super.first(set) // TODO: Add correct checks for this case. return super.first(set) // TODO: Add correct checks for this case.
@@ -94,7 +93,6 @@ open internal class SequenceSet(substring: CharSequence, val ignoreCase: Boolean
return when (set) { return when (set) {
is CharSet -> set.char == patternString[0] is CharSet -> set.char == patternString[0]
is RangeSet -> set.accepts(0, patternString.substring(0, 1)) > 0 is RangeSet -> set.accepts(0, patternString.substring(0, 1)) > 0
// TODO: perfrom a char to codepoint converter.
is SupplementaryRangeSet -> set.contains(patternString[0]) || patternString.length > 1 && set.contains(Char.toCodePoint(patternString[0], patternString[1])) is SupplementaryRangeSet -> set.contains(patternString[0]) || patternString.length > 1 && set.contains(Char.toCodePoint(patternString[0], patternString[1]))
is SupplementaryCharSet -> if (patternString.length > 1) set.codePoint == Char.toCodePoint(patternString[0], patternString[1]) is SupplementaryCharSet -> if (patternString.length > 1) set.codePoint == Char.toCodePoint(patternString[0], patternString[1])
else false else false
@@ -87,8 +87,6 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
//assumes int value of this supplementary codepoint as a parameter
// TODO: Tests crash here. Investigate why.
internal class SupplementaryCharSet(val codePoint: Int, ignoreCase: Boolean) internal class SupplementaryCharSet(val codePoint: Int, ignoreCase: Boolean)
: SequenceSet(fromCharArray(Char.toChars(codePoint), 0, 2), ignoreCase) { : SequenceSet(fromCharArray(Char.toChars(codePoint), 0, 2), ignoreCase) {
@@ -96,7 +94,6 @@ internal class SupplementaryCharSet(val codePoint: Int, ignoreCase: Boolean)
get() = patternString get() = patternString
override fun first(set: AbstractSet): Boolean { override fun first(set: AbstractSet): Boolean {
// TODO: replace with when
return when (set) { return when (set) {
is SupplementaryCharSet -> set.codePoint == codePoint is SupplementaryCharSet -> set.codePoint == codePoint
is SupplementaryRangeSet -> set.contains(codePoint) is SupplementaryRangeSet -> set.contains(codePoint)
@@ -91,7 +91,6 @@ package kotlin.text.regex
*/ */
open internal class SupplementaryRangeSet(charClass: AbstractCharClass, val ignoreCase: Boolean = false): SimpleSet() { open internal class SupplementaryRangeSet(charClass: AbstractCharClass, val ignoreCase: Boolean = false): SimpleSet() {
// TODO: may be add ignoreCase flag to CharClass
val chars = charClass.instance val chars = charClass.instance
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
@@ -91,10 +91,8 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: Could we use just CharSet instead of this one?
internal class LowSurrogateCharSet(low: Char) : CharSet(low) { internal class LowSurrogateCharSet(low: Char) : CharSet(low) {
// TODO: Remove bounds from MatchResultImpl.
override fun accepts(startIndex: Int, testString: CharSequence): Int { override fun accepts(startIndex: Int, testString: CharSequence): Int {
val result = super.accepts(startIndex, testString) val result = super.accepts(startIndex, testString)
if (result < 0 || testString.isHighSurrogate(startIndex - 1)) { if (result < 0 || testString.isHighSurrogate(startIndex - 1)) {
@@ -108,7 +108,7 @@ internal class SurrogateRangeSet(surrChars: AbstractCharClass) : RangeSet(surrCh
override fun first(set: AbstractSet): Boolean { override fun first(set: AbstractSet): Boolean {
return when (set) { return when (set) {
is SurrogateRangeSet -> true // TODO: May be add some check here. is SurrogateRangeSet -> true
is CharSet, is CharSet,
is RangeSet, is RangeSet,
is SupplementaryCharSet, is SupplementaryCharSet,
@@ -23,7 +23,6 @@ package kotlin.text.regex
* *
* @author Nikolay A. Kuznetsov * @author Nikolay A. Kuznetsov
*/ */
// TODO: May be rename?
internal class UnifiedQuantifierSet(quant: LeafQuantifierSet) : LeafQuantifierSet(Quantifier.starQuantifier, quant.leaf, quant.next, quant.type) { internal class UnifiedQuantifierSet(quant: LeafQuantifierSet) : LeafQuantifierSet(Quantifier.starQuantifier, quant.leaf, quant.next, quant.type) {
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int { override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
@@ -50,6 +49,6 @@ internal class UnifiedQuantifierSet(quant: LeafQuantifierSet) : LeafQuantifierSe
} }
init { init {
innerSet.next = this // TODO: O_o innerSet.next = this
} }
} }