This commit is contained in:
Irmen de Jong 2018-12-20 15:49:31 +01:00
parent e20e7f0232
commit 9ffc68acab
11 changed files with 216 additions and 147 deletions

View File

@ -11,7 +11,7 @@
; @todo docs: "integer / int will not result in float but is integer floor division." verify this! ; @todo docs: "integer / int will not result in float but is integer floor division." verify this!
sub toscreenx(float x, float z) -> word { sub toscreenx(float x, float z) -> word {
return 42 as word return 42.w as word
} }
asmsub blerp(ubyte x @ A, uword ding @ XY) -> clobbers() -> () { asmsub blerp(ubyte x @ A, uword ding @ XY) -> clobbers() -> () {

View File

@ -2,8 +2,8 @@ package prog8.ast
import org.antlr.v4.runtime.ParserRuleContext import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.tree.TerminalNode import org.antlr.v4.runtime.tree.TerminalNode
import prog8.compiler.CompilerException
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.compiler.intermediate.Value
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import prog8.functions.NotConstArgumentException import prog8.functions.NotConstArgumentException
@ -990,65 +990,8 @@ class TypecastExpression(var expression: IExpression, var type: DataType, overri
override fun isIterable(namespace: INameScope, heap: HeapValues) = type in IterableDatatypes override fun isIterable(namespace: INameScope, heap: HeapValues) = type in IterableDatatypes
override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? { override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? {
val cv = expression.constValue(namespace, heap) ?: return null val cv = expression.constValue(namespace, heap) ?: return null
return typecast(cv, type) val value = Value(cv.type, cv.asNumericValue!!).cast(type)
} return LiteralValue.fromNumber(value.numericValue(), value.type, position)
companion object {
fun typecast(cv: LiteralValue, type: DataType): LiteralValue? {
return when (cv.type) {
DataType.UBYTE -> {
when (type) {
DataType.UBYTE -> cv
DataType.BYTE -> TODO("ubyte->byte")
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = cv.asIntegerValue, position = cv.position)
DataType.WORD -> LiteralValue(DataType.WORD, wordvalue = cv.asIntegerValue, position = cv.position)
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = cv.asNumericValue!!.toDouble(), position = cv.position)
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
DataType.BYTE -> {
when (type) {
DataType.BYTE -> cv
DataType.UBYTE -> LiteralValue(DataType.UBYTE, (cv.asIntegerValue!! and 255).toShort(), position = cv.position)
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = cv.asIntegerValue!! and 65535, position = cv.position)
DataType.WORD -> LiteralValue(DataType.WORD, wordvalue = cv.asIntegerValue, position = cv.position)
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = cv.asNumericValue!!.toDouble(), position = cv.position)
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
DataType.UWORD -> {
when (type) {
DataType.BYTE -> TODO("uword->byte")
DataType.UBYTE -> LiteralValue(DataType.UBYTE, (cv.asIntegerValue!! and 255).toShort(), position = cv.position)
DataType.UWORD -> cv
DataType.WORD -> TODO("uword->word")
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = cv.asNumericValue!!.toDouble(), position = cv.position)
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
DataType.WORD -> {
when (type) {
DataType.BYTE -> TODO("word->byte")
DataType.UBYTE -> LiteralValue(DataType.UBYTE, (cv.asIntegerValue!! and 255).toShort(), position = cv.position)
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = cv.asIntegerValue!! and 65535, position = cv.position)
DataType.WORD -> cv
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue = cv.asNumericValue!!.toDouble(), position = cv.position)
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
DataType.FLOAT -> {
when (type) {
DataType.BYTE -> TODO("float->byte")
DataType.UBYTE -> LiteralValue(DataType.UBYTE, (cv.floatvalue!!.toInt() and 255).toShort(), position = cv.position)
DataType.UWORD -> LiteralValue(DataType.UWORD, wordvalue = cv.floatvalue!!.toInt() and 65535, position = cv.position)
DataType.WORD -> TODO("float->word")
DataType.FLOAT -> cv
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
else -> throw CompilerException("invalid type cast from ${cv.type} to $type")
}
}
} }
override fun toString(): String { override fun toString(): String {

View File

@ -1975,14 +1975,16 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.UBYTE -> when(sourceDt) { DataType.UBYTE -> when(sourceDt) {
DataType.UBYTE -> {} DataType.UBYTE -> {}
DataType.BYTE -> prog.instr(Opcode.CAST_B_TO_UB) DataType.BYTE -> prog.instr(Opcode.CAST_B_TO_UB)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.CAST_WRD_TO_UB) DataType.UWORD-> prog.instr(Opcode.CAST_UW_TO_UB)
DataType.WORD-> prog.instr(Opcode.CAST_W_TO_UB)
DataType.FLOAT -> prog.instr(Opcode.CAST_F_TO_UB) DataType.FLOAT -> prog.instr(Opcode.CAST_F_TO_UB)
else -> throw CompilerException("invalid cast type $sourceDt") else -> throw CompilerException("invalid cast type $sourceDt")
} }
DataType.BYTE -> when(sourceDt) { DataType.BYTE -> when(sourceDt) {
DataType.UBYTE -> prog.instr(Opcode.CAST_UB_TO_B) DataType.UBYTE -> prog.instr(Opcode.CAST_UB_TO_B)
DataType.BYTE -> {} DataType.BYTE -> {}
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.CAST_WRD_TO_B) DataType.UWORD -> prog.instr(Opcode.CAST_UW_TO_B)
DataType.WORD -> prog.instr(Opcode.CAST_W_TO_B)
DataType.FLOAT -> prog.instr(Opcode.CAST_F_TO_B) DataType.FLOAT -> prog.instr(Opcode.CAST_F_TO_B)
else -> throw CompilerException("invalid cast type $sourceDt") else -> throw CompilerException("invalid cast type $sourceDt")
} }

View File

@ -192,8 +192,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
when (ins1.opcode) { when (ins1.opcode) {
Opcode.CAST_B_TO_W, Opcode.CAST_B_TO_UW -> TODO("cast byte to (u)word") Opcode.CAST_B_TO_W, Opcode.CAST_B_TO_UW -> TODO("cast byte to (u)word")
Opcode.CAST_UB_TO_W, Opcode.CAST_UB_TO_UW -> TODO("cast ubyte to (u)word") Opcode.CAST_UB_TO_W, Opcode.CAST_UB_TO_UW -> TODO("cast ubyte to (u)word")
Opcode.CAST_WRD_TO_B -> TODO("cast (u)word to byte") Opcode.CAST_W_TO_B, Opcode.CAST_UW_TO_B -> TODO("cast (u)word to byte")
Opcode.CAST_WRD_TO_UB -> { Opcode.CAST_W_TO_UB, Opcode.CAST_UW_TO_UB -> {
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() and 255)) val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() and 255))
instructionsToReplace[index0] = ins instructionsToReplace[index0] = ins
instructionsToReplace[index1] = Instruction(Opcode.NOP) instructionsToReplace[index1] = Instruction(Opcode.NOP)
@ -208,6 +208,16 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
instructionsToReplace[index0] = ins instructionsToReplace[index0] = ins
instructionsToReplace[index1] = Instruction(Opcode.NOP) instructionsToReplace[index1] = Instruction(Opcode.NOP)
} }
Opcode.CAST_UW_TO_W -> {
val cv = ins0.arg!!.cast(DataType.WORD)
instructionsToReplace[index0] = Instruction(Opcode.PUSH_WORD, cv)
instructionsToReplace[index1] = Instruction(Opcode.NOP)
}
Opcode.CAST_W_TO_UW -> {
val cv = ins0.arg!!.cast(DataType.UWORD)
instructionsToReplace[index0] = Instruction(Opcode.PUSH_WORD, cv)
instructionsToReplace[index1] = Instruction(Opcode.NOP)
}
Opcode.DISCARD_WORD -> { Opcode.DISCARD_WORD -> {
instructionsToReplace[index0] = Instruction(Opcode.NOP) instructionsToReplace[index0] = Instruction(Opcode.NOP)
instructionsToReplace[index1] = Instruction(Opcode.NOP) instructionsToReplace[index1] = Instruction(Opcode.NOP)
@ -220,7 +230,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
fun optimizeByteConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) { fun optimizeByteConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
when (ins1.opcode) { when (ins1.opcode) {
Opcode.CAST_B_TO_UB, Opcode.CAST_UB_TO_B, Opcode.CAST_B_TO_UB, Opcode.CAST_UB_TO_B,
Opcode.CAST_WRD_TO_B, Opcode.CAST_WRD_TO_UB -> instructionsToReplace[index1] = Instruction(Opcode.NOP) Opcode.CAST_W_TO_B, Opcode.CAST_W_TO_UB,
Opcode.CAST_UW_TO_B, Opcode.CAST_UW_TO_UB -> instructionsToReplace[index1] = Instruction(Opcode.NOP)
Opcode.MSB -> throw CompilerException("msb of a byte") Opcode.MSB -> throw CompilerException("msb of a byte")
Opcode.CAST_UB_TO_UW -> { Opcode.CAST_UB_TO_UW -> {
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, ins0.arg!!.integerValue())) val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, ins0.arg!!.integerValue()))
@ -261,10 +272,12 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_UW,
Opcode.CAST_B_TO_W, Opcode.CAST_B_TO_W,
Opcode.CAST_B_TO_F, Opcode.CAST_B_TO_F,
Opcode.CAST_UW_TO_UB,
Opcode.CAST_UW_TO_B,
Opcode.CAST_UW_TO_W, Opcode.CAST_UW_TO_W,
Opcode.CAST_UW_TO_F, Opcode.CAST_UW_TO_F,
Opcode.CAST_WRD_TO_UB, Opcode.CAST_W_TO_UB,
Opcode.CAST_WRD_TO_B, Opcode.CAST_W_TO_B,
Opcode.CAST_W_TO_UW, Opcode.CAST_W_TO_UW,
Opcode.CAST_W_TO_F, Opcode.CAST_W_TO_F,
Opcode.CAST_F_TO_UB, Opcode.CAST_F_TO_UB,

View File

@ -119,7 +119,7 @@ enum class Opcode {
INV_WORD, INV_WORD,
// numeric type conversions // numeric type conversions
MSB, // note: lsb is equivalent to CAST_UW_TO_UB or CAST_WRD_TO_UB MSB, // note: lsb is equivalent to CAST_UW_TO_UB or CAST_W_TO_UB
CAST_UB_TO_B, CAST_UB_TO_B,
CAST_UB_TO_UW, CAST_UB_TO_UW,
CAST_UB_TO_W, CAST_UB_TO_W,
@ -128,10 +128,12 @@ enum class Opcode {
CAST_B_TO_UW, CAST_B_TO_UW,
CAST_B_TO_W, CAST_B_TO_W,
CAST_B_TO_F, CAST_B_TO_F,
CAST_WRD_TO_UB, // word and uword: just take the LSB CAST_W_TO_UB,
CAST_WRD_TO_B, // word and uword: just take the LSB CAST_W_TO_B,
CAST_W_TO_UW, CAST_W_TO_UW,
CAST_W_TO_F, CAST_W_TO_F,
CAST_UW_TO_UB,
CAST_UW_TO_B,
CAST_UW_TO_W, CAST_UW_TO_W,
CAST_UW_TO_F, CAST_UW_TO_F,
CAST_F_TO_UB, CAST_F_TO_UB,

View File

@ -1,13 +1,15 @@
package prog8.compiler.intermediate package prog8.compiler.intermediate
import prog8.ast.DataType import prog8.ast.*
import prog8.ast.IterableDatatypes import java.lang.Exception
import prog8.ast.NumericDatatypes
import prog8.stackvm.VmExecutionException
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.pow import kotlin.math.pow
class ValueException(msg: String?) : Exception(msg)
class Value(val type: DataType, numericvalueOrHeapId: Number) { class Value(val type: DataType, numericvalueOrHeapId: Number) {
private var byteval: Short? = null private var byteval: Short? = null
private var wordval: Int? = null private var wordval: Int? = null
@ -20,25 +22,25 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
when(type) { when(type) {
DataType.UBYTE -> { DataType.UBYTE -> {
if(numericvalueOrHeapId.toInt() !in 0..255) if(numericvalueOrHeapId.toInt() !in 0..255)
throw VmExecutionException("value out of range: $numericvalueOrHeapId") throw ValueException("value out of range: $numericvalueOrHeapId")
byteval = numericvalueOrHeapId.toShort() byteval = numericvalueOrHeapId.toShort()
asBooleanValue = byteval != (0.toShort()) asBooleanValue = byteval != (0.toShort())
} }
DataType.BYTE -> { DataType.BYTE -> {
if(numericvalueOrHeapId.toInt() !in -128..127) if(numericvalueOrHeapId.toInt() !in -128..127)
throw VmExecutionException("value out of range: $numericvalueOrHeapId") throw ValueException("value out of range: $numericvalueOrHeapId")
byteval = numericvalueOrHeapId.toShort() byteval = numericvalueOrHeapId.toShort()
asBooleanValue = byteval != (0.toShort()) asBooleanValue = byteval != (0.toShort())
} }
DataType.UWORD -> { DataType.UWORD -> {
if(numericvalueOrHeapId.toInt() !in 0..65535) if(numericvalueOrHeapId.toInt() !in 0..65535)
throw VmExecutionException("value out of range: $numericvalueOrHeapId") throw ValueException("value out of range: $numericvalueOrHeapId")
wordval = numericvalueOrHeapId.toInt() wordval = numericvalueOrHeapId.toInt()
asBooleanValue = wordval != 0 asBooleanValue = wordval != 0
} }
DataType.WORD -> { DataType.WORD -> {
if(numericvalueOrHeapId.toInt() !in -32768..32767) if(numericvalueOrHeapId.toInt() !in -32768..32767)
throw VmExecutionException("value out of range: $numericvalueOrHeapId") throw ValueException("value out of range: $numericvalueOrHeapId")
wordval = numericvalueOrHeapId.toInt() wordval = numericvalueOrHeapId.toInt()
asBooleanValue = wordval != 0 asBooleanValue = wordval != 0
} }
@ -48,7 +50,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
} }
else -> { else -> {
if(numericvalueOrHeapId !is Int || numericvalueOrHeapId<0) if(numericvalueOrHeapId !is Int || numericvalueOrHeapId<0)
throw VmExecutionException("for non-numeric types, the value should be a integer heapId >= 0") throw ValueException("for non-numeric types, the value should be a integer heapId >= 0")
heapId = numericvalueOrHeapId heapId = numericvalueOrHeapId
asBooleanValue=true asBooleanValue=true
} }
@ -81,7 +83,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UBYTE, DataType.BYTE -> byteval!! DataType.UBYTE, DataType.BYTE -> byteval!!
DataType.UWORD, DataType.WORD -> wordval!! DataType.UWORD, DataType.WORD -> wordval!!
DataType.FLOAT -> floatval!! DataType.FLOAT -> floatval!!
else -> throw VmExecutionException("invalid datatype for numeric value: $type") else -> throw ValueException("invalid datatype for numeric value: $type")
} }
} }
@ -89,8 +91,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> byteval!!.toInt() DataType.UBYTE, DataType.BYTE -> byteval!!.toInt()
DataType.UWORD, DataType.WORD -> wordval!! DataType.UWORD, DataType.WORD -> wordval!!
DataType.FLOAT -> throw VmExecutionException("float to integer loss of precision") DataType.FLOAT -> throw ValueException("float to integer loss of precision")
else -> throw VmExecutionException("invalid datatype for integer value: $type") else -> throw ValueException("invalid datatype for integer value: $type")
} }
} }
@ -112,12 +114,12 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
operator fun compareTo(other: Value): Int { operator fun compareTo(other: Value): Int {
return if (type in NumericDatatypes && other.type in NumericDatatypes) return if (type in NumericDatatypes && other.type in NumericDatatypes)
numericValue().toDouble().compareTo(other.numericValue().toDouble()) numericValue().toDouble().compareTo(other.numericValue().toDouble())
else throw VmExecutionException("comparison can only be done between two numeric values") else throw ValueException("comparison can only be done between two numeric values")
} }
private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value { private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value {
if(leftDt!=rightDt) if(leftDt!=rightDt)
throw VmExecutionException("left and right datatypes are not the same") throw ValueException("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 -> {
@ -131,7 +133,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.BYTE -> Value(DataType.BYTE, result.toInt()) DataType.BYTE -> Value(DataType.BYTE, result.toInt())
DataType.WORD -> Value(DataType.WORD, result.toInt()) DataType.WORD -> Value(DataType.WORD, result.toInt())
DataType.FLOAT -> Value(DataType.FLOAT, result) DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("$op on non-numeric type") else -> throw ValueException("$op on non-numeric type")
} }
} }
@ -141,13 +143,13 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UWORD -> Value(DataType.UWORD, result.toInt() and 65535) DataType.UWORD -> Value(DataType.UWORD, result.toInt() and 65535)
DataType.WORD -> Value(DataType.WORD, result.toInt()) DataType.WORD -> Value(DataType.WORD, result.toInt())
DataType.FLOAT -> Value(DataType.FLOAT, result) DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("$op on non-numeric type") else -> throw ValueException("$op on non-numeric type")
} }
} }
fun add(other: Value): Value { fun add(other: Value): Value {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if(other.type == DataType.FLOAT && (type!= DataType.FLOAT))
throw VmExecutionException("floating point loss of precision on type $type") throw ValueException("floating point loss of precision on type $type")
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()
@ -156,7 +158,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun sub(other: Value): Value { fun sub(other: Value): Value {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if(other.type == DataType.FLOAT && (type!= DataType.FLOAT))
throw VmExecutionException("floating point loss of precision on type $type") throw ValueException("floating point loss of precision on type $type")
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()
@ -165,7 +167,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun mul(other: Value): Value { fun mul(other: Value): Value {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if(other.type == DataType.FLOAT && (type!= DataType.FLOAT))
throw VmExecutionException("floating point loss of precision on type $type") throw ValueException("floating point loss of precision on type $type")
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()
@ -174,7 +176,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun div(other: Value): Value { fun div(other: Value): Value {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if(other.type == DataType.FLOAT && (type!= DataType.FLOAT))
throw VmExecutionException("floating point loss of precision on type $type") throw ValueException("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) {
@ -189,13 +191,13 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UBYTE -> Value(DataType.UBYTE, result) DataType.UBYTE -> Value(DataType.UBYTE, result)
DataType.UWORD -> Value(DataType.UWORD, result) DataType.UWORD -> Value(DataType.UWORD, result)
DataType.FLOAT -> Value(DataType.FLOAT, result) DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("div on non-numeric type") else -> throw ValueException("div on non-numeric type")
} }
} }
fun floordiv(other: Value): Value { fun floordiv(other: Value): Value {
if(other.type == DataType.FLOAT && (type!= DataType.FLOAT)) if(other.type == DataType.FLOAT && (type!= DataType.FLOAT))
throw VmExecutionException("floating point loss of precision on type $type") throw ValueException("floating point loss of precision on type $type")
val v1 = numericValue() val v1 = numericValue()
val v2 = other.numericValue() val v2 = other.numericValue()
val result = floor(v1.toDouble() / v2.toDouble()) val result = floor(v1.toDouble() / v2.toDouble())
@ -204,7 +206,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UBYTE -> Value(DataType.UBYTE, result) DataType.UBYTE -> Value(DataType.UBYTE, result)
DataType.UWORD -> Value(DataType.UWORD, result) DataType.UWORD -> Value(DataType.UWORD, result)
DataType.FLOAT -> Value(DataType.FLOAT, result) DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("div on non-numeric type") else -> throw ValueException("div on non-numeric type")
} }
} }
@ -228,7 +230,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return Value(type, (v shl 1) and 255) return Value(type, (v shl 1) and 255)
if(type==DataType.UWORD) if(type==DataType.UWORD)
return Value(type, (v shl 1) and 65535) return Value(type, (v shl 1) and 65535)
throw VmExecutionException("invalid type for shl: $type") throw ValueException("invalid type for shl: $type")
} }
fun shr(): Value { fun shr(): Value {
@ -237,7 +239,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return Value(type, (v ushr 1) and 255) return Value(type, (v ushr 1) and 255)
if(type==DataType.UWORD) if(type==DataType.UWORD)
return Value(type, (v ushr 1) and 65535) return Value(type, (v ushr 1) and 65535)
throw VmExecutionException("invalid type for shr: $type") throw ValueException("invalid type for shr: $type")
} }
fun rol(carry: Boolean): Pair<Value, Boolean> { fun rol(carry: Boolean): Pair<Value, Boolean> {
@ -255,7 +257,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
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(Value(DataType.UWORD, newval), newCarry) Pair(Value(DataType.UWORD, newval), newCarry)
} }
else -> throw VmExecutionException("rol can only work on byte/word") else -> throw ValueException("rol can only work on byte/word")
} }
} }
@ -274,7 +276,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
val newval = (v ushr 1) or (if(carry) 0x8000 else 0) val newval = (v ushr 1) or (if(carry) 0x8000 else 0)
Pair(Value(DataType.UWORD, newval), newCarry) Pair(Value(DataType.UWORD, newval), newCarry)
} }
else -> throw VmExecutionException("ror2 can only work on byte/word") else -> throw ValueException("ror2 can only work on byte/word")
} }
} }
@ -293,7 +295,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
val newval = (v and 0x7fff shl 1) or carry val newval = (v and 0x7fff shl 1) or carry
Value(DataType.UWORD, newval) Value(DataType.UWORD, newval)
} }
else -> throw VmExecutionException("rol2 can only work on byte/word") else -> throw ValueException("rol2 can only work on byte/word")
} }
} }
@ -312,7 +314,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
val newval = (v ushr 1) or carry val newval = (v ushr 1) or carry
Value(DataType.UWORD, newval) Value(DataType.UWORD, newval)
} }
else -> throw VmExecutionException("ror2 can only work on byte/word") else -> throw ValueException("ror2 can only work on byte/word")
} }
} }
@ -321,7 +323,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.BYTE -> Value(DataType.BYTE, -(byteval!!)) DataType.BYTE -> Value(DataType.BYTE, -(byteval!!))
DataType.WORD -> Value(DataType.WORD, -(wordval!!)) DataType.WORD -> Value(DataType.WORD, -(wordval!!))
DataType.FLOAT -> Value(DataType.FLOAT, -(floatval)!!) DataType.FLOAT -> Value(DataType.FLOAT, -(floatval)!!)
else -> throw VmExecutionException("neg can only work on byte/word/float") else -> throw ValueException("neg can only work on byte/word/float")
} }
} }
@ -330,7 +332,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.BYTE -> Value(DataType.BYTE, abs(byteval!!.toInt())) DataType.BYTE -> Value(DataType.BYTE, abs(byteval!!.toInt()))
DataType.WORD -> Value(DataType.WORD, abs(wordval!!)) DataType.WORD -> Value(DataType.WORD, abs(wordval!!))
DataType.FLOAT -> Value(DataType.FLOAT, abs(floatval!!)) DataType.FLOAT -> Value(DataType.FLOAT, abs(floatval!!))
else -> throw VmExecutionException("abs can only work on byte/word/float") else -> throw ValueException("abs can only work on byte/word/float")
} }
} }
@ -364,7 +366,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return when(type) { return when(type) {
DataType.UBYTE -> Value(DataType.UBYTE, byteval!!.toInt().inv() and 255) DataType.UBYTE -> Value(DataType.UBYTE, byteval!!.toInt().inv() and 255)
DataType.UWORD -> Value(DataType.UWORD, wordval!!.inv() and 65535) DataType.UWORD -> Value(DataType.UWORD, wordval!!.inv() and 65535)
else -> throw VmExecutionException("inv can only work on byte/word") else -> throw ValueException("inv can only work on byte/word")
} }
} }
@ -373,7 +375,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UBYTE -> Value(DataType.UBYTE, (byteval!! + 1) and 255) DataType.UBYTE -> Value(DataType.UBYTE, (byteval!! + 1) and 255)
DataType.UWORD -> Value(DataType.UWORD, (wordval!! + 1) and 65535) DataType.UWORD -> Value(DataType.UWORD, (wordval!! + 1) and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, floatval!! + 1) DataType.FLOAT -> Value(DataType.FLOAT, floatval!! + 1)
else -> throw VmExecutionException("inc can only work on byte/word/float") else -> throw ValueException("inc can only work on byte/word/float")
} }
} }
@ -382,7 +384,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
DataType.UBYTE -> Value(DataType.UBYTE, (byteval!! - 1) and 255) DataType.UBYTE -> Value(DataType.UBYTE, (byteval!! - 1) and 255)
DataType.UWORD -> Value(DataType.UWORD, (wordval!! - 1) and 65535) DataType.UWORD -> Value(DataType.UWORD, (wordval!! - 1) and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, floatval!! - 1) DataType.FLOAT -> Value(DataType.FLOAT, floatval!! - 1)
else -> throw VmExecutionException("dec can only work on byte/word/float") else -> throw ValueException("dec can only work on byte/word/float")
} }
} }
@ -390,7 +392,84 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> Value(DataType.UBYTE, 0) DataType.UBYTE, DataType.BYTE -> Value(DataType.UBYTE, 0)
DataType.UWORD, DataType.WORD -> Value(DataType.UBYTE, wordval!! ushr 8 and 255) DataType.UWORD, DataType.WORD -> Value(DataType.UBYTE, wordval!! ushr 8 and 255)
else -> throw VmExecutionException("msb can only work on (u)byte/(u)word") else -> throw ValueException("msb can only work on (u)byte/(u)word")
} }
} }
fun cast(targetType: DataType): Value {
return when (type) {
DataType.UBYTE -> {
when (targetType) {
DataType.UBYTE -> this
DataType.BYTE -> {
if(byteval!!<=127)
Value(DataType.BYTE, byteval!!)
else
Value(DataType.BYTE, -(256-byteval!!))
}
DataType.UWORD -> Value(DataType.UWORD, numericValue())
DataType.WORD -> Value(DataType.WORD, numericValue())
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
DataType.BYTE -> {
when (targetType) {
DataType.BYTE -> this
DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
DataType.WORD -> Value(DataType.WORD, integerValue())
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
DataType.UWORD -> {
when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> this
DataType.WORD -> {
if(integerValue()<=32767)
Value(DataType.WORD, integerValue())
else
Value(DataType.WORD, -(65536-integerValue()))
}
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
DataType.WORD -> {
when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
DataType.WORD -> this
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
DataType.FLOAT -> {
when (targetType) {
DataType.BYTE -> {
val integer=numericValue().toInt()
if(integer in -128..127)
Value(DataType.BYTE, integer)
else
throw AstException("overflow when casting float to byte: $this")
}
DataType.UBYTE -> Value(DataType.UBYTE, numericValue().toInt() and 255)
DataType.UWORD -> Value(DataType.UWORD, numericValue().toInt() and 65535)
DataType.WORD -> {
val integer=numericValue().toInt()
if(integer in -32768..32767)
Value(DataType.WORD, integer)
else
throw AstException("overflow when casting float to word: $this")
}
DataType.FLOAT -> this
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
else -> throw ValueException("invalid type cast from $type to $targetType")
}
}
} }

View File

@ -674,20 +674,20 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.CAST_UB_TO_B -> "" // is a no-op, just carry on with the byte as-is Opcode.CAST_UB_TO_B -> "" // is a no-op, just carry on with the byte as-is
Opcode.CAST_W_TO_UW -> "" // is a no-op, just carry on with the word as-is Opcode.CAST_W_TO_UW -> "" // is a no-op, just carry on with the word as-is
Opcode.CAST_UW_TO_W -> "" // is a no-op, just carry on with the word as-is Opcode.CAST_UW_TO_W -> "" // is a no-op, just carry on with the word as-is
Opcode.CAST_WRD_TO_UB -> "" // is a no-op, just carry on with the lsb of the (u)word as-is Opcode.CAST_W_TO_UB -> "" // is a no-op, just carry on with the lsb of the word as-is
Opcode.CAST_WRD_TO_B -> "" // is a no-op, just carry on with the lsb of the (u)word as-is Opcode.CAST_W_TO_B -> "" // is a no-op, just carry on with the lsb of the word as-is
Opcode.CAST_UW_TO_UB -> "" // is a no-op, just carry on with the lsb of the uword as-is
Opcode.CAST_UW_TO_B -> "" // is a no-op, just carry on with the lsb of the uword as-is
Opcode.CAST_UB_TO_F -> " jsr prog8_lib.stack_ub2float" Opcode.CAST_UB_TO_F -> " jsr prog8_lib.stack_ub2float"
Opcode.CAST_B_TO_F -> " jsr prog8_lib.stack_b2float" Opcode.CAST_B_TO_F -> " jsr prog8_lib.stack_b2float"
Opcode.CAST_UW_TO_F -> " jsr prog8_lib.stack_uw2float" Opcode.CAST_UW_TO_F -> " jsr prog8_lib.stack_uw2float"
Opcode.CAST_W_TO_F -> " jsr prog8_lib.stack_w2float" Opcode.CAST_W_TO_F -> " jsr prog8_lib.stack_w2float"
Opcode.CAST_UB_TO_UW -> " lda #0 | sta ${ESTACK_HI+1},x" // clear the msb Opcode.CAST_F_TO_UB -> " jsr prog8_lib.stack_float2ub"
Opcode.CAST_UB_TO_W -> TODO("ub2w") Opcode.CAST_F_TO_B -> " jsr prog8_lib.stack_float2b"
Opcode.CAST_B_TO_UW -> TODO("b2uw") Opcode.CAST_F_TO_UW -> " jsr prog8_lib.stack_float2uw"
Opcode.CAST_B_TO_W -> " ${signExtendA("${ESTACK_HI+1},x")}" // sign extend the lsb @todo missing an lda??? Opcode.CAST_F_TO_W -> " jsr prog8_lib.stack_float2w"
Opcode.CAST_F_TO_UB -> TODO("f2ub") Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${ESTACK_HI+1},x" // clear the msb
Opcode.CAST_F_TO_B -> TODO("f2b") Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " ${signExtendA("${ESTACK_HI+1},x")}" // sign extend the lsb @todo missing an lda???
Opcode.CAST_F_TO_UW -> TODO("f2uw")
Opcode.CAST_F_TO_W -> TODO("f2w")
Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x" Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x"
Opcode.DIV_UB -> " jsr prog8_lib.div_ub" Opcode.DIV_UB -> " jsr prog8_lib.div_ub"
@ -2715,8 +2715,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// byte var = wordvar as (u)byte // byte var = wordvar as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_WRD_TO_UB, Opcode.POP_VAR_BYTE), AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_UB, Opcode.POP_VAR_BYTE),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_WRD_TO_B, Opcode.POP_VAR_BYTE)) { segment -> listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_B, Opcode.POP_VAR_BYTE)) { segment ->
when(segment[2].callLabel) {
"A" -> " lda ${segment[0].callLabel}"
"X" -> " ldx ${segment[0].callLabel}"
"Y" -> " ldy ${segment[0].callLabel}"
else -> " lda ${segment[0].callLabel} | sta ${segment[2].callLabel}"
}
},
// byte var = uwordvar as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_UB, Opcode.POP_VAR_BYTE),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_B, Opcode.POP_VAR_BYTE)) { segment ->
when(segment[2].callLabel) { when(segment[2].callLabel) {
"A" -> " lda ${segment[0].callLabel}" "A" -> " lda ${segment[0].callLabel}"
"X" -> " ldx ${segment[0].callLabel}" "X" -> " ldx ${segment[0].callLabel}"
@ -2734,8 +2744,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
}, },
// push word var as (u)byte // push word var as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_WRD_TO_UB), AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_UB),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_WRD_TO_B)) { segment -> listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_W_TO_B)) { segment ->
" lda ${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex "
},
// push uword var as (u)byte
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_UB),
listOf(Opcode.PUSH_VAR_WORD, Opcode.CAST_UW_TO_B)) { segment ->
" lda ${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex " " lda ${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex "
}, },
// push msb(word var) // push msb(word var)

View File

@ -54,7 +54,6 @@ val BuiltinFunctions = mapOf(
"clear_carry" to FunctionSignature(false, emptyList(), null), "clear_carry" to FunctionSignature(false, emptyList(), null),
"set_irqd" to FunctionSignature(false, emptyList(), null), "set_irqd" to FunctionSignature(false, emptyList(), null),
"clear_irqd" to FunctionSignature(false, emptyList(), null), "clear_irqd" to FunctionSignature(false, emptyList(), null),
// @todo change the string conversion functions into "string as byte" type casts?
"str2byte" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.BYTE), "str2byte" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.BYTE),
"str2ubyte" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.UBYTE), "str2ubyte" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.UBYTE),
"str2word" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.WORD), "str2word" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.WORD),

