diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt index 6caed68cdaa..a9c15d68c64 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt @@ -24,9 +24,9 @@ fun main(args: Array) { Generators, StringJoinOps, SequenceOps, -// RangeOps, + RangeOps, Numeric, -// ComparableOps, + ComparableOps, // CommonArrays, // PlatformSpecialized, // PlatformSpecializedJS, diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Comparables.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Comparables.kt index 37232496026..af53cc5de70 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Comparables.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Comparables.kt @@ -1,14 +1,34 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package templates import templates.Family.* -fun comparables(): List { - val templates = arrayListOf() +object ComparableOps : TemplateGroupBase() { - templates add f("coerceAtLeast(minimumValue: SELF)") { + private val numericPrimitives = PrimitiveType.numericPrimitives.sortedBy { it.capacity }.toSet() + private val intPrimitives = setOf(PrimitiveType.Int, PrimitiveType.Long) + private val shortIntPrimitives = setOf(PrimitiveType.Byte, PrimitiveType.Short) + + val f_coerceAtLeast = fn("coerceAtLeast(minimumValue: SELF)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Ranges) - only(Primitives, Generic) - only(numericPrimitives) returns("SELF") typeParam("T: Comparable") doc { @@ -23,13 +43,13 @@ fun comparables(): List { return if (this < minimumValue) minimumValue else this """ } - } - templates add f("coerceAtMost(maximumValue: SELF)") { + val f_coerceAtMost = fn("coerceAtMost(maximumValue: SELF)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Ranges) - only(Primitives, Generic) - only(numericPrimitives) returns("SELF") typeParam("T: Comparable") doc { @@ -46,10 +66,11 @@ fun comparables(): List { } } - templates add f("coerceIn(range: ClosedRange)") { + val f_coerceIn_range_primitive = fn("coerceIn(range: ClosedRange)") { + include(Generic) + include(Primitives, intPrimitives) + } builder { sourceFile(SourceFile.Ranges) - only(Primitives, Generic) - only(PrimitiveType.Int, PrimitiveType.Long) returns("SELF") typeParam("T: Comparable") doc { @@ -87,9 +108,10 @@ fun comparables(): List { } } - templates add f("coerceIn(range: ClosedFloatingPointRange)") { + val f_coerceIn_fpRange = fn("coerceIn(range: ClosedFloatingPointRange)") { + include(Generic) + } builder { sourceFile(SourceFile.Ranges) - only(Generic) since("1.1") returns("SELF") typeParam("T: Comparable") @@ -115,15 +137,16 @@ fun comparables(): List { } - templates add f("minOf(a: T, b: T)") { + val f_minOf_2 = fn("minOf(a: T, b: T)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Comparisons) - only(Primitives, Generic) - only(numericPrimitives) since("1.1") typeParam("T: Comparable") returns("T") - customReceiver("") - inline(Primitives) { Inline.Only } + receiver("") + specialFor(Primitives) { inlineOnly() } doc { """ Returns the smaller of two values. @@ -131,50 +154,56 @@ fun comparables(): List { """ } // TODO: Add a note about NaN propagation for floats. - doc(Primitives) { - """Returns the smaller of two values.""" - } - bodyForTypes(Primitives, PrimitiveType.Byte, PrimitiveType.Short) { p -> - "return Math.min(a.toInt(), b.toInt()).to$p()" - } - // TODO: custom body for JS minOf(Long, Long) - body(Primitives) { - "return Math.min(a, b)" + specialFor(Primitives) { + doc { + """Returns the smaller of two values.""" + } + // TODO: custom body for JS minOf(Long, Long) + body { + "return Math.min(a, b)" + } + if (primitive in shortIntPrimitives) { + body { "return Math.min(a.toInt(), b.toInt()).to$primitive()" } + } } body(Generic) { "return if (a <= b) a else b" } } - templates add f("minOf(a: T, b: T, c: T)") { + val f_minOf = fn("minOf(a: T, b: T, c: T)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Comparisons) - only(Primitives, Generic) - only(numericPrimitives) since("1.1") typeParam("T: Comparable") returns("T") - customReceiver("") - inline(Primitives) { Inline.Only } + receiver("") + specialFor(Primitives) { inlineOnly() } // TODO: Add a note about NaN propagation for floats. doc { """ Returns the smaller of three values. """ } - bodyForTypes(Primitives, PrimitiveType.Byte, PrimitiveType.Short) { p -> - "return Math.min(a.toInt(), Math.min(b.toInt(), c.toInt())).to$p()" - } body { "return minOf(a, minOf(b, c))" } + specialFor(Primitives) { + if (primitive in shortIntPrimitives) { + body { "return Math.min(a.toInt(), Math.min(b.toInt(), c.toInt())).to$primitive()" } + } + } } - templates add f("minOf(a: T, b: T, comparator: Comparator)") { + val f_minOf_2_comparator = fn("minOf(a: T, b: T, comparator: Comparator)") { + include(Generic) + } builder { sourceFile(SourceFile.Comparisons) - only(Generic) since("1.1") returns("T") - customReceiver("") + receiver("") doc { """ Returns the smaller of two values according to the order specified by the given [comparator]. @@ -186,12 +215,13 @@ fun comparables(): List { } } - templates add f("minOf(a: T, b: T, c: T, comparator: Comparator)") { + val f_minOf_3_comparator = fn("minOf(a: T, b: T, c: T, comparator: Comparator)") { + include(Generic) + } builder { sourceFile(SourceFile.Comparisons) - only(Generic) since("1.1") returns("T") - customReceiver("") + receiver("") doc { """ Returns the smaller of three values according to the order specified by the given [comparator]. @@ -201,16 +231,17 @@ fun comparables(): List { "return minOf(a, minOf(b, c, comparator), comparator)" } } - - templates add f("maxOf(a: T, b: T)") { + + val f_maxOf_2 = fn("maxOf(a: T, b: T)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Comparisons) - only(Primitives, Generic) - only(numericPrimitives) since("1.1") typeParam("T: Comparable") returns("T") - customReceiver("") - inline(Primitives) { Inline.Only } + receiver("") + specialFor(Primitives) { inlineOnly() } doc { """ Returns the greater of two values. @@ -218,49 +249,55 @@ fun comparables(): List { """ } // TODO: Add a note about NaN propagation for floats. - doc(Primitives) { - """Returns the greater of two values.""" - } - bodyForTypes(Primitives, PrimitiveType.Byte, PrimitiveType.Short) { p -> - "return Math.max(a.toInt(), b.toInt()).to$p()" - } - body(Primitives) { - "return Math.max(a, b)" + specialFor(Primitives) { + doc { + """Returns the greater of two values.""" + } + body { + "return Math.max(a, b)" + } + if (primitive in shortIntPrimitives) { + body { "return Math.max(a.toInt(), b.toInt()).to$primitive()" } + } } body(Generic) { "return if (a >= b) a else b" } } - templates add f("maxOf(a: T, b: T, c: T)") { + val f_maxOf_3 = fn("maxOf(a: T, b: T, c: T)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Comparisons) - only(Primitives, Generic) - only(numericPrimitives) since("1.1") typeParam("T: Comparable") returns("T") - customReceiver("") - inline(Primitives) { Inline.Only } + receiver("") + specialFor(Primitives) { inlineOnly() } // TODO: Add a note about NaN propagation for floats. doc { """ Returns the greater of three values. """ } - bodyForTypes(Primitives, PrimitiveType.Byte, PrimitiveType.Short) { p -> - "return Math.max(a.toInt(), Math.max(b.toInt(), c.toInt())).to$p()" - } body { "return maxOf(a, maxOf(b, c))" } + specialFor(Primitives) { + if (primitive in shortIntPrimitives) { + body { "return Math.max(a.toInt(), Math.max(b.toInt(), c.toInt())).to$primitive()" } + } + } } - templates add f("maxOf(a: T, b: T, comparator: Comparator)") { + val f_maxOf_2_comparator = fn("maxOf(a: T, b: T, comparator: Comparator)") { + include(Generic) + } builder { sourceFile(SourceFile.Comparisons) - only(Generic) since("1.1") returns("T") - customReceiver("") + receiver("") doc { """ Returns the greater of two values according to the order specified by the given [comparator]. @@ -272,12 +309,13 @@ fun comparables(): List { } } - templates add f("maxOf(a: T, b: T, c: T, comparator: Comparator)") { + val f_maxOf_3_comparator = fn("maxOf(a: T, b: T, c: T, comparator: Comparator)") { + include(Generic) + } builder { sourceFile(SourceFile.Comparisons) - only(Generic) since("1.1") returns("T") - customReceiver("") + receiver("") doc { """ Returns the greater of three values according to the order specified by the given [comparator]. @@ -289,11 +327,13 @@ fun comparables(): List { } - templates add f("coerceIn(minimumValue: SELF, maximumValue: SELF)") { + val f_coerceIn_min_max = fn("coerceIn(minimumValue: SELF, maximumValue: SELF)") { + include(Generic) + include(Primitives, numericPrimitives) + } builder { sourceFile(SourceFile.Ranges) - only(Primitives, Generic) - only(numericPrimitives) - customSignature(Generic) { "coerceIn(minimumValue: SELF?, maximumValue: SELF?)" } + + specialFor(Generic) { signature("coerceIn(minimumValue: SELF?, maximumValue: SELF?)", notForSorting = true) } typeParam("T: Comparable") returns("SELF") doc { @@ -326,6 +366,4 @@ fun comparables(): List { """ } } - - return templates -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt index 482a807aba5..a7755b6b1cf 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt @@ -1,35 +1,55 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package templates import templates.Family.* import templates.PrimitiveType.Companion.maxByCapacity -fun ranges(): List { - val templates = arrayListOf() +object RangeOps : TemplateGroupBase() { - val rangePrimitives = listOf(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Char) - fun rangeElementType(fromType: PrimitiveType, toType: PrimitiveType) + private val rangePrimitives = setOf(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Char) + private fun rangeElementType(fromType: PrimitiveType, toType: PrimitiveType) = maxByCapacity(fromType, toType).let { if (it == PrimitiveType.Char) it else maxByCapacity(it, PrimitiveType.Int) } - fun Collection.permutations(): List> = flatMap { a -> map { b -> a to b } } + private fun Collection.permutations(): List> = flatMap { a -> map { b -> a to b } } - templates add f("reversed()") { - only(ProgressionsOfPrimitives) - only(rangePrimitives) - doc(ProgressionsOfPrimitives) { "Returns a progression that goes over the same range in the opposite direction with the same step." } + private val numericPrimitives = PrimitiveType.numericPrimitives + private val numericPermutations = numericPrimitives.permutations() + private val primitivePermutations = numericPermutations + (PrimitiveType.Char to PrimitiveType.Char) + private val integralPermutations = primitivePermutations.filter { it.first.isIntegral() && it.second.isIntegral() } + + + val f_reversed = fn("reversed()") { + include(ProgressionsOfPrimitives, rangePrimitives) + } builder { + doc { "Returns a progression that goes over the same range in the opposite direction with the same step." } returns("TProgression") - body(ProgressionsOfPrimitives) { + body { "return TProgression.fromClosedRange(last, first, -step)" } } - templates add f("step(step: SUM)") { + val f_step = fn("step(step: SUM)") { + include(ProgressionsOfPrimitives, rangePrimitives) + } builder { infix(true) - - only(ProgressionsOfPrimitives) - only(rangePrimitives) - doc(ProgressionsOfPrimitives) { "Returns a progression that goes over the same range with the given step." } + doc { "Returns a progression that goes over the same range with the given step." } returns("TProgression") - body(ProgressionsOfPrimitives) { + body { """ checkStepIsPositive(step > 0, step) return TProgression.fromClosedRange(first, last, if (this.step > 0) step else -step) @@ -37,14 +57,16 @@ fun ranges(): List { } } - fun downTo(fromType: PrimitiveType, toType: PrimitiveType) = f("downTo(to: $toType)") { - infix(true) - + val f_downTo = fn("downTo(to: Primitive)").byTwoPrimitives { + include(Primitives, integralPermutations) + } builderWith { (fromType, toType) -> sourceFile(SourceFile.Ranges) - only(Primitives) - only(fromType) + val elementType = rangeElementType(fromType, toType) val progressionType = elementType.name + "Progression" + + infix() + signature("downTo(to: $toType)") returns(progressionType) doc { @@ -55,6 +77,7 @@ fun ranges(): List { """ } + val fromExpr = if (elementType == fromType) "this" else "this.to$elementType()" val toExpr = if (elementType == toType) "to" else "to.to$elementType()" val incrementExpr = when (elementType) { @@ -64,22 +87,20 @@ fun ranges(): List { else -> "-1" } - body { "return $progressionType.fromClosedRange($fromExpr, $toExpr, $incrementExpr)" } + body { + "return $progressionType.fromClosedRange($fromExpr, $toExpr, $incrementExpr)" + } } - val numericPrimitives = PrimitiveType.numericPrimitives - val numericPermutations = numericPrimitives.permutations() - val primitivePermutations = numericPermutations + (PrimitiveType.Char to PrimitiveType.Char) - val integralPermutations = primitivePermutations.filter { it.first.isIntegral() && it.second.isIntegral() } - - templates addAll integralPermutations.map { downTo(it.first, it.second) } - - fun until(fromType: PrimitiveType, toType: PrimitiveType) = f("until(to: $toType)") { - infix(true) + val f_until = fn("until(to: Primitive)").byTwoPrimitives { + include(Primitives, integralPermutations) + } builderWith { (fromType, toType) -> sourceFile(SourceFile.Ranges) - only(Primitives) - only(fromType) + + infix() + signature("until(to: $toType)") + val elementType = rangeElementType(fromType, toType) val progressionType = elementType.name + "Range" returns(progressionType) @@ -116,14 +137,14 @@ fun ranges(): List { } } - templates addAll integralPermutations.map { until(it.first, it.second) } - - fun contains(rangeType: PrimitiveType, itemType: PrimitiveType) = f("contains(value: $itemType)") { - operator(true) + val f_contains = fn("contains(value: Primitive)").byTwoPrimitives { + include(Ranges, numericPermutations) + filter { _, (rangeType, itemType) -> rangeType != itemType } + } builderWith { (rangeType, itemType) -> + operator() + signature("contains(value: $itemType)") check(rangeType.isNumeric() == itemType.isNumeric()) { "Required rangeType and itemType both to be numeric or both not, got: $rangeType, $itemType" } - only(Ranges) - onlyPrimitives(Ranges, rangeType) platformName("${rangeType.name.decapitalize()}RangeContains") returns("Boolean") doc { "Checks if the specified [value] belongs to this range." } @@ -135,23 +156,18 @@ fun ranges(): List { } } - - templates addAll numericPermutations.filter { it.first != it.second }.map { contains(it.first, it.second) } - - fun narrowingExactOrNull(fromType: PrimitiveType, toType: PrimitiveType) = f("to${toType}ExactOrNull()") { + val f_toPrimitiveExactOrNull = fn("to{}ExactOrNull()").byTwoPrimitives { + include(Primitives, numericPermutations) + filter { _, (fromType, toType) -> fromType.capacity > toType.capacity && toType.isIntegral() } + } builderWith { (fromType, toType) -> + check(toType.isIntegral()) visibility("internal") sourceFile(SourceFile.Ranges) - check(toType.isIntegral()) + signature("to${toType}ExactOrNull()") returns("$toType?") - only(Primitives) - only(fromType) body { "return if (this in $toType.MIN_VALUE.to$fromType()..$toType.MAX_VALUE.to$fromType()) this.to$toType() else null" } } - - templates addAll numericPermutations.filter { it.first.capacity > it.second.capacity && it.second.isIntegral() }.map { narrowingExactOrNull(it.first, it.second) } - - return templates -} \ No newline at end of file +}