From 984d251a6debd371163a4aa8a26f7270bad386b6 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 19 Aug 2019 23:49:06 +0200 Subject: [PATCH] taking down the heapvalue mess, RuntimeValue class separation --- .../ast/processing/StatementReorderer.kt | 1 - compiler/src/prog8/compiler/Compiler.kt | 67 --- compiler/src/prog8/compiler/HeapValues.kt | 70 +++ .../c64/codegen/BuiltinFunctionsAsmGen.kt | 1 - compiler/src/prog8/vm/RuntimeValue.kt | 542 ++++++++++-------- compiler/src/prog8/vm/astvm/AstVm.kt | 258 +++++---- compiler/src/prog8/vm/astvm/Expressions.kt | 89 +-- .../src/prog8/vm/astvm/VariablesCreator.kt | 19 +- compiler/test/RuntimeValueTests.kt | 440 +++++++------- compiler/test/UnitTests.kt | 6 +- 10 files changed, 776 insertions(+), 717 deletions(-) create mode 100644 compiler/src/prog8/compiler/HeapValues.kt diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index 02c4a6d2e..79d19ce28 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -5,7 +5,6 @@ import prog8.ast.base.DataType import prog8.ast.base.FatalAstException import prog8.ast.base.initvarsSubName import prog8.ast.expressions.* -import prog8.ast.mangledStructMemberName import prog8.ast.statements.* diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 473f1ba51..3107d8d53 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1,13 +1,9 @@ package prog8.compiler -import prog8.ast.base.ArrayDatatypes -import prog8.ast.base.DataType -import prog8.ast.base.StringDatatypes import prog8.ast.expressions.AddressOf import java.io.File import java.io.InputStream import java.nio.file.Path -import java.util.* import kotlin.math.abs enum class OutputType { @@ -74,66 +70,3 @@ internal fun tryGetEmbeddedResource(name: String): InputStream? { return object{}.javaClass.getResourceAsStream("/prog8lib/$name") } -class HeapValues { - data class HeapValue(val type: DataType, val str: String?, val array: Array?, val doubleArray: DoubleArray?) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - other as HeapValue - return type==other.type && str==other.str && Arrays.equals(array, other.array) && Arrays.equals(doubleArray, other.doubleArray) - } - - override fun hashCode(): Int = Objects.hash(str, array, doubleArray) - } - - private val heap = mutableMapOf() - private var heapId = 1 - - fun size(): Int = heap.size - - fun addString(type: DataType, str: String): Int { - if (str.length > 255) - throw IllegalArgumentException("string length must be 0-255") - - // strings are 'interned' and shared if they're the isSameAs - val value = HeapValue(type, str, null, null) - - val existing = heap.filter { it.value==value }.map { it.key }.firstOrNull() - if(existing!=null) - return existing - val newId = heapId++ - heap[newId] = value - return newId - } - - fun addIntegerArray(type: DataType, array: Array): Int { - // arrays are never shared, don't check for existing - if(type !in ArrayDatatypes) - throw CompilerException("wrong array type") - val newId = heapId++ - heap[newId] = HeapValue(type, null, array, null) - return newId - } - - fun addDoublesArray(darray: DoubleArray): Int { - // arrays are never shared, don't check for existing - val newId = heapId++ - heap[newId] = HeapValue(DataType.ARRAY_F, null, null, darray) - return newId - } - - fun updateString(heapId: Int, str: String) { - val oldVal = heap[heapId] ?: throw IllegalArgumentException("heapId not found in heap") - if(oldVal.type in StringDatatypes) { - if (oldVal.str!!.length != str.length) - throw IllegalArgumentException("heap string length mismatch") - heap[heapId] = oldVal.copy(str = str) - } - else throw IllegalArgumentException("heap data type mismatch") - } - - fun get(heapId: Int): HeapValue { - return heap[heapId] ?: - throw IllegalArgumentException("heapId $heapId not found in heap") - } -} diff --git a/compiler/src/prog8/compiler/HeapValues.kt b/compiler/src/prog8/compiler/HeapValues.kt new file mode 100644 index 000000000..3be033079 --- /dev/null +++ b/compiler/src/prog8/compiler/HeapValues.kt @@ -0,0 +1,70 @@ +package prog8.compiler + +import prog8.ast.base.ArrayDatatypes +import prog8.ast.base.DataType +import prog8.ast.base.StringDatatypes +import java.util.* + +class HeapValues { + data class HeapValue(val type: DataType, val str: String?, val array: Array?, val doubleArray: DoubleArray?) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as HeapValue + return type==other.type && str==other.str && Arrays.equals(array, other.array) && Arrays.equals(doubleArray, other.doubleArray) + } + + override fun hashCode(): Int = Objects.hash(str, array, doubleArray) + } + + private val heap = mutableMapOf() + private var heapId = 1 + + fun size(): Int = heap.size + + fun addString(type: DataType, str: String): Int { + if (str.length > 255) + throw IllegalArgumentException("string length must be 0-255") + + // strings are 'interned' and shared if they're the isSameAs + val value = HeapValue(type, str, null, null) + + val existing = heap.filter { it.value==value }.map { it.key }.firstOrNull() + if(existing!=null) + return existing + val newId = heapId++ + heap[newId] = value + return newId + } + + fun addIntegerArray(type: DataType, array: Array): Int { + // arrays are never shared, don't check for existing + if(type !in ArrayDatatypes) + throw CompilerException("wrong array type") + val newId = heapId++ + heap[newId] = HeapValue(type, null, array, null) + return newId + } + + fun addDoublesArray(darray: DoubleArray): Int { + // arrays are never shared, don't check for existing + val newId = heapId++ + heap[newId] = HeapValue(DataType.ARRAY_F, null, null, darray) + return newId + } + + fun updateString(heapId: Int, str: String) { + val oldVal = heap[heapId] ?: throw IllegalArgumentException("heapId not found in heap") + if(oldVal.type in StringDatatypes) { + if (oldVal.str!!.length != str.length) + throw IllegalArgumentException("heap string length mismatch") + heap[heapId] = oldVal.copy(str = str) + } + else throw IllegalArgumentException("heap data type mismatch") + } + + fun get(heapId: Int): HeapValue { + return heap[heapId] ?: + throw IllegalArgumentException("heapId $heapId not found in heap") + } +} diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 115141aa8..363e9d79b 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -9,7 +9,6 @@ import prog8.ast.base.WordDatatypes import prog8.ast.expressions.* import prog8.ast.statements.AssignTarget import prog8.ast.statements.FunctionCallStatement -import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX diff --git a/compiler/src/prog8/vm/RuntimeValue.kt b/compiler/src/prog8/vm/RuntimeValue.kt index 2cb2b13a0..2f3a34826 100644 --- a/compiler/src/prog8/vm/RuntimeValue.kt +++ b/compiler/src/prog8/vm/RuntimeValue.kt @@ -1,10 +1,13 @@ package prog8.vm -import prog8.ast.base.* +import prog8.ast.base.ByteDatatypes +import prog8.ast.base.DataType +import prog8.ast.base.WordDatatypes import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.StringLiteralValue import prog8.compiler.target.c64.Petscii +import prog8.vm.astvm.VmExecutionException import java.util.* import kotlin.math.abs import kotlin.math.pow @@ -16,7 +19,13 @@ import kotlin.math.pow * It contains a value of a variable during run time of the program and provides arithmetic operations on the value. */ -open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=null, val array: Array?=null) { +abstract class RuntimeValueBase(val type: DataType) { + abstract fun numericValue(): Number + abstract fun integerValue(): Int +} + + +class RuntimeValueNumeric(type: DataType, num: Number): RuntimeValueBase(type) { val byteval: Short? val wordval: Int? @@ -24,37 +33,16 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= val asBoolean: Boolean companion object { - fun fromLv(literalValue: NumericLiteralValue): RuntimeValue { - return RuntimeValue(literalValue.type, num = literalValue.number) - } - - fun fromLv(string: StringLiteralValue): RuntimeValue { - return RuntimeValue(string.type, str = string.value) - } - - fun fromLv(array: ArrayLiteralValue): RuntimeValue { - return if (array.type == DataType.ARRAY_F) { - val doubleArray = array.value.map { (it as NumericLiteralValue).number }.toTypedArray() - RuntimeValue(array.type, array = doubleArray) - } else { - val resultArray = mutableListOf() - for (elt in array.value.withIndex()) { - if (elt.value is NumericLiteralValue) - resultArray.add((elt.value as NumericLiteralValue).number.toInt()) - else { - TODO("ADDRESSOF ${elt.value}") - } - } - RuntimeValue(array.type, array = resultArray.toTypedArray()) - } + fun fromLv(literalValue: NumericLiteralValue): RuntimeValueNumeric { + return RuntimeValueNumeric(literalValue.type, num = literalValue.number) } } init { - when(type) { + when (type) { DataType.UBYTE -> { - val inum = num!!.toInt() - if(inum !in 0 .. 255) + val inum = num.toInt() + if (inum !in 0..255) throw IllegalArgumentException("invalid value for ubyte: $inum") byteval = inum.toShort() wordval = null @@ -62,8 +50,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= asBoolean = byteval != 0.toShort() } DataType.BYTE -> { - val inum = num!!.toInt() - if(inum !in -128 .. 127) + val inum = num.toInt() + if (inum !in -128..127) throw IllegalArgumentException("invalid value for byte: $inum") byteval = inum.toShort() wordval = null @@ -71,8 +59,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= asBoolean = byteval != 0.toShort() } DataType.UWORD -> { - val inum = num!!.toInt() - if(inum !in 0 .. 65535) + val inum = num.toInt() + if (inum !in 0..65535) throw IllegalArgumentException("invalid value for uword: $inum") wordval = inum byteval = null @@ -80,8 +68,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= asBoolean = wordval != 0 } DataType.WORD -> { - val inum = num!!.toInt() - if(inum !in -32768 .. 32767) + val inum = num.toInt() + if (inum !in -32768..32767) throw IllegalArgumentException("invalid value for word: $inum") wordval = inum byteval = null @@ -89,50 +77,38 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= asBoolean = wordval != 0 } DataType.FLOAT -> { - floatval = num!!.toDouble() + floatval = num.toDouble() byteval = null wordval = null asBoolean = floatval != 0.0 } - else -> { - byteval = null - wordval = null - floatval = null - asBoolean = true - } + else -> throw VmExecutionException("not a numeric value") } } override fun toString(): String { - return when(type) { + return when (type) { DataType.UBYTE -> "ub:%02x".format(byteval) DataType.BYTE -> { - if(byteval!!<0) + if (byteval!! < 0) "b:-%02x".format(abs(byteval.toInt())) else "b:%02x".format(byteval) } DataType.UWORD -> "uw:%04x".format(wordval) DataType.WORD -> { - if(wordval!!<0) + if (wordval!! < 0) "w:-%04x".format(abs(wordval)) else "w:%04x".format(wordval) } DataType.FLOAT -> "f:$floatval" - DataType.STR -> "str:$str" - DataType.STR_S -> "str_s:$str" - DataType.ARRAY_UB -> "array_ub:..." - DataType.ARRAY_B -> "array_b:..." - DataType.ARRAY_UW -> "array_uw:..." - DataType.ARRAY_W -> "array_w:..." - DataType.ARRAY_F -> "array_f:..." - DataType.STRUCT -> "struct:..." + else -> "???" } } - fun numericValue(): Number { - return when(type) { + override fun numericValue(): Number { + return when (type) { in ByteDatatypes -> byteval!! in WordDatatypes -> wordval!! DataType.FLOAT -> floatval!! @@ -140,8 +116,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= } } - fun integerValue(): Int { - return when(type) { + override fun integerValue(): Int { + return when (type) { in ByteDatatypes -> byteval!!.toInt() in WordDatatypes -> wordval!! DataType.FLOAT -> throw ArithmeticException("float to integer loss of precision") @@ -152,73 +128,69 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= override fun hashCode(): Int = Objects.hash(byteval, wordval, floatval, type) override fun equals(other: Any?): Boolean { - if(other==null || other !is RuntimeValue) + if (other == null || other !is RuntimeValueNumeric) return false - return compareTo(other)==0 // note: datatype doesn't matter + return compareTo(other) == 0 // note: datatype doesn't matter } - operator fun compareTo(other: RuntimeValue): Int { - return if (type in NumericDatatypes && other.type in NumericDatatypes) - numericValue().toDouble().compareTo(other.numericValue().toDouble()) - else throw ArithmeticException("comparison can only be done between two numeric values") - } + operator fun compareTo(other: RuntimeValueNumeric): Int = numericValue().toDouble().compareTo(other.numericValue().toDouble()) - private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): RuntimeValue { - if(leftDt!=rightDt) + private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): RuntimeValueNumeric { + if (leftDt != rightDt) throw ArithmeticException("left and right datatypes are not the same") - if(result.toDouble() < 0 ) { - return when(leftDt) { + if (result.toDouble() < 0) { + return when (leftDt) { DataType.UBYTE, DataType.UWORD -> { // storing a negative number in an unsigned one is done by storing the 2's complement instead val number = abs(result.toDouble().toInt()) - if(leftDt== DataType.UBYTE) - RuntimeValue(DataType.UBYTE, (number xor 255) + 1) + if (leftDt == DataType.UBYTE) + RuntimeValueNumeric(DataType.UBYTE, (number xor 255) + 1) else - RuntimeValue(DataType.UWORD, (number xor 65535) + 1) + RuntimeValueNumeric(DataType.UWORD, (number xor 65535) + 1) } DataType.BYTE -> { - val v=result.toInt() and 255 - if(v<128) - RuntimeValue(DataType.BYTE, v) + val v = result.toInt() and 255 + if (v < 128) + RuntimeValueNumeric(DataType.BYTE, v) else - RuntimeValue(DataType.BYTE, v-256) + RuntimeValueNumeric(DataType.BYTE, v - 256) } DataType.WORD -> { - val v=result.toInt() and 65535 - if(v<32768) - RuntimeValue(DataType.WORD, v) + val v = result.toInt() and 65535 + if (v < 32768) + RuntimeValueNumeric(DataType.WORD, v) else - RuntimeValue(DataType.WORD, v-65536) + RuntimeValueNumeric(DataType.WORD, v - 65536) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, result) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, result) else -> throw ArithmeticException("$op on non-numeric type") } } - return when(leftDt) { - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, result.toInt() and 255) + return when (leftDt) { + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, result.toInt() and 255) DataType.BYTE -> { val v = result.toInt() and 255 - if(v<128) - RuntimeValue(DataType.BYTE, v) + if (v < 128) + RuntimeValueNumeric(DataType.BYTE, v) else - RuntimeValue(DataType.BYTE, v-256) + RuntimeValueNumeric(DataType.BYTE, v - 256) } - DataType.UWORD -> RuntimeValue(DataType.UWORD, result.toInt() and 65535) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, result.toInt() and 65535) DataType.WORD -> { val v = result.toInt() and 65535 - if(v<32768) - RuntimeValue(DataType.WORD, v) + if (v < 32768) + RuntimeValueNumeric(DataType.WORD, v) else - RuntimeValue(DataType.WORD, v-65536) + RuntimeValueNumeric(DataType.WORD, v - 65536) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, result) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, result) else -> throw ArithmeticException("$op on non-numeric type") } } - fun add(other: RuntimeValue): RuntimeValue { - if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) + fun add(other: RuntimeValueNumeric): RuntimeValueNumeric { + if (other.type == DataType.FLOAT && (type != DataType.FLOAT)) throw ArithmeticException("floating point loss of precision on type $type") val v1 = numericValue() val v2 = other.numericValue() @@ -226,8 +198,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= return arithResult(type, result, other.type, "add") } - fun sub(other: RuntimeValue): RuntimeValue { - if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) + fun sub(other: RuntimeValueNumeric): RuntimeValueNumeric { + if (other.type == DataType.FLOAT && (type != DataType.FLOAT)) throw ArithmeticException("floating point loss of precision on type $type") val v1 = numericValue() val v2 = other.numericValue() @@ -235,8 +207,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= return arithResult(type, result, other.type, "sub") } - fun mul(other: RuntimeValue): RuntimeValue { - if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) + fun mul(other: RuntimeValueNumeric): RuntimeValueNumeric { + if (other.type == DataType.FLOAT && (type != DataType.FLOAT)) throw ArithmeticException("floating point loss of precision on type $type") val v1 = numericValue() val v2 = other.numericValue() @@ -244,317 +216,318 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= return arithResult(type, result, other.type, "mul") } - fun div(other: RuntimeValue): RuntimeValue { - if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) + fun div(other: RuntimeValueNumeric): RuntimeValueNumeric { + if (other.type == DataType.FLOAT && (type != DataType.FLOAT)) throw ArithmeticException("floating point loss of precision on type $type") val v1 = numericValue() val v2 = other.numericValue() - if(v2.toDouble()==0.0) { + if (v2.toDouble() == 0.0) { when (type) { - DataType.UBYTE -> return RuntimeValue(DataType.UBYTE, 255) - DataType.BYTE -> return RuntimeValue(DataType.BYTE, 127) - DataType.UWORD -> return RuntimeValue(DataType.UWORD, 65535) - DataType.WORD -> return RuntimeValue(DataType.WORD, 32767) - else -> {} + DataType.UBYTE -> return RuntimeValueNumeric(DataType.UBYTE, 255) + DataType.BYTE -> return RuntimeValueNumeric(DataType.BYTE, 127) + DataType.UWORD -> return RuntimeValueNumeric(DataType.UWORD, 65535) + DataType.WORD -> return RuntimeValueNumeric(DataType.WORD, 32767) + else -> { + } } } val result = v1.toDouble() / v2.toDouble() // NOTE: integer division returns integer result! - return when(type) { - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, result) - DataType.BYTE -> RuntimeValue(DataType.BYTE, result) - DataType.UWORD -> RuntimeValue(DataType.UWORD, result) - DataType.WORD -> RuntimeValue(DataType.WORD, result) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, result) + return when (type) { + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, result) + DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, result) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, result) + DataType.WORD -> RuntimeValueNumeric(DataType.WORD, result) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, result) else -> throw ArithmeticException("div on non-numeric type") } } - fun remainder(other: RuntimeValue): RuntimeValue { + fun remainder(other: RuntimeValueNumeric): RuntimeValueNumeric { val v1 = numericValue() val v2 = other.numericValue() val result = v1.toDouble() % v2.toDouble() return arithResult(type, result, other.type, "remainder") } - fun pow(other: RuntimeValue): RuntimeValue { + fun pow(other: RuntimeValueNumeric): RuntimeValueNumeric { val v1 = numericValue() val v2 = other.numericValue() val result = v1.toDouble().pow(v2.toDouble()) - return arithResult(type, result, other.type,"pow") + return arithResult(type, result, other.type, "pow") } - fun shl(): RuntimeValue { + fun shl(): RuntimeValueNumeric { val v = integerValue() return when (type) { - DataType.UBYTE -> RuntimeValue(type, (v shl 1) and 255) - DataType.UWORD -> RuntimeValue(type, (v shl 1) and 65535) + DataType.UBYTE -> RuntimeValueNumeric(type, (v shl 1) and 255) + DataType.UWORD -> RuntimeValueNumeric(type, (v shl 1) and 65535) DataType.BYTE -> { val value = v shl 1 - if(value<128) - RuntimeValue(type, value) + if (value < 128) + RuntimeValueNumeric(type, value) else - RuntimeValue(type, value-256) + RuntimeValueNumeric(type, value - 256) } DataType.WORD -> { val value = v shl 1 - if(value<32768) - RuntimeValue(type, value) + if (value < 32768) + RuntimeValueNumeric(type, value) else - RuntimeValue(type, value-65536) + RuntimeValueNumeric(type, value - 65536) } else -> throw ArithmeticException("invalid type for shl: $type") } } - fun shr(): RuntimeValue { + fun shr(): RuntimeValueNumeric { val v = integerValue() - return when(type){ - DataType.UBYTE -> RuntimeValue(type, v ushr 1) - DataType.BYTE -> RuntimeValue(type, v shr 1) - DataType.UWORD -> RuntimeValue(type, v ushr 1) - DataType.WORD -> RuntimeValue(type, v shr 1) + return when (type) { + DataType.UBYTE -> RuntimeValueNumeric(type, v ushr 1) + DataType.BYTE -> RuntimeValueNumeric(type, v shr 1) + DataType.UWORD -> RuntimeValueNumeric(type, v ushr 1) + DataType.WORD -> RuntimeValueNumeric(type, v shr 1) else -> throw ArithmeticException("invalid type for shr: $type") } } - fun rol(carry: Boolean): Pair { + fun rol(carry: Boolean): Pair { // 9 or 17 bit rotate left (with carry)) - return when(type) { + return when (type) { DataType.UBYTE, DataType.BYTE -> { val v = byteval!!.toInt() val newCarry = (v and 0x80) != 0 - val newval = (v and 0x7f shl 1) or (if(carry) 1 else 0) - Pair(RuntimeValue(DataType.UBYTE, newval), newCarry) + val newval = (v and 0x7f shl 1) or (if (carry) 1 else 0) + Pair(RuntimeValueNumeric(DataType.UBYTE, newval), newCarry) } DataType.UWORD, DataType.WORD -> { val v = wordval!! val newCarry = (v and 0x8000) != 0 - val newval = (v and 0x7fff shl 1) or (if(carry) 1 else 0) - Pair(RuntimeValue(DataType.UWORD, newval), newCarry) + val newval = (v and 0x7fff shl 1) or (if (carry) 1 else 0) + Pair(RuntimeValueNumeric(DataType.UWORD, newval), newCarry) } else -> throw ArithmeticException("rol can only work on byte/word") } } - fun ror(carry: Boolean): Pair { + fun ror(carry: Boolean): Pair { // 9 or 17 bit rotate right (with carry) - return when(type) { + return when (type) { DataType.UBYTE, DataType.BYTE -> { val v = byteval!!.toInt() val newCarry = v and 1 != 0 - val newval = (v ushr 1) or (if(carry) 0x80 else 0) - Pair(RuntimeValue(DataType.UBYTE, newval), newCarry) + val newval = (v ushr 1) or (if (carry) 0x80 else 0) + Pair(RuntimeValueNumeric(DataType.UBYTE, newval), newCarry) } DataType.UWORD, DataType.WORD -> { val v = wordval!! val newCarry = v and 1 != 0 - val newval = (v ushr 1) or (if(carry) 0x8000 else 0) - Pair(RuntimeValue(DataType.UWORD, newval), newCarry) + val newval = (v ushr 1) or (if (carry) 0x8000 else 0) + Pair(RuntimeValueNumeric(DataType.UWORD, newval), newCarry) } else -> throw ArithmeticException("ror2 can only work on byte/word") } } - fun rol2(): RuntimeValue { + fun rol2(): RuntimeValueNumeric { // 8 or 16 bit rotate left - return when(type) { + return when (type) { DataType.UBYTE, DataType.BYTE -> { val v = byteval!!.toInt() val carry = (v and 0x80) ushr 7 val newval = (v and 0x7f shl 1) or carry - RuntimeValue(DataType.UBYTE, newval) + RuntimeValueNumeric(DataType.UBYTE, newval) } DataType.UWORD, DataType.WORD -> { val v = wordval!! val carry = (v and 0x8000) ushr 15 val newval = (v and 0x7fff shl 1) or carry - RuntimeValue(DataType.UWORD, newval) + RuntimeValueNumeric(DataType.UWORD, newval) } else -> throw ArithmeticException("rol2 can only work on byte/word") } } - fun ror2(): RuntimeValue { + fun ror2(): RuntimeValueNumeric { // 8 or 16 bit rotate right - return when(type) { + return when (type) { DataType.UBYTE, DataType.BYTE -> { val v = byteval!!.toInt() val carry = v and 1 shl 7 val newval = (v ushr 1) or carry - RuntimeValue(DataType.UBYTE, newval) + RuntimeValueNumeric(DataType.UBYTE, newval) } DataType.UWORD, DataType.WORD -> { val v = wordval!! val carry = v and 1 shl 15 val newval = (v ushr 1) or carry - RuntimeValue(DataType.UWORD, newval) + RuntimeValueNumeric(DataType.UWORD, newval) } else -> throw ArithmeticException("ror2 can only work on byte/word") } } - fun neg(): RuntimeValue { - return when(type) { - DataType.BYTE -> RuntimeValue(DataType.BYTE, -(byteval!!)) - DataType.WORD -> RuntimeValue(DataType.WORD, -(wordval!!)) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, -(floatval)!!) + fun neg(): RuntimeValueNumeric { + return when (type) { + DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, -(byteval!!)) + DataType.WORD -> RuntimeValueNumeric(DataType.WORD, -(wordval!!)) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, -(floatval)!!) else -> throw ArithmeticException("neg can only work on byte/word/float") } } - fun abs(): RuntimeValue { - return when(type) { - DataType.BYTE -> RuntimeValue(DataType.BYTE, abs(byteval!!.toInt())) - DataType.WORD -> RuntimeValue(DataType.WORD, abs(wordval!!)) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(floatval!!)) + fun abs(): RuntimeValueNumeric { + return when (type) { + DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, abs(byteval!!.toInt())) + DataType.WORD -> RuntimeValueNumeric(DataType.WORD, abs(wordval!!)) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, abs(floatval!!)) else -> throw ArithmeticException("abs can only work on byte/word/float") } } - fun bitand(other: RuntimeValue): RuntimeValue { + fun bitand(other: RuntimeValueNumeric): RuntimeValueNumeric { val v1 = integerValue() val v2 = other.integerValue() val result = v1 and v2 - return RuntimeValue(type, result) + return RuntimeValueNumeric(type, result) } - fun bitor(other: RuntimeValue): RuntimeValue { + fun bitor(other: RuntimeValueNumeric): RuntimeValueNumeric { val v1 = integerValue() val v2 = other.integerValue() val result = v1 or v2 - return RuntimeValue(type, result) + return RuntimeValueNumeric(type, result) } - fun bitxor(other: RuntimeValue): RuntimeValue { + fun bitxor(other: RuntimeValueNumeric): RuntimeValueNumeric { val v1 = integerValue() val v2 = other.integerValue() val result = v1 xor v2 - return RuntimeValue(type, result) + return RuntimeValueNumeric(type, result) } - fun and(other: RuntimeValue) = RuntimeValue(DataType.UBYTE, if (this.asBoolean && other.asBoolean) 1 else 0) - fun or(other: RuntimeValue) = RuntimeValue(DataType.UBYTE, if (this.asBoolean || other.asBoolean) 1 else 0) - fun xor(other: RuntimeValue) = RuntimeValue(DataType.UBYTE, if (this.asBoolean xor other.asBoolean) 1 else 0) - fun not() = RuntimeValue(DataType.UBYTE, if (this.asBoolean) 0 else 1) + fun and(other: RuntimeValueNumeric) = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean && other.asBoolean) 1 else 0) + fun or(other: RuntimeValueNumeric) = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean || other.asBoolean) 1 else 0) + fun xor(other: RuntimeValueNumeric) = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean xor other.asBoolean) 1 else 0) + fun not() = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean) 0 else 1) - fun inv(): RuntimeValue { - return when(type) { - DataType.UBYTE -> RuntimeValue(type, byteval!!.toInt().inv() and 255) - DataType.UWORD -> RuntimeValue(type, wordval!!.inv() and 65535) - DataType.BYTE -> RuntimeValue(type, byteval!!.toInt().inv()) - DataType.WORD -> RuntimeValue(type, wordval!!.inv()) + fun inv(): RuntimeValueNumeric { + return when (type) { + DataType.UBYTE -> RuntimeValueNumeric(type, byteval!!.toInt().inv() and 255) + DataType.UWORD -> RuntimeValueNumeric(type, wordval!!.inv() and 65535) + DataType.BYTE -> RuntimeValueNumeric(type, byteval!!.toInt().inv()) + DataType.WORD -> RuntimeValueNumeric(type, wordval!!.inv()) else -> throw ArithmeticException("inv can only work on byte/word") } } - fun inc(): RuntimeValue { - return when(type) { - DataType.UBYTE -> RuntimeValue(type, (byteval!! + 1) and 255) - DataType.UWORD -> RuntimeValue(type, (wordval!! + 1) and 65535) + fun inc(): RuntimeValueNumeric { + return when (type) { + DataType.UBYTE -> RuntimeValueNumeric(type, (byteval!! + 1) and 255) + DataType.UWORD -> RuntimeValueNumeric(type, (wordval!! + 1) and 65535) DataType.BYTE -> { val newval = byteval!! + 1 - if(newval == 128) - RuntimeValue(type, -128) + if (newval == 128) + RuntimeValueNumeric(type, -128) else - RuntimeValue(type, newval) + RuntimeValueNumeric(type, newval) } DataType.WORD -> { val newval = wordval!! + 1 - if(newval == 32768) - RuntimeValue(type, -32768) + if (newval == 32768) + RuntimeValueNumeric(type, -32768) else - RuntimeValue(type, newval) + RuntimeValueNumeric(type, newval) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, floatval!! + 1) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, floatval!! + 1) else -> throw ArithmeticException("inc can only work on numeric types") } } - fun dec(): RuntimeValue { - return when(type) { - DataType.UBYTE -> RuntimeValue(type, (byteval!! - 1) and 255) - DataType.UWORD -> RuntimeValue(type, (wordval!! - 1) and 65535) + fun dec(): RuntimeValueNumeric { + return when (type) { + DataType.UBYTE -> RuntimeValueNumeric(type, (byteval!! - 1) and 255) + DataType.UWORD -> RuntimeValueNumeric(type, (wordval!! - 1) and 65535) DataType.BYTE -> { val newval = byteval!! - 1 - if(newval == -129) - RuntimeValue(type, 127) + if (newval == -129) + RuntimeValueNumeric(type, 127) else - RuntimeValue(type, newval) + RuntimeValueNumeric(type, newval) } DataType.WORD -> { val newval = wordval!! - 1 - if(newval == -32769) - RuntimeValue(type, 32767) + if (newval == -32769) + RuntimeValueNumeric(type, 32767) else - RuntimeValue(type, newval) + RuntimeValueNumeric(type, newval) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, floatval!! - 1) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, floatval!! - 1) else -> throw ArithmeticException("dec can only work on numeric types") } } - fun msb(): RuntimeValue { - return when(type) { - in ByteDatatypes -> RuntimeValue(DataType.UBYTE, 0) - in WordDatatypes -> RuntimeValue(DataType.UBYTE, wordval!! ushr 8 and 255) + fun msb(): RuntimeValueNumeric { + return when (type) { + in ByteDatatypes -> RuntimeValueNumeric(DataType.UBYTE, 0) + in WordDatatypes -> RuntimeValueNumeric(DataType.UBYTE, wordval!! ushr 8 and 255) else -> throw ArithmeticException("msb can only work on (u)byte/(u)word") } } - fun cast(targetType: DataType): RuntimeValue { + fun cast(targetType: DataType): RuntimeValueNumeric { return when (type) { DataType.UBYTE -> { when (targetType) { DataType.UBYTE -> this DataType.BYTE -> { - val nval=byteval!!.toInt() - if(nval<128) - RuntimeValue(DataType.BYTE, nval) + val nval = byteval!!.toInt() + if (nval < 128) + RuntimeValueNumeric(DataType.BYTE, nval) else - RuntimeValue(DataType.BYTE, nval-256) + RuntimeValueNumeric(DataType.BYTE, nval - 256) } - DataType.UWORD -> RuntimeValue(DataType.UWORD, numericValue()) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, numericValue()) DataType.WORD -> { val nval = numericValue().toInt() - if(nval<32768) - RuntimeValue(DataType.WORD, nval) + if (nval < 32768) + RuntimeValueNumeric(DataType.WORD, nval) else - RuntimeValue(DataType.WORD, nval-65536) + RuntimeValueNumeric(DataType.WORD, nval - 65536) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, numericValue()) else -> throw ArithmeticException("invalid type cast from $type to $targetType") } } DataType.BYTE -> { when (targetType) { DataType.BYTE -> this - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 255) - DataType.UWORD -> RuntimeValue(DataType.UWORD, integerValue() and 65535) - DataType.WORD -> RuntimeValue(DataType.WORD, integerValue()) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, integerValue() and 255) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, integerValue() and 65535) + DataType.WORD -> RuntimeValueNumeric(DataType.WORD, integerValue()) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, numericValue()) else -> throw ArithmeticException("invalid type cast from $type to $targetType") } } DataType.UWORD -> { when (targetType) { DataType.BYTE -> { - val v=integerValue() - if(v<128) - RuntimeValue(DataType.BYTE, v) + val v = integerValue() + if (v < 128) + RuntimeValueNumeric(DataType.BYTE, v) else - RuntimeValue(DataType.BYTE, v-256) + RuntimeValueNumeric(DataType.BYTE, v - 256) } - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 255) + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, integerValue() and 255) DataType.UWORD -> this DataType.WORD -> { - val v=integerValue() - if(v<32768) - RuntimeValue(DataType.WORD, v) + val v = integerValue() + if (v < 32768) + RuntimeValueNumeric(DataType.WORD, v) else - RuntimeValue(DataType.WORD, v-65536) + RuntimeValueNumeric(DataType.WORD, v - 65536) } - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, numericValue()) else -> throw ArithmeticException("invalid type cast from $type to $targetType") } } @@ -562,33 +535,33 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= when (targetType) { DataType.BYTE -> { val v = integerValue() and 255 - if(v<128) - RuntimeValue(DataType.BYTE, v) + if (v < 128) + RuntimeValueNumeric(DataType.BYTE, v) else - RuntimeValue(DataType.BYTE, v-256) + RuntimeValueNumeric(DataType.BYTE, v - 256) } - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 65535) - DataType.UWORD -> RuntimeValue(DataType.UWORD, integerValue()) + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, integerValue() and 65535) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, integerValue()) DataType.WORD -> this - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, numericValue()) else -> throw ArithmeticException("invalid type cast from $type to $targetType") } } DataType.FLOAT -> { when (targetType) { DataType.BYTE -> { - val integer=numericValue().toInt() - if(integer in -128..127) - RuntimeValue(DataType.BYTE, integer) + val integer = numericValue().toInt() + if (integer in -128..127) + RuntimeValueNumeric(DataType.BYTE, integer) else throw ArithmeticException("overflow when casting float to byte: $this") } - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, numericValue().toInt()) - DataType.UWORD -> RuntimeValue(DataType.UWORD, numericValue().toInt()) + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, numericValue().toInt()) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, numericValue().toInt()) DataType.WORD -> { - val integer=numericValue().toInt() - if(integer in -32768..32767) - RuntimeValue(DataType.WORD, integer) + val integer = numericValue().toInt() + if (integer in -32768..32767) + RuntimeValueNumeric(DataType.WORD, integer) else throw ArithmeticException("overflow when casting float to word: $this") } @@ -599,22 +572,97 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= else -> throw ArithmeticException("invalid type cast from $type to $targetType") } } +} - open fun iterator(): Iterator { - return when (type) { - in StringDatatypes -> { - Petscii.encodePetscii(str!!, true).iterator() - } - in ArrayDatatypes -> { - array!!.iterator() - } - else -> throw IllegalArgumentException("cannot iterate over $this") + +class RuntimeValueString(type: DataType, val str: String): RuntimeValueBase(type) { + companion object { + fun fromLv(string: StringLiteralValue): RuntimeValueString { + return RuntimeValueString(string.type, str = string.value) } } + + override fun toString(): String { + return when (type) { + DataType.STR -> "str:$str" + DataType.STR_S -> "str_s:$str" + else -> "???" + } + } + + override fun hashCode(): Int = Objects.hash(type, str) + + override fun equals(other: Any?): Boolean { + if (other == null || other !is RuntimeValueString) + return false + return type == other.type && str == other.str + } + + fun iterator(): Iterator = Petscii.encodePetscii(str, true).iterator() + + override fun numericValue(): Number { + throw VmExecutionException("string is not a number") + } + + override fun integerValue(): Int { + throw VmExecutionException("string is not a number") + } } -class RuntimeValueRange(type: DataType, val range: IntProgression): RuntimeValue(type, array=range.toList().toTypedArray()) { +open class RuntimeValueArray(type: DataType, val array: Array): RuntimeValueBase(type) { + + companion object { + fun fromLv(array: ArrayLiteralValue): RuntimeValueArray { + return if (array.type == DataType.ARRAY_F) { + val doubleArray = array.value.map { (it as NumericLiteralValue).number }.toTypedArray() + RuntimeValueArray(array.type, array = doubleArray) + } else { + val resultArray = mutableListOf() + for (elt in array.value.withIndex()) { + if (elt.value is NumericLiteralValue) + resultArray.add((elt.value as NumericLiteralValue).number.toInt()) + else { + TODO("ADDRESSOF ${elt.value}") + } + } + RuntimeValueArray(array.type, array = resultArray.toTypedArray()) + } + } + } + + override fun toString(): String { + return when (type) { + DataType.ARRAY_UB -> "array_ub:..." + DataType.ARRAY_B -> "array_b:..." + DataType.ARRAY_UW -> "array_uw:..." + DataType.ARRAY_W -> "array_w:..." + DataType.ARRAY_F -> "array_f:..." + else -> "???" + } + } + + override fun hashCode(): Int = Objects.hash(type, array) + + override fun equals(other: Any?): Boolean { + if (other == null || other !is RuntimeValueArray) + return false + return type == other.type && array.contentEquals(other.array) + } + + open fun iterator(): Iterator = array.iterator() + + override fun numericValue(): Number { + throw VmExecutionException("array is not a number") + } + + override fun integerValue(): Int { + throw VmExecutionException("array is not a number") + } +} + + +class RuntimeValueRange(type: DataType, val range: IntProgression): RuntimeValueArray(type, range.toList().toTypedArray()) { override fun iterator(): Iterator { return range.iterator() } diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 3ebe9cf84..37ce114d1 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -10,8 +10,7 @@ import prog8.ast.statements.* import prog8.compiler.IntegerOrAddressOf import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.Petscii -import prog8.vm.RuntimeValue -import prog8.vm.RuntimeValueRange +import prog8.vm.* import java.awt.EventQueue import java.io.CharConversionException import java.util.* @@ -72,7 +71,7 @@ class StatusFlags { class RuntimeVariables { - fun define(scope: INameScope, name: String, initialValue: RuntimeValue) { + fun define(scope: INameScope, name: String, initialValue: RuntimeValueBase) { val where = vars.getValue(scope) where[name] = initialValue vars[scope] = where @@ -84,7 +83,7 @@ class RuntimeVariables { memvars[scope] = where } - fun set(scope: INameScope, name: String, value: RuntimeValue) { + fun set(scope: INameScope, name: String, value: RuntimeValueBase) { val where = vars.getValue(scope) val existing = where[name] if(existing==null) { @@ -98,7 +97,7 @@ class RuntimeVariables { vars[scope] = where } - fun get(scope: INameScope, name: String): RuntimeValue { + fun get(scope: INameScope, name: String): RuntimeValueBase { val where = vars.getValue(scope) return where[name] ?: throw NoSuchElementException("no such runtime variable: ${scope.name}.$name") } @@ -117,7 +116,7 @@ class RuntimeVariables { set(scope2, name2, v1) } - private val vars = mutableMapOf>().withDefault { mutableMapOf() } + private val vars = mutableMapOf>().withDefault { mutableMapOf() } private val memvars = mutableMapOf>().withDefault { mutableMapOf() } } @@ -134,9 +133,9 @@ class AstVm(val program: Program) { private val rnd = Random(0) private val statusFlagsSave = Stack() - private val registerXsave = Stack() - private val registerYsave = Stack() - private val registerAsave = Stack() + private val registerXsave = Stack() + private val registerYsave = Stack() + private val registerAsave = Stack() init { @@ -182,7 +181,7 @@ class AstVm(val program: Program) { fun run() { try { - val init = VariablesCreator(runtimeVariables, program.heap) + val init = VariablesCreator(runtimeVariables) init.visit(program) // initialize all global variables @@ -263,11 +262,11 @@ class AstVm(val program: Program) { class LoopControlBreak : Exception() class LoopControlContinue : Exception() - class LoopControlReturn(val returnvalue: RuntimeValue?) : Exception() + class LoopControlReturn(val returnvalue: RuntimeValueNumeric?) : Exception() class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception() - internal fun executeSubroutine(sub: Subroutine, arguments: List, startAtLabel: Label?=null): RuntimeValue? { + internal fun executeSubroutine(sub: Subroutine, arguments: List, startAtLabel: Label?=null): RuntimeValueNumeric? { if(sub.isAsmSubroutine) { return performSyscall(sub, arguments) } @@ -335,7 +334,7 @@ class AstVm(val program: Program) { val target = stmt.target.targetStatement(program.namespace) when (target) { is Subroutine -> { - val args = evaluate(stmt.arglist) + val args = evaluate(stmt.arglist).map { it as RuntimeValueNumeric } if (target.isAsmSubroutine) { performSyscall(target, args) } else { @@ -348,7 +347,7 @@ class AstVm(val program: Program) { // swap cannot be implemented as a function, so inline it here executeSwap(stmt) } else { - val args = evaluate(stmt.arglist) + val args = evaluate(stmt.arglist).map { it as RuntimeValueNumeric } performBuiltinFunction(target.name, args, statusflags) } } @@ -362,7 +361,7 @@ class AstVm(val program: Program) { if(stmt.value==null) null else - evaluate(stmt.value!!, evalCtx) + evaluate(stmt.value!!, evalCtx) as RuntimeValueNumeric throw LoopControlReturn(value) } is Continue -> throw LoopControlContinue() @@ -380,10 +379,10 @@ class AstVm(val program: Program) { val identScope = ident.definingScope() when(ident.type){ VarDeclType.VAR -> { - var value = runtimeVariables.get(identScope, ident.name) + var value = runtimeVariables.get(identScope, ident.name) as RuntimeValueNumeric value = when { - stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) - stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) + stmt.operator == "++" -> value.add(RuntimeValueNumeric(value.type, 1)) + stmt.operator == "--" -> value.sub(RuntimeValueNumeric(value.type, 1)) else -> throw VmExecutionException("strange postincdec operator $stmt") } runtimeVariables.set(identScope, ident.name, value) @@ -401,7 +400,7 @@ class AstVm(val program: Program) { } } stmt.target.memoryAddress != null -> { - val addr = evaluate(stmt.target.memoryAddress!!.addressExpression, evalCtx).integerValue() + val addr = (evaluate(stmt.target.memoryAddress!!.addressExpression, evalCtx) as RuntimeValueNumeric).integerValue() val newval = when { stmt.operator == "++" -> mem.getUByte(addr)+1 and 255 stmt.operator == "--" -> mem.getUByte(addr)-1 and 255 @@ -411,12 +410,12 @@ class AstVm(val program: Program) { } stmt.target.arrayindexed != null -> { val arrayvar = stmt.target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!! - val arrayvalue = runtimeVariables.get(arrayvar.definingScope(), arrayvar.name) - val index = evaluate(stmt.target.arrayindexed!!.arrayspec.index, evalCtx).integerValue() + val arrayvalue = runtimeVariables.get(arrayvar.definingScope(), arrayvar.name) as RuntimeValueArray + val index = (evaluate(stmt.target.arrayindexed!!.arrayspec.index, evalCtx) as RuntimeValueNumeric).integerValue() val elementType = stmt.target.arrayindexed!!.inferType(program) if(!elementType.isKnown) throw VmExecutionException("unknown/void elt type") - var value = RuntimeValue(elementType.typeOrElse(DataType.BYTE), arrayvalue.array!![index].toInt()) + var value = RuntimeValueNumeric(elementType.typeOrElse(DataType.BYTE), arrayvalue.array[index].toInt()) value = when { stmt.operator == "++" -> value.inc() stmt.operator == "--" -> value.dec() @@ -425,10 +424,10 @@ class AstVm(val program: Program) { arrayvalue.array[index] = value.numericValue() } stmt.target.register != null -> { - var value = runtimeVariables.get(program.namespace, stmt.target.register!!.name) + var value = runtimeVariables.get(program.namespace, stmt.target.register!!.name) as RuntimeValueNumeric value = when { - stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) - stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) + stmt.operator == "++" -> value.add(RuntimeValueNumeric(value.type, 1)) + stmt.operator == "--" -> value.sub(RuntimeValueNumeric(value.type, 1)) else -> throw VmExecutionException("strange postincdec operator $stmt") } runtimeVariables.set(program.namespace, stmt.target.register!!.name, value) @@ -439,7 +438,7 @@ class AstVm(val program: Program) { is Jump -> throw LoopControlJump(stmt.identifier, stmt.address, stmt.generatedLabel) is InlineAssembly -> { if (sub is Subroutine) { - val args = sub.parameters.map { runtimeVariables.get(sub, it.name) } + val args = sub.parameters.map { runtimeVariables.get(sub, it.name) as RuntimeValueNumeric } performSyscall(sub, args) throw LoopControlReturn(null) } @@ -447,7 +446,7 @@ class AstVm(val program: Program) { } is AnonymousScope -> executeAnonymousScope(stmt) is IfStatement -> { - val condition = evaluate(stmt.condition, evalCtx) + val condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric if (condition.asBoolean) executeAnonymousScope(stmt.truepart) else @@ -478,7 +477,13 @@ class AstVm(val program: Program) { loopvarDt = dt.typeOrElse(DataType.UBYTE) loopvar = stmt.loopVar!! } - val iterator = iterable.iterator() + val iterator = + when (iterable) { + is RuntimeValueRange -> iterable.iterator() + is RuntimeValueArray -> iterable.iterator() + is RuntimeValueString -> iterable.iterator() + else -> throw VmExecutionException("not iterable") + } for (loopvalue in iterator) { try { oneForCycle(stmt, loopvarDt, loopvalue, loopvar) @@ -490,11 +495,11 @@ class AstVm(val program: Program) { } } is WhileLoop -> { - var condition = evaluate(stmt.condition, evalCtx) + var condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric while (condition.asBoolean) { try { executeAnonymousScope(stmt.body) - condition = evaluate(stmt.condition, evalCtx) + condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric } catch (b: LoopControlBreak) { break } catch (c: LoopControlContinue) { @@ -504,7 +509,7 @@ class AstVm(val program: Program) { } is RepeatLoop -> { do { - val condition = evaluate(stmt.untilCondition, evalCtx) + val condition = evaluate(stmt.untilCondition, evalCtx) as RuntimeValueNumeric try { executeAnonymousScope(stmt.body) } catch (b: LoopControlBreak) { @@ -515,7 +520,7 @@ class AstVm(val program: Program) { } while (!condition.asBoolean) } is WhenStatement -> { - val condition=evaluate(stmt.condition, evalCtx) + val condition=evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric for(choice in stmt.choices) { if(choice.values==null) { // the 'else' choice @@ -523,7 +528,7 @@ class AstVm(val program: Program) { break } else { val value = choice.values!!.single().constValue(evalCtx.program) ?: throw VmExecutionException("can only use const values in when choices ${choice.position}") - val rtval = RuntimeValue.fromLv(value) + val rtval = RuntimeValueNumeric.fromLv(value) if(condition==rtval) { executeAnonymousScope(choice.statements) break @@ -548,7 +553,7 @@ class AstVm(val program: Program) { performAssignment(target2, value1, swap, evalCtx) } - fun performAssignment(target: AssignTarget, value: RuntimeValue, contextStmt: Statement, evalCtx: EvalContext) { + fun performAssignment(target: AssignTarget, value: RuntimeValueBase, contextStmt: Statement, evalCtx: EvalContext) { val targetIdent = target.identifier val targetArrayIndexed = target.arrayindexed when { @@ -558,27 +563,27 @@ class AstVm(val program: Program) { if (decl.type == VarDeclType.MEMORY) { val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name) when (decl.datatype) { - DataType.UBYTE -> mem.setUByte(address, value.byteval!!) - DataType.BYTE -> mem.setSByte(address, value.byteval!!) - DataType.UWORD -> mem.setUWord(address, value.wordval!!) - DataType.WORD -> mem.setSWord(address, value.wordval!!) - DataType.FLOAT -> mem.setFloat(address, value.floatval!!) - DataType.STR -> mem.setString(address, value.str!!) - DataType.STR_S -> mem.setScreencodeString(address, value.str!!) + DataType.UBYTE -> mem.setUByte(address, (value as RuntimeValueNumeric).byteval!!) + DataType.BYTE -> mem.setSByte(address, (value as RuntimeValueNumeric).byteval!!) + DataType.UWORD -> mem.setUWord(address, (value as RuntimeValueNumeric).wordval!!) + DataType.WORD -> mem.setSWord(address, (value as RuntimeValueNumeric).wordval!!) + DataType.FLOAT -> mem.setFloat(address, (value as RuntimeValueNumeric).floatval!!) + DataType.STR -> mem.setString(address, (value as RuntimeValueString).str) + DataType.STR_S -> mem.setScreencodeString(address, (value as RuntimeValueString).str) else -> throw VmExecutionException("weird memaddress type $decl") } } else runtimeVariables.set(decl.definingScope(), decl.name, value) } target.memoryAddress != null -> { - val address = evaluate(target.memoryAddress.addressExpression, evalCtx).wordval!! - evalCtx.mem.setUByte(address, value.byteval!!) + val address = (evaluate(target.memoryAddress.addressExpression, evalCtx) as RuntimeValueNumeric).wordval!! + evalCtx.mem.setUByte(address, (value as RuntimeValueNumeric).byteval!!) } targetArrayIndexed != null -> { val vardecl = targetArrayIndexed.identifier.targetVarDecl(program.namespace)!! if(vardecl.type==VarDeclType.VAR) { val array = evaluate(targetArrayIndexed.identifier, evalCtx) - val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx) + val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx) as RuntimeValueNumeric when (array.type) { DataType.ARRAY_UB -> { if (value.type != DataType.UBYTE) @@ -607,20 +612,21 @@ class AstVm(val program: Program) { else -> throw VmExecutionException("strange array type ${array.type}") } if (array.type in ArrayDatatypes) - array.array!![index.integerValue()] = value.numericValue() + (array as RuntimeValueArray).array[index.integerValue()] = value.numericValue() else if (array.type in StringDatatypes) { val indexInt = index.integerValue() val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true) - val newstr = array.str!!.replaceRange(indexInt, indexInt + 1, newchr) + val newstr = (array as RuntimeValueString).str.replaceRange(indexInt, indexInt + 1, newchr) val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl ?: throw VmExecutionException("can't find assignment target ${target.identifier}") val identScope = ident.definingScope() - runtimeVariables.set(identScope, ident.name, RuntimeValue(array.type, str = newstr)) + runtimeVariables.set(identScope, ident.name, RuntimeValueString(array.type, newstr)) } } else { + value as RuntimeValueNumeric val address = (vardecl.value as NumericLiteralValue).number.toInt() - val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx).integerValue() + val index = (evaluate(targetArrayIndexed.arrayspec.index, evalCtx) as RuntimeValueNumeric).integerValue() val elementType = targetArrayIndexed.inferType(program) if(!elementType.isKnown) throw VmExecutionException("unknown/void array elt type $targetArrayIndexed") @@ -644,14 +650,14 @@ class AstVm(val program: Program) { private fun oneForCycle(stmt: ForLoop, loopvarDt: DataType, loopValue: Number, loopVar: IdentifierReference) { // assign the new loop value to the loopvar, and run the code performAssignment(AssignTarget(null, loopVar, null, null, loopVar.position), - RuntimeValue(loopvarDt, loopValue), stmt.body.statements.first(), evalCtx) + RuntimeValueNumeric(loopvarDt, loopValue), stmt.body.statements.first(), evalCtx) executeAnonymousScope(stmt.body) } private fun evaluate(args: List) = args.map { evaluate(it, evalCtx) } - private fun performSyscall(sub: Subroutine, args: List): RuntimeValue? { - var result: RuntimeValue? = null + private fun performSyscall(sub: Subroutine, args: List): RuntimeValueNumeric? { + var result: RuntimeValueNumeric? = null when (sub.scopedname) { "c64scr.print" -> { // if the argument is an UWORD, consider it to be the "address" of the string (=heapId) @@ -659,7 +665,7 @@ class AstVm(val program: Program) { val str = program.heap.get(args[0].wordval!!).str!! dialog.canvas.printText(str, true) } else - dialog.canvas.printText(args[0].str!!, true) + throw VmExecutionException("print non-heap string") } "c64scr.print_ub" -> { dialog.canvas.printText(args[0].byteval!!.toString(), true) @@ -735,7 +741,7 @@ class AstVm(val program: Program) { val origStr = program.heap.get(heapId).str!! val paddedStr=inputStr.padEnd(origStr.length+1, '\u0000').substring(0, origStr.length) program.heap.updateString(heapId, paddedStr) - result = RuntimeValue(DataType.UBYTE, paddedStr.indexOf('\u0000')) + result = RuntimeValueNumeric(DataType.UBYTE, paddedStr.indexOf('\u0000')) } "c64flt.print_f" -> { dialog.canvas.printText(args[0].floatval.toString(), false) @@ -751,13 +757,13 @@ class AstVm(val program: Program) { Thread.sleep(10) } val char=dialog.keyboardBuffer.pop() - result = RuntimeValue(DataType.UBYTE, char.toShort()) + result = RuntimeValueNumeric(DataType.UBYTE, char.toShort()) } "c64utils.str2uword" -> { val heapId = args[0].wordval!! val argString = program.heap.get(heapId).str!! val numericpart = argString.takeWhile { it.isDigit() } - result = RuntimeValue(DataType.UWORD, numericpart.toInt() and 65535) + result = RuntimeValueNumeric(DataType.UWORD, numericpart.toInt() and 65535) } else -> TODO("syscall ${sub.scopedname} $sub") } @@ -765,120 +771,120 @@ class AstVm(val program: Program) { return result } - private fun performBuiltinFunction(name: String, args: List, statusflags: StatusFlags): RuntimeValue? { + private fun performBuiltinFunction(name: String, args: List, statusflags: StatusFlags): RuntimeValueNumeric? { return when (name) { - "rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255) - "rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535) - "rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble()) - "lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255) - "msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255) - "sin" -> RuntimeValue(DataType.FLOAT, sin(args[0].numericValue().toDouble())) + "rnd" -> RuntimeValueNumeric(DataType.UBYTE, rnd.nextInt() and 255) + "rndw" -> RuntimeValueNumeric(DataType.UWORD, rnd.nextInt() and 65535) + "rndf" -> RuntimeValueNumeric(DataType.FLOAT, rnd.nextDouble()) + "lsb" -> RuntimeValueNumeric(DataType.UBYTE, args[0].integerValue() and 255) + "msb" -> RuntimeValueNumeric(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255) + "sin" -> RuntimeValueNumeric(DataType.FLOAT, sin(args[0].numericValue().toDouble())) "sin8" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (127.0 * sin(rad)).toShort()) + RuntimeValueNumeric(DataType.BYTE, (127.0 * sin(rad)).toShort()) } "sin8u" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort()) + RuntimeValueNumeric(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort()) } "sin16" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (32767.0 * sin(rad)).toShort()) + RuntimeValueNumeric(DataType.BYTE, (32767.0 * sin(rad)).toShort()) } "sin16u" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * sin(rad)).toShort()) + RuntimeValueNumeric(DataType.UBYTE, (32768.0 + 32767.5 * sin(rad)).toShort()) } - "cos" -> RuntimeValue(DataType.FLOAT, cos(args[0].numericValue().toDouble())) + "cos" -> RuntimeValueNumeric(DataType.FLOAT, cos(args[0].numericValue().toDouble())) "cos8" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (127.0 * cos(rad)).toShort()) + RuntimeValueNumeric(DataType.BYTE, (127.0 * cos(rad)).toShort()) } "cos8u" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort()) + RuntimeValueNumeric(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort()) } "cos16" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (32767.0 * cos(rad)).toShort()) + RuntimeValueNumeric(DataType.BYTE, (32767.0 * cos(rad)).toShort()) } "cos16u" -> { val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * cos(rad)).toShort()) + RuntimeValueNumeric(DataType.UBYTE, (32768.0 + 32767.5 * cos(rad)).toShort()) } - "tan" -> RuntimeValue(DataType.FLOAT, tan(args[0].numericValue().toDouble())) - "atan" -> RuntimeValue(DataType.FLOAT, atan(args[0].numericValue().toDouble())) - "ln" -> RuntimeValue(DataType.FLOAT, ln(args[0].numericValue().toDouble())) - "log2" -> RuntimeValue(DataType.FLOAT, log2(args[0].numericValue().toDouble())) - "sqrt" -> RuntimeValue(DataType.FLOAT, sqrt(args[0].numericValue().toDouble())) - "sqrt16" -> RuntimeValue(DataType.UBYTE, sqrt(args[0].wordval!!.toDouble()).toInt()) - "rad" -> RuntimeValue(DataType.FLOAT, Math.toRadians(args[0].numericValue().toDouble())) - "deg" -> RuntimeValue(DataType.FLOAT, Math.toDegrees(args[0].numericValue().toDouble())) - "round" -> RuntimeValue(DataType.FLOAT, round(args[0].numericValue().toDouble())) - "floor" -> RuntimeValue(DataType.FLOAT, floor(args[0].numericValue().toDouble())) - "ceil" -> RuntimeValue(DataType.FLOAT, ceil(args[0].numericValue().toDouble())) + "tan" -> RuntimeValueNumeric(DataType.FLOAT, tan(args[0].numericValue().toDouble())) + "atan" -> RuntimeValueNumeric(DataType.FLOAT, atan(args[0].numericValue().toDouble())) + "ln" -> RuntimeValueNumeric(DataType.FLOAT, ln(args[0].numericValue().toDouble())) + "log2" -> RuntimeValueNumeric(DataType.FLOAT, log2(args[0].numericValue().toDouble())) + "sqrt" -> RuntimeValueNumeric(DataType.FLOAT, sqrt(args[0].numericValue().toDouble())) + "sqrt16" -> RuntimeValueNumeric(DataType.UBYTE, sqrt((args[0] as RuntimeValueNumeric).wordval!!.toDouble()).toInt()) + "rad" -> RuntimeValueNumeric(DataType.FLOAT, Math.toRadians(args[0].numericValue().toDouble())) + "deg" -> RuntimeValueNumeric(DataType.FLOAT, Math.toDegrees(args[0].numericValue().toDouble())) + "round" -> RuntimeValueNumeric(DataType.FLOAT, round(args[0].numericValue().toDouble())) + "floor" -> RuntimeValueNumeric(DataType.FLOAT, floor(args[0].numericValue().toDouble())) + "ceil" -> RuntimeValueNumeric(DataType.FLOAT, ceil(args[0].numericValue().toDouble())) "rol" -> { - val (result, newCarry) = args[0].rol(statusflags.carry) + val (result, newCarry) = (args[0] as RuntimeValueNumeric).rol(statusflags.carry) statusflags.carry = newCarry return result } - "rol2" -> args[0].rol2() + "rol2" -> (args[0] as RuntimeValueNumeric).rol2() "ror" -> { - val (result, newCarry) = args[0].ror(statusflags.carry) + val (result, newCarry) = (args[0] as RuntimeValueNumeric).ror(statusflags.carry) statusflags.carry = newCarry return result } - "ror2" -> args[0].ror2() - "lsl" -> args[0].shl() - "lsr" -> args[0].shr() + "ror2" -> (args[0] as RuntimeValueNumeric).ror2() + "lsl" -> (args[0] as RuntimeValueNumeric).shl() + "lsr" -> (args[0] as RuntimeValueNumeric).shr() "abs" -> { when (args[0].type) { - DataType.UBYTE -> args[0] - DataType.BYTE -> RuntimeValue(DataType.UBYTE, abs(args[0].numericValue().toDouble())) - DataType.UWORD -> args[0] - DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble())) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble())) + DataType.UBYTE -> (args[0] as RuntimeValueNumeric) + DataType.BYTE -> RuntimeValueNumeric(DataType.UBYTE, abs(args[0].numericValue().toDouble())) + DataType.UWORD -> (args[0] as RuntimeValueNumeric) + DataType.WORD -> RuntimeValueNumeric(DataType.UWORD, abs(args[0].numericValue().toDouble())) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, abs(args[0].numericValue().toDouble())) else -> throw VmExecutionException("strange abs type ${args[0]}") } } "max" -> { - val numbers = args.single().array!!.map { it.toDouble() } - RuntimeValue(ArrayElementTypes.getValue(args[0].type), numbers.max()) + val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() } + RuntimeValueNumeric(ArrayElementTypes.getValue(args[0].type), numbers.max()!!) } "min" -> { - val numbers = args.single().array!!.map { it.toDouble() } - RuntimeValue(ArrayElementTypes.getValue(args[0].type), numbers.min()) + val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() } + RuntimeValueNumeric(ArrayElementTypes.getValue(args[0].type), numbers.min()!!) } "sum" -> { - val sum = args.single().array!!.map { it.toDouble() }.sum() + val sum = (args.single() as RuntimeValueArray).array.map { it.toDouble() }.sum() when (args[0].type) { - DataType.ARRAY_UB -> RuntimeValue(DataType.UWORD, sum) - DataType.ARRAY_B -> RuntimeValue(DataType.WORD, sum) - DataType.ARRAY_UW -> RuntimeValue(DataType.UWORD, sum) - DataType.ARRAY_W -> RuntimeValue(DataType.WORD, sum) - DataType.ARRAY_F -> RuntimeValue(DataType.FLOAT, sum) + DataType.ARRAY_UB -> RuntimeValueNumeric(DataType.UWORD, sum) + DataType.ARRAY_B -> RuntimeValueNumeric(DataType.WORD, sum) + DataType.ARRAY_UW -> RuntimeValueNumeric(DataType.UWORD, sum) + DataType.ARRAY_W -> RuntimeValueNumeric(DataType.WORD, sum) + DataType.ARRAY_F -> RuntimeValueNumeric(DataType.FLOAT, sum) else -> throw VmExecutionException("weird sum type ${args[0]}") } } "any" -> { - val numbers = args.single().array!!.map { it.toDouble() } - RuntimeValue(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0) + val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() } + RuntimeValueNumeric(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0) } "all" -> { - val numbers = args.single().array!!.map { it.toDouble() } - RuntimeValue(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0) + val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() } + RuntimeValueNumeric(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0) } "swap" -> throw VmExecutionException("swap() cannot be implemented as a function") "strlen" -> { - val zeroIndex = args[0].str!!.indexOf(0.toChar()) + val zeroIndex = (args[0] as RuntimeValueString).str.indexOf(0.toChar()) if (zeroIndex >= 0) - RuntimeValue(DataType.UBYTE, zeroIndex) + RuntimeValueNumeric(DataType.UBYTE, zeroIndex) else - RuntimeValue(DataType.UBYTE, args[0].str!!.length) + RuntimeValueNumeric(DataType.UBYTE, (args[0] as RuntimeValueString).str.length) } "memset" -> { - val heapId = args[0].wordval!! + val heapId = (args[0] as RuntimeValueNumeric).wordval!! val target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array") val amount = args[1].integerValue() val value = args[2].integerValue() @@ -888,7 +894,7 @@ class AstVm(val program: Program) { null } "memsetw" -> { - val heapId = args[0].wordval!! + val heapId = (args[0] as RuntimeValueNumeric).wordval!! val target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array") val amount = args[1].integerValue() val value = args[2].integerValue() @@ -899,8 +905,8 @@ class AstVm(val program: Program) { null } "memcopy" -> { - val sourceHeapId = args[0].wordval!! - val destHeapId = args[1].wordval!! + val sourceHeapId = (args[0] as RuntimeValueNumeric).wordval!! + val destHeapId = (args[1] as RuntimeValueNumeric).wordval!! val source = program.heap.get(sourceHeapId).array!! val dest = program.heap.get(destHeapId).array!! val amount = args[2].integerValue() @@ -911,7 +917,7 @@ class AstVm(val program: Program) { } "mkword" -> { val result = (args[1].integerValue() shl 8) or args[0].integerValue() - RuntimeValue(DataType.UWORD, result) + RuntimeValueNumeric(DataType.UWORD, result) } "set_carry" -> { statusflags.carry=true @@ -934,13 +940,13 @@ class AstVm(val program: Program) { val zero = if(statusflags.zero) 2 else 0 val irqd = if(statusflags.irqd) 4 else 0 val negative = if(statusflags.negative) 128 else 0 - RuntimeValue(DataType.UBYTE, carry or zero or irqd or negative) + RuntimeValueNumeric(DataType.UBYTE, carry or zero or irqd or negative) } "rsave" -> { statusFlagsSave.push(statusflags) - registerAsave.push(runtimeVariables.get(program.namespace, Register.A.name)) - registerXsave.push(runtimeVariables.get(program.namespace, Register.X.name)) - registerYsave.push(runtimeVariables.get(program.namespace, Register.Y.name)) + registerAsave.push(runtimeVariables.get(program.namespace, Register.A.name) as RuntimeValueNumeric) + registerXsave.push(runtimeVariables.get(program.namespace, Register.X.name) as RuntimeValueNumeric) + registerYsave.push(runtimeVariables.get(program.namespace, Register.Y.name) as RuntimeValueNumeric) null } "rrestore" -> { @@ -955,21 +961,21 @@ class AstVm(val program: Program) { null } "sort" -> { - val array=args.single() - array.array!!.sort() + val array=args.single() as RuntimeValueArray + array.array.sort() null } "reverse" -> { - val array=args.single() - array.array!!.reverse() + val array=args.single() as RuntimeValueArray + array.array.reverse() null } "sgn" -> { val value = args.single().numericValue().toDouble() when { - value<0.0 -> RuntimeValue(DataType.BYTE, -1) - value==0.0 -> RuntimeValue(DataType.BYTE, 0) - else -> RuntimeValue(DataType.BYTE, 1) + value<0.0 -> RuntimeValueNumeric(DataType.BYTE, -1) + value==0.0 -> RuntimeValueNumeric(DataType.BYTE, 0) + else -> RuntimeValueNumeric(DataType.BYTE, 1) } } else -> TODO("builtin function $name") diff --git a/compiler/src/prog8/vm/astvm/Expressions.kt b/compiler/src/prog8/vm/astvm/Expressions.kt index bc87703e5..ea249e0a5 100644 --- a/compiler/src/prog8/vm/astvm/Expressions.kt +++ b/compiler/src/prog8/vm/astvm/Expressions.kt @@ -10,12 +10,11 @@ import prog8.ast.statements.BuiltinFunctionStatementPlaceholder import prog8.ast.statements.Label import prog8.ast.statements.Subroutine import prog8.ast.statements.VarDecl -import prog8.vm.RuntimeValue -import prog8.vm.RuntimeValueRange +import prog8.vm.* -typealias BuiltinfunctionCaller = (name: String, args: List, flags: StatusFlags) -> RuntimeValue? -typealias SubroutineCaller = (sub: Subroutine, args: List, startAtLabel: Label?) -> RuntimeValue? +typealias BuiltinfunctionCaller = (name: String, args: List, flags: StatusFlags) -> RuntimeValueNumeric? +typealias SubroutineCaller = (sub: Subroutine, args: List, startAtLabel: Label?) -> RuntimeValueNumeric? class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, @@ -23,34 +22,34 @@ class EvalContext(val program: Program, val mem: Memory, val statusflags: Status val performBuiltinFunction: BuiltinfunctionCaller, val executeSubroutine: SubroutineCaller) -fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { +fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValueBase { val constval = expr.constValue(ctx.program) if(constval!=null) - return RuntimeValue.fromLv(constval) + return RuntimeValueNumeric.fromLv(constval) when(expr) { - is NumericLiteralValue -> return RuntimeValue.fromLv(expr) - is StringLiteralValue -> return RuntimeValue.fromLv(expr) - is ArrayLiteralValue -> return RuntimeValue.fromLv(expr) + is NumericLiteralValue -> return RuntimeValueNumeric.fromLv(expr) + is StringLiteralValue -> return RuntimeValueString.fromLv(expr) + is ArrayLiteralValue -> return RuntimeValueArray.fromLv(expr) is PrefixExpression -> { return when(expr.operator) { - "-" -> evaluate(expr.expression, ctx).neg() - "~" -> evaluate(expr.expression, ctx).inv() - "not" -> evaluate(expr.expression, ctx).not() + "-" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).neg() + "~" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).inv() + "not" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).not() // unary '+' should have been optimized away else -> throw VmExecutionException("unsupported prefix operator "+expr.operator) } } is BinaryExpression -> { - val left = evaluate(expr.left, ctx) - val right = evaluate(expr.right, ctx) + val left = evaluate(expr.left, ctx) as RuntimeValueNumeric + val right = evaluate(expr.right, ctx) as RuntimeValueNumeric return when(expr.operator) { - "<" -> RuntimeValue(DataType.UBYTE, if (left < right) 1 else 0) - "<=" -> RuntimeValue(DataType.UBYTE, if (left <= right) 1 else 0) - ">" -> RuntimeValue(DataType.UBYTE, if (left > right) 1 else 0) - ">=" -> RuntimeValue(DataType.UBYTE, if (left >= right) 1 else 0) - "==" -> RuntimeValue(DataType.UBYTE, if (left == right) 1 else 0) - "!=" -> RuntimeValue(DataType.UBYTE, if (left != right) 1 else 0) + "<" -> RuntimeValueNumeric(DataType.UBYTE, if (left < right) 1 else 0) + "<=" -> RuntimeValueNumeric(DataType.UBYTE, if (left <= right) 1 else 0) + ">" -> RuntimeValueNumeric(DataType.UBYTE, if (left > right) 1 else 0) + ">=" -> RuntimeValueNumeric(DataType.UBYTE, if (left >= right) 1 else 0) + "==" -> RuntimeValueNumeric(DataType.UBYTE, if (left == right) 1 else 0) + "!=" -> RuntimeValueNumeric(DataType.UBYTE, if (left != right) 1 else 0) "+" -> left.add(right) "-" -> left.sub(right) "*" -> left.mul(right) @@ -78,32 +77,36 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { } is ArrayIndexedExpression -> { val array = evaluate(expr.identifier, ctx) - val index = evaluate(expr.arrayspec.index, ctx) - return if(array.array!=null) { - val value = array.array[index.integerValue()] - RuntimeValue(ArrayElementTypes.getValue(array.type), value) - } else { - val value = array.str!![index.integerValue()] - RuntimeValue(ArrayElementTypes.getValue(array.type), value.toShort()) + val index = evaluate(expr.arrayspec.index, ctx) as RuntimeValueNumeric + return when (array) { + is RuntimeValueString -> { + val value = array.str[index.integerValue()] + RuntimeValueNumeric(ArrayElementTypes.getValue(array.type), value.toShort()) + } + is RuntimeValueArray -> { + val value = array.array[index.integerValue()] + RuntimeValueNumeric(ArrayElementTypes.getValue(array.type), value) + } + else -> throw VmExecutionException("weird type") } } is TypecastExpression -> { - return evaluate(expr.expression, ctx).cast(expr.type) + return (evaluate(expr.expression, ctx) as RuntimeValueNumeric).cast(expr.type) } is AddressOf -> { // we support: address of heap var -> the heap id return try { val heapId = expr.identifier.heapId(ctx.program.namespace) - RuntimeValue(DataType.UWORD, heapId) + RuntimeValueNumeric(DataType.UWORD, heapId) } catch( f: FatalAstException) { // fallback: use the hash of the name, so we have at least *a* value... val address = expr.identifier.hashCode() and 65535 - RuntimeValue(DataType.UWORD, address) + RuntimeValueNumeric(DataType.UWORD, address) } } is DirectMemoryRead -> { - val address = evaluate(expr.addressExpression, ctx).wordval!! - return RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address)) + val address = (evaluate(expr.addressExpression, ctx) as RuntimeValueNumeric).wordval!! + return RuntimeValueNumeric(DataType.UBYTE, ctx.mem.getUByte(address)) } is RegisterExpr -> return ctx.runtimeVars.get(ctx.program.namespace, expr.register.name) is IdentifierReference -> { @@ -116,13 +119,13 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { else -> { val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name) return when(variable.datatype) { - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address)) - DataType.BYTE -> RuntimeValue(DataType.BYTE, ctx.mem.getSByte(address)) - DataType.UWORD -> RuntimeValue(DataType.UWORD, ctx.mem.getUWord(address)) - DataType.WORD -> RuntimeValue(DataType.WORD, ctx.mem.getSWord(address)) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, ctx.mem.getFloat(address)) - DataType.STR -> RuntimeValue(DataType.STR, str = ctx.mem.getString(address)) - DataType.STR_S -> RuntimeValue(DataType.STR_S, str = ctx.mem.getScreencodeString(address)) + DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, ctx.mem.getUByte(address)) + DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, ctx.mem.getSByte(address)) + DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, ctx.mem.getUWord(address)) + DataType.WORD -> RuntimeValueNumeric(DataType.WORD, ctx.mem.getSWord(address)) + DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, ctx.mem.getFloat(address)) + DataType.STR -> RuntimeValueString(DataType.STR, ctx.mem.getString(address)) + DataType.STR_S -> RuntimeValueString(DataType.STR_S, ctx.mem.getScreencodeString(address)!!) else -> throw VmExecutionException("unexpected datatype $variable") } } @@ -132,7 +135,7 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { } is FunctionCall -> { val sub = expr.target.targetStatement(ctx.program.namespace) - val args = expr.arglist.map { evaluate(it, ctx) } + val args = expr.arglist.map { evaluate(it, ctx) as RuntimeValueNumeric } return when(sub) { is Subroutine -> { val result = ctx.executeSubroutine(sub, args, null) @@ -158,9 +161,9 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { else throw VmExecutionException("couldn't determine datatype") } - val fromVal = evaluate(expr.from, ctx).integerValue() - val toVal = evaluate(expr.to, ctx).integerValue() - val stepVal = evaluate(expr.step, ctx).integerValue() + val fromVal = (evaluate(expr.from, ctx) as RuntimeValueNumeric).integerValue() + val toVal = (evaluate(expr.to, ctx) as RuntimeValueNumeric).integerValue() + val stepVal = (evaluate(expr.step, ctx) as RuntimeValueNumeric).integerValue() val range = makeRange(fromVal, toVal, stepVal) val dt = expr.inferType(ctx.program) if(dt.isKnown) diff --git a/compiler/src/prog8/vm/astvm/VariablesCreator.kt b/compiler/src/prog8/vm/astvm/VariablesCreator.kt index 44800845c..f632d4850 100644 --- a/compiler/src/prog8/vm/astvm/VariablesCreator.kt +++ b/compiler/src/prog8/vm/astvm/VariablesCreator.kt @@ -13,16 +13,17 @@ import prog8.ast.statements.Statement import prog8.ast.statements.StructDecl import prog8.ast.statements.VarDecl import prog8.ast.statements.ZeropageWish -import prog8.compiler.HeapValues -import prog8.vm.RuntimeValue +import prog8.vm.RuntimeValueArray +import prog8.vm.RuntimeValueNumeric +import prog8.vm.RuntimeValueString -class VariablesCreator(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstModifyingVisitor { +class VariablesCreator(private val runtimeVariables: RuntimeVariables) : IAstModifyingVisitor { override fun visit(program: Program) { // define the three registers as global variables - runtimeVariables.define(program.namespace, Register.A.name, RuntimeValue(DataType.UBYTE, 0)) - runtimeVariables.define(program.namespace, Register.X.name, RuntimeValue(DataType.UBYTE, 255)) - runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0)) + runtimeVariables.define(program.namespace, Register.A.name, RuntimeValueNumeric(DataType.UBYTE, 0)) + runtimeVariables.define(program.namespace, Register.X.name, RuntimeValueNumeric(DataType.UBYTE, 255)) + runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValueNumeric(DataType.UBYTE, 0)) val globalpos = Position("<>", 0, 0, 0) val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.DONTCARE, null, Register.A.name, null, @@ -49,12 +50,12 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v if(decl.datatype!=DataType.STRUCT) { val numericLv = decl.value as? NumericLiteralValue val value = if(numericLv!=null) { - RuntimeValue.fromLv(numericLv) + RuntimeValueNumeric.fromLv(numericLv) } else { if(decl.value is StringLiteralValue) - RuntimeValue.fromLv(decl.value as StringLiteralValue) + RuntimeValueString.fromLv(decl.value as StringLiteralValue) else - RuntimeValue.fromLv(decl.value as ArrayLiteralValue) + RuntimeValueArray.fromLv(decl.value as ArrayLiteralValue) } runtimeVariables.define(decl.definingScope(), decl.name, value) } diff --git a/compiler/test/RuntimeValueTests.kt b/compiler/test/RuntimeValueTests.kt index ffd59b8e3..882ff1fd3 100644 --- a/compiler/test/RuntimeValueTests.kt +++ b/compiler/test/RuntimeValueTests.kt @@ -3,66 +3,66 @@ package prog8tests import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import prog8.ast.base.DataType -import prog8.vm.RuntimeValue +import prog8.vm.RuntimeValueNumeric import kotlin.test.* -private fun sameValueAndType(v1: RuntimeValue, v2: RuntimeValue): Boolean { +private fun sameValueAndType(v1: RuntimeValueNumeric, v2: RuntimeValueNumeric): Boolean { return v1.type==v2.type && v1==v2 } @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestRuntimeValue { +class TestRuntimeValueNumeric { @Test fun testValueRanges() { - assertEquals(0, RuntimeValue(DataType.UBYTE, 0).integerValue()) - assertEquals(255, RuntimeValue(DataType.UBYTE, 255).integerValue()) - assertFailsWith { RuntimeValue(DataType.UBYTE, -1)} - assertFailsWith { RuntimeValue(DataType.UBYTE, 256)} + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 255).integerValue()) + assertFailsWith { RuntimeValueNumeric(DataType.UBYTE, -1)} + assertFailsWith { RuntimeValueNumeric(DataType.UBYTE, 256)} - assertEquals(0, RuntimeValue(DataType.BYTE, 0).integerValue()) - assertEquals(-128, RuntimeValue(DataType.BYTE, -128).integerValue()) - assertEquals(127, RuntimeValue(DataType.BYTE, 127).integerValue()) - assertFailsWith { RuntimeValue(DataType.BYTE, -129)} - assertFailsWith { RuntimeValue(DataType.BYTE, 128)} + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 0).integerValue()) + assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -128).integerValue()) + assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 127).integerValue()) + assertFailsWith { RuntimeValueNumeric(DataType.BYTE, -129)} + assertFailsWith { RuntimeValueNumeric(DataType.BYTE, 128)} - assertEquals(0, RuntimeValue(DataType.UWORD, 0).integerValue()) - assertEquals(65535, RuntimeValue(DataType.UWORD, 65535).integerValue()) - assertFailsWith { RuntimeValue(DataType.UWORD, -1)} - assertFailsWith { RuntimeValue(DataType.UWORD, 65536)} + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 65535).integerValue()) + assertFailsWith { RuntimeValueNumeric(DataType.UWORD, -1)} + assertFailsWith { RuntimeValueNumeric(DataType.UWORD, 65536)} - assertEquals(0, RuntimeValue(DataType.WORD, 0).integerValue()) - assertEquals(-32768, RuntimeValue(DataType.WORD, -32768).integerValue()) - assertEquals(32767, RuntimeValue(DataType.WORD, 32767).integerValue()) - assertFailsWith { RuntimeValue(DataType.WORD, -32769)} - assertFailsWith { RuntimeValue(DataType.WORD, 32768)} + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 0).integerValue()) + assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32768).integerValue()) + assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32767).integerValue()) + assertFailsWith { RuntimeValueNumeric(DataType.WORD, -32769)} + assertFailsWith { RuntimeValueNumeric(DataType.WORD, 32768)} } @Test fun testTruthiness() { - assertFalse(RuntimeValue(DataType.BYTE, 0).asBoolean) - assertFalse(RuntimeValue(DataType.UBYTE, 0).asBoolean) - assertFalse(RuntimeValue(DataType.WORD, 0).asBoolean) - assertFalse(RuntimeValue(DataType.UWORD, 0).asBoolean) - assertFalse(RuntimeValue(DataType.FLOAT, 0.0).asBoolean) + assertFalse(RuntimeValueNumeric(DataType.BYTE, 0).asBoolean) + assertFalse(RuntimeValueNumeric(DataType.UBYTE, 0).asBoolean) + assertFalse(RuntimeValueNumeric(DataType.WORD, 0).asBoolean) + assertFalse(RuntimeValueNumeric(DataType.UWORD, 0).asBoolean) + assertFalse(RuntimeValueNumeric(DataType.FLOAT, 0.0).asBoolean) - assertTrue(RuntimeValue(DataType.BYTE, 42).asBoolean) - assertTrue(RuntimeValue(DataType.UBYTE, 42).asBoolean) - assertTrue(RuntimeValue(DataType.WORD, 42).asBoolean) - assertTrue(RuntimeValue(DataType.UWORD, 42).asBoolean) - assertTrue(RuntimeValue(DataType.FLOAT, 42.0).asBoolean) - assertTrue(RuntimeValue(DataType.BYTE, -42).asBoolean) - assertTrue(RuntimeValue(DataType.WORD, -42).asBoolean) - assertTrue(RuntimeValue(DataType.FLOAT, -42.0).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.BYTE, 42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.UBYTE, 42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.WORD, 42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.UWORD, 42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, 42.0).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.BYTE, -42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.WORD, -42).asBoolean) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, -42.0).asBoolean) } @Test fun testIdentity() { - val v = RuntimeValue(DataType.UWORD, 12345) + val v = RuntimeValueNumeric(DataType.UWORD, 12345) assertEquals(v, v) assertFalse(v != v) assertTrue(v<=v) @@ -70,283 +70,283 @@ class TestRuntimeValue { assertFalse(vv) - assertTrue(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100))) + assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100))) } @Test fun testEqualsAndNotEquals() { - assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100)) - assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 100)) - assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 100)) - assertEquals(RuntimeValue(DataType.UWORD, 254), RuntimeValue(DataType.UBYTE, 254)) - assertEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12345)) - assertEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12345)) - assertEquals(RuntimeValue(DataType.FLOAT, 100.0), RuntimeValue(DataType.UBYTE, 100)) - assertEquals(RuntimeValue(DataType.FLOAT, 22239.0), RuntimeValue(DataType.UWORD, 22239)) - assertEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.99)) + assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100)) + assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 100)) + assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 100)) + assertEquals(RuntimeValueNumeric(DataType.UWORD, 254), RuntimeValueNumeric(DataType.UBYTE, 254)) + assertEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12345)) + assertEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12345)) + assertEquals(RuntimeValueNumeric(DataType.FLOAT, 100.0), RuntimeValueNumeric(DataType.UBYTE, 100)) + assertEquals(RuntimeValueNumeric(DataType.FLOAT, 22239.0), RuntimeValueNumeric(DataType.UWORD, 22239)) + assertEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.99)) - assertTrue(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 100))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 100))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 254), RuntimeValue(DataType.UBYTE, 254))) - assertTrue(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12345))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12345))) - assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 100.0), RuntimeValue(DataType.UBYTE, 100))) - assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 22239.0), RuntimeValue(DataType.UWORD, 22239))) - assertTrue(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.99))) + assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 100))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 100))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 254), RuntimeValueNumeric(DataType.UBYTE, 254))) + assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12345))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12345))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 100.0), RuntimeValueNumeric(DataType.UBYTE, 100))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 22239.0), RuntimeValueNumeric(DataType.UWORD, 22239))) + assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.99))) - assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 101)) - assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 101)) - assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 101)) - assertNotEquals(RuntimeValue(DataType.UWORD, 245), RuntimeValue(DataType.UBYTE, 246)) - assertNotEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12346)) - assertNotEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12346)) - assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UBYTE, 9)) - assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UWORD, 9)) - assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.0)) + assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 101)) + assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 101)) + assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 101)) + assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 245), RuntimeValueNumeric(DataType.UBYTE, 246)) + assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12346)) + assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12346)) + assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UBYTE, 9)) + assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UWORD, 9)) + assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.0)) - assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 101))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 101))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 101))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 245), RuntimeValue(DataType.UBYTE, 246))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12346))) - assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12346))) - assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UBYTE, 9))) - assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UWORD, 9))) - assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.0))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 101))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 101))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 101))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 245), RuntimeValueNumeric(DataType.UBYTE, 246))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12346))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12346))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UBYTE, 9))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UWORD, 9))) + assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.0))) } @Test fun testGreaterThan(){ - assertTrue(RuntimeValue(DataType.UBYTE, 100) > RuntimeValue(DataType.UBYTE, 99)) - assertTrue(RuntimeValue(DataType.UWORD, 254) > RuntimeValue(DataType.UWORD, 253)) - assertTrue(RuntimeValue(DataType.FLOAT, 100.0) > RuntimeValue(DataType.FLOAT, 99.9)) + assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) > RuntimeValueNumeric(DataType.UBYTE, 99)) + assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) > RuntimeValueNumeric(DataType.UWORD, 253)) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) > RuntimeValueNumeric(DataType.FLOAT, 99.9)) - assertTrue(RuntimeValue(DataType.UBYTE, 100) >= RuntimeValue(DataType.UBYTE, 100)) - assertTrue(RuntimeValue(DataType.UWORD, 254) >= RuntimeValue(DataType.UWORD, 254)) - assertTrue(RuntimeValue(DataType.FLOAT, 100.0) >= RuntimeValue(DataType.FLOAT, 100.0)) + assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) >= RuntimeValueNumeric(DataType.UBYTE, 100)) + assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) >= RuntimeValueNumeric(DataType.UWORD, 254)) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) >= RuntimeValueNumeric(DataType.FLOAT, 100.0)) - assertFalse(RuntimeValue(DataType.UBYTE, 100) > RuntimeValue(DataType.UBYTE, 100)) - assertFalse(RuntimeValue(DataType.UWORD, 254) > RuntimeValue(DataType.UWORD, 254)) - assertFalse(RuntimeValue(DataType.FLOAT, 100.0) > RuntimeValue(DataType.FLOAT, 100.0)) + assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) > RuntimeValueNumeric(DataType.UBYTE, 100)) + assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) > RuntimeValueNumeric(DataType.UWORD, 254)) + assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) > RuntimeValueNumeric(DataType.FLOAT, 100.0)) - assertFalse(RuntimeValue(DataType.UBYTE, 100) >= RuntimeValue(DataType.UBYTE, 101)) - assertFalse(RuntimeValue(DataType.UWORD, 254) >= RuntimeValue(DataType.UWORD, 255)) - assertFalse(RuntimeValue(DataType.FLOAT, 100.0) >= RuntimeValue(DataType.FLOAT, 100.1)) + assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) >= RuntimeValueNumeric(DataType.UBYTE, 101)) + assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) >= RuntimeValueNumeric(DataType.UWORD, 255)) + assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) >= RuntimeValueNumeric(DataType.FLOAT, 100.1)) } @Test fun testLessThan() { - assertTrue(RuntimeValue(DataType.UBYTE, 100) < RuntimeValue(DataType.UBYTE, 101)) - assertTrue(RuntimeValue(DataType.UWORD, 254) < RuntimeValue(DataType.UWORD, 255)) - assertTrue(RuntimeValue(DataType.FLOAT, 100.0) < RuntimeValue(DataType.FLOAT, 100.1)) + assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) < RuntimeValueNumeric(DataType.UBYTE, 101)) + assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) < RuntimeValueNumeric(DataType.UWORD, 255)) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) < RuntimeValueNumeric(DataType.FLOAT, 100.1)) - assertTrue(RuntimeValue(DataType.UBYTE, 100) <= RuntimeValue(DataType.UBYTE, 100)) - assertTrue(RuntimeValue(DataType.UWORD, 254) <= RuntimeValue(DataType.UWORD, 254)) - assertTrue(RuntimeValue(DataType.FLOAT, 100.0) <= RuntimeValue(DataType.FLOAT, 100.0)) + assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) <= RuntimeValueNumeric(DataType.UBYTE, 100)) + assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) <= RuntimeValueNumeric(DataType.UWORD, 254)) + assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) <= RuntimeValueNumeric(DataType.FLOAT, 100.0)) - assertFalse(RuntimeValue(DataType.UBYTE, 100) < RuntimeValue(DataType.UBYTE, 100)) - assertFalse(RuntimeValue(DataType.UWORD, 254) < RuntimeValue(DataType.UWORD, 254)) - assertFalse(RuntimeValue(DataType.FLOAT, 100.0) < RuntimeValue(DataType.FLOAT, 100.0)) + assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) < RuntimeValueNumeric(DataType.UBYTE, 100)) + assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) < RuntimeValueNumeric(DataType.UWORD, 254)) + assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) < RuntimeValueNumeric(DataType.FLOAT, 100.0)) - assertFalse(RuntimeValue(DataType.UBYTE, 100) <= RuntimeValue(DataType.UBYTE, 99)) - assertFalse(RuntimeValue(DataType.UWORD, 254) <= RuntimeValue(DataType.UWORD, 253)) - assertFalse(RuntimeValue(DataType.FLOAT, 100.0) <= RuntimeValue(DataType.FLOAT, 99.9)) + assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) <= RuntimeValueNumeric(DataType.UBYTE, 99)) + assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) <= RuntimeValueNumeric(DataType.UWORD, 253)) + assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) <= RuntimeValueNumeric(DataType.FLOAT, 99.9)) } @Test fun testNoDtConversion() { assertFailsWith { - RuntimeValue(DataType.UWORD, 100).add(RuntimeValue(DataType.UBYTE, 120)) + RuntimeValueNumeric(DataType.UWORD, 100).add(RuntimeValueNumeric(DataType.UBYTE, 120)) } assertFailsWith { - RuntimeValue(DataType.UBYTE, 100).add(RuntimeValue(DataType.UWORD, 120)) + RuntimeValueNumeric(DataType.UBYTE, 100).add(RuntimeValueNumeric(DataType.UWORD, 120)) } assertFailsWith { - RuntimeValue(DataType.FLOAT, 100.22).add(RuntimeValue(DataType.UWORD, 120)) + RuntimeValueNumeric(DataType.FLOAT, 100.22).add(RuntimeValueNumeric(DataType.UWORD, 120)) } assertFailsWith { - RuntimeValue(DataType.UWORD, 1002).add(RuntimeValue(DataType.FLOAT, 120.22)) + RuntimeValueNumeric(DataType.UWORD, 1002).add(RuntimeValueNumeric(DataType.FLOAT, 120.22)) } assertFailsWith { - RuntimeValue(DataType.FLOAT, 100.22).add(RuntimeValue(DataType.UBYTE, 120)) + RuntimeValueNumeric(DataType.FLOAT, 100.22).add(RuntimeValueNumeric(DataType.UBYTE, 120)) } assertFailsWith { - RuntimeValue(DataType.UBYTE, 12).add(RuntimeValue(DataType.FLOAT, 120.22)) + RuntimeValueNumeric(DataType.UBYTE, 12).add(RuntimeValueNumeric(DataType.FLOAT, 120.22)) } } @Test fun testNoAutoFloatConversion() { assertFailsWith { - RuntimeValue(DataType.UBYTE, 233).add(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UBYTE, 233).add(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } assertFailsWith { - RuntimeValue(DataType.UWORD, 233).add(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UWORD, 233).add(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } assertFailsWith { - RuntimeValue(DataType.UBYTE, 233).mul(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UBYTE, 233).mul(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } assertFailsWith { - RuntimeValue(DataType.UWORD, 233).mul(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UWORD, 233).mul(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } assertFailsWith { - RuntimeValue(DataType.UBYTE, 233).div(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UBYTE, 233).div(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } assertFailsWith { - RuntimeValue(DataType.UWORD, 233).div(RuntimeValue(DataType.FLOAT, 1.234)) + RuntimeValueNumeric(DataType.UWORD, 233).div(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } - val result = RuntimeValue(DataType.FLOAT, 233.333).add(RuntimeValue(DataType.FLOAT, 1.234)) + val result = RuntimeValueNumeric(DataType.FLOAT, 233.333).add(RuntimeValueNumeric(DataType.FLOAT, 1.234)) } @Test fun arithmetictestUbyte() { - assertEquals(255, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 55)).integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 56)).integerValue()) - assertEquals(1, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 57)).integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 200).add(RuntimeValueNumeric(DataType.UBYTE, 55)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 200).add(RuntimeValueNumeric(DataType.UBYTE, 56)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UBYTE, 200).add(RuntimeValueNumeric(DataType.UBYTE, 57)).integerValue()) - assertEquals(1, RuntimeValue(DataType.UBYTE, 2).sub(RuntimeValue(DataType.UBYTE, 1)).integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 2).sub(RuntimeValue(DataType.UBYTE, 2)).integerValue()) - assertEquals(255, RuntimeValue(DataType.UBYTE, 2).sub(RuntimeValue(DataType.UBYTE, 3)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 1)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 2)).integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 3)).integerValue()) - assertEquals(255, RuntimeValue(DataType.UBYTE, 254).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 255).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 1).dec().integerValue()) - assertEquals(255, RuntimeValue(DataType.UBYTE, 0).dec().integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 254).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 255).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 1).dec().integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 0).dec().integerValue()) - assertEquals(255, RuntimeValue(DataType.UBYTE, 0).inv().integerValue()) - assertEquals(0b00110011, RuntimeValue(DataType.UBYTE, 0b11001100).inv().integerValue()) -// assertEquals(0, RuntimeValue(DataType.UBYTE, 0).neg().integerValue()) -// assertEquals(0, RuntimeValue(DataType.UBYTE, 0).neg().integerValue()) - assertEquals(1, RuntimeValue(DataType.UBYTE, 0).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 1).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 111).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UBYTE, 255).not().integerValue()) + assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 0).inv().integerValue()) + assertEquals(0b00110011, RuntimeValueNumeric(DataType.UBYTE, 0b11001100).inv().integerValue()) +// assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).neg().integerValue()) +// assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).neg().integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UBYTE, 0).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 1).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 111).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 255).not().integerValue()) - assertEquals(200, RuntimeValue(DataType.UBYTE, 20).mul(RuntimeValue(DataType.UBYTE, 10)).integerValue()) - assertEquals(144, RuntimeValue(DataType.UBYTE, 20).mul(RuntimeValue(DataType.UBYTE, 20)).integerValue()) + assertEquals(200, RuntimeValueNumeric(DataType.UBYTE, 20).mul(RuntimeValueNumeric(DataType.UBYTE, 10)).integerValue()) + assertEquals(144, RuntimeValueNumeric(DataType.UBYTE, 20).mul(RuntimeValueNumeric(DataType.UBYTE, 20)).integerValue()) - assertEquals(25, RuntimeValue(DataType.UBYTE, 5).pow(RuntimeValue(DataType.UBYTE, 2)).integerValue()) - assertEquals(125, RuntimeValue(DataType.UBYTE, 5).pow(RuntimeValue(DataType.UBYTE, 3)).integerValue()) - assertEquals(113, RuntimeValue(DataType.UBYTE, 5).pow(RuntimeValue(DataType.UBYTE, 4)).integerValue()) + assertEquals(25, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 2)).integerValue()) + assertEquals(125, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 3)).integerValue()) + assertEquals(113, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 4)).integerValue()) - assertEquals(100, RuntimeValue(DataType.UBYTE, 50).shl().integerValue()) - assertEquals(200, RuntimeValue(DataType.UBYTE, 100).shl().integerValue()) - assertEquals(144, RuntimeValue(DataType.UBYTE, 200).shl().integerValue()) + assertEquals(100, RuntimeValueNumeric(DataType.UBYTE, 50).shl().integerValue()) + assertEquals(200, RuntimeValueNumeric(DataType.UBYTE, 100).shl().integerValue()) + assertEquals(144, RuntimeValueNumeric(DataType.UBYTE, 200).shl().integerValue()) } @Test fun arithmetictestUWord() { - assertEquals(65535, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5535)).integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5536)).integerValue()) - assertEquals(1, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5537)).integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 60000).add(RuntimeValueNumeric(DataType.UWORD, 5535)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 60000).add(RuntimeValueNumeric(DataType.UWORD, 5536)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UWORD, 60000).add(RuntimeValueNumeric(DataType.UWORD, 5537)).integerValue()) - assertEquals(1, RuntimeValue(DataType.UWORD, 2).sub(RuntimeValue(DataType.UWORD, 1)).integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 2).sub(RuntimeValue(DataType.UWORD, 2)).integerValue()) - assertEquals(65535, RuntimeValue(DataType.UWORD, 2).sub(RuntimeValue(DataType.UWORD, 3)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 1)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 2)).integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 3)).integerValue()) - assertEquals(65535, RuntimeValue(DataType.UWORD, 65534).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 65535).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 1).dec().integerValue()) - assertEquals(65535, RuntimeValue(DataType.UWORD, 0).dec().integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 65534).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 65535).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 1).dec().integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 0).dec().integerValue()) - assertEquals(65535, RuntimeValue(DataType.UWORD, 0).inv().integerValue()) - assertEquals(0b0011001101010101, RuntimeValue(DataType.UWORD, 0b1100110010101010).inv().integerValue()) -// assertEquals(0, RuntimeValue(DataType.UWORD, 0).neg().integerValue()) -// assertEquals(0, RuntimeValue(DataType.UWORD, 0).neg().integerValue()) - assertEquals(1, RuntimeValue(DataType.UWORD, 0).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 1).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 11111).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.UWORD, 65535).not().integerValue()) + assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 0).inv().integerValue()) + assertEquals(0b0011001101010101, RuntimeValueNumeric(DataType.UWORD, 0b1100110010101010).inv().integerValue()) +// assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).neg().integerValue()) +// assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).neg().integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.UWORD, 0).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 1).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 11111).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 65535).not().integerValue()) - assertEquals(2000, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 10)).integerValue()) - assertEquals(40000, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 200)).integerValue()) - assertEquals(14464, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 400)).integerValue()) + assertEquals(2000, RuntimeValueNumeric(DataType.UWORD, 200).mul(RuntimeValueNumeric(DataType.UWORD, 10)).integerValue()) + assertEquals(40000, RuntimeValueNumeric(DataType.UWORD, 200).mul(RuntimeValueNumeric(DataType.UWORD, 200)).integerValue()) + assertEquals(14464, RuntimeValueNumeric(DataType.UWORD, 200).mul(RuntimeValueNumeric(DataType.UWORD, 400)).integerValue()) - assertEquals(15625, RuntimeValue(DataType.UWORD, 5).pow(RuntimeValue(DataType.UWORD, 6)).integerValue()) - assertEquals(12589, RuntimeValue(DataType.UWORD, 5).pow(RuntimeValue(DataType.UWORD, 7)).integerValue()) + assertEquals(15625, RuntimeValueNumeric(DataType.UWORD, 5).pow(RuntimeValueNumeric(DataType.UWORD, 6)).integerValue()) + assertEquals(12589, RuntimeValueNumeric(DataType.UWORD, 5).pow(RuntimeValueNumeric(DataType.UWORD, 7)).integerValue()) - assertEquals(10000, RuntimeValue(DataType.UWORD, 5000).shl().integerValue()) - assertEquals(60000, RuntimeValue(DataType.UWORD, 30000).shl().integerValue()) - assertEquals(14464, RuntimeValue(DataType.UWORD, 40000).shl().integerValue()) + assertEquals(10000, RuntimeValueNumeric(DataType.UWORD, 5000).shl().integerValue()) + assertEquals(60000, RuntimeValueNumeric(DataType.UWORD, 30000).shl().integerValue()) + assertEquals(14464, RuntimeValueNumeric(DataType.UWORD, 40000).shl().integerValue()) } @Test fun arithmetictestByte() { - assertEquals(127, RuntimeValue(DataType.BYTE, 100).add(RuntimeValue(DataType.BYTE, 27)).integerValue()) - assertEquals(-128, RuntimeValue(DataType.BYTE, 100).add(RuntimeValue(DataType.BYTE, 28)).integerValue()) - assertEquals(-127, RuntimeValue(DataType.BYTE, 100).add(RuntimeValue(DataType.BYTE, 29)).integerValue()) + assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 100).add(RuntimeValueNumeric(DataType.BYTE, 27)).integerValue()) + assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, 100).add(RuntimeValueNumeric(DataType.BYTE, 28)).integerValue()) + assertEquals(-127, RuntimeValueNumeric(DataType.BYTE, 100).add(RuntimeValueNumeric(DataType.BYTE, 29)).integerValue()) - assertEquals(1, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 1)).integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 2)).integerValue()) - assertEquals(-1, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 3)).integerValue()) - assertEquals(-128, RuntimeValue(DataType.BYTE, -100).sub(RuntimeValue(DataType.BYTE, 28)).integerValue()) - assertEquals(127, RuntimeValue(DataType.BYTE, -100).sub(RuntimeValue(DataType.BYTE, 29)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 1)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 2)).integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 3)).integerValue()) + assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -100).sub(RuntimeValueNumeric(DataType.BYTE, 28)).integerValue()) + assertEquals(127, RuntimeValueNumeric(DataType.BYTE, -100).sub(RuntimeValueNumeric(DataType.BYTE, 29)).integerValue()) - assertEquals(127, RuntimeValue(DataType.BYTE, 126).inc().integerValue()) - assertEquals(-128, RuntimeValue(DataType.BYTE, 127).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, 1).dec().integerValue()) - assertEquals(-1, RuntimeValue(DataType.BYTE, 0).dec().integerValue()) - assertEquals(-128, RuntimeValue(DataType.BYTE, -127).dec().integerValue()) - assertEquals(127, RuntimeValue(DataType.BYTE, -128).dec().integerValue()) + assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 126).inc().integerValue()) + assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, 127).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 1).dec().integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 0).dec().integerValue()) + assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -127).dec().integerValue()) + assertEquals(127, RuntimeValueNumeric(DataType.BYTE, -128).dec().integerValue()) - assertEquals(-1, RuntimeValue(DataType.BYTE, 0).inv().integerValue()) - assertEquals(-103, RuntimeValue(DataType.BYTE, 0b01100110).inv().integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, 0).neg().integerValue()) - assertEquals(-2, RuntimeValue(DataType.BYTE, 2).neg().integerValue()) - assertEquals(1, RuntimeValue(DataType.BYTE, 0).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, 1).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, 111).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.BYTE, -33).not().integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 0).inv().integerValue()) + assertEquals(-103, RuntimeValueNumeric(DataType.BYTE, 0b01100110).inv().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 0).neg().integerValue()) + assertEquals(-2, RuntimeValueNumeric(DataType.BYTE, 2).neg().integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.BYTE, 0).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 1).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 111).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.BYTE, -33).not().integerValue()) - assertEquals(100, RuntimeValue(DataType.BYTE, 10).mul(RuntimeValue(DataType.BYTE, 10)).integerValue()) - assertEquals(-56, RuntimeValue(DataType.BYTE, 20).mul(RuntimeValue(DataType.BYTE, 10)).integerValue()) + assertEquals(100, RuntimeValueNumeric(DataType.BYTE, 10).mul(RuntimeValueNumeric(DataType.BYTE, 10)).integerValue()) + assertEquals(-56, RuntimeValueNumeric(DataType.BYTE, 20).mul(RuntimeValueNumeric(DataType.BYTE, 10)).integerValue()) - assertEquals(25, RuntimeValue(DataType.BYTE, 5).pow(RuntimeValue(DataType.BYTE, 2)).integerValue()) - assertEquals(125, RuntimeValue(DataType.BYTE, 5).pow(RuntimeValue(DataType.BYTE, 3)).integerValue()) - assertEquals(113, RuntimeValue(DataType.BYTE, 5).pow(RuntimeValue(DataType.BYTE, 4)).integerValue()) + assertEquals(25, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 2)).integerValue()) + assertEquals(125, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 3)).integerValue()) + assertEquals(113, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 4)).integerValue()) - assertEquals(100, RuntimeValue(DataType.BYTE, 50).shl().integerValue()) - assertEquals(-56, RuntimeValue(DataType.BYTE, 100).shl().integerValue()) - assertEquals(-2, RuntimeValue(DataType.BYTE, -1).shl().integerValue()) + assertEquals(100, RuntimeValueNumeric(DataType.BYTE, 50).shl().integerValue()) + assertEquals(-56, RuntimeValueNumeric(DataType.BYTE, 100).shl().integerValue()) + assertEquals(-2, RuntimeValueNumeric(DataType.BYTE, -1).shl().integerValue()) } @Test fun arithmetictestWorrd() { - assertEquals(32767, RuntimeValue(DataType.WORD, 32700).add(RuntimeValue(DataType.WORD, 67)).integerValue()) - assertEquals(-32768, RuntimeValue(DataType.WORD, 32700).add(RuntimeValue(DataType.WORD, 68)).integerValue()) - assertEquals(-32767, RuntimeValue(DataType.WORD, 32700).add(RuntimeValue(DataType.WORD, 69)).integerValue()) + assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32700).add(RuntimeValueNumeric(DataType.WORD, 67)).integerValue()) + assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, 32700).add(RuntimeValueNumeric(DataType.WORD, 68)).integerValue()) + assertEquals(-32767, RuntimeValueNumeric(DataType.WORD, 32700).add(RuntimeValueNumeric(DataType.WORD, 69)).integerValue()) - assertEquals(1, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 1)).integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 2)).integerValue()) - assertEquals(-1, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 3)).integerValue()) - assertEquals(-32768, RuntimeValue(DataType.WORD, -32700).sub(RuntimeValue(DataType.WORD, 68)).integerValue()) - assertEquals(32767, RuntimeValue(DataType.WORD, -32700).sub(RuntimeValue(DataType.WORD, 69)).integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 1)).integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 2)).integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 3)).integerValue()) + assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32700).sub(RuntimeValueNumeric(DataType.WORD, 68)).integerValue()) + assertEquals(32767, RuntimeValueNumeric(DataType.WORD, -32700).sub(RuntimeValueNumeric(DataType.WORD, 69)).integerValue()) - assertEquals(32767, RuntimeValue(DataType.WORD, 32766).inc().integerValue()) - assertEquals(-32768, RuntimeValue(DataType.WORD, 32767).inc().integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, 1).dec().integerValue()) - assertEquals(-1, RuntimeValue(DataType.WORD, 0).dec().integerValue()) - assertEquals(-32768, RuntimeValue(DataType.WORD, -32767).dec().integerValue()) - assertEquals(32767, RuntimeValue(DataType.WORD, -32768).dec().integerValue()) + assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32766).inc().integerValue()) + assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, 32767).inc().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 1).dec().integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 0).dec().integerValue()) + assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32767).dec().integerValue()) + assertEquals(32767, RuntimeValueNumeric(DataType.WORD, -32768).dec().integerValue()) - assertEquals(-1, RuntimeValue(DataType.WORD, 0).inv().integerValue()) - assertEquals(-103, RuntimeValue(DataType.WORD, 0b01100110).inv().integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, 0).neg().integerValue()) - assertEquals(-2, RuntimeValue(DataType.WORD, 2).neg().integerValue()) - assertEquals(1, RuntimeValue(DataType.WORD, 0).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, 1).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, 111).not().integerValue()) - assertEquals(0, RuntimeValue(DataType.WORD, -33).not().integerValue()) + assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 0).inv().integerValue()) + assertEquals(-103, RuntimeValueNumeric(DataType.WORD, 0b01100110).inv().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 0).neg().integerValue()) + assertEquals(-2, RuntimeValueNumeric(DataType.WORD, 2).neg().integerValue()) + assertEquals(1, RuntimeValueNumeric(DataType.WORD, 0).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 1).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, 111).not().integerValue()) + assertEquals(0, RuntimeValueNumeric(DataType.WORD, -33).not().integerValue()) - assertEquals(10000, RuntimeValue(DataType.WORD, 100).mul(RuntimeValue(DataType.WORD, 100)).integerValue()) - assertEquals(-25536, RuntimeValue(DataType.WORD, 200).mul(RuntimeValue(DataType.WORD, 200)).integerValue()) + assertEquals(10000, RuntimeValueNumeric(DataType.WORD, 100).mul(RuntimeValueNumeric(DataType.WORD, 100)).integerValue()) + assertEquals(-25536, RuntimeValueNumeric(DataType.WORD, 200).mul(RuntimeValueNumeric(DataType.WORD, 200)).integerValue()) - assertEquals(15625, RuntimeValue(DataType.WORD, 5).pow(RuntimeValue(DataType.WORD, 6)).integerValue()) - assertEquals(-6487, RuntimeValue(DataType.WORD, 9).pow(RuntimeValue(DataType.WORD, 5)).integerValue()) + assertEquals(15625, RuntimeValueNumeric(DataType.WORD, 5).pow(RuntimeValueNumeric(DataType.WORD, 6)).integerValue()) + assertEquals(-6487, RuntimeValueNumeric(DataType.WORD, 9).pow(RuntimeValueNumeric(DataType.WORD, 5)).integerValue()) - assertEquals(18000, RuntimeValue(DataType.WORD, 9000).shl().integerValue()) - assertEquals(-25536, RuntimeValue(DataType.WORD, 20000).shl().integerValue()) - assertEquals(-2, RuntimeValue(DataType.WORD, -1).shl().integerValue()) + assertEquals(18000, RuntimeValueNumeric(DataType.WORD, 9000).shl().integerValue()) + assertEquals(-25536, RuntimeValueNumeric(DataType.WORD, 20000).shl().integerValue()) + assertEquals(-2, RuntimeValueNumeric(DataType.WORD, -1).shl().integerValue()) } } diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index 8ccd852aa..54c3f8b99 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -15,7 +15,7 @@ import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE import prog8.compiler.target.c64.MachineDefinition.Mflpt5 import prog8.compiler.target.c64.Petscii -import prog8.vm.RuntimeValue +import prog8.vm.RuntimeValueNumeric import java.io.CharConversionException import kotlin.test.* @@ -380,8 +380,8 @@ class TestPetscii { @Test fun testStackvmValueComparisons() { - val ten = RuntimeValue(DataType.FLOAT, 10) - val nine = RuntimeValue(DataType.UWORD, 9) + val ten = RuntimeValueNumeric(DataType.FLOAT, 10) + val nine = RuntimeValueNumeric(DataType.UWORD, 9) assertEquals(ten, ten) assertNotEquals(ten, nine) assertFalse(ten != ten)