New J2K: move all literal conversion stuff to LiteralConversion & add octal literals conversion

This commit is contained in:
Ilya Kirillov
2019-05-29 14:04:05 +03:00
parent 60b2b81e9c
commit e04c984e48
5 changed files with 105 additions and 170 deletions
@@ -81,6 +81,7 @@ object ConversionsRunner {
+MethodReferenceToLambdaConversion(context)
+BuiltinMembersConversion(context)
+ImplicitCastsConversion(context)
+LiteralConversion()
+CollectImportsConversion(context)
+SortClassMembersConversion()
@@ -92,7 +92,6 @@ class ImplicitCastsConversion(private val context: NewJ2kConverterContext) : Rec
}
}
private fun JKExpression.castStringToRegex(toType: JKType): JKExpression? {
if (toType.safeAs<JKClassType>()?.classReference?.fqName != "java.util.regex.Pattern") return null
val expressionType = type(context.symbolProvider) ?: return null
@@ -133,7 +132,7 @@ class ImplicitCastsConversion(private val context: NewJ2kConverterContext) : Rec
return JKJavaLiteralExpressionImpl(
literal,
expectedType
).fixLiteral(expectedType)
)
}
}
@@ -1,65 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.nj2k.conversions
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.nj2k.tree.impl.*
class JavaStandartMethodsConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKClass) return recurse(element)
for (declaration in element.classBody.declarations) {
if (declaration !is JKJavaMethodImpl) continue
if (fixToStringMethod(declaration)) continue
if (fixFinalizeMethod(declaration, element)) continue
if (fixCloneMethod(declaration)) {
element.inheritance.implements +=
JKTypeElementImpl(
JKClassTypeImpl(
JKUnresolvedClassSymbol("Cloneable"),
emptyList(), Nullability.NotNull
)
)
continue
}
}
return recurse(element)
}
private fun fixToStringMethod(method: JKJavaMethodImpl): Boolean {
if (method.name.value != "toString") return false
if (method.parameters.isNotEmpty()) return false
val type = (method.returnType.type as? JKClassType)
?.takeIf { it.classReference.name == "String" }
?.updateNullability(Nullability.NotNull) ?: return false
method.returnType = JKTypeElementImpl(type)
return true
}
private fun fixCloneMethod(method: JKJavaMethodImpl): Boolean {
if (method.name.value != "clone") return false
if (method.parameters.isNotEmpty()) return false
val type = (method.returnType.type as? JKClassType)
?.takeIf { it.classReference.name == "Object" }
?.updateNullability(Nullability.NotNull) ?: return false
method.returnType = JKTypeElementImpl(type)
return true
}
private fun fixFinalizeMethod(method: JKJavaMethodImpl, containingClass: JKClass): Boolean {
if (method.name.value != "finalize") return false
if (method.parameters.isNotEmpty()) return false
if (method.returnType.type != JKJavaVoidType) return false
if (method.modality == Modality.OVERRIDE) {
method.modality =
if (containingClass.modality == Modality.OPEN) Modality.OPEN
else Modality.FINAL
}
return true
}
}
@@ -5,13 +5,112 @@
package org.jetbrains.kotlin.nj2k.conversions
import org.jetbrains.kotlin.nj2k.fixLiteral
import org.jetbrains.kotlin.nj2k.tree.JKJavaLiteralExpression
import org.jetbrains.kotlin.nj2k.tree.JKTreeElement
import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.nj2k.tree.impl.JKKtLiteralExpressionImpl
import java.math.BigInteger
class LiteralConversion : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKJavaLiteralExpression) return recurse(element)
return element.fixLiteral(element.type)
return element.convertLiteral()
}
private fun JKLiteralExpression.convertLiteral(): JKLiteralExpression =
when (type) {
JKLiteralExpression.LiteralType.DOUBLE -> toDoubleLiteral()
JKLiteralExpression.LiteralType.FLOAT -> toFloatLiteral()
JKLiteralExpression.LiteralType.LONG -> toLongLiteral()
JKLiteralExpression.LiteralType.INT -> toIntLiteral()
JKLiteralExpression.LiteralType.CHAR -> convertCharLiteral()
JKLiteralExpression.LiteralType.STRING -> toStringLiteral()
else -> this
}.withNonCodeElementsFrom(this)
private fun JKLiteralExpression.toDoubleLiteral() =
JKKtLiteralExpressionImpl(
literal.cleanFloatAndDoubleLiterals()
.let { text ->
if (!text.contains(".") && !text.contains("e", true))
"$text."
else text
}.let { text ->
if (text.endsWith(".")) "${text}0" else text
},
JKLiteralExpression.LiteralType.DOUBLE
)
private fun JKLiteralExpression.toFloatLiteral() =
JKKtLiteralExpressionImpl(
literal.cleanFloatAndDoubleLiterals()
.let { text ->
if (!text.endsWith("f")) "${text}f"
else text
},
JKLiteralExpression.LiteralType.FLOAT
)
private fun JKLiteralExpression.toStringLiteral() =
JKKtLiteralExpressionImpl(literal.replace("((?:\\\\)*)\\\\([0-3]?[0-7]{1,2})".toRegex()) { matchResult ->
val leadingBackslashes = matchResult.groupValues[1]
if (leadingBackslashes.length % 2 == 0)
kotlin.String.format("%s\\u%04x", leadingBackslashes, java.lang.Integer.parseInt(matchResult.groupValues[2], 8))
else matchResult.value
}.replace("\\$([A-Za-z]+|\\{)".toRegex(), "\\\\$0"), JKLiteralExpression.LiteralType.STRING)
private fun JKLiteralExpression.convertCharLiteral(): JKKtLiteralExpression =
JKKtLiteralExpressionImpl(
literal.replace("\\\\([0-3]?[0-7]{1,2})".toRegex()) {
String.format("\\u%04x", Integer.parseInt(it.groupValues[1], 8))
},
JKLiteralExpression.LiteralType.CHAR
)
private fun JKLiteralExpression.toIntLiteral(): JKKtLiteralExpression =
JKKtLiteralExpressionImpl(
literal
.replace("l", "", ignoreCase = true)
.convertHexLiteral(isLongLiteral = false)
.convertOctalLiteral(),
JKLiteralExpression.LiteralType.INT
)
private fun JKLiteralExpression.toLongLiteral(): JKKtLiteralExpression =
JKKtLiteralExpressionImpl(
literal
.replace("l", "", ignoreCase = true)
.convertHexLiteral(isLongLiteral = true)
.convertOctalLiteral() + "L",
JKLiteralExpression.LiteralType.LONG
)
private fun String.convertHexLiteral(isLongLiteral: Boolean): String {
if (!startsWith("0x", ignoreCase = true)) return this
val value = BigInteger(drop(2), 16)
return when {
isLongLiteral && value.bitLength() > 63 ->
"-0x${value.toLong().toString(16).substring(1)}"
!isLongLiteral && value.bitLength() > 31 ->
"-0x${value.toInt().toString(16).substring(1)}"
else -> this
}
}
private fun String.convertOctalLiteral(): String {
if (!startsWith("0") || length == 1 || get(1).toLowerCase() == 'x') return this
val value = BigInteger(drop(1), 8)
return value.toString()
}
private fun String.cleanFloatAndDoubleLiterals() =
replace("L", "", ignoreCase = true)
.replace("d", "", ignoreCase = true)
.replace(".e", "e", ignoreCase = true)
.replace(".f", "", ignoreCase = true)
.replace("f", "", ignoreCase = true)
}
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.math.BigInteger
fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Nullable): JKClassType =
JKClassTypeImpl(
@@ -375,104 +374,6 @@ fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: NewJ2kConverterC
|| it.isInDecrementOrIncrement()
}
fun JKLiteralExpression.fixLiteral(expectedType: JKLiteralExpression.LiteralType): JKLiteralExpression =
when (expectedType) {
JKLiteralExpression.LiteralType.DOUBLE -> convertDoubleLiteral(literal)
JKLiteralExpression.LiteralType.FLOAT -> convertFloatLiteral(literal)
JKLiteralExpression.LiteralType.LONG, JKLiteralExpression.LiteralType.INT -> convertIntegerLiteral(this)
JKLiteralExpression.LiteralType.CHAR -> convertCharLiteral(literal)
JKLiteralExpression.LiteralType.STRING -> convertStringLiteral(literal)
else -> this
}.withNonCodeElementsFrom(this)
private fun convertDoubleLiteral(text: String): JKKtLiteralExpression {
var newText =
text.replace("L", "", true)
.replace("d", "", true)
.replace(".e", "e", true)
.replace(".f", "", true)
.replace("f", "", true)
if (!newText.contains(".") && !newText.contains("e", true))
newText += "."
if (newText.endsWith("."))
newText += "0"
return JKKtLiteralExpressionImpl(
newText,
JKLiteralExpression.LiteralType.DOUBLE
)
}
private fun convertFloatLiteral(text: String): JKKtLiteralExpressionImpl {
return JKKtLiteralExpressionImpl(
text.replace("L", "", true)
.replace(".f", "f", true)
.replace("F", "f")
.replace(".e", "e", true)
.let {
if (!it.endsWith("f")) "${it}f"
else it
},
JKLiteralExpression.LiteralType.FLOAT
)
}
private fun convertStringLiteral(text: String): JKKtLiteralExpressionImpl {
var newText = text.replace("((?:\\\\)*)\\\\([0-3]?[0-7]{1,2})".toRegex()) {
val leadingBackslashes = it.groupValues[1]
if (leadingBackslashes.length % 2 == 0) {
String.format("%s\\u%04x", leadingBackslashes, Integer.parseInt(it.groupValues[2], 8))
} else {
it.value
}
}
newText = newText.replace("\\$([A-Za-z]+|\\{)".toRegex(), "\\\\$0")
return JKKtLiteralExpressionImpl(newText, JKLiteralExpression.LiteralType.STRING)
}
private fun convertCharLiteral(text: String): JKKtLiteralExpression {
return JKKtLiteralExpressionImpl(
text.replace("\\\\([0-3]?[0-7]{1,2})".toRegex()) {
String.format("\\u%04x", Integer.parseInt(it.groupValues[1], 8))
},
JKLiteralExpression.LiteralType.CHAR
)
}
private fun convertIntegerLiteral(element: JKLiteralExpression): JKKtLiteralExpression {
var text = element.literal
if (element.type == JKLiteralExpression.LiteralType.LONG) {
text = text.replace("l", "L").let {
if (!it.endsWith("L")) it + "L" else it
}
}
fun isHexLiteral(text: String) = text.startsWith("0x") || text.startsWith("0X")
if ((element.type == JKLiteralExpression.LiteralType.LONG || element.type == JKLiteralExpression.LiteralType.INT) && isHexLiteral(text)) {
val v = BigInteger(text.substring(2).replace("L", ""), 16)
if (text.contains("L")) {
if (v.bitLength() > 63) {
text = "-0x${v.toLong().toString(16).substring(1)}L"
}
} else {
if (v.bitLength() > 31) {
text = "-0x${v.toInt().toString(16).substring(1)}"
}
}
} else if (element.type == JKLiteralExpression.LiteralType.INT) {
text = element.literal
}
return JKKtLiteralExpressionImpl(
text,
element.type
)
}
fun equalsExpression(left: JKExpression, right: JKExpression, symbolProvider: JKSymbolProvider) =
kotlinBinaryExpression(
left,