Commonize Char.titlecaseChar() and Char.titlecase() #KT-44369
This commit is contained in:
@@ -92,10 +92,8 @@ fun main(args: Array<String>) {
|
||||
fun addOneToManyMappingsGenerators(generatedDir: File, target: KotlinTarget) {
|
||||
val uppercase = OneToManyMappingsGenerator.forUppercase(generatedDir.resolve("_OneToManyUppercaseMappings.kt"), target, bmpUnicodeDataLines)
|
||||
val lowercase = OneToManyMappingsGenerator.forLowercase(generatedDir.resolve("_OneToManyLowercaseMappings.kt"), target, bmpUnicodeDataLines)
|
||||
val titlecase = OneToManyMappingsGenerator.forTitlecase(generatedDir.resolve("_OneToManyTitlecaseMappings.kt"), target, bmpUnicodeDataLines)
|
||||
oneToManyMappingsGenerators.add(uppercase)
|
||||
oneToManyMappingsGenerators.add(lowercase)
|
||||
oneToManyMappingsGenerators.add(titlecase)
|
||||
}
|
||||
|
||||
var categoryTestGenerator: CharCategoryTestGenerator? = null
|
||||
@@ -112,11 +110,16 @@ fun main(args: Array<String>) {
|
||||
val categoryTestFile = baseDir.resolve("libraries/stdlib/js/test/text/unicodeData/_CharCategoryTest.kt")
|
||||
categoryTestGenerator = CharCategoryTestGenerator(categoryTestFile)
|
||||
|
||||
val commonGeneratedDir = baseDir.resolve("libraries/stdlib/common/src/generated")
|
||||
oneToManyMappingsGenerators.add(OneToManyMappingsGenerator.forTitlecase(commonGeneratedDir.resolve("_OneToManyTitlecaseMappings.kt"), bmpUnicodeDataLines))
|
||||
|
||||
val jsGeneratedDir = baseDir.resolve("libraries/stdlib/js/src/generated/")
|
||||
addRangesGenerators(jsGeneratedDir, KotlinTarget.JS)
|
||||
oneToOneMappingsGenerators.add(MappingsGenerator.forTitlecase(jsGeneratedDir.resolve("_TitlecaseMappings.kt")))
|
||||
|
||||
val jsIrGeneratedDir = baseDir.resolve("libraries/stdlib/js-ir/src/generated/")
|
||||
addRangesGenerators(jsIrGeneratedDir, KotlinTarget.JS_IR)
|
||||
oneToOneMappingsGenerators.add(MappingsGenerator.forTitlecase(jsIrGeneratedDir.resolve("_TitlecaseMappings.kt")))
|
||||
|
||||
// For debugging. To see the file content
|
||||
fun downloadFile(fromUrl: String) {
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ import generators.unicode.hexToInt
|
||||
import java.util.TreeMap
|
||||
|
||||
internal abstract class OneToManyMappingsBuilder(bmpUnicodeDataLines: List<UnicodeDataLine>) {
|
||||
private val bmpUnicodeDataLines = bmpUnicodeDataLines.associateBy { it.char.hexToInt() }
|
||||
protected val bmpUnicodeDataLines = bmpUnicodeDataLines.associateBy { it.char.hexToInt() }
|
||||
private val mappings = TreeMap<Int, List<String>>()
|
||||
|
||||
fun append(line: SpecialCasingLine) {
|
||||
@@ -33,7 +33,7 @@ internal abstract class OneToManyMappingsBuilder(bmpUnicodeDataLines: List<Unico
|
||||
}
|
||||
|
||||
private fun mapping(charCode: Int, line: SpecialCasingLine): List<String>? {
|
||||
val mapping = line.mapping()
|
||||
val mapping = line.mapping() ?: return null
|
||||
|
||||
check(mapping.isNotEmpty() && mapping.all { it.isNotEmpty() })
|
||||
|
||||
@@ -53,6 +53,6 @@ internal abstract class OneToManyMappingsBuilder(bmpUnicodeDataLines: List<Unico
|
||||
return mapping
|
||||
}
|
||||
|
||||
abstract fun SpecialCasingLine.mapping(): List<String>
|
||||
abstract fun SpecialCasingLine.mapping(): List<String>?
|
||||
abstract fun UnicodeDataLine.mapping(): String
|
||||
}
|
||||
+21
-1
@@ -7,8 +7,28 @@ package generators.unicode.mappings.oneToMany.builders
|
||||
|
||||
import generators.unicode.SpecialCasingLine
|
||||
import generators.unicode.UnicodeDataLine
|
||||
import generators.unicode.hexToInt
|
||||
|
||||
internal class OneToManyTitlecaseMappingsBuilder(bmpUnicodeDataLines: List<UnicodeDataLine>) : OneToManyMappingsBuilder(bmpUnicodeDataLines) {
|
||||
override fun SpecialCasingLine.mapping(): List<String> = titlecaseMapping
|
||||
private fun lower(char: Int): Int {
|
||||
return bmpUnicodeDataLines[char]?.lowercaseMapping?.takeIf { it.isNotEmpty() }?.hexToInt() ?: char
|
||||
}
|
||||
|
||||
override fun SpecialCasingLine.mapping(): List<String>? {
|
||||
val title = titlecaseMapping.map { it.hexToInt().toChar() }.joinToString(separator = "")
|
||||
val upperFirst = uppercaseMapping[0].hexToInt().toChar()
|
||||
|
||||
// The version of Unicode in JVM executing this code is likely different than the version of the Unicode being parsed.
|
||||
// Thus use the Unicode data being parsed to convert chars to lowercase.
|
||||
val lowercasedTail = uppercaseMapping.drop(1).map { lower(it.hexToInt()).toChar() }.joinToString(separator = "")
|
||||
|
||||
// Skip titlecase mappings that can be derived by lowercasing tail characters
|
||||
if (title == upperFirst + lowercasedTail) {
|
||||
return null
|
||||
}
|
||||
|
||||
return titlecaseMapping
|
||||
}
|
||||
|
||||
override fun UnicodeDataLine.mapping(): String = titlecaseMapping
|
||||
}
|
||||
|
||||
+18
-14
@@ -5,27 +5,31 @@
|
||||
|
||||
package generators.unicode.mappings.oneToMany.writers
|
||||
|
||||
import generators.unicode.ranges.RangesWritingStrategy
|
||||
import generators.unicode.writeMappings
|
||||
import generators.unicode.toHexCharLiteral
|
||||
import java.io.FileWriter
|
||||
|
||||
internal class OneToManyTitlecaseMappingsWriter(private val strategy: RangesWritingStrategy) : OneToManyMappingsWriter {
|
||||
internal class OneToManyTitlecaseMappingsWriter : OneToManyMappingsWriter {
|
||||
override fun write(mappings: Map<Int, List<String>>, writer: FileWriter) {
|
||||
strategy.beforeWritingRanges(writer)
|
||||
writer.writeMappings(mappings, strategy)
|
||||
strategy.afterWritingRanges(writer)
|
||||
writer.appendLine()
|
||||
writer.appendLine(titlecaseImpl())
|
||||
// We have decided to ignore GREEK EXTENDED block due to their rare usage.
|
||||
// It also leads to decreased js code size and simplified implementation.
|
||||
val nonGreekExtended = mappings.filterNot { it.key in 0x1f00..0x1fff }
|
||||
|
||||
check(nonGreekExtended.size == 1)
|
||||
val n = nonGreekExtended.keys.single()
|
||||
check(n == 0x0149) // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
|
||||
|
||||
// one-to-many titlecase equivalent of the char is "\u02BC\u004E", the same as the uppercase equivalent
|
||||
writer.appendLine(titlecaseImpl(n.toHexCharLiteral()))
|
||||
}
|
||||
|
||||
private fun titlecaseImpl(): String = """
|
||||
private fun titlecaseImpl(apostropheN: String): String = """
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
internal fun Char.titlecaseImpl(): String {
|
||||
val code = this.toInt()
|
||||
val index = binarySearchRange(keys, code)
|
||||
if (index >= 0 && keys[index] == code) {
|
||||
return values[index]
|
||||
val uppercase = uppercase()
|
||||
if (uppercase.length > 1) {
|
||||
return if (this == $apostropheN) uppercase else uppercase[0] + uppercase.substring(1).lowercase()
|
||||
}
|
||||
return titlecaseCharImpl().toString()
|
||||
return titlecaseChar().toString()
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
+4
-1
@@ -22,15 +22,18 @@ internal class TitlecaseMappingsWriter : MappingsWriter {
|
||||
|
||||
writer.append(
|
||||
"""
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
internal fun Char.titlecaseCharImpl(): Char {
|
||||
val code = this.toInt()
|
||||
// Letters repeating <Lu, Lt, Ll> sequence and code of the Lt is a multiple of 3, e.g. <DŽ, Dž, dž>
|
||||
if (${rangeChecks(LuLtLlMappings, "code")}) {
|
||||
return (3 * ((code + 1) / 3)).toChar()
|
||||
}
|
||||
// Lower case letters whose title case mapping equivalent is equal to the original letter
|
||||
if (${rangeChecks(zeroMappings, "code")}) {
|
||||
return this
|
||||
}
|
||||
return uppercaseCharImpl()
|
||||
return uppercaseChar()
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user