translator: add support range operator (..)

This commit is contained in:
Alexey Stepanov
2016-08-23 18:09:29 +03:00
parent 7f14915716
commit 8c0d575a6f
6 changed files with 236 additions and 2 deletions
+90
View File
@@ -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
}
+48
View File
@@ -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)
}
}
+20
View File
@@ -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)
}
+69
View File
@@ -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
}
}
@@ -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
}
@@ -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