View File

@ -1345,11 +1345,26 @@ class StackVm(private var traceOutputFile: String?) {
throw VmExecutionException("expected string to be on heap") throw VmExecutionException("expected string to be on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
} }
Opcode.CAST_UB_TO_B, Opcode.CAST_WRD_TO_B, Opcode.CAST_F_TO_B -> typecast(DataType.BYTE) Opcode.CAST_UB_TO_B -> typecast(DataType.UBYTE, DataType.BYTE)
Opcode.CAST_B_TO_UB, Opcode.CAST_WRD_TO_UB, Opcode.CAST_F_TO_UB -> typecast(DataType.UBYTE) Opcode.CAST_W_TO_B -> typecast(DataType.WORD, DataType.BYTE)
Opcode.CAST_UB_TO_UW, Opcode.CAST_B_TO_UW, Opcode.CAST_W_TO_UW, Opcode.CAST_F_TO_UW -> typecast(DataType.UWORD) Opcode.CAST_UW_TO_B -> typecast(DataType.UWORD, DataType.BYTE)
Opcode.CAST_UB_TO_W, Opcode.CAST_B_TO_W, Opcode.CAST_UW_TO_W, Opcode.CAST_F_TO_W -> typecast(DataType.WORD) Opcode.CAST_F_TO_B -> typecast(DataType.FLOAT, DataType.BYTE)
Opcode.CAST_UB_TO_F, Opcode.CAST_B_TO_F, Opcode.CAST_UW_TO_F, Opcode.CAST_W_TO_F -> typecast(DataType.FLOAT) Opcode.CAST_B_TO_UB-> typecast(DataType.BYTE, DataType.UBYTE)
Opcode.CAST_W_TO_UB -> typecast(DataType.WORD, DataType.UBYTE)
Opcode.CAST_UW_TO_UB -> typecast(DataType.UWORD, DataType.UBYTE)
Opcode.CAST_F_TO_UB -> typecast(DataType.FLOAT, DataType.UBYTE)
Opcode.CAST_UB_TO_UW -> typecast(DataType.UBYTE, DataType.UWORD)
Opcode.CAST_B_TO_UW -> typecast(DataType.BYTE, DataType.UWORD)
Opcode.CAST_W_TO_UW -> typecast(DataType.WORD, DataType.UWORD)
Opcode.CAST_F_TO_UW -> typecast(DataType.FLOAT, DataType.UWORD)
Opcode.CAST_UB_TO_W -> typecast(DataType.UBYTE, DataType.WORD)
Opcode.CAST_B_TO_W -> typecast(DataType.BYTE, DataType.WORD)
Opcode.CAST_UW_TO_W -> typecast(DataType.UWORD, DataType.WORD)
Opcode.CAST_F_TO_W -> typecast(DataType.FLOAT, DataType.WORD)
Opcode.CAST_UB_TO_F -> typecast(DataType.UBYTE, DataType.FLOAT)
Opcode.CAST_B_TO_F -> typecast(DataType.BYTE, DataType.FLOAT)
Opcode.CAST_UW_TO_F -> typecast(DataType.UWORD, DataType.FLOAT)
Opcode.CAST_W_TO_F -> typecast(DataType.WORD, DataType.FLOAT)
//else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}") //else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
} }
@ -1362,11 +1377,11 @@ class StackVm(private var traceOutputFile: String?) {
return ins.next return ins.next
} }
private fun typecast(type: DataType) { private fun typecast(from: DataType, to: DataType) {
val value = evalstack.pop() val value = evalstack.pop()
val lv = LiteralValue.optimalNumeric(value.numericValue(), Position("?", 0, 0, 0)) checkDt(value, from)
val lv2 = TypecastExpression.typecast(lv, type) ?: throw VmExecutionException("type cast error") val cv = value.cast(to)
evalstack.push(Value(lv2.type, lv2.asNumericValue!!)) evalstack.push(cv)
} }
private fun dispatchSyscall(ins: Instruction) { private fun dispatchSyscall(ins: Instruction) {

View File

@ -9,6 +9,7 @@ import prog8.compiler.HeapValues
import prog8.compiler.intermediate.Instruction import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value import prog8.compiler.intermediate.Value
import prog8.compiler.intermediate.ValueException
import prog8.stackvm.* import prog8.stackvm.*
import kotlin.test.* import kotlin.test.*
@ -413,10 +414,10 @@ class TestStackVmOpcodes {
fun testInv() { fun testInv() {
testUnaryOperator(Value(DataType.UBYTE, 123), Opcode.INV_BYTE, Value(DataType.UBYTE, 0x84)) testUnaryOperator(Value(DataType.UBYTE, 123), Opcode.INV_BYTE, Value(DataType.UBYTE, 0x84))
testUnaryOperator(Value(DataType.UWORD, 4044), Opcode.INV_WORD, Value(DataType.UWORD, 0xf033)) testUnaryOperator(Value(DataType.UWORD, 4044), Opcode.INV_WORD, Value(DataType.UWORD, 0xf033))
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV_BYTE, Value(DataType.BYTE, 0x84)) testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV_BYTE, Value(DataType.BYTE, 0x84))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_WORD, Value(DataType.WORD, 0xf033)) testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_WORD, Value(DataType.WORD, 0xf033))
} }
} }
@ -537,13 +538,13 @@ class TestStackVmOpcodes {
fun testW2Float() { fun testW2Float() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 52345)), Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -12345)),
Instruction(Opcode.CAST_W_TO_F), Instruction(Opcode.CAST_W_TO_F),
Instruction(Opcode.CAST_W_TO_F) Instruction(Opcode.CAST_W_TO_F)
) )
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
vm.step(3) vm.step(3)
assertEquals(Value(DataType.FLOAT, 52345.0), vm.evalstack.pop()) assertEquals(Value(DataType.FLOAT, -12345.0), vm.evalstack.pop())
assertFailsWith<VmExecutionException> { assertFailsWith<VmExecutionException> {
vm.step(1) vm.step(1)
} }

