taking down the heapvalue mess, RuntimeValue class separation

This commit is contained in:
Irmen de Jong 2019-08-19 23:49:06 +02:00
parent 8c3b43f3ed
commit 984d251a6d
10 changed files with 776 additions and 717 deletions

View File

@ -5,7 +5,6 @@ import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException import prog8.ast.base.FatalAstException
import prog8.ast.base.initvarsSubName import prog8.ast.base.initvarsSubName
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.mangledStructMemberName
import prog8.ast.statements.* import prog8.ast.statements.*

View File

@ -1,13 +1,9 @@
package prog8.compiler package prog8.compiler
import prog8.ast.base.ArrayDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.StringDatatypes
import prog8.ast.expressions.AddressOf import prog8.ast.expressions.AddressOf
import java.io.File import java.io.File
import java.io.InputStream import java.io.InputStream
import java.nio.file.Path import java.nio.file.Path
import java.util.*
import kotlin.math.abs import kotlin.math.abs
enum class OutputType { enum class OutputType {
@ -74,66 +70,3 @@ internal fun tryGetEmbeddedResource(name: String): InputStream? {
return object{}.javaClass.getResourceAsStream("/prog8lib/$name") return object{}.javaClass.getResourceAsStream("/prog8lib/$name")
} }
class HeapValues {
data class HeapValue(val type: DataType, val str: String?, val array: Array<IntegerOrAddressOf>?, 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<Int, HeapValue>()
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<IntegerOrAddressOf>): 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")
}
}

View File

@ -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<IntegerOrAddressOf>?, 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<Int, HeapValue>()
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<IntegerOrAddressOf>): 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")
}
}

View File

@ -9,7 +9,6 @@ import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX

View File

