datatype cleanups

This commit is contained in:
Irmen de Jong 2019-02-25 01:08:10 +01:00
parent 95f7c9bad0
commit 2f1249489b
13 changed files with 210 additions and 179 deletions

View File

@ -103,9 +103,11 @@ val IterableDatatypes = setOf(
DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_W,
DataType.ARRAY_F) DataType.ARRAY_F)
val StringDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) val ByteDatatypes = setOf(DataType.UBYTE, DataType.BYTE)
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT) val WordDatatypes = setOf(DataType.UWORD, DataType.WORD)
val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD) val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
val StringDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F) val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
@ -918,19 +920,19 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
DataType.BYTE -> when(rightDt) { DataType.BYTE -> when(rightDt) {
DataType.BYTE, DataType.UBYTE -> DataType.BYTE in ByteDatatypes -> DataType.BYTE
DataType.WORD, DataType.UWORD -> DataType.WORD in WordDatatypes -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
DataType.UWORD -> when(rightDt) { DataType.UWORD -> when(rightDt) {
DataType.UBYTE, DataType.UWORD -> DataType.UWORD in ByteDatatypes -> DataType.UWORD
DataType.BYTE, DataType.WORD -> DataType.WORD in WordDatatypes -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
DataType.WORD -> when(rightDt) { DataType.WORD -> when(rightDt) {
DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD -> DataType.WORD in IntegerDatatypes -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
@ -1073,8 +1075,8 @@ class LiteralValue(val type: DataType,
fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue { fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> LiteralValue(type, bytevalue = value.toShort(), position = position) in ByteDatatypes -> LiteralValue(type, bytevalue = value.toShort(), position = position)
DataType.UWORD, DataType.WORD -> LiteralValue(type, wordvalue = value.toInt(), position = position) in WordDatatypes -> LiteralValue(type, wordvalue = value.toInt(), position = position)
DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position) DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position)
else -> throw FatalAstException("non numeric datatype") else -> throw FatalAstException("non numeric datatype")
} }
@ -1110,8 +1112,8 @@ class LiteralValue(val type: DataType,
init { init {
when(type){ when(type){
DataType.UBYTE, DataType.BYTE -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue") in ByteDatatypes -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue")
DataType.UWORD, DataType.WORD -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue") in WordDatatypes -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue") DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
in StringDatatypes -> in StringDatatypes ->
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId") if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")

View File

@ -830,6 +830,19 @@ private class AstChecker(private val namespace: INameScope,
if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference) if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position) printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position)
} }
// check if the argument types match the register(pairs)
val asmParamReg = target.asmParameterRegisters[arg.first.index]
if(asmParamReg.statusflag!=null) {
if(argDt !in ByteDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for statusflag", position))
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
if(argDt !in ByteDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for single register", position))
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if(argDt !in WordDatatypes+ IterableDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be word type for register pair", position))
}
} }
} }
} }
@ -954,8 +967,8 @@ private class AstChecker(private val namespace: INameScope,
when (targetDt) { when (targetDt) {
DataType.FLOAT -> { DataType.FLOAT -> {
val number = when(value.type) { val number = when(value.type) {
DataType.UBYTE, DataType.BYTE -> value.bytevalue!!.toDouble() in ByteDatatypes -> value.bytevalue!!.toDouble()
DataType.UWORD, DataType.WORD -> value.wordvalue!!.toDouble() in WordDatatypes -> value.wordvalue!!.toDouble()
DataType.FLOAT -> value.floatvalue!! DataType.FLOAT -> value.floatvalue!!
else -> return err("numeric value expected") else -> return err("numeric value expected")
} }

View File

@ -237,12 +237,11 @@ internal class Compiler(private val rootModule: Module,
private fun opcodePush(dt: DataType): Opcode { private fun opcodePush(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE in ByteDatatypes -> Opcode.PUSH_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD in WordDatatypes -> Opcode.PUSH_WORD
in IterableDatatypes -> Opcode.PUSH_WORD
DataType.FLOAT -> Opcode.PUSH_FLOAT DataType.FLOAT -> Opcode.PUSH_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
} }
} }
@ -280,12 +279,11 @@ internal class Compiler(private val rootModule: Module,
private fun opcodePushvar(dt: DataType): Opcode { private fun opcodePushvar(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_VAR_BYTE in ByteDatatypes -> Opcode.PUSH_VAR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_VAR_WORD in WordDatatypes -> Opcode.PUSH_VAR_WORD
in IterableDatatypes -> Opcode.PUSH_ADDR_HEAPVAR
DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_ADDR_HEAPVAR
} }
} }
@ -313,34 +311,31 @@ internal class Compiler(private val rootModule: Module,
private fun opcodeDiscard(dt: DataType): Opcode { private fun opcodeDiscard(dt: DataType): Opcode {
return when(dt) { return when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.DISCARD_BYTE in ByteDatatypes -> Opcode.DISCARD_BYTE
DataType.UWORD, DataType.WORD -> Opcode.DISCARD_WORD in WordDatatypes -> Opcode.DISCARD_WORD
in IterableDatatypes -> Opcode.DISCARD_WORD
DataType.FLOAT -> Opcode.DISCARD_FLOAT DataType.FLOAT -> Opcode.DISCARD_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.DISCARD_WORD
} }
} }
private fun opcodePopvar(dt: DataType): Opcode { private fun opcodePopvar(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.POP_VAR_BYTE in ByteDatatypes -> Opcode.POP_VAR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.POP_VAR_WORD in WordDatatypes -> Opcode.POP_VAR_WORD
in IterableDatatypes -> Opcode.POP_VAR_WORD
DataType.FLOAT -> Opcode.POP_VAR_FLOAT DataType.FLOAT -> Opcode.POP_VAR_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_VAR_WORD
} }
} }
private fun opcodePopmem(dt: DataType): Opcode { private fun opcodePopmem(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE in ByteDatatypes -> Opcode.POP_MEM_BYTE
DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD in WordDatatypes -> Opcode.POP_MEM_WORD
in IterableDatatypes -> Opcode.POP_MEM_WORD
DataType.FLOAT -> Opcode.POP_MEM_FLOAT DataType.FLOAT -> Opcode.POP_MEM_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_MEM_WORD
} }
} }
@ -517,8 +512,8 @@ internal class Compiler(private val rootModule: Module,
if(trueGoto!=null) { if(trueGoto!=null) {
// optimization for if (condition) goto .... // optimization for if (condition) goto ....
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
translate(trueGoto, conditionJumpOpcode) translate(trueGoto, conditionJumpOpcode)
@ -527,8 +522,8 @@ internal class Compiler(private val rootModule: Module,
} }
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JZ in ByteDatatypes -> Opcode.JZ
DataType.UWORD, DataType.WORD -> Opcode.JZW in WordDatatypes -> Opcode.JZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
val labelEnd = makeLabel("end") val labelEnd = makeLabel("end")
@ -573,8 +568,8 @@ internal class Compiler(private val rootModule: Module,
} }
DataType.BYTE -> { DataType.BYTE -> {
when(rightDt) { when(rightDt) {
DataType.UBYTE, DataType.BYTE -> DataType.BYTE in ByteDatatypes -> DataType.BYTE
DataType.UWORD, DataType.WORD -> DataType.WORD in WordDatatypes -> DataType.WORD
DataType.FLOAT -> { DataType.FLOAT -> {
printWarning(floatWarning, leftpos) printWarning(floatWarning, leftpos)
DataType.FLOAT DataType.FLOAT
@ -662,20 +657,20 @@ internal class Compiler(private val rootModule: Module,
else -> { else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) { when(lv.type) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!)) in ByteDatatypes -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!))
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!)) in WordDatatypes -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!))
DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!)) DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!))
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("string should have been moved into heap ${lv.position}") throw CompilerException("string should have been moved into heap ${lv.position}")
TODO("push address of string with PUSH_ADDR_HEAPVAR") TODO("push address of string with PUSH_ADDR_HEAPVAR")
} }
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, in ArrayDatatypes -> {
DataType.ARRAY_B, DataType.ARRAY_W -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("array should have been moved into heap ${lv.position}") throw CompilerException("array should have been moved into heap ${lv.position}")
TODO("push address of array with PUSH_WORD") TODO("push address of array with PUSH_WORD")
} }
else -> throw CompilerException("weird datatype")
} }
} }
} }
@ -714,12 +709,12 @@ internal class Compiler(private val rootModule: Module,
else -> {} else -> {}
} }
DataType.UWORD -> when(targetDt) { DataType.UWORD -> when(targetDt) {
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type") in ByteDatatypes -> throw CompilerException("narrowing type")
DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F) DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F)
else -> {} else -> {}
} }
DataType.WORD -> when(targetDt) { DataType.WORD -> when(targetDt) {
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type") in ByteDatatypes -> throw CompilerException("narrowing type")
DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F) DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F)
else -> {} else -> {}
} }
@ -893,12 +888,12 @@ internal class Compiler(private val rootModule: Module,
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHL_BYTE) in ByteDatatypes -> prog.instr(Opcode.SHL_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHL_WORD) in WordDatatypes -> prog.instr(Opcode.SHL_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"lsr" -> { "lsr" -> {
val arg = args.single() val arg = args.single()
@ -928,34 +923,34 @@ internal class Compiler(private val rootModule: Module,
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROR_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR_WORD) in WordDatatypes -> prog.instr(Opcode.ROR_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"rol2" -> { "rol2" -> {
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROL2_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROL2_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROL2_WORD) in WordDatatypes -> prog.instr(Opcode.ROL2_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"ror2" -> { "ror2" -> {
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR2_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROR2_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR2_WORD) in WordDatatypes -> prog.instr(Opcode.ROR2_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"set_carry" -> prog.instr(Opcode.SEC) "set_carry" -> prog.instr(Opcode.SEC)
"clear_carry" -> prog.instr(Opcode.CLC) "clear_carry" -> prog.instr(Opcode.CLC)
@ -1116,7 +1111,7 @@ internal class Compiler(private val rootModule: Module,
translate(assignA) translate(assignA)
translate(assignY) translate(assignY)
} }
DataType.UWORD, DataType.WORD -> { in WordDatatypes -> {
translate(arg.first) translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD) prog.instr(Opcode.POP_REGAY_WORD)
} }
@ -1249,43 +1244,43 @@ internal class Compiler(private val rootModule: Module,
} }
"&" -> { "&" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITAND_BYTE in ByteDatatypes -> Opcode.BITAND_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITAND_WORD in WordDatatypes -> Opcode.BITAND_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"|" -> { "|" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITOR_BYTE in ByteDatatypes -> Opcode.BITOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITOR_WORD in WordDatatypes -> Opcode.BITOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"^" -> { "^" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITXOR_BYTE in ByteDatatypes -> Opcode.BITXOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITXOR_WORD in WordDatatypes -> Opcode.BITXOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"and" -> { "and" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.AND_BYTE in ByteDatatypes -> Opcode.AND_BYTE
DataType.UWORD, DataType.WORD -> Opcode.AND_WORD in WordDatatypes -> Opcode.AND_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"or" -> { "or" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.OR_BYTE in ByteDatatypes -> Opcode.OR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.OR_WORD in WordDatatypes -> Opcode.OR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"xor" -> { "xor" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.XOR_BYTE in ByteDatatypes -> Opcode.XOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.XOR_WORD in WordDatatypes -> Opcode.XOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
@ -1331,16 +1326,16 @@ internal class Compiler(private val rootModule: Module,
} }
"==" -> { "==" -> {
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.EQUAL_BYTE in ByteDatatypes -> Opcode.EQUAL_BYTE
DataType.UWORD, DataType.WORD -> Opcode.EQUAL_WORD in WordDatatypes -> Opcode.EQUAL_WORD
DataType.FLOAT -> Opcode.EQUAL_F DataType.FLOAT -> Opcode.EQUAL_F
else -> throw CompilerException("only byte/word/lfoat possible") else -> throw CompilerException("only byte/word/lfoat possible")
} }
} }
"!=" -> { "!=" -> {
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.NOTEQUAL_BYTE in ByteDatatypes -> Opcode.NOTEQUAL_BYTE
DataType.UWORD, DataType.WORD -> Opcode.NOTEQUAL_WORD in WordDatatypes -> Opcode.NOTEQUAL_WORD
DataType.FLOAT -> Opcode.NOTEQUAL_F DataType.FLOAT -> Opcode.NOTEQUAL_F
else -> throw CompilerException("only byte/word/lfoat possible") else -> throw CompilerException("only byte/word/lfoat possible")
} }
@ -1371,8 +1366,8 @@ internal class Compiler(private val rootModule: Module,
} }
} else if(operator=="<<") { } else if(operator=="<<") {
when (leftDt) { when (leftDt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHIFTEDL_BYTE) in ByteDatatypes -> prog.instr(Opcode.SHIFTEDL_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHIFTEDL_WORD) in WordDatatypes -> prog.instr(Opcode.SHIFTEDL_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
} }
@ -1395,15 +1390,15 @@ internal class Compiler(private val rootModule: Module,
} }
"~" -> { "~" -> {
when(operandDt) { when(operandDt) {
DataType.UBYTE, DataType.BYTE -> Opcode.INV_BYTE in ByteDatatypes -> Opcode.INV_BYTE
DataType.UWORD, DataType.WORD -> Opcode.INV_WORD in WordDatatypes -> Opcode.INV_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"not" -> { "not" -> {
when(operandDt) { when(operandDt) {
DataType.UBYTE, DataType.BYTE -> Opcode.NOT_BYTE in ByteDatatypes -> Opcode.NOT_BYTE
DataType.UWORD, DataType.WORD -> Opcode.NOT_WORD in WordDatatypes -> Opcode.NOT_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
@ -1514,7 +1509,7 @@ internal class Compiler(private val rootModule: Module,
// convert value to target datatype if possible // convert value to target datatype if possible
// @todo use convertType()???? // @todo use convertType()????
when(targetDt) { when(targetDt) {
DataType.UBYTE, DataType.BYTE -> in ByteDatatypes ->
if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE) if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE)
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.WORD -> { DataType.WORD -> {
@ -1550,9 +1545,9 @@ internal class Compiler(private val rootModule: Module,
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
} }
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
null -> throw CompilerException("could not determine targetdt") else -> throw CompilerException("weird/unknonwn targetdt")
} }
} }
@ -1787,9 +1782,7 @@ internal class Compiler(private val rootModule: Module,
val numElements: Int val numElements: Int
when(iterableValue.type) { when(iterableValue.type) {
DataType.UBYTE, DataType.BYTE, !in IterableDatatypes -> throw CompilerException("non-iterableValue type")
DataType.UWORD, DataType.WORD,
DataType.FLOAT -> throw CompilerException("non-iterableValue type")
DataType.STR_P, DataType.STR_PS -> throw CompilerException("can't iterate string type ${iterableValue.type}") DataType.STR_P, DataType.STR_PS -> throw CompilerException("can't iterate string type ${iterableValue.type}")
DataType.STR, DataType.STR_S -> { DataType.STR, DataType.STR_S -> {
numElements = iterableValue.strvalue(heap).length numElements = iterableValue.strvalue(heap).length
@ -1804,6 +1797,7 @@ internal class Compiler(private val rootModule: Module,
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize
if(numElements>255) throw CompilerException("string length > 255") if(numElements>255) throw CompilerException("string length > 255")
} }
else -> throw CompilerException("weird datatype")
} }
if(loop.loopRegister!=null && loop.loopRegister==Register.X) if(loop.loopRegister!=null && loop.loopRegister==Register.X)
@ -2053,8 +2047,8 @@ internal class Compiler(private val rootModule: Module,
} }
// TODO: optimize this to use a compare + branch opcode somehow? // TODO: optimize this to use a compare + branch opcode somehow?
val conditionJumpOpcode = when(targetStatement!!.datatype) { val conditionJumpOpcode = when(targetStatement!!.datatype) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget") else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)
@ -2105,8 +2099,8 @@ internal class Compiler(private val rootModule: Module,
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.condition) translate(stmt.condition)
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)
@ -2142,8 +2136,8 @@ internal class Compiler(private val rootModule: Module,
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.untilCondition) translate(stmt.untilCondition)
val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JZ in ByteDatatypes -> Opcode.JZ
DataType.UWORD, DataType.WORD -> Opcode.JZW in WordDatatypes -> Opcode.JZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)

View File

@ -20,8 +20,8 @@ abstract class Zeropage(protected val options: CompilationOptions) {
val size = val size =
when (datatype) { when (datatype) {
DataType.UBYTE, DataType.BYTE -> 1 in ByteDatatypes -> 1
DataType.UWORD, DataType.WORD -> 2 in WordDatatypes -> 2
DataType.FLOAT -> { DataType.FLOAT -> {
if (options.floats) { if (options.floats) {
if(position!=null) if(position!=null)

View File

@ -389,20 +389,20 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
when(decl.type) { when(decl.type) {
VarDeclType.VAR -> { VarDeclType.VAR -> {
val value = when(decl.datatype) { val value = when(decl.datatype) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!) in NumericDatatypes -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
val litval = (decl.value as LiteralValue) val litval = (decl.value as LiteralValue)
if(litval.heapId==null) if(litval.heapId==null)
throw CompilerException("string should already be in the heap") throw CompilerException("string should already be in the heap")
Value(decl.datatype, litval.heapId) Value(decl.datatype, litval.heapId)
} }
DataType.ARRAY_B, DataType.ARRAY_W, in ArrayDatatypes -> {
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> {
val litval = (decl.value as LiteralValue) val litval = (decl.value as LiteralValue)
if(litval.heapId==null) if(litval.heapId==null)
throw CompilerException("array should already be in the heap") throw CompilerException("array should already be in the heap")
Value(decl.datatype, litval.heapId) Value(decl.datatype, litval.heapId)
} }
else -> throw CompilerException("weird datatype")
} }
currentBlock.variables[scopedname] = value currentBlock.variables[scopedname] = value
if(decl.zeropage) if(decl.zeropage)

View File

@ -79,8 +79,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun numericValue(): Number { fun numericValue(): Number {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> byteval!! in ByteDatatypes -> byteval!!
DataType.UWORD, DataType.WORD -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> floatval!! DataType.FLOAT -> floatval!!
else -> throw ValueException("invalid datatype for numeric value: $type") else -> throw ValueException("invalid datatype for numeric value: $type")
} }
@ -88,8 +88,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun integerValue(): Int { fun integerValue(): Int {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> byteval!!.toInt() in ByteDatatypes -> byteval!!.toInt()
DataType.UWORD, DataType.WORD -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> throw ValueException("float to integer loss of precision") DataType.FLOAT -> throw ValueException("float to integer loss of precision")
else -> throw ValueException("invalid datatype for integer value: $type") else -> throw ValueException("invalid datatype for integer value: $type")
} }
@ -393,8 +393,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun msb(): Value { fun msb(): Value {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> Value(DataType.UBYTE, 0) in ByteDatatypes -> Value(DataType.UBYTE, 0)
DataType.UWORD, DataType.WORD -> Value(DataType.UBYTE, wordval!! ushr 8 and 255) in WordDatatypes -> Value(DataType.UBYTE, wordval!! ushr 8 and 255)
else -> throw ValueException("msb can only work on (u)byte/(u)word") else -> throw ValueException("msb can only work on (u)byte/(u)word")
} }
} }
@ -428,7 +428,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
} }
DataType.UWORD -> { DataType.UWORD -> {
when (targetType) { when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255) in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> this DataType.UWORD -> this
DataType.WORD -> { DataType.WORD -> {
if(integerValue()<=32767) if(integerValue()<=32767)
@ -442,7 +442,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
} }
DataType.WORD -> { DataType.WORD -> {
when (targetType) { when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255) in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535) DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
DataType.WORD -> this DataType.WORD -> this
DataType.FLOAT -> Value(DataType.FLOAT, numericValue()) DataType.FLOAT -> Value(DataType.FLOAT, numericValue())

View File

@ -78,7 +78,7 @@ val BuiltinFunctions = mapOf(
"memset" to FunctionSignature(false, listOf( "memset" to FunctionSignature(false, listOf(
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)), BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)),
BuiltinFunctionParam("bytevalue", setOf(DataType.UBYTE, DataType.BYTE))), null), BuiltinFunctionParam("bytevalue", ByteDatatypes)), null),
"memsetw" to FunctionSignature(false, listOf( "memsetw" to FunctionSignature(false, listOf(
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("numwords", setOf(DataType.UWORD)), BuiltinFunctionParam("numwords", setOf(DataType.UWORD)),
@ -126,14 +126,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
if(arglist is IdentifierReference) { if(arglist is IdentifierReference) {
val dt = arglist.resultingDatatype(namespace, heap) val dt = arglist.resultingDatatype(namespace, heap)
return when(dt) { return when(dt) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT, in NumericDatatypes -> dt!!
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt in StringDatatypes -> dt!!
DataType.ARRAY_UB -> DataType.UBYTE DataType.ARRAY_UB -> DataType.UBYTE
DataType.ARRAY_B -> DataType.BYTE DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
null -> throw FatalAstException("function '$function' requires one argument which is an iterable") else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
} }
} }
throw FatalAstException("function '$function' requires one argument which is an iterable") throw FatalAstException("function '$function' requires one argument which is an iterable")
@ -148,8 +148,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
"abs" -> { "abs" -> {
val dt = args.single().resultingDatatype(namespace, heap) val dt = args.single().resultingDatatype(namespace, heap)
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE in ByteDatatypes -> DataType.UBYTE
DataType.UWORD, DataType.WORD -> DataType.UWORD in WordDatatypes -> DataType.UWORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("weird datatype passed to abs $dt") else -> throw FatalAstException("weird datatype passed to abs $dt")
} }
@ -157,13 +157,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
"max", "min" -> { "max", "min" -> {
val dt = datatypeFromIterableArg(args.single()) val dt = datatypeFromIterableArg(args.single())
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> dt in NumericDatatypes -> dt
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UBYTE in StringDatatypes -> DataType.UBYTE
DataType.ARRAY_UB -> DataType.UBYTE DataType.ARRAY_UB -> DataType.UBYTE
DataType.ARRAY_B -> DataType.BYTE DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
else -> null
} }
} }
"sum" -> { "sum" -> {
@ -175,7 +176,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UWORD in StringDatatypes -> DataType.UWORD
else -> null
} }
} }
"len" -> { "len" -> {
@ -325,15 +327,14 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
throw CompilerException("array length exceeds byte limit ${argument.position}") throw CompilerException("array length exceeds byte limit ${argument.position}")
LiteralValue.optimalInteger(arraySize, args[0].position) LiteralValue.optimalInteger(arraySize, args[0].position)
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
val str = argument.strvalue(heap) val str = argument.strvalue(heap)
if(str.length>255) if(str.length>255)
throw CompilerException("string length exceeds byte limit ${argument.position}") throw CompilerException("string length exceeds byte limit ${argument.position}")
LiteralValue.optimalInteger(str.length, args[0].position) LiteralValue.optimalInteger(str.length, args[0].position)
} }
DataType.UBYTE, DataType.BYTE, in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
DataType.UWORD, DataType.WORD, else -> throw CompilerException("weird datatype")
DataType.FLOAT -> throw SyntaxError("len of weird argument ${args[0]}", position)
} }
} }

View File

@ -1,6 +1,7 @@
package prog8.stackvm package prog8.stackvm
import prog8.ast.DataType import prog8.ast.DataType
import prog8.ast.NumericDatatypes
import prog8.ast.Position import prog8.ast.Position
import prog8.ast.unescape import prog8.ast.unescape
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
@ -103,7 +104,8 @@ class Program (val name: String,
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray() val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
heap.add(it.second, doublearray) heap.add(it.second, doublearray)
} }
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("invalid heap value type ${it.second}") in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}")
else -> throw VmExecutionException("weird datatype")
} }
} }
} }

View File

@ -4,7 +4,10 @@ import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.empty import org.hamcrest.Matchers.empty
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.ByteDatatypes
import prog8.ast.DataType import prog8.ast.DataType
import prog8.ast.IterableDatatypes
import prog8.ast.WordDatatypes
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.compiler.intermediate.Instruction import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Opcode
@ -1234,12 +1237,11 @@ class TestStackVmOpcodes {
private fun pushOpcode(dt: DataType): Opcode { private fun pushOpcode(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE in ByteDatatypes -> Opcode.PUSH_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD in WordDatatypes -> Opcode.PUSH_WORD
in IterableDatatypes -> Opcode.PUSH_WORD
DataType.FLOAT -> Opcode.PUSH_FLOAT DataType.FLOAT -> Opcode.PUSH_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw IllegalArgumentException("invalid datatype")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
} }
} }

View File

@ -5,7 +5,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/build" /> <excludeFolder url="file://$MODULE_DIR$/build" />
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.7 (py3)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -321,6 +321,11 @@ be set to zero only for the first run of the program. A second run will utilize
where it left off (but your code will be a bit smaller because no initialization instructions where it left off (but your code will be a bit smaller because no initialization instructions
are generated) are generated)
.. caution::
variables that get allocated in zero-page will *not* have a zero starting value when you omit
the variable's initialization. They'll be whatever the last value in that zero page
location was. So it's best to don't depend on the uninitialized starting value!
.. warning:: .. warning::
this behavior may change in a future version so that subsequent runs always this behavior may change in a future version so that subsequent runs always
use the same initial values use the same initial values
@ -462,11 +467,7 @@ There are various built-in functions such as sin(), cos(), min(), max() that can
You can also reference idendifiers defined elsewhere in your code. You can also reference idendifiers defined elsewhere in your code.
.. attention:: .. attention::
**Data type conversion (during calculations) and floating point handling:** **Floating points used in expressions:**
BYTE values used in arithmetic expressions (calculations) will be automatically converted into WORD values
if the calculation needs that to store the resulting value. Once a WORD value is used, all other results will be WORDs as well
(there's no automatic conversion of WORD into BYTE).
When a floating point value is used in a calculation, the result will be a floating point, and byte or word values When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating
@ -494,6 +495,28 @@ Usually the normal precedence rules apply (``*`` goes before ``+`` etc.) but sub
within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20, within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20,
and ``(true or false) and false`` is false instead of true. and ``(true or false) and false`` is false instead of true.
.. attention::
**calculations keep their datatype:**
When you do calculations on a BYTE type, the result will remain a BYTE.
When you do calculations on a WORD type, the result will remain a WORD.
For instance::
byte b = 44
word w = b*55 ; the result will be 116! (even though the target variable is a word)
w *= 999 ; the result will be -15188 (the multiplication stays within a word)
The compiler will NOT give a warning about this! It's doing this for
performance reasons - so you won't get sudden 16 bit (or even float)
calculations where you needed only simple fast byte arithmetic.
If you do need the extended resulting value, cast at least one of the
operands of an operator to the larger datatype. For example::
byte b = 44
word w = b*55.w ; the result will be 2420
w = (b as word)*55 ; same result
Subroutines Subroutines
----------- -----------

View File

@ -10,15 +10,24 @@
memset(sieve, 256, false) ; clear the sieve memset(sieve, 256, false) ; clear the sieve
; calculate primes ; calculate primes
; @todo fix this, it misses some primes....
c64scr.print("prime numbers up to 255:\n\n") c64scr.print("prime numbers up to 255:\n\n")
ubyte amount
while true { while true {
ubyte prime = find_next_prime() ubyte prime = find_next_prime()
if prime==0 if prime==0
break break
c64scr.print_ub(prime) c64scr.print_ub(prime)
c64scr.print(", ") c64scr.print(", ")
amount++
} }
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print("amount of primes: ")
c64scr.print_ub(amount)
c64.CHROUT('\n')
} }

