| /* |
| * Copyright 2010-2023 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.generators.builtins.numbers.primitives |
| |
| import org.jetbrains.kotlin.generators.builtins.PrimitiveType |
| import java.io.PrintWriter |
| |
| class JsPrimitivesGenerator(writer: PrintWriter) : BasePrimitivesGenerator(writer) { |
| |
| override fun FileBuilder.modifyGeneratedFile() { |
| suppress("NON_ABSTRACT_FUNCTION_WITH_NO_BODY") |
| suppress("UNUSED_PARAMETER") |
| } |
| |
| override fun PropertyBuilder.modifyGeneratedCompanionObjectProperty(thisKind: PrimitiveType) { |
| if (this.name in setOf("POSITIVE_INFINITY", "NEGATIVE_INFINITY", "NaN")) { |
| annotations += "Suppress(\"DIVISION_BY_ZERO\")" |
| } |
| } |
| |
| override fun ClassBuilder.modifyGeneratedClass(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| annotations += "Suppress(\"NOTHING_TO_INLINE\")" |
| primaryConstructor { |
| visibility = MethodVisibility.INTERNAL |
| parameter { |
| name = "internal val low" |
| type = PrimitiveType.INT.capitalized |
| } |
| parameter { |
| name = "internal val high" |
| type = PrimitiveType.INT.capitalized |
| } |
| } |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedCompareTo(thisKind: PrimitiveType, otherKind: PrimitiveType) { |
| modifyGeneratedBinaryOperation(thisKind, otherKind) |
| } |
| |
| override fun MethodBuilder.modifyGeneratedBinaryOperation(thisKind: PrimitiveType, otherKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| if (thisKind == otherKind) { |
| val implMethod = when (methodName) { |
| "compareTo" -> "compare" |
| "plus" -> "add" |
| "minus" -> "subtract" |
| "times" -> "multiply" |
| "div" -> "divide" |
| "rem" -> "modulo" |
| else -> error("Unsupported binary operation: $methodName") |
| } |
| "this.$implMethod(other)".setAsExpressionBody() |
| } else { |
| modifySignature { isInline = true } |
| "this${thisKind.castToIfNecessary(otherKind)}.${methodName}(other${otherKind.castToIfNecessary(thisKind)})".setAsExpressionBody() |
| } |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedUnaryOperation(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| when (methodName) { |
| "inc" -> "this + 1L" |
| "dec" -> "this - 1L" |
| "unaryMinus" -> "this.inv() + 1L" |
| "unaryPlus" -> { |
| modifySignature { isInline = true } |
| "this" |
| } |
| else -> error(methodName) |
| }.setAsExpressionBody() |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedRangeTo(thisKind: PrimitiveType, otherKind: PrimitiveType, opReturnType: PrimitiveType) { |
| if (thisKind != PrimitiveType.LONG) { |
| noBody() |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedBitShiftOperators(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| val implMethod = when (methodName) { |
| "shl" -> "shiftLeft" |
| "shr" -> "shiftRight" |
| "ushr" -> "shiftRightUnsigned" |
| else -> error(methodName) |
| } |
| "$implMethod(bitCount)".setAsExpressionBody() |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedBitwiseOperators(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| if (methodName == "inv") { |
| "Long(low.inv(), high.inv())".setAsExpressionBody() |
| } else { |
| "Long(this.low $methodName other.low, this.high $methodName other.high)".setAsExpressionBody() |
| } |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedConversions(thisKind: PrimitiveType, otherKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| when (otherKind) { |
| PrimitiveType.CHAR, |
| PrimitiveType.BYTE, |
| PrimitiveType.SHORT -> "low.to${otherKind.capitalized}()" |
| PrimitiveType.INT -> "low" |
| PrimitiveType.LONG -> "this" |
| PrimitiveType.FLOAT -> "toDouble().toFloat()" |
| PrimitiveType.DOUBLE -> "toNumber()" |
| else -> error("Unsupported type $otherKind for Long conversion") |
| }.setAsExpressionBody() |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedEquals(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| "other is Long && equalsLong(other)".setAsExpressionBody() |
| } |
| } |
| |
| override fun MethodBuilder.modifyGeneratedToString(thisKind: PrimitiveType) { |
| if (thisKind == PrimitiveType.LONG) { |
| "this.toStringImpl(radix = 10)".setAsExpressionBody() |
| } |
| } |
| |
| override fun ClassBuilder.generateAdditionalMethods(thisKind: PrimitiveType) { |
| method { |
| signature { |
| isOverride = true |
| methodName = "hashCode" |
| returnType = PrimitiveType.INT.capitalized |
| } |
| if (thisKind == PrimitiveType.LONG) { |
| "hashCode(this)".setAsExpressionBody() |
| } |
| } |
| |
| if (thisKind == PrimitiveType.LONG) { |
| method { |
| additionalComments = """ |
| This method is used by JavaScript to convert objects of type Long to primitives. |
| This is essential for the JavaScript interop. |
| JavaScript functions that expect `number` are imported in Kotlin as expecting `kotlin.Number` |
| (in our standard library, and also in user projects if they use Dukat for generating external declarations). |
| Because `kotlin.Number` is a supertype of `Long` too, there has to be a way for JS to know how to handle Longs. |
| See KT-50202 |
| """.trimIndent() |
| annotations += "JsName(\"valueOf\")" |
| signature { |
| visibility = MethodVisibility.INTERNAL |
| methodName = "valueOf" |
| returnType = PrimitiveType.DOUBLE.capitalized |
| } |
| "toDouble()".setAsExpressionBody() |
| } |
| } |
| } |
| } |