Generate docs for floorDiv and mod and improve docs for div and rem

Refactor operator documentation generation for primitives and unsigned
types so that it is easier to specialize it.

Manually sync docs of numeric types in js-ir stdlib.

 KT-26234
This commit is contained in:
Ilya Gorbunov
2021-03-02 09:54:10 +03:00
parent 50d4979531
commit 7e2c365b79
11 changed files with 899 additions and 191 deletions
+13
View File
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.generators.builtins
import org.jetbrains.kotlin.generators.builtins.ProgressionKind.*
import java.io.PrintWriter
enum class PrimitiveType(val byteSize: Int) {
BYTE(1),
@@ -65,3 +66,15 @@ fun hashLong(v: String) = "($v xor ($v ushr 32))"
fun convert(v: String, from: UnsignedType, to: UnsignedType) = if (from == to) v else "$v.to${to.capitalized}()"
fun convert(v: String, from: PrimitiveType, to: PrimitiveType) = if (from == to) v else "$v.to${to.capitalized}()"
fun PrintWriter.printDoc(documentation: String, indent: String) {
val docLines = documentation.lines()
if (docLines.size == 1) {
this.println("$indent/** $documentation */")
} else {
this.println("$indent/**")
docLines.forEach { this.println("$indent * $it") }
this.println("$indent */")
}
}
+45 -10
View File
@@ -8,16 +8,17 @@ package org.jetbrains.kotlin.generators.builtins.numbers
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.convert
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator
import org.jetbrains.kotlin.generators.builtins.printDoc
import java.io.PrintWriter
class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) {
companion object {
internal val binaryOperators: Map<String, String> = mapOf(
"plus" to "Adds the other value to this value.",
"minus" to "Subtracts the other value from this value.",
"times" to "Multiplies this value by the other value.",
"div" to "Divides this value by the other value.",
"rem" to "Calculates the remainder of dividing this value by the other value."
internal val binaryOperators: List<String> = listOf(
"plus",
"minus",
"times",
"div",
"rem",
)
internal val unaryOperators: Map<String, String> = mapOf(
"inc" to "Increments this value.",
@@ -45,6 +46,37 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) {
* The shift distance actually used is therefore always in the range `0..${kind.bitSize - 1}`.
"""
}
internal fun binaryOperatorDoc(operator: String, operand1: PrimitiveType, operand2: PrimitiveType): String = when (operator) {
"plus" -> "Adds the other value to this value."
"minus" -> "Subtracts the other value from this value."
"times" -> "Multiplies this value by the other value."
"div" -> {
if (operand1.isIntegral && operand2.isIntegral)
"Divides this value by the other value, truncating the result to an integer that is closer to zero."
else
"Divides this value by the other value."
}
"floorDiv" ->
"Divides this value by the other value, flooring the result to an integer that is closer to negative infinity."
"rem" -> {
"""
Calculates the remainder of truncating division of this value by the other value.
The result is either zero or has the same sign as the _dividend_ and has the absolute value less than the absolute value of the divisor.
""".trimIndent()
}
"mod" -> {
"""
Calculates the remainder of flooring division of this value by the other value.
The result is either zero or has the same sign as the _divisor_ and has the absolute value less than the absolute value of the divisor.
""".trimIndent() + if (operand1.isFloatingPoint)
"\n\n" + "If the result cannot be represented exactly, it is rounded to the nearest representable number. In this case the absolute value of the result can be less than or _equal to_ the absolute value of the divisor."
else ""
}
else -> error("No documentation for operator $operator")
}
}
private val typeDescriptions: Map<PrimitiveType, String> = mapOf(
PrimitiveType.DOUBLE to "double-precision 64-bit IEEE 754 floating point number",
@@ -173,16 +205,16 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) {
}
private fun generateBinaryOperators(thisKind: PrimitiveType) {
for ((name, doc) in binaryOperators) {
generateOperator(name, doc, thisKind)
for (name in binaryOperators) {
generateOperator(name, thisKind)
}
}
private fun generateOperator(name: String, doc: String, thisKind: PrimitiveType) {
private fun generateOperator(name: String, thisKind: PrimitiveType) {
for (otherKind in PrimitiveType.onlyNumeric) {
val returnType = getOperatorReturnType(thisKind, otherKind)
out.println(" /** $doc */")
out.printDoc(binaryOperatorDoc(name, thisKind, otherKind), " ")
when (name) {
"rem" ->
out.println(" @SinceKotlin(\"1.1\")")
@@ -427,6 +459,7 @@ class GenerateFloorDivMod(out: PrintWriter) : BuiltInsSourceGenerator(out) {
private fun generateFloorDiv(thisKind: PrimitiveType, otherKind: PrimitiveType) {
val returnType = getOperatorReturnType(thisKind, otherKind)
val returnTypeName = returnType.capitalized
out.printDoc(GeneratePrimitives.binaryOperatorDoc("floorDiv", thisKind, otherKind), "")
out.println("""@SinceKotlin("1.5")""")
out.println("@kotlin.internal.InlineOnly")
val declaration = "public inline fun ${thisKind.capitalized}.floorDiv(other: ${otherKind.capitalized}): $returnTypeName"
@@ -451,6 +484,7 @@ class GenerateFloorDivMod(out: PrintWriter) : BuiltInsSourceGenerator(out) {
private fun generateMod(thisKind: PrimitiveType, otherKind: PrimitiveType) {
val operationType = getOperatorReturnType(thisKind, otherKind)
val returnType = otherKind
out.printDoc(GeneratePrimitives.binaryOperatorDoc("mod", thisKind, otherKind),"")
out.println("""@SinceKotlin("1.5")""")
out.println("@kotlin.internal.InlineOnly")
val declaration = "public inline fun ${thisKind.capitalized}.mod(other: ${otherKind.capitalized}): ${returnType.capitalized}"
@@ -475,6 +509,7 @@ class GenerateFloorDivMod(out: PrintWriter) : BuiltInsSourceGenerator(out) {
private fun generateFpMod(thisKind: PrimitiveType, otherKind: PrimitiveType) {
val operationType = getOperatorReturnType(thisKind, otherKind)
out.printDoc(GeneratePrimitives.binaryOperatorDoc("mod", thisKind, otherKind), "")
out.println("""@SinceKotlin("1.5")""")
out.println("@kotlin.internal.InlineOnly")
val declaration = "public inline fun ${thisKind.capitalized}.mod(other: ${otherKind.capitalized}): ${operationType.capitalized}"
+35 -11
View File
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.generators.builtins.unsigned
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.UnsignedType
import org.jetbrains.kotlin.generators.builtins.convert
import org.jetbrains.kotlin.generators.builtins.*
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator
import org.jetbrains.kotlin.generators.builtins.numbers.GeneratePrimitives
import java.io.File
@@ -37,6 +35,32 @@ class UnsignedTypeGenerator(val type: UnsignedType, out: PrintWriter) : BuiltIns
val className = type.capitalized
val storageType = type.asSigned.capitalized
internal fun binaryOperatorDoc(operator: String, operand1: UnsignedType, operand2: UnsignedType): String = when (operator) {
"floorDiv" ->
"""
Divides this value by the other value, flooring the result to an integer that is closer to negative infinity.
For unsigned types, the results of flooring division and truncating division are the same.
""".trimIndent()
"rem" -> {
"""
Calculates the remainder of truncating division of this value by the other value.
The result is always less than the divisor.
""".trimIndent()
}
"mod" -> {
"""
Calculates the remainder of flooring division of this value by the other value.
The result is always less than the divisor.
For unsigned types, the remainders of flooring division and truncating division are the same.
""".trimIndent()
}
else -> GeneratePrimitives.binaryOperatorDoc(operator, operand1.asSigned, operand2.asSigned)
}
override fun generateBody() {
out.println("import kotlin.experimental.*")
@@ -124,18 +148,18 @@ class UnsignedTypeGenerator(val type: UnsignedType, out: PrintWriter) : BuiltIns
}
private fun generateBinaryOperators() {
for ((name, doc) in GeneratePrimitives.binaryOperators) {
generateOperator(name, doc)
for (name in GeneratePrimitives.binaryOperators) {
generateOperator(name)
}
generateFloorDivMod("floorDiv", "TODO")
generateFloorDivMod("mod", "TODO")
generateFloorDivMod("floorDiv")
generateFloorDivMod("mod")
}
private fun generateOperator(name: String, doc: String) {
private fun generateOperator(name: String) {
for (otherType in UnsignedType.values()) {
val returnType = getOperatorReturnType(type, otherType)
out.println(" /** $doc */")
out.printDoc(binaryOperatorDoc(name, type, otherType), " ")
out.println(" @kotlin.internal.InlineOnly")
out.print(" public inline operator fun $name(other: ${otherType.capitalized}): ${returnType.capitalized} = ")
if (type == otherType && type == returnType) {
@@ -152,12 +176,12 @@ class UnsignedTypeGenerator(val type: UnsignedType, out: PrintWriter) : BuiltIns
out.println()
}
private fun generateFloorDivMod(name: String, doc: String) {
private fun generateFloorDivMod(name: String) {
for (otherType in UnsignedType.values()) {
val operationType = getOperatorReturnType(type, otherType)
val returnType = if (name == "mod") otherType else operationType
out.println(" /** $doc */")
out.printDoc(binaryOperatorDoc(name, type, otherType), " ")
out.println(" @kotlin.internal.InlineOnly")
out.print(" public inline fun $name(other: ${otherType.capitalized}): ${returnType.capitalized} = ")
if (type == otherType && type == operationType) {