From 8c0d575a6ff3b0cbaf1a3baafcfac0f260bfe76a Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Tue, 23 Aug 2016 18:09:29 +0300 Subject: [PATCH] translator: add support range operator (..) --- kotstd/include/Iterators.kt | 90 +++++++++++++++++++ kotstd/include/Progressions.kt | 48 ++++++++++ kotstd/include/Ranges.kt | 20 +++++ kotstd/include/progressionUtil.kt | 69 ++++++++++++++ .../kotlinnative/translator/BlockCodegen.kt | 9 +- .../translator/llvm/LLVMExpression.kt | 2 +- 6 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 kotstd/include/Iterators.kt create mode 100644 kotstd/include/Progressions.kt create mode 100644 kotstd/include/Ranges.kt create mode 100644 kotstd/include/progressionUtil.kt diff --git a/kotstd/include/Iterators.kt b/kotstd/include/Iterators.kt new file mode 100644 index 00000000000..8242c0fee41 --- /dev/null +++ b/kotstd/include/Iterators.kt @@ -0,0 +1,90 @@ +/** An iterator over a sequence of values of type `Byte`. */ +public abstract class ByteIterator { + final fun next() = nextByte() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextByte(): Byte + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Char`. */ +public abstract class CharIterator { + final fun next() = nextChar() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextChar(): Char + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Short`. */ +public abstract class ShortIterator { + final fun next() = nextShort() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextShort(): Short + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Int`. */ +class IntIterator(first: Int, last: Int, val step: Int) { + private var next = first + private val finalElement = last + private var hasNext: Boolean = if (step > 0) first <= last else first >= last + + fun hasNext(): Boolean = hasNext + + fun nextInt(): Int { + val value = next + if (value == finalElement) { + hasNext = false + } + else { + next += step + } + return value + } +} + + +/** An iterator over a sequence of values of type `Long`. */ +public abstract class LongIterator { + final fun next() = nextLong() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextLong(): Long + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Float`. */ +public abstract class FloatIterator { + final fun next() = nextFloat() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextFloat(): Float + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Double`. */ +public abstract class DoubleIterator { + final fun next() = nextDouble() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextDouble(): Double + + public abstract fun hasNext(): Boolean +} + +/** An iterator over a sequence of values of type `Boolean`. */ +public abstract class BooleanIterator { + final fun next() = nextBoolean() + + /** Returns the next value in the sequence without boxing. */ + public abstract fun nextBoolean(): Boolean + + public abstract fun hasNext(): Boolean +} \ No newline at end of file diff --git a/kotstd/include/Progressions.kt b/kotstd/include/Progressions.kt new file mode 100644 index 00000000000..9000ffbaacf --- /dev/null +++ b/kotstd/include/Progressions.kt @@ -0,0 +1,48 @@ +/** + * A progression of values of type `Int`. + */ +public open class IntProgression +constructor +( + start: Int, + endInclusive: Int, + val step: Int +) { + init { + if (step == 0) { + println("Step must be non-zero.") + assert(false) + } + } + + /** + * The first element in the progression. + */ + public val first: Int = start + + /** + * The last element in the progression. + */ + public val last: Int = getProgressionLastElement(start.toInt(), endInclusive.toInt(), step).toInt() + + + fun iterator(): IntIterator = IntIterator(first, last, step) + + /** Checks if the progression is empty. */ + public open fun isEmpty(): Boolean = if (step > 0) first > last else first < last + + //[TODO] equals + + override fun hashCode(): Int = + if (isEmpty()) -1 else (31 * (31 * first + last) + step) + + companion object { + /** + * Creates IntProgression 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: Int, rangeEnd: Int, step: Int): IntProgression = IntProgression(rangeStart, rangeEnd, step) + } +} diff --git a/kotstd/include/Ranges.kt b/kotstd/include/Ranges.kt new file mode 100644 index 00000000000..afec9bfffad --- /dev/null +++ b/kotstd/include/Ranges.kt @@ -0,0 +1,20 @@ +public class IntRange(val start: Int, val endInclusive: Int) { + val progression = IntProgression(start, endInclusive, 1) + val first: Int + val last: Int + + init { + this.first = progression.first + this.last = progression.last + } + + fun contains(value: Int): Boolean = first <= value && value <= last + + fun isEmpty(): Boolean = first > last + + fun iterator(): IntIterator = progression.iterator() + + override fun hashCode(): Int = + if (isEmpty()) -1 else (31 * first + last) + +} diff --git a/kotstd/include/progressionUtil.kt b/kotstd/include/progressionUtil.kt new file mode 100644 index 00000000000..03b42ca1561 --- /dev/null +++ b/kotstd/include/progressionUtil.kt @@ -0,0 +1,69 @@ +// a mod b (in arithmetical sense) +private fun mod(a: Int, b: Int): Int { + val mod = a % b + return if (mod >= 0) mod else mod + b +} + +private fun mod(a: Long, b: Long): Long { + val mod = a % b + return if (mod >= 0) mod else mod + b +} + +// (a - b) mod c +private fun differenceModulo(a: Int, b: Int, c: Int): Int { + return mod(mod(a, c) - mod(b, c), c) +} + +private fun differenceModulo(a: Long, b: Long, c: Long): Long { + return mod(mod(a, c) - mod(b, c), c) +} + +/** + * Calculates the final element of a bounded arithmetic progression, i.e. the last element of the progression which is in the range + * from [start] to [end] in case of a positive [step], or from [end] to [start] in case of a negative + * [step]. + * + * No validation on passed parameters is performed. The given parameters should satisfy the condition: either + * `step > 0` and `start >= end`, or `step < 0` and`start >= end`. + * @param start first element of the progression + * @param end ending bound for the progression + * @param step increment, or difference of successive elements in the progression + * @return the final element of the progression + * @suppress + */ +fun getProgressionLastElement(start: Int, end: Int, step: Int): Int { + if (step > 0) { + return end - differenceModulo(end, start, step) + } else if (step < 0) { + return end + differenceModulo(start, end, -step) + } else { + println("Step is zero.") + assert(false) + return -1 + } +} + +/** + * Calculates the final element of a bounded arithmetic progression, i.e. the last element of the progression which is in the range + * from [start] to [end] in case of a positive [step], or from [end] to [start] in case of a negative + * [step]. + * + * No validation on passed parameters is performed. The given parameters should satisfy the condition: either + * `step > 0` and `start >= end`, or `step < 0` and`start >= end`. + * @param start first element of the progression + * @param end ending bound for the progression + * @param step increment, or difference of successive elements in the progression + * @return the final element of the progression + * @suppress + */ +internal fun getProgressionLastElement(start: Long, end: Long, step: Long): Long { + if (step > 0) { + return end - differenceModulo(end, start, step) + } else if (step < 0) { + return end + differenceModulo(start, end, -step) + } else { + println("Step is zero.") + assert(false) + return -1L + } +} diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index f13f4dedde7..d0622c89968 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -785,6 +785,13 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va codeBuilder.storeVariable(firstOp, resultOp) return LLVMExpression(resultOp.type, "load ${firstOp.getType()} $firstOp, align ${firstOp.type!!.align}") } + ".." -> { + val descriptor = state.classes["IntRange"] + val arguments = listOf(firstOp, secondNativeOp) + val detectedConstructor = LLVMType.mangleFunctionTypes(arguments.map { it.type!! }) + val result = evaluateConstructorCallExpression(LLVMVariable(descriptor!!.fullName + detectedConstructor, descriptor.type, scope = LLVMVariableScope()), arguments) + return LLVMExpression(result!!.type!!, "load ${descriptor.type}** $result, align ${descriptor.type.align}", pointer = 1) + } else -> throw UnsupportedOperationException("Unknown binary operator: $operator(${firstNativeOp.type}, ${secondNativeOp.type})") } } @@ -863,7 +870,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } else -> addPrimitiveReferenceOperation(referenceName!!, firstOp, secondNativeOp) } - val resultOp = codeBuilder.getNewVariable(llvmExpression.variableType) + val resultOp = codeBuilder.getNewVariable(llvmExpression.variableType, pointer = llvmExpression.pointer) codeBuilder.addAssignment(resultOp, llvmExpression) return resultOp } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMExpression.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMExpression.kt index 934fce48685..c145f1fb8aa 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMExpression.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMExpression.kt @@ -2,7 +2,7 @@ package org.kotlinnative.translator.llvm import org.kotlinnative.translator.llvm.types.LLVMType -class LLVMExpression(val variableType: LLVMType, val llvmCode: String) : LLVMNode() { +class LLVMExpression(val variableType: LLVMType, val llvmCode: String, val pointer: Int = 0) : LLVMNode() { override fun toString(): String = llvmCode