mirror of
https://github.com/irmen/prog8.git
synced 2024-11-16 22:09:56 +00:00
casts
This commit is contained in:
parent
e20e7f0232
commit
9ffc68acab
@ -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() -> () {
|
||||||
|
@ -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 {
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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),
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user