Move builtins generators to their own source set

Make them depend on bootstrap stdlib.
This is to prevent recompiling the entire project when we need just to
generate builtins sources.
This commit is contained in:
Ilya Gorbunov
2018-04-26 00:07:17 +03:00
parent a704a1b6d0
commit 7438d12ad7
14 changed files with 51 additions and 32 deletions
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.arrayIterators
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.*
import java.io.PrintWriter
class GenerateArrayIterators(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.jvm.internal"
override fun generateBody() {
for (kind in PrimitiveType.values()) {
val s = kind.capitalized
out.println("private class Array${s}Iterator(private val array: ${s}Array) : ${s}Iterator() {")
out.println(" private var index = 0")
out.println(" override fun hasNext() = index < array.size")
out.println(" override fun next$s() = try { array[index++] } catch (e: ArrayIndexOutOfBoundsException) { index -= 1; throw NoSuchElementException(e.message) }")
out.println("}")
out.println()
}
for (kind in PrimitiveType.values()) {
val s = kind.capitalized
out.println("public fun iterator(array: ${s}Array): ${s}Iterator = Array${s}Iterator(array)")
}
}
}
+56
View File
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.arrays
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator
import java.io.PrintWriter
class GenerateArrays(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin"
override fun generateBody() {
for (kind in PrimitiveType.values()) {
val typeLower = kind.name.toLowerCase()
val s = kind.capitalized
val defaultValue = if (kind == PrimitiveType.BOOLEAN) "false" else "zero"
out.println("/**")
out.println(" * An array of ${typeLower}s. When targeting the JVM, instances of this class are represented as `$typeLower[]`.")
out.println(" * @constructor Creates a new array of the specified [size], with all elements initialized to $defaultValue.")
out.println(" */")
out.println("public class ${s}Array(size: Int) {")
out.println(" /**")
out.println(" * Creates a new array of the specified [size], where each element is calculated by calling the specified")
out.println(" * [init] function. The [init] function returns an array element given its index.")
out.println(" */")
out.println(" public inline constructor(size: Int, init: (Int) -> $s)")
out.println()
out.println(" /** Returns the array element at the given [index]. This method can be called using the index operator. */")
out.println(" public operator fun get(index: Int): $s")
out.println(" /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */")
out.println(" public operator fun set(index: Int, value: $s): Unit")
out.println()
out.println(" /** Returns the number of elements in the array. */")
out.println(" public val size: Int")
out.println()
out.println(" /** Creates an iterator over the elements of the array. */")
out.println(" public operator fun iterator(): ${s}Iterator")
out.println("}")
out.println()
}
}
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins
import org.jetbrains.kotlin.generators.builtins.ProgressionKind.*
import kotlin.properties.Delegates
enum class PrimitiveType {
BYTE,
CHAR,
SHORT,
INT,
LONG,
FLOAT,
DOUBLE,
BOOLEAN;
val capitalized: String get() = name.toLowerCase().capitalize()
companion object {
val exceptBoolean = PrimitiveType.values().filterNot { it == BOOLEAN }
val onlyNumeric = PrimitiveType.values().filterNot { it == BOOLEAN || it == CHAR }
}
}
enum class ProgressionKind {
CHAR,
INT,
LONG;
val capitalized: String get() = name.toLowerCase().capitalize()
}
fun progressionIncrementType(kind: ProgressionKind) = when (kind) {
CHAR -> "Int"
else -> kind.capitalized
}
fun areEqualNumbers(v: String) = "$v == other.$v"
fun hashLong(v: String) = "($v xor ($v ushr 32))"
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.functions
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator
import java.io.PrintWriter
val MAX_PARAM_COUNT = 22
class GenerateFunctions(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.jvm.functions"
fun generateTypeParameters(i: Int, variance: Boolean) {
out.print("<")
for (j in 1..i) {
if (variance) out.print("in ")
out.print("P$j, ")
}
generateReturnTypeParameter(variance)
out.print(">")
}
fun generateReturnTypeParameter(variance: Boolean) {
if (variance) out.print("out ")
out.print("R")
}
override fun generateBody() {
for (i in 0..MAX_PARAM_COUNT) {
generateDocumentation(i)
out.print("public interface Function$i")
generateTypeParameters(i, variance = true)
generateSuperClass()
generateFunctionClassBody(i)
}
}
fun generateDocumentation(i: Int) {
val suffix = if (i == 1) "" else "s"
out.println("/** A function that takes $i argument${suffix}. */")
}
fun generateSuperClass() {
out.print(" : Function<")
generateReturnTypeParameter(variance = false)
out.print(">")
}
fun generateFunctionClassBody(i: Int) {
out.println(" {")
generateInvokeSignature(i)
out.println("}")
}
fun generateInvokeSignature(i: Int) {
if (i == 0) {
out.println(" /** Invokes the function. */")
}
else {
val suffix = if (i == 1) "" else "s"
out.println(" /** Invokes the function with the specified argument${suffix}. */")
}
out.print(" public operator fun invoke(")
for (j in 1..i) {
out.print("p$j: P$j")
if (j < i) {
out.print(", ")
}
}
out.println("): R")
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.generateBuiltIns
import org.jetbrains.kotlin.generators.builtins.arrayIterators.GenerateArrayIterators
import org.jetbrains.kotlin.generators.builtins.arrays.GenerateArrays
import org.jetbrains.kotlin.generators.builtins.functions.GenerateFunctions
import org.jetbrains.kotlin.generators.builtins.iterators.GenerateIterators
import org.jetbrains.kotlin.generators.builtins.progressionIterators.GenerateProgressionIterators
import org.jetbrains.kotlin.generators.builtins.progressions.GenerateProgressions
import org.jetbrains.kotlin.generators.builtins.ranges.GeneratePrimitives
import org.jetbrains.kotlin.generators.builtins.ranges.GenerateRanges
import org.xml.sax.InputSource
import java.io.File
import java.io.PrintWriter
import javax.xml.xpath.XPathFactory
fun assertExists(file: File) {
if (!file.exists()) error("Output dir does not exist: ${file.absolutePath}")
}
val BUILT_INS_NATIVE_DIR = File("core/builtins/native/")
val BUILT_INS_SRC_DIR = File("core/builtins/src/")
val RUNTIME_JVM_DIR = File("libraries/stdlib/jvm/runtime/")
abstract class BuiltInsSourceGenerator(val out: PrintWriter) {
protected abstract fun generateBody(): Unit
protected open fun getPackage(): String = "kotlin"
enum class Language {
KOTLIN,
JAVA
}
fun generate() {
out.println(readCopyrightNoticeFromProfile(File(".idea/copyright/apache.xml")))
// Don't include generator class name in the message: these are built-in sources,
// and we don't want to scare users with any internal information about our project
out.println("// Auto-generated file. DO NOT EDIT!")
out.println()
out.print("package ${getPackage()}")
out.println()
out.println()
generateBody()
}
}
fun readCopyrightNoticeFromProfile(copyrightProfile: File): String {
val template = copyrightProfile.reader().use { reader ->
XPathFactory.newInstance().newXPath().evaluate("/component/copyright/option[@name='notice']/@value", InputSource(reader))
}
val yearTemplate = "&#36;today.year"
val year = java.time.LocalDate.now().year.toString()
assert(yearTemplate in template)
return template.replace(yearTemplate, year).lines().joinToString("", prefix = "/*\n", postfix = " */\n") { " * $it\n" }
}
fun generateBuiltIns(generate: (File, (PrintWriter) -> BuiltInsSourceGenerator) -> Unit) {
assertExists(BUILT_INS_NATIVE_DIR)
assertExists(BUILT_INS_SRC_DIR)
assertExists(RUNTIME_JVM_DIR)
generate(File(RUNTIME_JVM_DIR, "kotlin/jvm/functions/Functions.kt")) { GenerateFunctions(it) }
generate(File(BUILT_INS_NATIVE_DIR, "kotlin/Arrays.kt")) { GenerateArrays(it) }
generate(File(BUILT_INS_NATIVE_DIR, "kotlin/Primitives.kt")) { GeneratePrimitives(it) }
generate(File(BUILT_INS_SRC_DIR, "kotlin/Iterators.kt")) { GenerateIterators(it) }
generate(File(RUNTIME_JVM_DIR, "kotlin/jvm/internal/ArrayIterators.kt")) { GenerateArrayIterators(it) }
generate(File(BUILT_INS_SRC_DIR, "kotlin/ProgressionIterators.kt")) { GenerateProgressionIterators(it) }
generate(File(BUILT_INS_SRC_DIR, "kotlin/Progressions.kt")) { GenerateProgressions(it) }
generate(File(BUILT_INS_SRC_DIR, "kotlin/Ranges.kt")) { GenerateRanges(it) }
}
fun main(args: Array<String>) {
generateBuiltIns { file, generator ->
println("generating $file")
file.parentFile?.mkdirs()
PrintWriter(file).use {
generator(it).generate()
}
}
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.iterators
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.*
import java.io.PrintWriter
class GenerateIterators(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.collections"
override fun generateBody() {
for (kind in PrimitiveType.values()) {
val s = kind.capitalized
out.println("/** An iterator over a sequence of values of type `$s`. */")
out.println("public abstract class ${s}Iterator : Iterator<$s> {" )
out.println(" override final fun next() = next$s()")
out.println()
out.println(" /** Returns the next value in the sequence without boxing. */")
out.println(" public abstract fun next$s(): $s")
out.println("}")
out.println()
}
}
}
+226
View File
@@ -0,0 +1,226 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.ranges
import org.jetbrains.kotlin.generators.builtins.PrimitiveType
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator
import java.io.PrintWriter
class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) {
private 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.",
"mod" to "Calculates the remainder of dividing this value by the other value.",
"rem" to "Calculates the remainder of dividing this value by the other value."
)
private val unaryOperators: Map<String, String> = mapOf(
"inc" to "Increments this value.",
"dec" to "Decrements this value.",
"unaryPlus" to "Returns this value.",
"unaryMinus" to "Returns the negative of this value.")
private val shiftOperators: Map<String, String> = mapOf(
"shl" to "Shifts this value left by the [bitCount] number of bits.",
"shr" to "Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit.",
"ushr" to "Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros.")
private val bitwiseOperators: Map<String, String> = mapOf(
"and" to "Performs a bitwise AND operation between the two values.",
"or" to "Performs a bitwise OR operation between the two values.",
"xor" to "Performs a bitwise XOR operation between the two values.")
private val typeDescriptions: Map<PrimitiveType, String> = mapOf(
PrimitiveType.DOUBLE to "double-precision 64-bit IEEE 754 floating point number",
PrimitiveType.FLOAT to "single-precision 32-bit IEEE 754 floating point number",
PrimitiveType.LONG to "64-bit signed integer",
PrimitiveType.INT to "32-bit signed integer",
PrimitiveType.SHORT to "16-bit signed integer",
PrimitiveType.BYTE to "8-bit signed integer",
PrimitiveType.CHAR to "16-bit Unicode character"
)
private fun primitiveConstants(type: PrimitiveType): List<Any> = when (type) {
PrimitiveType.INT -> listOf(java.lang.Integer.MIN_VALUE, java.lang.Integer.MAX_VALUE)
PrimitiveType.BYTE -> listOf(java.lang.Byte.MIN_VALUE, java.lang.Byte.MAX_VALUE)
PrimitiveType.SHORT -> listOf(java.lang.Short.MIN_VALUE, java.lang.Short.MAX_VALUE)
PrimitiveType.LONG -> listOf((java.lang.Long.MIN_VALUE + 1).toString() + "L - 1L", java.lang.Long.MAX_VALUE.toString() + "L")
// PrimitiveType.DOUBLE -> listOf(java.lang.Double.MIN_VALUE, java.lang.Double.MAX_VALUE, "1.0/0.0", "-1.0/0.0", "0.0/0.0")
// PrimitiveType.FLOAT -> listOf(java.lang.Float.MIN_VALUE, java.lang.Float.MAX_VALUE, "1.0F/0.0F", "-1.0F/0.0F", "0.0F/0.0F").map { it as? String ?: "${it}F" }
else -> throw IllegalArgumentException("type: $type")
}
override fun generateBody() {
for (kind in PrimitiveType.onlyNumeric) {
val className = kind.capitalized
generateDoc(kind)
out.println("public class $className private constructor() : Number(), Comparable<$className> {")
out.print(" companion object ")
if (kind == PrimitiveType.FLOAT || kind == PrimitiveType.DOUBLE) {
//val (minValue, maxValue, posInf, negInf, nan) = primitiveConstants(kind)
out.println("""{
/**
* A constant holding the smallest *positive* nonzero value of $className.
*/
public val MIN_VALUE: $className
/**
* A constant holding the largest positive finite value of $className.
*/
public val MAX_VALUE: $className
/**
* A constant holding the positive infinity value of $className.
*/
public val POSITIVE_INFINITY: $className
/**
* A constant holding the negative infinity value of $className.
*/
public val NEGATIVE_INFINITY: $className
/**
* A constant holding the "not a number" value of $className.
*/
public val NaN: $className
}""")
}
if (kind == PrimitiveType.INT || kind == PrimitiveType.LONG || kind == PrimitiveType.SHORT || kind == PrimitiveType.BYTE) {
val (minValue, maxValue) = primitiveConstants(kind)
out.println("""{
/**
* A constant holding the minimum value an instance of $className can have.
*/
public const val MIN_VALUE: $className = $minValue
/**
* A constant holding the maximum value an instance of $className can have.
*/
public const val MAX_VALUE: $className = $maxValue
}""")
}
generateCompareTo(kind)
generateBinaryOperators(kind)
generateUnaryOperators(kind)
generateRangeTo(kind)
if (kind == PrimitiveType.INT || kind == PrimitiveType.LONG) {
generateBitShiftOperators(className)
}
if (kind == PrimitiveType.INT || kind == PrimitiveType.LONG /* || kind == PrimitiveType.BYTE || kind == PrimitiveType.SHORT */) {
generateBitwiseOperators(className, since = if (kind == PrimitiveType.BYTE || kind == PrimitiveType.SHORT) "1.1" else null)
}
generateConversions()
out.println("}\n")
}
}
private fun generateDoc(kind: PrimitiveType) {
out.println("/**")
out.println(" * Represents a ${typeDescriptions[kind]}.")
out.println(" * On the JVM, non-nullable values of this type are represented as values of the primitive type `${kind.name.toLowerCase()}`.")
out.println(" */")
}
private fun generateCompareTo(thisKind: PrimitiveType) {
for (otherKind in PrimitiveType.onlyNumeric) {
out.println("""
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/""")
out.print(" public ")
if (otherKind == thisKind) out.print("override ")
out.println("operator fun compareTo(other: ${otherKind.capitalized}): Int")
}
out.println()
}
private fun generateBinaryOperators(thisKind: PrimitiveType) {
for ((name, doc) in binaryOperators) {
generateOperator(name, doc, thisKind)
}
}
private fun generateOperator(name: String, doc: String, thisKind: PrimitiveType) {
for (otherKind in PrimitiveType.onlyNumeric) {
val returnType = getOperatorReturnType(thisKind, otherKind)
out.println(" /** $doc */")
when (name) {
"rem" ->
out.println(" @SinceKotlin(\"1.1\")")
"mod" ->
out.println(" @Deprecated(\"Use rem(other) instead\", ReplaceWith(\"rem(other)\"), DeprecationLevel.WARNING)")
}
out.println(" public operator fun $name(other: ${otherKind.capitalized}): ${returnType.capitalized}")
}
out.println()
}
private fun generateRangeTo(thisKind: PrimitiveType) {
for (otherKind in PrimitiveType.onlyNumeric) {
val returnType =
maxByDomainCapacity(thisKind, otherKind)
.let { if (it == PrimitiveType.CHAR) it else maxByDomainCapacity(it, PrimitiveType.INT) }
if (returnType == PrimitiveType.DOUBLE || returnType == PrimitiveType.FLOAT)
continue
out.println(" /** Creates a range from this value to the specified [other] value. */")
out.println(" public operator fun rangeTo(other: ${otherKind.capitalized}): ${returnType.capitalized}Range")
}
out.println()
}
private fun generateUnaryOperators(kind: PrimitiveType) {
for ((name, doc) in unaryOperators) {
val returnType = if (kind in listOf(PrimitiveType.SHORT, PrimitiveType.BYTE, PrimitiveType.CHAR) &&
name in listOf("unaryPlus", "unaryMinus")) "Int" else kind.capitalized
out.println(" /** $doc */")
out.println(" public operator fun $name(): $returnType")
}
out.println()
}
private fun generateBitShiftOperators(className: String) {
for ((name, doc) in shiftOperators) {
out.println(" /** $doc */")
out.println(" public infix fun $name(bitCount: Int): $className")
}
}
private fun generateBitwiseOperators(className: String, since: String?) {
for ((name, doc) in bitwiseOperators) {
out.println(" /** $doc */")
since?.let { out.println(" @SinceKotlin(\"$it\")") }
out.println(" public infix fun $name(other: $className): $className")
}
out.println(" /** Inverts the bits in this value. */")
since?.let { out.println(" @SinceKotlin(\"$it\")") }
out.println(" public fun inv(): $className")
out.println()
}
private fun generateConversions() {
for (otherKind in PrimitiveType.exceptBoolean) {
val name = otherKind.capitalized
out.println(" public override fun to$name(): $name")
}
}
private fun maxByDomainCapacity(type1: PrimitiveType, type2: PrimitiveType): PrimitiveType
= if (type1.ordinal > type2.ordinal) type1 else type2
private fun getOperatorReturnType(kind1: PrimitiveType, kind2: PrimitiveType): PrimitiveType {
require(kind1 != PrimitiveType.BOOLEAN) { "kind1 must not be BOOLEAN" }
require(kind2 != PrimitiveType.BOOLEAN) { "kind2 must not be BOOLEAN" }
return maxByDomainCapacity(maxByDomainCapacity(kind1, kind2), PrimitiveType.INT)
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.progressionIterators
import org.jetbrains.kotlin.generators.builtins.*
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.*
import org.jetbrains.kotlin.generators.builtins.ProgressionKind.*
import java.io.PrintWriter
fun integerProgressionIterator(kind: ProgressionKind): String {
val t = kind.capitalized
val incrementType = progressionIncrementType(kind)
val (toInt, toType) = when (kind) {
CHAR -> ".toInt()" to ".to$t()"
else -> "" to ""
}
return """/**
* An iterator over a progression of values of type `$t`.
* @property step the number by which the value is incremented on each step.
*/
internal class ${t}ProgressionIterator(first: $t, last: $t, val step: $incrementType) : ${t}Iterator() {
private val finalElement = last$toInt
private var hasNext: Boolean = if (step > 0) first <= last else first >= last
private var next = if (hasNext) first$toInt else finalElement
override fun hasNext(): Boolean = hasNext
override fun next$t(): $t {
val value = next
if (value == finalElement) {
if (!hasNext) throw kotlin.NoSuchElementException()
hasNext = false
}
else {
next += step
}
return value$toType
}
}"""
}
class GenerateProgressionIterators(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.ranges"
override fun generateBody() {
for (kind in ProgressionKind.values()) {
out.println(integerProgressionIterator(kind))
out.println()
}
}
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.progressions
import org.jetbrains.kotlin.generators.builtins.*
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.*
import org.jetbrains.kotlin.generators.builtins.ProgressionKind.*
import java.io.PrintWriter
class GenerateProgressions(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.ranges"
private fun generateDiscreteBody(kind: ProgressionKind) {
val t = kind.capitalized
val progression = "${t}Progression"
val incrementType = progressionIncrementType(kind)
fun compare(v: String) = areEqualNumbers(v)
val zero = when (kind) {
LONG -> "0L"
else -> "0"
}
val checkZero = "if (step == $zero) throw kotlin.IllegalArgumentException(\"Step must be non-zero\")"
val hashCode = "=\n" + when (kind) {
CHAR ->
" if (isEmpty()) -1 else (31 * (31 * first.toInt() + last.toInt()) + step)"
INT ->
" if (isEmpty()) -1 else (31 * (31 * first + last) + step)"
LONG ->
" if (isEmpty()) -1 else (31 * (31 * ${hashLong("first")} + ${hashLong("last")}) + ${hashLong("step")}).toInt()"
else -> throw IllegalArgumentException()
}
out.println(
"""/**
* A progression of values of type `$t`.
*/
public open class $progression
internal constructor
(
start: $t,
endInclusive: $t,
step: $incrementType
) : Iterable<$t> {
init {
$checkZero
}
/**
* The first element in the progression.
*/
public val first: $t = start
/**
* The last element in the progression.
*/
public val last: $t = getProgressionLastElement(start.to$incrementType(), endInclusive.to$incrementType(), step).to$t()
/**
* The step of the progression.
*/
public val step: $incrementType = step
override fun iterator(): ${t}Iterator = ${t}ProgressionIterator(first, last, step)
/** Checks if the progression is empty. */
public open fun isEmpty(): Boolean = if (step > 0) first > last else first < last
override fun equals(other: Any?): Boolean =
other is $progression && (isEmpty() && other.isEmpty() ||
${compare("first")} && ${compare("last")} && ${compare("step")})
override fun hashCode(): Int $hashCode
override fun toString(): String = ${"if (step > 0) \"\$first..\$last step \$step\" else \"\$first downTo \$last step \${-step}\""}
companion object {
/**
* Creates $progression within the specified bounds of a closed range.
* The progression starts with the [rangeStart] value and goes toward the [rangeEnd] value not excluding it, with the specified [step].
* In order to go backwards the [step] must be negative.
*/
public fun fromClosedRange(rangeStart: $t, rangeEnd: $t, step: $incrementType): $progression = $progression(rangeStart, rangeEnd, step)
}
}""")
out.println()
}
override fun generateBody() {
out.println("import kotlin.internal.getProgressionLastElement")
out.println()
for (kind in ProgressionKind.values()) {
generateDiscreteBody(kind)
}
}
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.generators.builtins.ranges
import org.jetbrains.kotlin.generators.builtins.*
import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.*
import org.jetbrains.kotlin.generators.builtins.ProgressionKind.*
import java.io.PrintWriter
class GenerateRanges(out: PrintWriter) : BuiltInsSourceGenerator(out) {
override fun getPackage() = "kotlin.ranges"
override fun generateBody() {
for (kind in ProgressionKind.values()) {
val t = kind.capitalized
val range = "${t}Range"
val increment = "1"
val emptyBounds = when (kind) {
CHAR -> "1.toChar(), 0.toChar()"
else -> "1, 0"
}
fun compare(v: String) = areEqualNumbers(v)
val hashCode = when (kind) {
CHAR -> "=\n" +
" if (isEmpty()) -1 else (31 * first.toInt() + last.toInt())"
INT -> "=\n" +
" if (isEmpty()) -1 else (31 * first + last)"
LONG -> "=\n" +
" if (isEmpty()) -1 else (31 * ${hashLong("first")} + ${hashLong("last")}).toInt()"
}
val toString = "\"\$first..\$last\""
out.println(
"""/**
* A range of values of type `$t`.
*/
public class $range(start: $t, endInclusive: $t) : ${t}Progression(start, endInclusive, $increment), ClosedRange<$t> {
override val start: $t get() = first
override val endInclusive: $t get() = last
override fun contains(value: $t): Boolean = first <= value && value <= last
override fun isEmpty(): Boolean = first > last
override fun equals(other: Any?): Boolean =
other is $range && (isEmpty() && other.isEmpty() ||
${compare("first")} && ${compare("last")})
override fun hashCode(): Int $hashCode
override fun toString(): String = $toString
companion object {
/** An empty range of values of type $t. */
public val EMPTY: $range = $range($emptyBounds)
}
}""")
out.println()
}
}
}