@ -1,10 +1,13 @@
package prog8.vm 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.ArrayLiteralValue
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.StringLiteralValue import prog8.ast.expressions.StringLiteralValue
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.astvm.VmExecutionException
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.pow 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. * 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<Number>?=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 byteval: Short?
val wordval: Int? val wordval: Int?
@ -24,37 +33,16 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
val asBoolean: Boolean val asBoolean: Boolean
companion object { companion object {
fun fromLv(literalValue: NumericLiteralValue): RuntimeValue { fun fromLv(literalValue: NumericLiteralValue): RuntimeValueNumeric {
return RuntimeValue(literalValue.type, num = literalValue.number) return RuntimeValueNumeric(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<Number>()
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())
}
} }
} }
init { init {
when(type) { when (type) {
DataType.UBYTE -> { DataType.UBYTE -> {
val inum = num!!.toInt() val inum = num.toInt()
if(inum !in 0 .. 255) if (inum !in 0..255)
throw IllegalArgumentException("invalid value for ubyte: $inum") throw IllegalArgumentException("invalid value for ubyte: $inum")
byteval = inum.toShort() byteval = inum.toShort()
wordval = null wordval = null
@ -62,8 +50,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
asBoolean = byteval != 0.toShort() asBoolean = byteval != 0.toShort()
} }
DataType.BYTE -> { DataType.BYTE -> {
val inum = num!!.toInt() val inum = num.toInt()
if(inum !in -128 .. 127) if (inum !in -128..127)
throw IllegalArgumentException("invalid value for byte: $inum") throw IllegalArgumentException("invalid value for byte: $inum")
byteval = inum.toShort() byteval = inum.toShort()
wordval = null wordval = null
@ -71,8 +59,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
asBoolean = byteval != 0.toShort() asBoolean = byteval != 0.toShort()
} }
DataType.UWORD -> { DataType.UWORD -> {
val inum = num!!.toInt() val inum = num.toInt()
if(inum !in 0 .. 65535) if (inum !in 0..65535)
throw IllegalArgumentException("invalid value for uword: $inum") throw IllegalArgumentException("invalid value for uword: $inum")
wordval = inum wordval = inum
byteval = null byteval = null
@ -80,8 +68,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
asBoolean = wordval != 0 asBoolean = wordval != 0
} }
DataType.WORD -> { DataType.WORD -> {
val inum = num!!.toInt() val inum = num.toInt()
if(inum !in -32768 .. 32767) if (inum !in -32768..32767)
throw IllegalArgumentException("invalid value for word: $inum") throw IllegalArgumentException("invalid value for word: $inum")
wordval = inum wordval = inum
byteval = null byteval = null
@ -89,50 +77,38 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
asBoolean = wordval != 0 asBoolean = wordval != 0
} }
DataType.FLOAT -> { DataType.FLOAT -> {
floatval = num!!.toDouble() floatval = num.toDouble()
byteval = null byteval = null
wordval = null wordval = null
asBoolean = floatval != 0.0 asBoolean = floatval != 0.0
} }
else -> { else -> throw VmExecutionException("not a numeric value")
byteval = null
wordval = null
floatval = null
asBoolean = true
}
} }
} }
override fun toString(): String { override fun toString(): String {
return when(type) { return when (type) {
DataType.UBYTE -> "ub:%02x".format(byteval) DataType.UBYTE -> "ub:%02x".format(byteval)
DataType.BYTE -> { DataType.BYTE -> {
if(byteval!!<0) if (byteval!! < 0)
"b:-%02x".format(abs(byteval.toInt())) "b:-%02x".format(abs(byteval.toInt()))
else else
"b:%02x".format(byteval) "b:%02x".format(byteval)
} }
DataType.UWORD -> "uw:%04x".format(wordval) DataType.UWORD -> "uw:%04x".format(wordval)
DataType.WORD -> { DataType.WORD -> {
if(wordval!!<0) if (wordval!! < 0)
"w:-%04x".format(abs(wordval)) "w:-%04x".format(abs(wordval))
else else
"w:%04x".format(wordval) "w:%04x".format(wordval)
} }
DataType.FLOAT -> "f:$floatval" DataType.FLOAT -> "f:$floatval"
DataType.STR -> "str:$str" else -> "???"
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:..."
} }
} }
fun numericValue(): Number { override fun numericValue(): Number {
return when(type) { return when (type) {
in ByteDatatypes -> byteval!! in ByteDatatypes -> byteval!!
in WordDatatypes -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> floatval!! DataType.FLOAT -> floatval!!
@ -140,8 +116,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
} }
} }
fun integerValue(): Int { override fun integerValue(): Int {
return when(type) { return when (type) {
in ByteDatatypes -> byteval!!.toInt() in ByteDatatypes -> byteval!!.toInt()
in WordDatatypes -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> throw ArithmeticException("float to integer loss of precision") 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 hashCode(): Int = Objects.hash(byteval, wordval, floatval, type)
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if(other==null || other !is RuntimeValue) if (other == null || other !is RuntimeValueNumeric)
return false 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 { operator fun compareTo(other: RuntimeValueNumeric): Int = numericValue().toDouble().compareTo(other.numericValue().toDouble())
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")
}
private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): RuntimeValue { private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): RuntimeValueNumeric {
if(leftDt!=rightDt) if (leftDt != rightDt)
throw ArithmeticException("left and right datatypes are not the same") throw ArithmeticException("left and right datatypes are not the same")
if(result.toDouble() < 0 ) { if (result.toDouble() < 0) {
return when(leftDt) { return when (leftDt) {
DataType.UBYTE, DataType.UWORD -> { DataType.UBYTE, DataType.UWORD -> {
// storing a negative number in an unsigned one is done by storing the 2's complement instead // storing a negative number in an unsigned one is done by storing the 2's complement instead
val number = abs(result.toDouble().toInt()) val number = abs(result.toDouble().toInt())
if(leftDt== DataType.UBYTE) if (leftDt == DataType.UBYTE)
RuntimeValue(DataType.UBYTE, (number xor 255) + 1) RuntimeValueNumeric(DataType.UBYTE, (number xor 255) + 1)
else 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)
else
RuntimeValue(DataType.BYTE, v-256)
}
DataType.WORD -> {
val v=result.toInt() and 65535
if(v<32768)
RuntimeValue(DataType.WORD, v)
else
RuntimeValue(DataType.WORD, v-65536)
}
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, result)
else -> throw ArithmeticException("$op on non-numeric type")
}
}
return when(leftDt) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, result.toInt() and 255)
DataType.BYTE -> { DataType.BYTE -> {
val v = result.toInt() and 255 val v = result.toInt() and 255
if(v<128) if (v < 128)
RuntimeValue(DataType.BYTE, v) RuntimeValueNumeric(DataType.BYTE, v)
else else
RuntimeValue(DataType.BYTE, v-256) RuntimeValueNumeric(DataType.BYTE, v - 256)
} }
DataType.UWORD -> RuntimeValue(DataType.UWORD, result.toInt() and 65535)
DataType.WORD -> { DataType.WORD -> {
val v = result.toInt() and 65535 val v = result.toInt() and 65535
if(v<32768) if (v < 32768)
RuntimeValue(DataType.WORD, v) RuntimeValueNumeric(DataType.WORD, v)
else 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") else -> throw ArithmeticException("$op on non-numeric type")
} }
} }
fun add(other: RuntimeValue): RuntimeValue { return when (leftDt) {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, result.toInt() and 255)
DataType.BYTE -> {
val v = result.toInt() and 255
if (v < 128)
RuntimeValueNumeric(DataType.BYTE, v)
else
RuntimeValueNumeric(DataType.BYTE, v - 256)
}
DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, result.toInt() and 65535)
DataType.WORD -> {
val v = result.toInt() and 65535
if (v < 32768)
RuntimeValueNumeric(DataType.WORD, v)
else
RuntimeValueNumeric(DataType.WORD, v - 65536)
}
DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, result)
else -> throw ArithmeticException("$op on non-numeric type")
}
}
fun add(other: RuntimeValueNumeric): RuntimeValueNumeric {
if (other.type == DataType.FLOAT && (type != DataType.FLOAT))
throw ArithmeticException("floating point loss of precision on type $type") throw ArithmeticException("floating point loss of precision on type $type")
val v1 = numericValue() val v1 = numericValue()
val v2 = other.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") return arithResult(type, result, other.type, "add")
} }
fun sub(other: RuntimeValue): RuntimeValue { fun sub(other: RuntimeValueNumeric): RuntimeValueNumeric {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if (other.type == DataType.FLOAT && (type != DataType.FLOAT))
throw ArithmeticException("floating point loss of precision on type $type") throw ArithmeticException("floating point loss of precision on type $type")
val v1 = numericValue() val v1 = numericValue()
val v2 = other.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") return arithResult(type, result, other.type, "sub")
} }
fun mul(other: RuntimeValue): RuntimeValue { fun mul(other: RuntimeValueNumeric): RuntimeValueNumeric {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if (other.type == DataType.FLOAT && (type != DataType.FLOAT))
throw ArithmeticException("floating point loss of precision on type $type") throw ArithmeticException("floating point loss of precision on type $type")
val v1 = numericValue() val v1 = numericValue()
val v2 = other.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") return arithResult(type, result, other.type, "mul")
} }
fun div(other: RuntimeValue): RuntimeValue { fun div(other: RuntimeValueNumeric): RuntimeValueNumeric {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if (other.type == DataType.FLOAT && (type != DataType.FLOAT))
throw ArithmeticException("floating point loss of precision on type $type") throw ArithmeticException("floating point loss of precision on type $type")
val v1 = numericValue() val v1 = numericValue()
val v2 = other.numericValue() val v2 = other.numericValue()
if(v2.toDouble()==0.0) { if (v2.toDouble() == 0.0) {
when (type) { when (type) {
DataType.UBYTE -> return RuntimeValue(DataType.UBYTE, 255) DataType.UBYTE -> return RuntimeValueNumeric(DataType.UBYTE, 255)
DataType.BYTE -> return RuntimeValue(DataType.BYTE, 127) DataType.BYTE -> return RuntimeValueNumeric(DataType.BYTE, 127)
DataType.UWORD -> return RuntimeValue(DataType.UWORD, 65535) DataType.UWORD -> return RuntimeValueNumeric(DataType.UWORD, 65535)
DataType.WORD -> return RuntimeValue(DataType.WORD, 32767) DataType.WORD -> return RuntimeValueNumeric(DataType.WORD, 32767)
else -> {} else -> {
}
} }
} }
val result = v1.toDouble() / v2.toDouble() val result = v1.toDouble() / v2.toDouble()
// NOTE: integer division returns integer result! // NOTE: integer division returns integer result!
return when(type) { return when (type) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, result) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, result)
DataType.BYTE -> RuntimeValue(DataType.BYTE, result) DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, result)
DataType.UWORD -> RuntimeValue(DataType.UWORD, result) DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, result)
DataType.WORD -> RuntimeValue(DataType.WORD, result) DataType.WORD -> RuntimeValueNumeric(DataType.WORD, result)
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, result) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, result)
else -> throw ArithmeticException("div on non-numeric type") else -> throw ArithmeticException("div on non-numeric type")
} }
} }
fun remainder(other: RuntimeValue): RuntimeValue { fun remainder(other: RuntimeValueNumeric): RuntimeValueNumeric {
val v1 = numericValue() val v1 = numericValue()
val v2 = other.numericValue() val v2 = other.numericValue()
val result = v1.toDouble() % v2.toDouble() val result = v1.toDouble() % v2.toDouble()
return arithResult(type, result, other.type, "remainder") return arithResult(type, result, other.type, "remainder")
} }
fun pow(other: RuntimeValue): RuntimeValue { fun pow(other: RuntimeValueNumeric): RuntimeValueNumeric {
val v1 = numericValue() val v1 = numericValue()
val v2 = other.numericValue() val v2 = other.numericValue()
val result = v1.toDouble().pow(v2.toDouble()) 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() val v = integerValue()
return when (type) { return when (type) {
DataType.UBYTE -> RuntimeValue(type, (v shl 1) and 255) DataType.UBYTE -> RuntimeValueNumeric(type, (v shl 1) and 255)
DataType.UWORD -> RuntimeValue(type, (v shl 1) and 65535) DataType.UWORD -> RuntimeValueNumeric(type, (v shl 1) and 65535)
DataType.BYTE -> { DataType.BYTE -> {
val value = v shl 1 val value = v shl 1
if(value<128) if (value < 128)
RuntimeValue(type, value) RuntimeValueNumeric(type, value)
else else
RuntimeValue(type, value-256) RuntimeValueNumeric(type, value - 256)
} }
DataType.WORD -> { DataType.WORD -> {
val value = v shl 1 val value = v shl 1
if(value<32768) if (value < 32768)
RuntimeValue(type, value) RuntimeValueNumeric(type, value)
else else
RuntimeValue(type, value-65536) RuntimeValueNumeric(type, value - 65536)
} }
else -> throw ArithmeticException("invalid type for shl: $type") else -> throw ArithmeticException("invalid type for shl: $type")
} }
} }
fun shr(): RuntimeValue { fun shr(): RuntimeValueNumeric {
val v = integerValue() val v = integerValue()
return when(type){ return when (type) {
DataType.UBYTE -> RuntimeValue(type, v ushr 1) DataType.UBYTE -> RuntimeValueNumeric(type, v ushr 1)
DataType.BYTE -> RuntimeValue(type, v shr 1) DataType.BYTE -> RuntimeValueNumeric(type, v shr 1)
DataType.UWORD -> RuntimeValue(type, v ushr 1) DataType.UWORD -> RuntimeValueNumeric(type, v ushr 1)
DataType.WORD -> RuntimeValue(type, v shr 1) DataType.WORD -> RuntimeValueNumeric(type, v shr 1)
else -> throw ArithmeticException("invalid type for shr: $type") else -> throw ArithmeticException("invalid type for shr: $type")
} }
} }
fun rol(carry: Boolean): Pair<RuntimeValue, Boolean> { fun rol(carry: Boolean): Pair<RuntimeValueNumeric, Boolean> {
// 9 or 17 bit rotate left (with carry)) // 9 or 17 bit rotate left (with carry))
return when(type) { return when (type) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
val v = byteval!!.toInt() val v = byteval!!.toInt()
val newCarry = (v and 0x80) != 0 val newCarry = (v and 0x80) != 0
val newval = (v and 0x7f shl 1) or (if(carry) 1 else 0) val newval = (v and 0x7f shl 1) or (if (carry) 1 else 0)
Pair(RuntimeValue(DataType.UBYTE, newval), newCarry) Pair(RuntimeValueNumeric(DataType.UBYTE, newval), newCarry)
} }
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
val v = wordval!! val v = wordval!!
val newCarry = (v and 0x8000) != 0 val newCarry = (v and 0x8000) != 0
val newval = (v and 0x7fff shl 1) or (if(carry) 1 else 0) val newval = (v and 0x7fff shl 1) or (if (carry) 1 else 0)
Pair(RuntimeValue(DataType.UWORD, newval), newCarry) Pair(RuntimeValueNumeric(DataType.UWORD, newval), newCarry)
} }
else -> throw ArithmeticException("rol can only work on byte/word") else -> throw ArithmeticException("rol can only work on byte/word")
} }
} }
fun ror(carry: Boolean): Pair<RuntimeValue, Boolean> { fun ror(carry: Boolean): Pair<RuntimeValueNumeric, Boolean> {
// 9 or 17 bit rotate right (with carry) // 9 or 17 bit rotate right (with carry)
return when(type) { return when (type) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
val v = byteval!!.toInt() val v = byteval!!.toInt()
val newCarry = v and 1 != 0 val newCarry = v and 1 != 0
val newval = (v ushr 1) or (if(carry) 0x80 else 0) val newval = (v ushr 1) or (if (carry) 0x80 else 0)
Pair(RuntimeValue(DataType.UBYTE, newval), newCarry) Pair(RuntimeValueNumeric(DataType.UBYTE, newval), newCarry)
} }
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
val v = wordval!! val v = wordval!!
val newCarry = v and 1 != 0 val newCarry = v and 1 != 0
val newval = (v ushr 1) or (if(carry) 0x8000 else 0) val newval = (v ushr 1) or (if (carry) 0x8000 else 0)
Pair(RuntimeValue(DataType.UWORD, newval), newCarry) Pair(RuntimeValueNumeric(DataType.UWORD, newval), newCarry)
} }
else -> throw ArithmeticException("ror2 can only work on byte/word") else -> throw ArithmeticException("ror2 can only work on byte/word")
} }
} }
fun rol2(): RuntimeValue { fun rol2(): RuntimeValueNumeric {
// 8 or 16 bit rotate left // 8 or 16 bit rotate left
return when(type) { return when (type) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
val v = byteval!!.toInt() val v = byteval!!.toInt()
val carry = (v and 0x80) ushr 7 val carry = (v and 0x80) ushr 7
val newval = (v and 0x7f shl 1) or carry val newval = (v and 0x7f shl 1) or carry
RuntimeValue(DataType.UBYTE, newval) RuntimeValueNumeric(DataType.UBYTE, newval)
} }
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
val v = wordval!! val v = wordval!!
val carry = (v and 0x8000) ushr 15 val carry = (v and 0x8000) ushr 15
val newval = (v and 0x7fff shl 1) or carry 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") else -> throw ArithmeticException("rol2 can only work on byte/word")
} }
} }
fun ror2(): RuntimeValue { fun ror2(): RuntimeValueNumeric {
// 8 or 16 bit rotate right // 8 or 16 bit rotate right
return when(type) { return when (type) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
val v = byteval!!.toInt() val v = byteval!!.toInt()
val carry = v and 1 shl 7 val carry = v and 1 shl 7
val newval = (v ushr 1) or carry val newval = (v ushr 1) or carry
RuntimeValue(DataType.UBYTE, newval) RuntimeValueNumeric(DataType.UBYTE, newval)
} }
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
val v = wordval!! val v = wordval!!
val carry = v and 1 shl 15 val carry = v and 1 shl 15
val newval = (v ushr 1) or carry 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") else -> throw ArithmeticException("ror2 can only work on byte/word")
} }
} }
fun neg(): RuntimeValue { fun neg(): RuntimeValueNumeric {
return when(type) { return when (type) {
DataType.BYTE -> RuntimeValue(DataType.BYTE, -(byteval!!)) DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, -(byteval!!))
DataType.WORD -> RuntimeValue(DataType.WORD, -(wordval!!)) DataType.WORD -> RuntimeValueNumeric(DataType.WORD, -(wordval!!))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, -(floatval)!!) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, -(floatval)!!)
else -> throw ArithmeticException("neg can only work on byte/word/float") else -> throw ArithmeticException("neg can only work on byte/word/float")
} }
} }
fun abs(): RuntimeValue { fun abs(): RuntimeValueNumeric {
return when(type) { return when (type) {
DataType.BYTE -> RuntimeValue(DataType.BYTE, abs(byteval!!.toInt())) DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, abs(byteval!!.toInt()))
DataType.WORD -> RuntimeValue(DataType.WORD, abs(wordval!!)) DataType.WORD -> RuntimeValueNumeric(DataType.WORD, abs(wordval!!))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(floatval!!)) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, abs(floatval!!))
else -> throw ArithmeticException("abs can only work on byte/word/float") 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 v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1 and v2 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 v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1 or v2 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 v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1 xor v2 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 and(other: RuntimeValueNumeric) = RuntimeValueNumeric(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 or(other: RuntimeValueNumeric) = RuntimeValueNumeric(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 xor(other: RuntimeValueNumeric) = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean xor other.asBoolean) 1 else 0)
fun not() = RuntimeValue(DataType.UBYTE, if (this.asBoolean) 0 else 1) fun not() = RuntimeValueNumeric(DataType.UBYTE, if (this.asBoolean) 0 else 1)
fun inv(): RuntimeValue { fun inv(): RuntimeValueNumeric {
return when(type) { return when (type) {
DataType.UBYTE -> RuntimeValue(type, byteval!!.toInt().inv() and 255) DataType.UBYTE -> RuntimeValueNumeric(type, byteval!!.toInt().inv() and 255)
DataType.UWORD -> RuntimeValue(type, wordval!!.inv() and 65535) DataType.UWORD -> RuntimeValueNumeric(type, wordval!!.inv() and 65535)
DataType.BYTE -> RuntimeValue(type, byteval!!.toInt().inv()) DataType.BYTE -> RuntimeValueNumeric(type, byteval!!.toInt().inv())
DataType.WORD -> RuntimeValue(type, wordval!!.inv()) DataType.WORD -> RuntimeValueNumeric(type, wordval!!.inv())
else -> throw ArithmeticException("inv can only work on byte/word") else -> throw ArithmeticException("inv can only work on byte/word")
} }
} }
fun inc(): RuntimeValue { fun inc(): RuntimeValueNumeric {
return when(type) { return when (type) {
DataType.UBYTE -> RuntimeValue(type, (byteval!! + 1) and 255) DataType.UBYTE -> RuntimeValueNumeric(type, (byteval!! + 1) and 255)
DataType.UWORD -> RuntimeValue(type, (wordval!! + 1) and 65535) DataType.UWORD -> RuntimeValueNumeric(type, (wordval!! + 1) and 65535)
DataType.BYTE -> { DataType.BYTE -> {
val newval = byteval!! + 1 val newval = byteval!! + 1
if(newval == 128) if (newval == 128)
RuntimeValue(type, -128) RuntimeValueNumeric(type, -128)
else else
RuntimeValue(type, newval) RuntimeValueNumeric(type, newval)
} }
DataType.WORD -> { DataType.WORD -> {
val newval = wordval!! + 1 val newval = wordval!! + 1
if(newval == 32768) if (newval == 32768)
RuntimeValue(type, -32768) RuntimeValueNumeric(type, -32768)
else 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") else -> throw ArithmeticException("inc can only work on numeric types")
} }
} }
fun dec(): RuntimeValue { fun dec(): RuntimeValueNumeric {
return when(type) { return when (type) {
DataType.UBYTE -> RuntimeValue(type, (byteval!! - 1) and 255) DataType.UBYTE -> RuntimeValueNumeric(type, (byteval!! - 1) and 255)
DataType.UWORD -> RuntimeValue(type, (wordval!! - 1) and 65535) DataType.UWORD -> RuntimeValueNumeric(type, (wordval!! - 1) and 65535)
DataType.BYTE -> { DataType.BYTE -> {
val newval = byteval!! - 1 val newval = byteval!! - 1
if(newval == -129) if (newval == -129)
RuntimeValue(type, 127) RuntimeValueNumeric(type, 127)
else else
RuntimeValue(type, newval) RuntimeValueNumeric(type, newval)
} }
DataType.WORD -> { DataType.WORD -> {
val newval = wordval!! - 1 val newval = wordval!! - 1
if(newval == -32769) if (newval == -32769)
RuntimeValue(type, 32767) RuntimeValueNumeric(type, 32767)
else 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") else -> throw ArithmeticException("dec can only work on numeric types")
} }
} }
fun msb(): RuntimeValue { fun msb(): RuntimeValueNumeric {
return when(type) { return when (type) {
in ByteDatatypes -> RuntimeValue(DataType.UBYTE, 0) in ByteDatatypes -> RuntimeValueNumeric(DataType.UBYTE, 0)
in WordDatatypes -> RuntimeValue(DataType.UBYTE, wordval!! ushr 8 and 255) in WordDatatypes -> RuntimeValueNumeric(DataType.UBYTE, wordval!! ushr 8 and 255)
else -> throw ArithmeticException("msb can only work on (u)byte/(u)word") 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) { return when (type) {
DataType.UBYTE -> { DataType.UBYTE -> {
when (targetType) { when (targetType) {
DataType.UBYTE -> this DataType.UBYTE -> this
DataType.BYTE -> { DataType.BYTE -> {
val nval=byteval!!.toInt() val nval = byteval!!.toInt()
if(nval<128) if (nval < 128)
RuntimeValue(DataType.BYTE, nval) RuntimeValueNumeric(DataType.BYTE, nval)
else 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 -> { DataType.WORD -> {
val nval = numericValue().toInt() val nval = numericValue().toInt()
if(nval<32768) if (nval < 32768)
RuntimeValue(DataType.WORD, nval) RuntimeValueNumeric(DataType.WORD, nval)
else 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") else -> throw ArithmeticException("invalid type cast from $type to $targetType")
} }
} }
DataType.BYTE -> { DataType.BYTE -> {
when (targetType) { when (targetType) {
DataType.BYTE -> this DataType.BYTE -> this
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 255) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> RuntimeValue(DataType.UWORD, integerValue() and 65535) DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, integerValue() and 65535)
DataType.WORD -> RuntimeValue(DataType.WORD, integerValue()) DataType.WORD -> RuntimeValueNumeric(DataType.WORD, integerValue())
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, numericValue())
else -> throw ArithmeticException("invalid type cast from $type to $targetType") else -> throw ArithmeticException("invalid type cast from $type to $targetType")
} }
} }
DataType.UWORD -> { DataType.UWORD -> {
when (targetType) { when (targetType) {
DataType.BYTE -> { DataType.BYTE -> {
val v=integerValue() val v = integerValue()
if(v<128) if (v < 128)
RuntimeValue(DataType.BYTE, v) RuntimeValueNumeric(DataType.BYTE, v)
else 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.UWORD -> this
DataType.WORD -> { DataType.WORD -> {
val v=integerValue() val v = integerValue()
if(v<32768) if (v < 32768)
RuntimeValue(DataType.WORD, v) RuntimeValueNumeric(DataType.WORD, v)
else 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") 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) { when (targetType) {
DataType.BYTE -> { DataType.BYTE -> {
val v = integerValue() and 255 val v = integerValue() and 255
if(v<128) if (v < 128)
RuntimeValue(DataType.BYTE, v) RuntimeValueNumeric(DataType.BYTE, v)
else else
RuntimeValue(DataType.BYTE, v-256) RuntimeValueNumeric(DataType.BYTE, v - 256)
} }
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 65535) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, integerValue() and 65535)
DataType.UWORD -> RuntimeValue(DataType.UWORD, integerValue()) DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, integerValue())
DataType.WORD -> this 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") else -> throw ArithmeticException("invalid type cast from $type to $targetType")
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
when (targetType) { when (targetType) {
DataType.BYTE -> { DataType.BYTE -> {
val integer=numericValue().toInt() val integer = numericValue().toInt()
if(integer in -128..127) if (integer in -128..127)
RuntimeValue(DataType.BYTE, integer) RuntimeValueNumeric(DataType.BYTE, integer)
else else
throw ArithmeticException("overflow when casting float to byte: $this") throw ArithmeticException("overflow when casting float to byte: $this")
} }
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, numericValue().toInt()) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, numericValue().toInt())
DataType.UWORD -> RuntimeValue(DataType.UWORD, numericValue().toInt()) DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, numericValue().toInt())
DataType.WORD -> { DataType.WORD -> {
val integer=numericValue().toInt() val integer = numericValue().toInt()
if(integer in -32768..32767) if (integer in -32768..32767)
RuntimeValue(DataType.WORD, integer) RuntimeValueNumeric(DataType.WORD, integer)
else else
throw ArithmeticException("overflow when casting float to word: $this") 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") else -> throw ArithmeticException("invalid type cast from $type to $targetType")
} }
} }
}
open fun iterator(): Iterator<Number> {
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) { return when (type) {
in StringDatatypes -> { DataType.STR -> "str:$str"
Petscii.encodePetscii(str!!, true).iterator() DataType.STR_S -> "str_s:$str"
else -> "???"
} }
in ArrayDatatypes -> {
array!!.iterator()
} }
else -> throw IllegalArgumentException("cannot iterate over $this")
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<Number> = 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<Number>): 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<Number>()
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<Number> = 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<Number> { override fun iterator(): Iterator<Number> {
return range.iterator() return range.iterator()
} }

View File

@ -10,8 +10,7 @@ import prog8.ast.statements.*
import prog8.compiler.IntegerOrAddressOf import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.target.c64.MachineDefinition import prog8.compiler.target.c64.MachineDefinition
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.RuntimeValue import prog8.vm.*
import prog8.vm.RuntimeValueRange
import java.awt.EventQueue import java.awt.EventQueue
import java.io.CharConversionException import java.io.CharConversionException
import java.util.* import java.util.*
@ -72,7 +71,7 @@ class StatusFlags {
class RuntimeVariables { class RuntimeVariables {
fun define(scope: INameScope, name: String, initialValue: RuntimeValue) { fun define(scope: INameScope, name: String, initialValue: RuntimeValueBase) {
val where = vars.getValue(scope) val where = vars.getValue(scope)
where[name] = initialValue where[name] = initialValue
vars[scope] = where vars[scope] = where
@ -84,7 +83,7 @@ class RuntimeVariables {
memvars[scope] = where 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 where = vars.getValue(scope)
val existing = where[name] val existing = where[name]
if(existing==null) { if(existing==null) {
@ -98,7 +97,7 @@ class RuntimeVariables {
vars[scope] = where vars[scope] = where
} }
fun get(scope: INameScope, name: String): RuntimeValue { fun get(scope: INameScope, name: String): RuntimeValueBase {
val where = vars.getValue(scope) val where = vars.getValue(scope)
return where[name] ?: throw NoSuchElementException("no such runtime variable: ${scope.name}.$name") return where[name] ?: throw NoSuchElementException("no such runtime variable: ${scope.name}.$name")
} }
@ -117,7 +116,7 @@ class RuntimeVariables {
set(scope2, name2, v1) set(scope2, name2, v1)
} }
private val vars = mutableMapOf<INameScope, MutableMap<String, RuntimeValue>>().withDefault { mutableMapOf() } private val vars = mutableMapOf<INameScope, MutableMap<String, RuntimeValueBase>>().withDefault { mutableMapOf() }
private val memvars = mutableMapOf<INameScope, MutableMap<String, Int>>().withDefault { mutableMapOf() } private val memvars = mutableMapOf<INameScope, MutableMap<String, Int>>().withDefault { mutableMapOf() }
} }
@ -134,9 +133,9 @@ class AstVm(val program: Program) {
private val rnd = Random(0) private val rnd = Random(0)
private val statusFlagsSave = Stack<StatusFlags>() private val statusFlagsSave = Stack<StatusFlags>()
private val registerXsave = Stack<RuntimeValue>() private val registerXsave = Stack<RuntimeValueNumeric>()
private val registerYsave = Stack<RuntimeValue>() private val registerYsave = Stack<RuntimeValueNumeric>()
private val registerAsave = Stack<RuntimeValue>() private val registerAsave = Stack<RuntimeValueNumeric>()
init { init {
@ -182,7 +181,7 @@ class AstVm(val program: Program) {
fun run() { fun run() {
try { try {
val init = VariablesCreator(runtimeVariables, program.heap) val init = VariablesCreator(runtimeVariables)
init.visit(program) init.visit(program)
// initialize all global variables // initialize all global variables
@ -263,11 +262,11 @@ class AstVm(val program: Program) {
class LoopControlBreak : Exception() class LoopControlBreak : Exception()
class LoopControlContinue : 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() class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception()
internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValue>, startAtLabel: Label?=null): RuntimeValue? { internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValueNumeric>, startAtLabel: Label?=null): RuntimeValueNumeric? {
if(sub.isAsmSubroutine) { if(sub.isAsmSubroutine) {
return performSyscall(sub, arguments) return performSyscall(sub, arguments)
} }
@ -335,7 +334,7 @@ class AstVm(val program: Program) {
val target = stmt.target.targetStatement(program.namespace) val target = stmt.target.targetStatement(program.namespace)
when (target) { when (target) {
is Subroutine -> { is Subroutine -> {
val args = evaluate(stmt.arglist) val args = evaluate(stmt.arglist).map { it as RuntimeValueNumeric }
if (target.isAsmSubroutine) { if (target.isAsmSubroutine) {
performSyscall(target, args) performSyscall(target, args)
} else { } else {
@ -348,7 +347,7 @@ class AstVm(val program: Program) {
// swap cannot be implemented as a function, so inline it here // swap cannot be implemented as a function, so inline it here
executeSwap(stmt) executeSwap(stmt)
} else { } else {
val args = evaluate(stmt.arglist) val args = evaluate(stmt.arglist).map { it as RuntimeValueNumeric }
performBuiltinFunction(target.name, args, statusflags) performBuiltinFunction(target.name, args, statusflags)
} }
} }
@ -362,7 +361,7 @@ class AstVm(val program: Program) {
if(stmt.value==null) if(stmt.value==null)
null null
else else
evaluate(stmt.value!!, evalCtx) evaluate(stmt.value!!, evalCtx) as RuntimeValueNumeric
throw LoopControlReturn(value) throw LoopControlReturn(value)
} }
is Continue -> throw LoopControlContinue() is Continue -> throw LoopControlContinue()
@ -380,10 +379,10 @@ class AstVm(val program: Program) {
val identScope = ident.definingScope() val identScope = ident.definingScope()
when(ident.type){ when(ident.type){
VarDeclType.VAR -> { VarDeclType.VAR -> {
var value = runtimeVariables.get(identScope, ident.name) var value = runtimeVariables.get(identScope, ident.name) as RuntimeValueNumeric
value = when { value = when {
stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) stmt.operator == "++" -> value.add(RuntimeValueNumeric(value.type, 1))
stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) stmt.operator == "--" -> value.sub(RuntimeValueNumeric(value.type, 1))
else -> throw VmExecutionException("strange postincdec operator $stmt") else -> throw VmExecutionException("strange postincdec operator $stmt")
} }
runtimeVariables.set(identScope, ident.name, value) runtimeVariables.set(identScope, ident.name, value)
@ -401,7 +400,7 @@ class AstVm(val program: Program) {
} }
} }
stmt.target.memoryAddress != null -> { 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 { val newval = when {
stmt.operator == "++" -> mem.getUByte(addr)+1 and 255 stmt.operator == "++" -> mem.getUByte(addr)+1 and 255
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 -> { stmt.target.arrayindexed != null -> {
val arrayvar = stmt.target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!! val arrayvar = stmt.target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!!
val arrayvalue = runtimeVariables.get(arrayvar.definingScope(), arrayvar.name) val arrayvalue = runtimeVariables.get(arrayvar.definingScope(), arrayvar.name) as RuntimeValueArray
val index = evaluate(stmt.target.arrayindexed!!.arrayspec.index, evalCtx).integerValue() val index = (evaluate(stmt.target.arrayindexed!!.arrayspec.index, evalCtx) as RuntimeValueNumeric).integerValue()
val elementType = stmt.target.arrayindexed!!.inferType(program) val elementType = stmt.target.arrayindexed!!.inferType(program)
if(!elementType.isKnown) if(!elementType.isKnown)
throw VmExecutionException("unknown/void elt type") 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 { value = when {
stmt.operator == "++" -> value.inc() stmt.operator == "++" -> value.inc()
stmt.operator == "--" -> value.dec() stmt.operator == "--" -> value.dec()
@ -425,10 +424,10 @@ class AstVm(val program: Program) {
arrayvalue.array[index] = value.numericValue() arrayvalue.array[index] = value.numericValue()
} }
stmt.target.register != null -> { 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 { value = when {
stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) stmt.operator == "++" -> value.add(RuntimeValueNumeric(value.type, 1))
stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) stmt.operator == "--" -> value.sub(RuntimeValueNumeric(value.type, 1))
else -> throw VmExecutionException("strange postincdec operator $stmt") else -> throw VmExecutionException("strange postincdec operator $stmt")
} }
runtimeVariables.set(program.namespace, stmt.target.register!!.name, value) 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 Jump -> throw LoopControlJump(stmt.identifier, stmt.address, stmt.generatedLabel)
is InlineAssembly -> { is InlineAssembly -> {
if (sub is Subroutine) { 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) performSyscall(sub, args)
throw LoopControlReturn(null) throw LoopControlReturn(null)
} }
@ -447,7 +446,7 @@ class AstVm(val program: Program) {
} }
is AnonymousScope -> executeAnonymousScope(stmt) is AnonymousScope -> executeAnonymousScope(stmt)
is IfStatement -> { is IfStatement -> {
val condition = evaluate(stmt.condition, evalCtx) val condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric
if (condition.asBoolean) if (condition.asBoolean)
executeAnonymousScope(stmt.truepart) executeAnonymousScope(stmt.truepart)
else else
@ -478,7 +477,13 @@ class AstVm(val program: Program) {
loopvarDt = dt.typeOrElse(DataType.UBYTE) loopvarDt = dt.typeOrElse(DataType.UBYTE)
loopvar = stmt.loopVar!! 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) { for (loopvalue in iterator) {
try { try {
oneForCycle(stmt, loopvarDt, loopvalue, loopvar) oneForCycle(stmt, loopvarDt, loopvalue, loopvar)
@ -490,11 +495,11 @@ class AstVm(val program: Program) {
} }
} }
is WhileLoop -> { is WhileLoop -> {
var condition = evaluate(stmt.condition, evalCtx) var condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric
while (condition.asBoolean) { while (condition.asBoolean) {
try { try {
executeAnonymousScope(stmt.body) executeAnonymousScope(stmt.body)
condition = evaluate(stmt.condition, evalCtx) condition = evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric
} catch (b: LoopControlBreak) { } catch (b: LoopControlBreak) {
break break
} catch (c: LoopControlContinue) { } catch (c: LoopControlContinue) {
@ -504,7 +509,7 @@ class AstVm(val program: Program) {
} }
is RepeatLoop -> { is RepeatLoop -> {
do { do {
val condition = evaluate(stmt.untilCondition, evalCtx) val condition = evaluate(stmt.untilCondition, evalCtx) as RuntimeValueNumeric
try { try {
executeAnonymousScope(stmt.body) executeAnonymousScope(stmt.body)
} catch (b: LoopControlBreak) { } catch (b: LoopControlBreak) {
@ -515,7 +520,7 @@ class AstVm(val program: Program) {
} while (!condition.asBoolean) } while (!condition.asBoolean)
} }
is WhenStatement -> { is WhenStatement -> {
val condition=evaluate(stmt.condition, evalCtx) val condition=evaluate(stmt.condition, evalCtx) as RuntimeValueNumeric
for(choice in stmt.choices) { for(choice in stmt.choices) {
if(choice.values==null) { if(choice.values==null) {
// the 'else' choice // the 'else' choice
@ -523,7 +528,7 @@ class AstVm(val program: Program) {
break break
} else { } else {
val value = choice.values!!.single().constValue(evalCtx.program) ?: throw VmExecutionException("can only use const values in when choices ${choice.position}") 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) { if(condition==rtval) {
executeAnonymousScope(choice.statements) executeAnonymousScope(choice.statements)
break break
@ -548,7 +553,7 @@ class AstVm(val program: Program) {
performAssignment(target2, value1, swap, evalCtx) 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 targetIdent = target.identifier
val targetArrayIndexed = target.arrayindexed val targetArrayIndexed = target.arrayindexed
when { when {
@ -558,27 +563,27 @@ class AstVm(val program: Program) {
if (decl.type == VarDeclType.MEMORY) { if (decl.type == VarDeclType.MEMORY) {
val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name) val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name)
when (decl.datatype) { when (decl.datatype) {
DataType.UBYTE -> mem.setUByte(address, value.byteval!!) DataType.UBYTE -> mem.setUByte(address, (value as RuntimeValueNumeric).byteval!!)
DataType.BYTE -> mem.setSByte(address, value.byteval!!) DataType.BYTE -> mem.setSByte(address, (value as RuntimeValueNumeric).byteval!!)
DataType.UWORD -> mem.setUWord(address, value.wordval!!) DataType.UWORD -> mem.setUWord(address, (value as RuntimeValueNumeric).wordval!!)
DataType.WORD -> mem.setSWord(address, value.wordval!!) DataType.WORD -> mem.setSWord(address, (value as RuntimeValueNumeric).wordval!!)
DataType.FLOAT -> mem.setFloat(address, value.floatval!!) DataType.FLOAT -> mem.setFloat(address, (value as RuntimeValueNumeric).floatval!!)
DataType.STR -> mem.setString(address, value.str!!) DataType.STR -> mem.setString(address, (value as RuntimeValueString).str)
DataType.STR_S -> mem.setScreencodeString(address, value.str!!) DataType.STR_S -> mem.setScreencodeString(address, (value as RuntimeValueString).str)
else -> throw VmExecutionException("weird memaddress type $decl") else -> throw VmExecutionException("weird memaddress type $decl")
} }
} else } else
runtimeVariables.set(decl.definingScope(), decl.name, value) runtimeVariables.set(decl.definingScope(), decl.name, value)
} }
target.memoryAddress != null -> { target.memoryAddress != null -> {
val address = evaluate(target.memoryAddress.addressExpression, evalCtx).wordval!! val address = (evaluate(target.memoryAddress.addressExpression, evalCtx) as RuntimeValueNumeric).wordval!!
evalCtx.mem.setUByte(address, value.byteval!!) evalCtx.mem.setUByte(address, (value as RuntimeValueNumeric).byteval!!)
} }
targetArrayIndexed != null -> { targetArrayIndexed != null -> {
val vardecl = targetArrayIndexed.identifier.targetVarDecl(program.namespace)!! val vardecl = targetArrayIndexed.identifier.targetVarDecl(program.namespace)!!
if(vardecl.type==VarDeclType.VAR) { if(vardecl.type==VarDeclType.VAR) {
val array = evaluate(targetArrayIndexed.identifier, evalCtx) 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) { when (array.type) {
DataType.ARRAY_UB -> { DataType.ARRAY_UB -> {
if (value.type != DataType.UBYTE) if (value.type != DataType.UBYTE)
@ -607,20 +612,21 @@ class AstVm(val program: Program) {
else -> throw VmExecutionException("strange array type ${array.type}") else -> throw VmExecutionException("strange array type ${array.type}")
} }
if (array.type in ArrayDatatypes) 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) { else if (array.type in StringDatatypes) {
val indexInt = index.integerValue() val indexInt = index.integerValue()
val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true) 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 val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}") ?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val identScope = ident.definingScope() val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, RuntimeValue(array.type, str = newstr)) runtimeVariables.set(identScope, ident.name, RuntimeValueString(array.type, newstr))
} }
} }
else { else {
value as RuntimeValueNumeric
val address = (vardecl.value as NumericLiteralValue).number.toInt() 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) val elementType = targetArrayIndexed.inferType(program)
if(!elementType.isKnown) if(!elementType.isKnown)
throw VmExecutionException("unknown/void array elt type $targetArrayIndexed") 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) { private fun oneForCycle(stmt: ForLoop, loopvarDt: DataType, loopValue: Number, loopVar: IdentifierReference) {
// assign the new loop value to the loopvar, and run the code // assign the new loop value to the loopvar, and run the code
performAssignment(AssignTarget(null, loopVar, null, null, loopVar.position), 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) executeAnonymousScope(stmt.body)
} }
private fun evaluate(args: List<Expression>) = args.map { evaluate(it, evalCtx) } private fun evaluate(args: List<Expression>) = args.map { evaluate(it, evalCtx) }
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>): RuntimeValue? { private fun performSyscall(sub: Subroutine, args: List<RuntimeValueNumeric>): RuntimeValueNumeric? {
var result: RuntimeValue? = null var result: RuntimeValueNumeric? = null
when (sub.scopedname) { when (sub.scopedname) {
"c64scr.print" -> { "c64scr.print" -> {
// if the argument is an UWORD, consider it to be the "address" of the string (=heapId) // 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!! val str = program.heap.get(args[0].wordval!!).str!!
dialog.canvas.printText(str, true) dialog.canvas.printText(str, true)
} else } else
dialog.canvas.printText(args[0].str!!, true) throw VmExecutionException("print non-heap string")
} }
"c64scr.print_ub" -> { "c64scr.print_ub" -> {
dialog.canvas.printText(args[0].byteval!!.toString(), true) 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 origStr = program.heap.get(heapId).str!!
val paddedStr=inputStr.padEnd(origStr.length+1, '\u0000').substring(0, origStr.length) val paddedStr=inputStr.padEnd(origStr.length+1, '\u0000').substring(0, origStr.length)
program.heap.updateString(heapId, paddedStr) program.heap.updateString(heapId, paddedStr)
result = RuntimeValue(DataType.UBYTE, paddedStr.indexOf('\u0000')) result = RuntimeValueNumeric(DataType.UBYTE, paddedStr.indexOf('\u0000'))
} }
"c64flt.print_f" -> { "c64flt.print_f" -> {
dialog.canvas.printText(args[0].floatval.toString(), false) dialog.canvas.printText(args[0].floatval.toString(), false)
@ -751,13 +757,13 @@ class AstVm(val program: Program) {
Thread.sleep(10) Thread.sleep(10)
} }
val char=dialog.keyboardBuffer.pop() val char=dialog.keyboardBuffer.pop()
result = RuntimeValue(DataType.UBYTE, char.toShort()) result = RuntimeValueNumeric(DataType.UBYTE, char.toShort())
} }
"c64utils.str2uword" -> { "c64utils.str2uword" -> {
val heapId = args[0].wordval!! val heapId = args[0].wordval!!
val argString = program.heap.get(heapId).str!! val argString = program.heap.get(heapId).str!!
val numericpart = argString.takeWhile { it.isDigit() } 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") else -> TODO("syscall ${sub.scopedname} $sub")
} }
@ -765,120 +771,120 @@ class AstVm(val program: Program) {
return result return result
} }
private fun performBuiltinFunction(name: String, args: List<RuntimeValue>, statusflags: StatusFlags): RuntimeValue? { private fun performBuiltinFunction(name: String, args: List<RuntimeValueBase>, statusflags: StatusFlags): RuntimeValueNumeric? {
return when (name) { return when (name) {
"rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255) "rnd" -> RuntimeValueNumeric(DataType.UBYTE, rnd.nextInt() and 255)
"rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535) "rndw" -> RuntimeValueNumeric(DataType.UWORD, rnd.nextInt() and 65535)
"rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble()) "rndf" -> RuntimeValueNumeric(DataType.FLOAT, rnd.nextDouble())
"lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255) "lsb" -> RuntimeValueNumeric(DataType.UBYTE, args[0].integerValue() and 255)
"msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255) "msb" -> RuntimeValueNumeric(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255)
"sin" -> RuntimeValue(DataType.FLOAT, sin(args[0].numericValue().toDouble())) "sin" -> RuntimeValueNumeric(DataType.FLOAT, sin(args[0].numericValue().toDouble()))
"sin8" -> { "sin8" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "sin8u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "sin16" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "sin16u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "cos8" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "cos8u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "cos16" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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" -> { "cos16u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI 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())) "tan" -> RuntimeValueNumeric(DataType.FLOAT, tan(args[0].numericValue().toDouble()))
"atan" -> RuntimeValue(DataType.FLOAT, atan(args[0].numericValue().toDouble())) "atan" -> RuntimeValueNumeric(DataType.FLOAT, atan(args[0].numericValue().toDouble()))
"ln" -> RuntimeValue(DataType.FLOAT, ln(args[0].numericValue().toDouble())) "ln" -> RuntimeValueNumeric(DataType.FLOAT, ln(args[0].numericValue().toDouble()))
"log2" -> RuntimeValue(DataType.FLOAT, log2(args[0].numericValue().toDouble())) "log2" -> RuntimeValueNumeric(DataType.FLOAT, log2(args[0].numericValue().toDouble()))
"sqrt" -> RuntimeValue(DataType.FLOAT, sqrt(args[0].numericValue().toDouble())) "sqrt" -> RuntimeValueNumeric(DataType.FLOAT, sqrt(args[0].numericValue().toDouble()))
"sqrt16" -> RuntimeValue(DataType.UBYTE, sqrt(args[0].wordval!!.toDouble()).toInt()) "sqrt16" -> RuntimeValueNumeric(DataType.UBYTE, sqrt((args[0] as RuntimeValueNumeric).wordval!!.toDouble()).toInt())
"rad" -> RuntimeValue(DataType.FLOAT, Math.toRadians(args[0].numericValue().toDouble())) "rad" -> RuntimeValueNumeric(DataType.FLOAT, Math.toRadians(args[0].numericValue().toDouble()))
"deg" -> RuntimeValue(DataType.FLOAT, Math.toDegrees(args[0].numericValue().toDouble())) "deg" -> RuntimeValueNumeric(DataType.FLOAT, Math.toDegrees(args[0].numericValue().toDouble()))
"round" -> RuntimeValue(DataType.FLOAT, round(args[0].numericValue().toDouble())) "round" -> RuntimeValueNumeric(DataType.FLOAT, round(args[0].numericValue().toDouble()))
"floor" -> RuntimeValue(DataType.FLOAT, floor(args[0].numericValue().toDouble())) "floor" -> RuntimeValueNumeric(DataType.FLOAT, floor(args[0].numericValue().toDouble()))
"ceil" -> RuntimeValue(DataType.FLOAT, ceil(args[0].numericValue().toDouble())) "ceil" -> RuntimeValueNumeric(DataType.FLOAT, ceil(args[0].numericValue().toDouble()))
"rol" -> { "rol" -> {
val (result, newCarry) = args[0].rol(statusflags.carry) val (result, newCarry) = (args[0] as RuntimeValueNumeric).rol(statusflags.carry)
statusflags.carry = newCarry statusflags.carry = newCarry
return result return result
} }
"rol2" -> args[0].rol2() "rol2" -> (args[0] as RuntimeValueNumeric).rol2()
"ror" -> { "ror" -> {
val (result, newCarry) = args[0].ror(statusflags.carry) val (result, newCarry) = (args[0] as RuntimeValueNumeric).ror(statusflags.carry)
statusflags.carry = newCarry statusflags.carry = newCarry
return result return result
} }
"ror2" -> args[0].ror2() "ror2" -> (args[0] as RuntimeValueNumeric).ror2()
"lsl" -> args[0].shl() "lsl" -> (args[0] as RuntimeValueNumeric).shl()
"lsr" -> args[0].shr() "lsr" -> (args[0] as RuntimeValueNumeric).shr()
"abs" -> { "abs" -> {
when (args[0].type) { when (args[0].type) {
DataType.UBYTE -> args[0] DataType.UBYTE -> (args[0] as RuntimeValueNumeric)
DataType.BYTE -> RuntimeValue(DataType.UBYTE, abs(args[0].numericValue().toDouble())) DataType.BYTE -> RuntimeValueNumeric(DataType.UBYTE, abs(args[0].numericValue().toDouble()))
DataType.UWORD -> args[0] DataType.UWORD -> (args[0] as RuntimeValueNumeric)
DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble())) DataType.WORD -> RuntimeValueNumeric(DataType.UWORD, abs(args[0].numericValue().toDouble()))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble())) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, abs(args[0].numericValue().toDouble()))
else -> throw VmExecutionException("strange abs type ${args[0]}") else -> throw VmExecutionException("strange abs type ${args[0]}")
} }
} }
"max" -> { "max" -> {
val numbers = args.single().array!!.map { it.toDouble() } val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() }
RuntimeValue(ArrayElementTypes.getValue(args[0].type), numbers.max()) RuntimeValueNumeric(ArrayElementTypes.getValue(args[0].type), numbers.max()!!)
} }
"min" -> { "min" -> {
val numbers = args.single().array!!.map { it.toDouble() } val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() }
RuntimeValue(ArrayElementTypes.getValue(args[0].type), numbers.min()) RuntimeValueNumeric(ArrayElementTypes.getValue(args[0].type), numbers.min()!!)
} }
"sum" -> { "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) { when (args[0].type) {
DataType.ARRAY_UB -> RuntimeValue(DataType.UWORD, sum) DataType.ARRAY_UB -> RuntimeValueNumeric(DataType.UWORD, sum)
DataType.ARRAY_B -> RuntimeValue(DataType.WORD, sum) DataType.ARRAY_B -> RuntimeValueNumeric(DataType.WORD, sum)
DataType.ARRAY_UW -> RuntimeValue(DataType.UWORD, sum) DataType.ARRAY_UW -> RuntimeValueNumeric(DataType.UWORD, sum)
DataType.ARRAY_W -> RuntimeValue(DataType.WORD, sum) DataType.ARRAY_W -> RuntimeValueNumeric(DataType.WORD, sum)
DataType.ARRAY_F -> RuntimeValue(DataType.FLOAT, sum) DataType.ARRAY_F -> RuntimeValueNumeric(DataType.FLOAT, sum)
else -> throw VmExecutionException("weird sum type ${args[0]}") else -> throw VmExecutionException("weird sum type ${args[0]}")
} }
} }
"any" -> { "any" -> {
val numbers = args.single().array!!.map { it.toDouble() } val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() }
RuntimeValue(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0) RuntimeValueNumeric(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0)
} }
"all" -> { "all" -> {
val numbers = args.single().array!!.map { it.toDouble() } val numbers = (args.single() as RuntimeValueArray).array.map { it.toDouble() }
RuntimeValue(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0) RuntimeValueNumeric(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0)
} }
"swap" -> "swap" ->
throw VmExecutionException("swap() cannot be implemented as a function") throw VmExecutionException("swap() cannot be implemented as a function")
"strlen" -> { "strlen" -> {
val zeroIndex = args[0].str!!.indexOf(0.toChar()) val zeroIndex = (args[0] as RuntimeValueString).str.indexOf(0.toChar())
if (zeroIndex >= 0) if (zeroIndex >= 0)
RuntimeValue(DataType.UBYTE, zeroIndex) RuntimeValueNumeric(DataType.UBYTE, zeroIndex)
else else
RuntimeValue(DataType.UBYTE, args[0].str!!.length) RuntimeValueNumeric(DataType.UBYTE, (args[0] as RuntimeValueString).str.length)
} }
"memset" -> { "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 target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array")
val amount = args[1].integerValue() val amount = args[1].integerValue()
val value = args[2].integerValue() val value = args[2].integerValue()
@ -888,7 +894,7 @@ class AstVm(val program: Program) {
null null
} }
"memsetw" -> { "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 target = program.heap.get(heapId).array ?: throw VmExecutionException("memset target is not an array")
val amount = args[1].integerValue() val amount = args[1].integerValue()
val value = args[2].integerValue() val value = args[2].integerValue()
@ -899,8 +905,8 @@ class AstVm(val program: Program) {
null null
} }
"memcopy" -> { "memcopy" -> {
val sourceHeapId = args[0].wordval!! val sourceHeapId = (args[0] as RuntimeValueNumeric).wordval!!
val destHeapId = args[1].wordval!! val destHeapId = (args[1] as RuntimeValueNumeric).wordval!!
val source = program.heap.get(sourceHeapId).array!! val source = program.heap.get(sourceHeapId).array!!
val dest = program.heap.get(destHeapId).array!! val dest = program.heap.get(destHeapId).array!!
val amount = args[2].integerValue() val amount = args[2].integerValue()
@ -911,7 +917,7 @@ class AstVm(val program: Program) {
} }
"mkword" -> { "mkword" -> {
val result = (args[1].integerValue() shl 8) or args[0].integerValue() val result = (args[1].integerValue() shl 8) or args[0].integerValue()
RuntimeValue(DataType.UWORD, result) RuntimeValueNumeric(DataType.UWORD, result)
} }
"set_carry" -> { "set_carry" -> {
statusflags.carry=true statusflags.carry=true
@ -934,13 +940,13 @@ class AstVm(val program: Program) {
val zero = if(statusflags.zero) 2 else 0 val zero = if(statusflags.zero) 2 else 0
val irqd = if(statusflags.irqd) 4 else 0 val irqd = if(statusflags.irqd) 4 else 0
val negative = if(statusflags.negative) 128 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" -> { "rsave" -> {
statusFlagsSave.push(statusflags) statusFlagsSave.push(statusflags)
registerAsave.push(runtimeVariables.get(program.namespace, Register.A.name)) registerAsave.push(runtimeVariables.get(program.namespace, Register.A.name) as RuntimeValueNumeric)
registerXsave.push(runtimeVariables.get(program.namespace, Register.X.name)) registerXsave.push(runtimeVariables.get(program.namespace, Register.X.name) as RuntimeValueNumeric)
registerYsave.push(runtimeVariables.get(program.namespace, Register.Y.name)) registerYsave.push(runtimeVariables.get(program.namespace, Register.Y.name) as RuntimeValueNumeric)
null null
} }
"rrestore" -> { "rrestore" -> {
@ -955,21 +961,21 @@ class AstVm(val program: Program) {
null null
} }
"sort" -> { "sort" -> {
val array=args.single() val array=args.single() as RuntimeValueArray
array.array!!.sort() array.array.sort()
null null
} }
"reverse" -> { "reverse" -> {
val array=args.single() val array=args.single() as RuntimeValueArray
array.array!!.reverse() array.array.reverse()
null null
} }
"sgn" -> { "sgn" -> {
val value = args.single().numericValue().toDouble() val value = args.single().numericValue().toDouble()
when { when {
value<0.0 -> RuntimeValue(DataType.BYTE, -1) value<0.0 -> RuntimeValueNumeric(DataType.BYTE, -1)
value==0.0 -> RuntimeValue(DataType.BYTE, 0) value==0.0 -> RuntimeValueNumeric(DataType.BYTE, 0)
else -> RuntimeValue(DataType.BYTE, 1) else -> RuntimeValueNumeric(DataType.BYTE, 1)
} }
} }
else -> TODO("builtin function $name") else -> TODO("builtin function $name")

View File

@ -10,12 +10,11 @@ import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
import prog8.ast.statements.Label import prog8.ast.statements.Label
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.vm.RuntimeValue import prog8.vm.*
import prog8.vm.RuntimeValueRange
typealias BuiltinfunctionCaller = (name: String, args: List<RuntimeValue>, flags: StatusFlags) -> RuntimeValue? typealias BuiltinfunctionCaller = (name: String, args: List<RuntimeValueNumeric>, flags: StatusFlags) -> RuntimeValueNumeric?
typealias SubroutineCaller = (sub: Subroutine, args: List<RuntimeValue>, startAtLabel: Label?) -> RuntimeValue? typealias SubroutineCaller = (sub: Subroutine, args: List<RuntimeValueNumeric>, startAtLabel: Label?) -> RuntimeValueNumeric?
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, 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 performBuiltinFunction: BuiltinfunctionCaller,
val executeSubroutine: SubroutineCaller) val executeSubroutine: SubroutineCaller)
fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValueBase {
val constval = expr.constValue(ctx.program) val constval = expr.constValue(ctx.program)
if(constval!=null) if(constval!=null)
return RuntimeValue.fromLv(constval) return RuntimeValueNumeric.fromLv(constval)
when(expr) { when(expr) {
is NumericLiteralValue -> return RuntimeValue.fromLv(expr) is NumericLiteralValue -> return RuntimeValueNumeric.fromLv(expr)
is StringLiteralValue -> return RuntimeValue.fromLv(expr) is StringLiteralValue -> return RuntimeValueString.fromLv(expr)
is ArrayLiteralValue -> return RuntimeValue.fromLv(expr) is ArrayLiteralValue -> return RuntimeValueArray.fromLv(expr)
is PrefixExpression -> { is PrefixExpression -> {
return when(expr.operator) { return when(expr.operator) {
"-" -> evaluate(expr.expression, ctx).neg() "-" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).neg()
"~" -> evaluate(expr.expression, ctx).inv() "~" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).inv()
"not" -> evaluate(expr.expression, ctx).not() "not" -> (evaluate(expr.expression, ctx) as RuntimeValueNumeric).not()
// unary '+' should have been optimized away // unary '+' should have been optimized away
else -> throw VmExecutionException("unsupported prefix operator "+expr.operator) else -> throw VmExecutionException("unsupported prefix operator "+expr.operator)
} }
} }
is BinaryExpression -> { is BinaryExpression -> {
val left = evaluate(expr.left, ctx) val left = evaluate(expr.left, ctx) as RuntimeValueNumeric
val right = evaluate(expr.right, ctx) val right = evaluate(expr.right, ctx) as RuntimeValueNumeric
return when(expr.operator) { return when(expr.operator) {
"<" -> RuntimeValue(DataType.UBYTE, if (left < right) 1 else 0) "<" -> RuntimeValueNumeric(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)
">" -> RuntimeValue(DataType.UBYTE, if (left > right) 1 else 0) ">" -> RuntimeValueNumeric(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)
"==" -> RuntimeValue(DataType.UBYTE, if (left == right) 1 else 0) "==" -> RuntimeValueNumeric(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)
"+" -> left.add(right) "+" -> left.add(right)
"-" -> left.sub(right) "-" -> left.sub(right)
"*" -> left.mul(right) "*" -> left.mul(right)
@ -78,32 +77,36 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue {
} }
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
val array = evaluate(expr.identifier, ctx) val array = evaluate(expr.identifier, ctx)
val index = evaluate(expr.arrayspec.index, ctx) val index = evaluate(expr.arrayspec.index, ctx) as RuntimeValueNumeric
return if(array.array!=null) { 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()] val value = array.array[index.integerValue()]
RuntimeValue(ArrayElementTypes.getValue(array.type), value) RuntimeValueNumeric(ArrayElementTypes.getValue(array.type), value)
} else { }
val value = array.str!![index.integerValue()] else -> throw VmExecutionException("weird type")
RuntimeValue(ArrayElementTypes.getValue(array.type), value.toShort())
} }
} }
is TypecastExpression -> { is TypecastExpression -> {
return evaluate(expr.expression, ctx).cast(expr.type) return (evaluate(expr.expression, ctx) as RuntimeValueNumeric).cast(expr.type)
} }
is AddressOf -> { is AddressOf -> {
// we support: address of heap var -> the heap id // we support: address of heap var -> the heap id
return try { return try {
val heapId = expr.identifier.heapId(ctx.program.namespace) val heapId = expr.identifier.heapId(ctx.program.namespace)
RuntimeValue(DataType.UWORD, heapId) RuntimeValueNumeric(DataType.UWORD, heapId)
} catch( f: FatalAstException) { } catch( f: FatalAstException) {
// fallback: use the hash of the name, so we have at least *a* value... // fallback: use the hash of the name, so we have at least *a* value...
val address = expr.identifier.hashCode() and 65535 val address = expr.identifier.hashCode() and 65535
RuntimeValue(DataType.UWORD, address) RuntimeValueNumeric(DataType.UWORD, address)
} }
} }
is DirectMemoryRead -> { is DirectMemoryRead -> {
val address = evaluate(expr.addressExpression, ctx).wordval!! val address = (evaluate(expr.addressExpression, ctx) as RuntimeValueNumeric).wordval!!
return RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address)) return RuntimeValueNumeric(DataType.UBYTE, ctx.mem.getUByte(address))
} }
is RegisterExpr -> return ctx.runtimeVars.get(ctx.program.namespace, expr.register.name) is RegisterExpr -> return ctx.runtimeVars.get(ctx.program.namespace, expr.register.name)
is IdentifierReference -> { is IdentifierReference -> {
@ -116,13 +119,13 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue {
else -> { else -> {
val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name) val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name)
return when(variable.datatype) { return when(variable.datatype) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address)) DataType.UBYTE -> RuntimeValueNumeric(DataType.UBYTE, ctx.mem.getUByte(address))
DataType.BYTE -> RuntimeValue(DataType.BYTE, ctx.mem.getSByte(address)) DataType.BYTE -> RuntimeValueNumeric(DataType.BYTE, ctx.mem.getSByte(address))
DataType.UWORD -> RuntimeValue(DataType.UWORD, ctx.mem.getUWord(address)) DataType.UWORD -> RuntimeValueNumeric(DataType.UWORD, ctx.mem.getUWord(address))
DataType.WORD -> RuntimeValue(DataType.WORD, ctx.mem.getSWord(address)) DataType.WORD -> RuntimeValueNumeric(DataType.WORD, ctx.mem.getSWord(address))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, ctx.mem.getFloat(address)) DataType.FLOAT -> RuntimeValueNumeric(DataType.FLOAT, ctx.mem.getFloat(address))
DataType.STR -> RuntimeValue(DataType.STR, str = ctx.mem.getString(address)) DataType.STR -> RuntimeValueString(DataType.STR, ctx.mem.getString(address))
DataType.STR_S -> RuntimeValue(DataType.STR_S, str = ctx.mem.getScreencodeString(address)) DataType.STR_S -> RuntimeValueString(DataType.STR_S, ctx.mem.getScreencodeString(address)!!)
else -> throw VmExecutionException("unexpected datatype $variable") else -> throw VmExecutionException("unexpected datatype $variable")
} }
} }
@ -132,7 +135,7 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue {
} }
is FunctionCall -> { is FunctionCall -> {
val sub = expr.target.targetStatement(ctx.program.namespace) 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) { return when(sub) {
is Subroutine -> { is Subroutine -> {
val result = ctx.executeSubroutine(sub, args, null) val result = ctx.executeSubroutine(sub, args, null)
@ -158,9 +161,9 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue {
else else
throw VmExecutionException("couldn't determine datatype") throw VmExecutionException("couldn't determine datatype")
} }
val fromVal = evaluate(expr.from, ctx).integerValue() val fromVal = (evaluate(expr.from, ctx) as RuntimeValueNumeric).integerValue()
val toVal = evaluate(expr.to, ctx).integerValue() val toVal = (evaluate(expr.to, ctx) as RuntimeValueNumeric).integerValue()
val stepVal = evaluate(expr.step, ctx).integerValue() val stepVal = (evaluate(expr.step, ctx) as RuntimeValueNumeric).integerValue()
val range = makeRange(fromVal, toVal, stepVal) val range = makeRange(fromVal, toVal, stepVal)
val dt = expr.inferType(ctx.program) val dt = expr.inferType(ctx.program)
if(dt.isKnown) if(dt.isKnown)

View File

@ -13,16 +13,17 @@ import prog8.ast.statements.Statement
import prog8.ast.statements.StructDecl import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.ast.statements.ZeropageWish import prog8.ast.statements.ZeropageWish
import prog8.compiler.HeapValues import prog8.vm.RuntimeValueArray
import prog8.vm.RuntimeValue 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) { override fun visit(program: Program) {
// define the three registers as global variables // define the three registers as global variables
runtimeVariables.define(program.namespace, Register.A.name, RuntimeValue(DataType.UBYTE, 0)) runtimeVariables.define(program.namespace, Register.A.name, RuntimeValueNumeric(DataType.UBYTE, 0))
runtimeVariables.define(program.namespace, Register.X.name, RuntimeValue(DataType.UBYTE, 255)) runtimeVariables.define(program.namespace, Register.X.name, RuntimeValueNumeric(DataType.UBYTE, 255))
runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0)) runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValueNumeric(DataType.UBYTE, 0))
val globalpos = Position("<<global>>", 0, 0, 0) val globalpos = Position("<<global>>", 0, 0, 0)
val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.DONTCARE, null, Register.A.name, null, 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) { if(decl.datatype!=DataType.STRUCT) {
val numericLv = decl.value as? NumericLiteralValue val numericLv = decl.value as? NumericLiteralValue
val value = if(numericLv!=null) { val value = if(numericLv!=null) {
RuntimeValue.fromLv(numericLv) RuntimeValueNumeric.fromLv(numericLv)
} else { } else {
if(decl.value is StringLiteralValue) if(decl.value is StringLiteralValue)
RuntimeValue.fromLv(decl.value as StringLiteralValue) RuntimeValueString.fromLv(decl.value as StringLiteralValue)
else else
RuntimeValue.fromLv(decl.value as ArrayLiteralValue) RuntimeValueArray.fromLv(decl.value as ArrayLiteralValue)
} }
runtimeVariables.define(decl.definingScope(), decl.name, value) runtimeVariables.define(decl.definingScope(), decl.name, value)
} }

View File

@ -3,66 +3,66 @@ package prog8tests
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.vm.RuntimeValue import prog8.vm.RuntimeValueNumeric
import kotlin.test.* 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 return v1.type==v2.type && v1==v2
} }
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestRuntimeValue { class TestRuntimeValueNumeric {
@Test @Test
fun testValueRanges() { fun testValueRanges() {
assertEquals(0, RuntimeValue(DataType.UBYTE, 0).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).integerValue())
assertEquals(255, RuntimeValue(DataType.UBYTE, 255).integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 255).integerValue())
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.UBYTE, -1)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.UBYTE, -1)}
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.UBYTE, 256)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.UBYTE, 256)}
assertEquals(0, RuntimeValue(DataType.BYTE, 0).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 0).integerValue())
assertEquals(-128, RuntimeValue(DataType.BYTE, -128).integerValue()) assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -128).integerValue())
assertEquals(127, RuntimeValue(DataType.BYTE, 127).integerValue()) assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 127).integerValue())
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.BYTE, -129)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.BYTE, -129)}
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.BYTE, 128)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.BYTE, 128)}
assertEquals(0, RuntimeValue(DataType.UWORD, 0).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).integerValue())
assertEquals(65535, RuntimeValue(DataType.UWORD, 65535).integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 65535).integerValue())
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.UWORD, -1)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.UWORD, -1)}
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.UWORD, 65536)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.UWORD, 65536)}
assertEquals(0, RuntimeValue(DataType.WORD, 0).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 0).integerValue())
assertEquals(-32768, RuntimeValue(DataType.WORD, -32768).integerValue()) assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32768).integerValue())
assertEquals(32767, RuntimeValue(DataType.WORD, 32767).integerValue()) assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32767).integerValue())
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.WORD, -32769)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.WORD, -32769)}
assertFailsWith<IllegalArgumentException> { RuntimeValue(DataType.WORD, 32768)} assertFailsWith<IllegalArgumentException> { RuntimeValueNumeric(DataType.WORD, 32768)}
} }
@Test @Test
fun testTruthiness() fun testTruthiness()
{ {
assertFalse(RuntimeValue(DataType.BYTE, 0).asBoolean) assertFalse(RuntimeValueNumeric(DataType.BYTE, 0).asBoolean)
assertFalse(RuntimeValue(DataType.UBYTE, 0).asBoolean) assertFalse(RuntimeValueNumeric(DataType.UBYTE, 0).asBoolean)
assertFalse(RuntimeValue(DataType.WORD, 0).asBoolean) assertFalse(RuntimeValueNumeric(DataType.WORD, 0).asBoolean)
assertFalse(RuntimeValue(DataType.UWORD, 0).asBoolean) assertFalse(RuntimeValueNumeric(DataType.UWORD, 0).asBoolean)
assertFalse(RuntimeValue(DataType.FLOAT, 0.0).asBoolean) assertFalse(RuntimeValueNumeric(DataType.FLOAT, 0.0).asBoolean)
assertTrue(RuntimeValue(DataType.BYTE, 42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.BYTE, 42).asBoolean)
assertTrue(RuntimeValue(DataType.UBYTE, 42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.UBYTE, 42).asBoolean)
assertTrue(RuntimeValue(DataType.WORD, 42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.WORD, 42).asBoolean)
assertTrue(RuntimeValue(DataType.UWORD, 42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.UWORD, 42).asBoolean)
assertTrue(RuntimeValue(DataType.FLOAT, 42.0).asBoolean) assertTrue(RuntimeValueNumeric(DataType.FLOAT, 42.0).asBoolean)
assertTrue(RuntimeValue(DataType.BYTE, -42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.BYTE, -42).asBoolean)
assertTrue(RuntimeValue(DataType.WORD, -42).asBoolean) assertTrue(RuntimeValueNumeric(DataType.WORD, -42).asBoolean)
assertTrue(RuntimeValue(DataType.FLOAT, -42.0).asBoolean) assertTrue(RuntimeValueNumeric(DataType.FLOAT, -42.0).asBoolean)
} }
@Test @Test
fun testIdentity() { fun testIdentity() {
val v = RuntimeValue(DataType.UWORD, 12345) val v = RuntimeValueNumeric(DataType.UWORD, 12345)
assertEquals(v, v) assertEquals(v, v)
assertFalse(v != v) assertFalse(v != v)
assertTrue(v<=v) assertTrue(v<=v)
@ -70,283 +70,283 @@ class TestRuntimeValue {
assertFalse(v<v) assertFalse(v<v)
assertFalse(v>v) assertFalse(v>v)
assertTrue(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100))) assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100)))
} }
@Test @Test
fun testEqualsAndNotEquals() { fun testEqualsAndNotEquals() {
assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100)) assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100))
assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 100)) assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 100))
assertEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 100)) assertEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 100))
assertEquals(RuntimeValue(DataType.UWORD, 254), RuntimeValue(DataType.UBYTE, 254)) assertEquals(RuntimeValueNumeric(DataType.UWORD, 254), RuntimeValueNumeric(DataType.UBYTE, 254))
assertEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12345)) assertEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12345))
assertEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12345)) assertEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12345))
assertEquals(RuntimeValue(DataType.FLOAT, 100.0), RuntimeValue(DataType.UBYTE, 100)) assertEquals(RuntimeValueNumeric(DataType.FLOAT, 100.0), RuntimeValueNumeric(DataType.UBYTE, 100))
assertEquals(RuntimeValue(DataType.FLOAT, 22239.0), RuntimeValue(DataType.UWORD, 22239)) assertEquals(RuntimeValueNumeric(DataType.FLOAT, 22239.0), RuntimeValueNumeric(DataType.UWORD, 22239))
assertEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.99)) assertEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.99))
assertTrue(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 100))) assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 100)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 100))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 100)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 100))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 100)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 254), RuntimeValue(DataType.UBYTE, 254))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 254), RuntimeValueNumeric(DataType.UBYTE, 254)))
assertTrue(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12345))) assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12345)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12345))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12345)))
assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 100.0), RuntimeValue(DataType.UBYTE, 100))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 100.0), RuntimeValueNumeric(DataType.UBYTE, 100)))
assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 22239.0), RuntimeValue(DataType.UWORD, 22239))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 22239.0), RuntimeValueNumeric(DataType.UWORD, 22239)))
assertTrue(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.99))) assertTrue(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.99)))
assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 101)) assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 101))
assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 101)) assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 101))
assertNotEquals(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 101)) assertNotEquals(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 101))
assertNotEquals(RuntimeValue(DataType.UWORD, 245), RuntimeValue(DataType.UBYTE, 246)) assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 245), RuntimeValueNumeric(DataType.UBYTE, 246))
assertNotEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12346)) assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12346))
assertNotEquals(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12346)) assertNotEquals(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12346))
assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UBYTE, 9)) assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UBYTE, 9))
assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UWORD, 9)) assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UWORD, 9))
assertNotEquals(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.0)) assertNotEquals(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.0))
assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UBYTE, 101))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UBYTE, 101)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.UWORD, 101))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.UWORD, 101)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UBYTE, 100), RuntimeValue(DataType.FLOAT, 101))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UBYTE, 100), RuntimeValueNumeric(DataType.FLOAT, 101)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 245), RuntimeValue(DataType.UBYTE, 246))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 245), RuntimeValueNumeric(DataType.UBYTE, 246)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.UWORD, 12346))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.UWORD, 12346)))
assertFalse(sameValueAndType(RuntimeValue(DataType.UWORD, 12345), RuntimeValue(DataType.FLOAT, 12346))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.UWORD, 12345), RuntimeValueNumeric(DataType.FLOAT, 12346)))
assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UBYTE, 9))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UBYTE, 9)))
assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.UWORD, 9))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.UWORD, 9)))
assertFalse(sameValueAndType(RuntimeValue(DataType.FLOAT, 9.99), RuntimeValue(DataType.FLOAT, 9.0))) assertFalse(sameValueAndType(RuntimeValueNumeric(DataType.FLOAT, 9.99), RuntimeValueNumeric(DataType.FLOAT, 9.0)))
} }
@Test @Test
fun testGreaterThan(){ fun testGreaterThan(){
assertTrue(RuntimeValue(DataType.UBYTE, 100) > RuntimeValue(DataType.UBYTE, 99)) assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) > RuntimeValueNumeric(DataType.UBYTE, 99))
assertTrue(RuntimeValue(DataType.UWORD, 254) > RuntimeValue(DataType.UWORD, 253)) assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) > RuntimeValueNumeric(DataType.UWORD, 253))
assertTrue(RuntimeValue(DataType.FLOAT, 100.0) > RuntimeValue(DataType.FLOAT, 99.9)) assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) > RuntimeValueNumeric(DataType.FLOAT, 99.9))
assertTrue(RuntimeValue(DataType.UBYTE, 100) >= RuntimeValue(DataType.UBYTE, 100)) assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) >= RuntimeValueNumeric(DataType.UBYTE, 100))
assertTrue(RuntimeValue(DataType.UWORD, 254) >= RuntimeValue(DataType.UWORD, 254)) assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) >= RuntimeValueNumeric(DataType.UWORD, 254))
assertTrue(RuntimeValue(DataType.FLOAT, 100.0) >= RuntimeValue(DataType.FLOAT, 100.0)) assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) >= RuntimeValueNumeric(DataType.FLOAT, 100.0))
assertFalse(RuntimeValue(DataType.UBYTE, 100) > RuntimeValue(DataType.UBYTE, 100)) assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) > RuntimeValueNumeric(DataType.UBYTE, 100))
assertFalse(RuntimeValue(DataType.UWORD, 254) > RuntimeValue(DataType.UWORD, 254)) assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) > RuntimeValueNumeric(DataType.UWORD, 254))
assertFalse(RuntimeValue(DataType.FLOAT, 100.0) > RuntimeValue(DataType.FLOAT, 100.0)) assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) > RuntimeValueNumeric(DataType.FLOAT, 100.0))
assertFalse(RuntimeValue(DataType.UBYTE, 100) >= RuntimeValue(DataType.UBYTE, 101)) assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) >= RuntimeValueNumeric(DataType.UBYTE, 101))
assertFalse(RuntimeValue(DataType.UWORD, 254) >= RuntimeValue(DataType.UWORD, 255)) assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) >= RuntimeValueNumeric(DataType.UWORD, 255))
assertFalse(RuntimeValue(DataType.FLOAT, 100.0) >= RuntimeValue(DataType.FLOAT, 100.1)) assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) >= RuntimeValueNumeric(DataType.FLOAT, 100.1))
} }
@Test @Test
fun testLessThan() { fun testLessThan() {
assertTrue(RuntimeValue(DataType.UBYTE, 100) < RuntimeValue(DataType.UBYTE, 101)) assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) < RuntimeValueNumeric(DataType.UBYTE, 101))
assertTrue(RuntimeValue(DataType.UWORD, 254) < RuntimeValue(DataType.UWORD, 255)) assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) < RuntimeValueNumeric(DataType.UWORD, 255))
assertTrue(RuntimeValue(DataType.FLOAT, 100.0) < RuntimeValue(DataType.FLOAT, 100.1)) assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) < RuntimeValueNumeric(DataType.FLOAT, 100.1))
assertTrue(RuntimeValue(DataType.UBYTE, 100) <= RuntimeValue(DataType.UBYTE, 100)) assertTrue(RuntimeValueNumeric(DataType.UBYTE, 100) <= RuntimeValueNumeric(DataType.UBYTE, 100))
assertTrue(RuntimeValue(DataType.UWORD, 254) <= RuntimeValue(DataType.UWORD, 254)) assertTrue(RuntimeValueNumeric(DataType.UWORD, 254) <= RuntimeValueNumeric(DataType.UWORD, 254))
assertTrue(RuntimeValue(DataType.FLOAT, 100.0) <= RuntimeValue(DataType.FLOAT, 100.0)) assertTrue(RuntimeValueNumeric(DataType.FLOAT, 100.0) <= RuntimeValueNumeric(DataType.FLOAT, 100.0))
assertFalse(RuntimeValue(DataType.UBYTE, 100) < RuntimeValue(DataType.UBYTE, 100)) assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) < RuntimeValueNumeric(DataType.UBYTE, 100))
assertFalse(RuntimeValue(DataType.UWORD, 254) < RuntimeValue(DataType.UWORD, 254)) assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) < RuntimeValueNumeric(DataType.UWORD, 254))
assertFalse(RuntimeValue(DataType.FLOAT, 100.0) < RuntimeValue(DataType.FLOAT, 100.0)) assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) < RuntimeValueNumeric(DataType.FLOAT, 100.0))
assertFalse(RuntimeValue(DataType.UBYTE, 100) <= RuntimeValue(DataType.UBYTE, 99)) assertFalse(RuntimeValueNumeric(DataType.UBYTE, 100) <= RuntimeValueNumeric(DataType.UBYTE, 99))
assertFalse(RuntimeValue(DataType.UWORD, 254) <= RuntimeValue(DataType.UWORD, 253)) assertFalse(RuntimeValueNumeric(DataType.UWORD, 254) <= RuntimeValueNumeric(DataType.UWORD, 253))
assertFalse(RuntimeValue(DataType.FLOAT, 100.0) <= RuntimeValue(DataType.FLOAT, 99.9)) assertFalse(RuntimeValueNumeric(DataType.FLOAT, 100.0) <= RuntimeValueNumeric(DataType.FLOAT, 99.9))
} }
@Test @Test
fun testNoDtConversion() { fun testNoDtConversion() {
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UWORD, 100).add(RuntimeValue(DataType.UBYTE, 120)) RuntimeValueNumeric(DataType.UWORD, 100).add(RuntimeValueNumeric(DataType.UBYTE, 120))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UBYTE, 100).add(RuntimeValue(DataType.UWORD, 120)) RuntimeValueNumeric(DataType.UBYTE, 100).add(RuntimeValueNumeric(DataType.UWORD, 120))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.FLOAT, 100.22).add(RuntimeValue(DataType.UWORD, 120)) RuntimeValueNumeric(DataType.FLOAT, 100.22).add(RuntimeValueNumeric(DataType.UWORD, 120))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UWORD, 1002).add(RuntimeValue(DataType.FLOAT, 120.22)) RuntimeValueNumeric(DataType.UWORD, 1002).add(RuntimeValueNumeric(DataType.FLOAT, 120.22))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.FLOAT, 100.22).add(RuntimeValue(DataType.UBYTE, 120)) RuntimeValueNumeric(DataType.FLOAT, 100.22).add(RuntimeValueNumeric(DataType.UBYTE, 120))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UBYTE, 12).add(RuntimeValue(DataType.FLOAT, 120.22)) RuntimeValueNumeric(DataType.UBYTE, 12).add(RuntimeValueNumeric(DataType.FLOAT, 120.22))
} }
} }
@Test @Test
fun testNoAutoFloatConversion() { fun testNoAutoFloatConversion() {
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UBYTE, 233).add(RuntimeValue(DataType.FLOAT, 1.234)) RuntimeValueNumeric(DataType.UBYTE, 233).add(RuntimeValueNumeric(DataType.FLOAT, 1.234))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UWORD, 233).add(RuntimeValue(DataType.FLOAT, 1.234)) RuntimeValueNumeric(DataType.UWORD, 233).add(RuntimeValueNumeric(DataType.FLOAT, 1.234))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UBYTE, 233).mul(RuntimeValue(DataType.FLOAT, 1.234)) RuntimeValueNumeric(DataType.UBYTE, 233).mul(RuntimeValueNumeric(DataType.FLOAT, 1.234))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UWORD, 233).mul(RuntimeValue(DataType.FLOAT, 1.234)) RuntimeValueNumeric(DataType.UWORD, 233).mul(RuntimeValueNumeric(DataType.FLOAT, 1.234))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
RuntimeValue(DataType.UBYTE, 233).div(RuntimeValue(DataType.FLOAT, 1.234)) RuntimeValueNumeric(DataType.UBYTE, 233).div(RuntimeValueNumeric(DataType.FLOAT, 1.234))
} }
assertFailsWith<ArithmeticException> { assertFailsWith<ArithmeticException> {
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 @Test
fun arithmetictestUbyte() { fun arithmetictestUbyte() {
assertEquals(255, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 55)).integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 200).add(RuntimeValueNumeric(DataType.UBYTE, 55)).integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 56)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 200).add(RuntimeValueNumeric(DataType.UBYTE, 56)).integerValue())
assertEquals(1, RuntimeValue(DataType.UBYTE, 200).add(RuntimeValue(DataType.UBYTE, 57)).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(1, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 1)).integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 2).sub(RuntimeValue(DataType.UBYTE, 2)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 2)).integerValue())
assertEquals(255, RuntimeValue(DataType.UBYTE, 2).sub(RuntimeValue(DataType.UBYTE, 3)).integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 2).sub(RuntimeValueNumeric(DataType.UBYTE, 3)).integerValue())
assertEquals(255, RuntimeValue(DataType.UBYTE, 254).inc().integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 254).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 255).inc().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 255).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 1).dec().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 1).dec().integerValue())
assertEquals(255, RuntimeValue(DataType.UBYTE, 0).dec().integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 0).dec().integerValue())
assertEquals(255, RuntimeValue(DataType.UBYTE, 0).inv().integerValue()) assertEquals(255, RuntimeValueNumeric(DataType.UBYTE, 0).inv().integerValue())
assertEquals(0b00110011, RuntimeValue(DataType.UBYTE, 0b11001100).inv().integerValue()) assertEquals(0b00110011, RuntimeValueNumeric(DataType.UBYTE, 0b11001100).inv().integerValue())
// assertEquals(0, RuntimeValue(DataType.UBYTE, 0).neg().integerValue()) // assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).neg().integerValue())
// assertEquals(0, RuntimeValue(DataType.UBYTE, 0).neg().integerValue()) // assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 0).neg().integerValue())
assertEquals(1, RuntimeValue(DataType.UBYTE, 0).not().integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.UBYTE, 0).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 1).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 1).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 111).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 111).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UBYTE, 255).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UBYTE, 255).not().integerValue())
assertEquals(200, RuntimeValue(DataType.UBYTE, 20).mul(RuntimeValue(DataType.UBYTE, 10)).integerValue()) assertEquals(200, RuntimeValueNumeric(DataType.UBYTE, 20).mul(RuntimeValueNumeric(DataType.UBYTE, 10)).integerValue())
assertEquals(144, RuntimeValue(DataType.UBYTE, 20).mul(RuntimeValue(DataType.UBYTE, 20)).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(25, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 2)).integerValue())
assertEquals(125, RuntimeValue(DataType.UBYTE, 5).pow(RuntimeValue(DataType.UBYTE, 3)).integerValue()) assertEquals(125, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 3)).integerValue())
assertEquals(113, RuntimeValue(DataType.UBYTE, 5).pow(RuntimeValue(DataType.UBYTE, 4)).integerValue()) assertEquals(113, RuntimeValueNumeric(DataType.UBYTE, 5).pow(RuntimeValueNumeric(DataType.UBYTE, 4)).integerValue())
assertEquals(100, RuntimeValue(DataType.UBYTE, 50).shl().integerValue()) assertEquals(100, RuntimeValueNumeric(DataType.UBYTE, 50).shl().integerValue())
assertEquals(200, RuntimeValue(DataType.UBYTE, 100).shl().integerValue()) assertEquals(200, RuntimeValueNumeric(DataType.UBYTE, 100).shl().integerValue())
assertEquals(144, RuntimeValue(DataType.UBYTE, 200).shl().integerValue()) assertEquals(144, RuntimeValueNumeric(DataType.UBYTE, 200).shl().integerValue())
} }
@Test @Test
fun arithmetictestUWord() { fun arithmetictestUWord() {
assertEquals(65535, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5535)).integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 60000).add(RuntimeValueNumeric(DataType.UWORD, 5535)).integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5536)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 60000).add(RuntimeValueNumeric(DataType.UWORD, 5536)).integerValue())
assertEquals(1, RuntimeValue(DataType.UWORD, 60000).add(RuntimeValue(DataType.UWORD, 5537)).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(1, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 1)).integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 2).sub(RuntimeValue(DataType.UWORD, 2)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 2)).integerValue())
assertEquals(65535, RuntimeValue(DataType.UWORD, 2).sub(RuntimeValue(DataType.UWORD, 3)).integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 2).sub(RuntimeValueNumeric(DataType.UWORD, 3)).integerValue())
assertEquals(65535, RuntimeValue(DataType.UWORD, 65534).inc().integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 65534).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 65535).inc().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 65535).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 1).dec().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 1).dec().integerValue())
assertEquals(65535, RuntimeValue(DataType.UWORD, 0).dec().integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 0).dec().integerValue())
assertEquals(65535, RuntimeValue(DataType.UWORD, 0).inv().integerValue()) assertEquals(65535, RuntimeValueNumeric(DataType.UWORD, 0).inv().integerValue())
assertEquals(0b0011001101010101, RuntimeValue(DataType.UWORD, 0b1100110010101010).inv().integerValue()) assertEquals(0b0011001101010101, RuntimeValueNumeric(DataType.UWORD, 0b1100110010101010).inv().integerValue())
// assertEquals(0, RuntimeValue(DataType.UWORD, 0).neg().integerValue()) // assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).neg().integerValue())
// assertEquals(0, RuntimeValue(DataType.UWORD, 0).neg().integerValue()) // assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 0).neg().integerValue())
assertEquals(1, RuntimeValue(DataType.UWORD, 0).not().integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.UWORD, 0).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 1).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 1).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 11111).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 11111).not().integerValue())
assertEquals(0, RuntimeValue(DataType.UWORD, 65535).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.UWORD, 65535).not().integerValue())
assertEquals(2000, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 10)).integerValue()) assertEquals(2000, RuntimeValueNumeric(DataType.UWORD, 200).mul(RuntimeValueNumeric(DataType.UWORD, 10)).integerValue())
assertEquals(40000, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 200)).integerValue()) assertEquals(40000, RuntimeValueNumeric(DataType.UWORD, 200).mul(RuntimeValueNumeric(DataType.UWORD, 200)).integerValue())
assertEquals(14464, RuntimeValue(DataType.UWORD, 200).mul(RuntimeValue(DataType.UWORD, 400)).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(15625, RuntimeValueNumeric(DataType.UWORD, 5).pow(RuntimeValueNumeric(DataType.UWORD, 6)).integerValue())
assertEquals(12589, RuntimeValue(DataType.UWORD, 5).pow(RuntimeValue(DataType.UWORD, 7)).integerValue()) assertEquals(12589, RuntimeValueNumeric(DataType.UWORD, 5).pow(RuntimeValueNumeric(DataType.UWORD, 7)).integerValue())
assertEquals(10000, RuntimeValue(DataType.UWORD, 5000).shl().integerValue()) assertEquals(10000, RuntimeValueNumeric(DataType.UWORD, 5000).shl().integerValue())
assertEquals(60000, RuntimeValue(DataType.UWORD, 30000).shl().integerValue()) assertEquals(60000, RuntimeValueNumeric(DataType.UWORD, 30000).shl().integerValue())
assertEquals(14464, RuntimeValue(DataType.UWORD, 40000).shl().integerValue()) assertEquals(14464, RuntimeValueNumeric(DataType.UWORD, 40000).shl().integerValue())
} }
@Test @Test
fun arithmetictestByte() { fun arithmetictestByte() {
assertEquals(127, RuntimeValue(DataType.BYTE, 100).add(RuntimeValue(DataType.BYTE, 27)).integerValue()) assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 100).add(RuntimeValueNumeric(DataType.BYTE, 27)).integerValue())
assertEquals(-128, RuntimeValue(DataType.BYTE, 100).add(RuntimeValue(DataType.BYTE, 28)).integerValue()) assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, 100).add(RuntimeValueNumeric(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, 29)).integerValue())
assertEquals(1, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 1)).integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 1)).integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 2)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 2)).integerValue())
assertEquals(-1, RuntimeValue(DataType.BYTE, 2).sub(RuntimeValue(DataType.BYTE, 3)).integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 2).sub(RuntimeValueNumeric(DataType.BYTE, 3)).integerValue())
assertEquals(-128, RuntimeValue(DataType.BYTE, -100).sub(RuntimeValue(DataType.BYTE, 28)).integerValue()) assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -100).sub(RuntimeValueNumeric(DataType.BYTE, 28)).integerValue())
assertEquals(127, RuntimeValue(DataType.BYTE, -100).sub(RuntimeValue(DataType.BYTE, 29)).integerValue()) assertEquals(127, RuntimeValueNumeric(DataType.BYTE, -100).sub(RuntimeValueNumeric(DataType.BYTE, 29)).integerValue())
assertEquals(127, RuntimeValue(DataType.BYTE, 126).inc().integerValue()) assertEquals(127, RuntimeValueNumeric(DataType.BYTE, 126).inc().integerValue())
assertEquals(-128, RuntimeValue(DataType.BYTE, 127).inc().integerValue()) assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, 127).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, 1).dec().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 1).dec().integerValue())
assertEquals(-1, RuntimeValue(DataType.BYTE, 0).dec().integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 0).dec().integerValue())
assertEquals(-128, RuntimeValue(DataType.BYTE, -127).dec().integerValue()) assertEquals(-128, RuntimeValueNumeric(DataType.BYTE, -127).dec().integerValue())
assertEquals(127, RuntimeValue(DataType.BYTE, -128).dec().integerValue()) assertEquals(127, RuntimeValueNumeric(DataType.BYTE, -128).dec().integerValue())
assertEquals(-1, RuntimeValue(DataType.BYTE, 0).inv().integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.BYTE, 0).inv().integerValue())
assertEquals(-103, RuntimeValue(DataType.BYTE, 0b01100110).inv().integerValue()) assertEquals(-103, RuntimeValueNumeric(DataType.BYTE, 0b01100110).inv().integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, 0).neg().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 0).neg().integerValue())
assertEquals(-2, RuntimeValue(DataType.BYTE, 2).neg().integerValue()) assertEquals(-2, RuntimeValueNumeric(DataType.BYTE, 2).neg().integerValue())
assertEquals(1, RuntimeValue(DataType.BYTE, 0).not().integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.BYTE, 0).not().integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, 1).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 1).not().integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, 111).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, 111).not().integerValue())
assertEquals(0, RuntimeValue(DataType.BYTE, -33).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.BYTE, -33).not().integerValue())
assertEquals(100, RuntimeValue(DataType.BYTE, 10).mul(RuntimeValue(DataType.BYTE, 10)).integerValue()) assertEquals(100, RuntimeValueNumeric(DataType.BYTE, 10).mul(RuntimeValueNumeric(DataType.BYTE, 10)).integerValue())
assertEquals(-56, RuntimeValue(DataType.BYTE, 20).mul(RuntimeValue(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(25, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 2)).integerValue())
assertEquals(125, RuntimeValue(DataType.BYTE, 5).pow(RuntimeValue(DataType.BYTE, 3)).integerValue()) assertEquals(125, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 3)).integerValue())
assertEquals(113, RuntimeValue(DataType.BYTE, 5).pow(RuntimeValue(DataType.BYTE, 4)).integerValue()) assertEquals(113, RuntimeValueNumeric(DataType.BYTE, 5).pow(RuntimeValueNumeric(DataType.BYTE, 4)).integerValue())
assertEquals(100, RuntimeValue(DataType.BYTE, 50).shl().integerValue()) assertEquals(100, RuntimeValueNumeric(DataType.BYTE, 50).shl().integerValue())
assertEquals(-56, RuntimeValue(DataType.BYTE, 100).shl().integerValue()) assertEquals(-56, RuntimeValueNumeric(DataType.BYTE, 100).shl().integerValue())
assertEquals(-2, RuntimeValue(DataType.BYTE, -1).shl().integerValue()) assertEquals(-2, RuntimeValueNumeric(DataType.BYTE, -1).shl().integerValue())
} }
@Test @Test
fun arithmetictestWorrd() { fun arithmetictestWorrd() {
assertEquals(32767, RuntimeValue(DataType.WORD, 32700).add(RuntimeValue(DataType.WORD, 67)).integerValue()) assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32700).add(RuntimeValueNumeric(DataType.WORD, 67)).integerValue())
assertEquals(-32768, RuntimeValue(DataType.WORD, 32700).add(RuntimeValue(DataType.WORD, 68)).integerValue()) assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, 32700).add(RuntimeValueNumeric(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, 69)).integerValue())
assertEquals(1, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 1)).integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 1)).integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 2)).integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 2)).integerValue())
assertEquals(-1, RuntimeValue(DataType.WORD, 2).sub(RuntimeValue(DataType.WORD, 3)).integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 2).sub(RuntimeValueNumeric(DataType.WORD, 3)).integerValue())
assertEquals(-32768, RuntimeValue(DataType.WORD, -32700).sub(RuntimeValue(DataType.WORD, 68)).integerValue()) assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32700).sub(RuntimeValueNumeric(DataType.WORD, 68)).integerValue())
assertEquals(32767, RuntimeValue(DataType.WORD, -32700).sub(RuntimeValue(DataType.WORD, 69)).integerValue()) assertEquals(32767, RuntimeValueNumeric(DataType.WORD, -32700).sub(RuntimeValueNumeric(DataType.WORD, 69)).integerValue())
assertEquals(32767, RuntimeValue(DataType.WORD, 32766).inc().integerValue()) assertEquals(32767, RuntimeValueNumeric(DataType.WORD, 32766).inc().integerValue())
assertEquals(-32768, RuntimeValue(DataType.WORD, 32767).inc().integerValue()) assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, 32767).inc().integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, 1).dec().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 1).dec().integerValue())
assertEquals(-1, RuntimeValue(DataType.WORD, 0).dec().integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 0).dec().integerValue())
assertEquals(-32768, RuntimeValue(DataType.WORD, -32767).dec().integerValue()) assertEquals(-32768, RuntimeValueNumeric(DataType.WORD, -32767).dec().integerValue())
assertEquals(32767, RuntimeValue(DataType.WORD, -32768).dec().integerValue()) assertEquals(32767, RuntimeValueNumeric(DataType.WORD, -32768).dec().integerValue())
assertEquals(-1, RuntimeValue(DataType.WORD, 0).inv().integerValue()) assertEquals(-1, RuntimeValueNumeric(DataType.WORD, 0).inv().integerValue())
assertEquals(-103, RuntimeValue(DataType.WORD, 0b01100110).inv().integerValue()) assertEquals(-103, RuntimeValueNumeric(DataType.WORD, 0b01100110).inv().integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, 0).neg().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 0).neg().integerValue())
assertEquals(-2, RuntimeValue(DataType.WORD, 2).neg().integerValue()) assertEquals(-2, RuntimeValueNumeric(DataType.WORD, 2).neg().integerValue())
assertEquals(1, RuntimeValue(DataType.WORD, 0).not().integerValue()) assertEquals(1, RuntimeValueNumeric(DataType.WORD, 0).not().integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, 1).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 1).not().integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, 111).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, 111).not().integerValue())
assertEquals(0, RuntimeValue(DataType.WORD, -33).not().integerValue()) assertEquals(0, RuntimeValueNumeric(DataType.WORD, -33).not().integerValue())
assertEquals(10000, RuntimeValue(DataType.WORD, 100).mul(RuntimeValue(DataType.WORD, 100)).integerValue()) assertEquals(10000, RuntimeValueNumeric(DataType.WORD, 100).mul(RuntimeValueNumeric(DataType.WORD, 100)).integerValue())
assertEquals(-25536, RuntimeValue(DataType.WORD, 200).mul(RuntimeValue(DataType.WORD, 200)).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(15625, RuntimeValueNumeric(DataType.WORD, 5).pow(RuntimeValueNumeric(DataType.WORD, 6)).integerValue())
assertEquals(-6487, RuntimeValue(DataType.WORD, 9).pow(RuntimeValue(DataType.WORD, 5)).integerValue()) assertEquals(-6487, RuntimeValueNumeric(DataType.WORD, 9).pow(RuntimeValueNumeric(DataType.WORD, 5)).integerValue())
assertEquals(18000, RuntimeValue(DataType.WORD, 9000).shl().integerValue()) assertEquals(18000, RuntimeValueNumeric(DataType.WORD, 9000).shl().integerValue())
assertEquals(-25536, RuntimeValue(DataType.WORD, 20000).shl().integerValue()) assertEquals(-25536, RuntimeValueNumeric(DataType.WORD, 20000).shl().integerValue())
assertEquals(-2, RuntimeValue(DataType.WORD, -1).shl().integerValue()) assertEquals(-2, RuntimeValueNumeric(DataType.WORD, -1).shl().integerValue())
} }
} }

View File

@ -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.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.MachineDefinition.Mflpt5 import prog8.compiler.target.c64.MachineDefinition.Mflpt5
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.vm.RuntimeValue import prog8.vm.RuntimeValueNumeric
import java.io.CharConversionException import java.io.CharConversionException
import kotlin.test.* import kotlin.test.*
@ -380,8 +380,8 @@ class TestPetscii {
@Test @Test
fun testStackvmValueComparisons() { fun testStackvmValueComparisons() {
val ten = RuntimeValue(DataType.FLOAT, 10) val ten = RuntimeValueNumeric(DataType.FLOAT, 10)
val nine = RuntimeValue(DataType.UWORD, 9) val nine = RuntimeValueNumeric(DataType.UWORD, 9)
assertEquals(ten, ten) assertEquals(ten, ten)
assertNotEquals(ten, nine) assertNotEquals(ten, nine)
assertFalse(ten != ten) assertFalse(ten != ten)