View File

@ -5,53 +5,38 @@
; @todo test memset/memcopy (there's a bug in memcopy?) ; @todo test memset/memcopy (there's a bug in memcopy?)
; @todo see looplabelproblem.p8 ; @todo see problem in looplabelproblem.p8
; @todo fix primes.p8 (it misses some primes)
sub start() { sub start() {
ubyte xx
c64scr.print_ub(X) uword ypos=4
byte bb=44
byte bb2
word ww=4444
word ww2
bb2 = bb*55
ww2 = ww*55
ww2 = bb * 55.w ; @todo why is this resulting in a byte?
ypos += 5000 ; @todo fix "cannot assign word to uword"
c64scr.print_w(ww2)
c64.CHROUT('\n')
ww2 = (bb as word)*55
c64scr.print_w(ww2)
c64.CHROUT('\n') c64.CHROUT('\n')
A=c64scr.getchr(20,1) ;
c64scr.print_ub(A) ; memset($0400+(ypos+0)*40, 40, 1)
c64.CHROUT('\n') ; memset($0400+(ypos+1)*40, 40, 2)
xx=c64scr.getchr(20,1) ; memset($0400+(ypos+2)*40, 40, 3)
c64scr.print_ub(xx) ; memset($0400+(ypos+3)*40, 40, 4)
c64.CHROUT('\n')
c64scr.print_ub(X)
c64.CHROUT('\n')
A=1+c64scr.getchr(20,1)
c64scr.print_ub(A)
c64.CHROUT('\n')
xx=1+c64scr.getchr(20,1)
c64scr.print_ub(xx)
c64.CHROUT('\n')
c64scr.print_ub(X)
c64.CHROUT('\n')
A=c64scr.getchr(20,1)+1
c64scr.print_ub(A)
c64.CHROUT('\n')
xx=c64scr.getchr(20,1)+1
c64scr.print_ub(xx)
c64.CHROUT('\n')
c64scr.print_ub(X)
c64.CHROUT('\n')
;memsetw($0400+(ypos+1)*40, 20, $4455)
;memsetw($0400+(ypos+3)*40, 20, $4455)
} }
asmsub asm_routine(ubyte arg1 @ A, ubyte arg2 @ Y) -> clobbers() -> (ubyte @ A) {
return A+Y
}
sub drawNext(ubyte x) {
A=x
}
sub drawNextW(uword w) {
w++
}
} }