View File

@ -3,10 +3,10 @@ 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.DataType import prog8.ast.DataType
import prog8.ast.ExpressionError
import prog8.ast.LiteralValue import prog8.ast.LiteralValue
import prog8.ast.Position import prog8.ast.Position
import prog8.compiler.intermediate.Value import prog8.compiler.intermediate.Value
import prog8.compiler.intermediate.ValueException
import prog8.stackvm.VmExecutionException import prog8.stackvm.VmExecutionException
import kotlin.test.* import kotlin.test.*
@ -137,44 +137,44 @@ class TestStackVmValue {
@Test @Test
fun testNoDtConversion() { fun testNoDtConversion() {
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UWORD, 100).add(Value(DataType.UBYTE, 120)) Value(DataType.UWORD, 100).add(Value(DataType.UBYTE, 120))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UBYTE, 100).add(Value(DataType.UWORD, 120)) Value(DataType.UBYTE, 100).add(Value(DataType.UWORD, 120))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.FLOAT, 100.22).add(Value(DataType.UWORD, 120)) Value(DataType.FLOAT, 100.22).add(Value(DataType.UWORD, 120))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UWORD, 1002).add(Value(DataType.FLOAT, 120.22)) Value(DataType.UWORD, 1002).add(Value(DataType.FLOAT, 120.22))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.FLOAT, 100.22).add(Value(DataType.UBYTE, 120)) Value(DataType.FLOAT, 100.22).add(Value(DataType.UBYTE, 120))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UBYTE, 12).add(Value(DataType.FLOAT, 120.22)) Value(DataType.UBYTE, 12).add(Value(DataType.FLOAT, 120.22))
} }
} }
@Test @Test
fun testNoAutoFloatConversion() { fun testNoAutoFloatConversion() {
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UBYTE, 233).add(Value(DataType.FLOAT, 1.234)) Value(DataType.UBYTE, 233).add(Value(DataType.FLOAT, 1.234))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UWORD, 233).add(Value(DataType.FLOAT, 1.234)) Value(DataType.UWORD, 233).add(Value(DataType.FLOAT, 1.234))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UBYTE, 233).mul(Value(DataType.FLOAT, 1.234)) Value(DataType.UBYTE, 233).mul(Value(DataType.FLOAT, 1.234))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UWORD, 233).mul(Value(DataType.FLOAT, 1.234)) Value(DataType.UWORD, 233).mul(Value(DataType.FLOAT, 1.234))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UBYTE, 233).div(Value(DataType.FLOAT, 1.234)) Value(DataType.UBYTE, 233).div(Value(DataType.FLOAT, 1.234))
} }
assertFailsWith<VmExecutionException> { assertFailsWith<ValueException> {
Value(DataType.UWORD, 233).div(Value(DataType.FLOAT, 1.234)) Value(DataType.UWORD, 233).div(Value(DataType.FLOAT, 1.234))
} }
val result = Value(DataType.FLOAT, 233.333).add(Value(DataType.FLOAT, 1.234)) val result = Value(DataType.FLOAT, 233.333).add(Value(DataType.FLOAT, 1.234))