mirror of
https://github.com/irmen/prog8.git
synced 2024-09-29 08:57:51 +00:00
improve datatype assignment checks
This commit is contained in:
parent
c40fc584d6
commit
48a6a05109
@ -10,19 +10,23 @@
|
|||||||
ubyte secretnumber = 0
|
ubyte secretnumber = 0
|
||||||
ubyte attempts_left = 10
|
ubyte attempts_left = 10
|
||||||
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
||||||
|
uword testword
|
||||||
|
|
||||||
|
testword = guess ; @todo fix str addrss
|
||||||
|
testword = "sadfsafsdf" ; @todo fix str address
|
||||||
|
secretnumber = "\n" ; @todo fix argument conversion to UBYTE
|
||||||
c64utils.init_system()
|
c64utils.init_system()
|
||||||
c64.VMCSB |= 2 ; activate lowercase charset
|
c64.VMCSB |= 2 ; activate lowercase charset
|
||||||
|
|
||||||
; greeting
|
; greeting
|
||||||
c64scr.print_string("Enter your name: ")
|
c64scr.print_string("Enter your name: ")
|
||||||
Y = c64scr.input_chars(name) ; @todo fix argument type check
|
Y = c64scr.input_chars(name)
|
||||||
c64.CHROUT("\n") ; @todo fix argument type check
|
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
|
||||||
c64.CHROUT("\n")
|
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
|
||||||
c64scr.print_string("Hello, ")
|
c64scr.print_string("Hello, ")
|
||||||
c64scr.print_string(name)
|
c64scr.print_string(name)
|
||||||
c64.CHROUT(".")
|
c64.CHROUT(".") ; @todo fix argument conversion to UBYTE
|
||||||
c64.CHROUT("\n")
|
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
|
||||||
|
|
||||||
; create a secret random number from 1-100
|
; create a secret random number from 1-100
|
||||||
c64.RNDA(0) ; fac = rnd(0)
|
c64.RNDA(0) ; fac = rnd(0)
|
||||||
@ -30,7 +34,7 @@
|
|||||||
c64.MUL10() ; .. and now *100
|
c64.MUL10() ; .. and now *100
|
||||||
c64.FADDH() ; add 0.5..
|
c64.FADDH() ; add 0.5..
|
||||||
c64.FADDH() ; and again, so +1 total
|
c64.FADDH() ; and again, so +1 total
|
||||||
A, Y = c64flt.GETADRAY()
|
A, Y = c64flt.GETADRAY() ; @todo fix return value type check
|
||||||
secretnumber = A
|
secretnumber = A
|
||||||
;A=math.randbyte()
|
;A=math.randbyte()
|
||||||
;A+=c64.RASTER
|
;A+=c64.RASTER
|
||||||
@ -47,10 +51,10 @@ ask_guess:
|
|||||||
|
|
||||||
c64scr.print_string(" left.\nWhat is your next guess? ")
|
c64scr.print_string(" left.\nWhat is your next guess? ")
|
||||||
Y = c64scr.input_chars(guess)
|
Y = c64scr.input_chars(guess)
|
||||||
c64.CHROUT("\n")
|
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
|
||||||
freadstr_arg = guess
|
freadstr_arg = guess ; @todo put string's adress in uword variable
|
||||||
c64.FREADSTR(A)
|
c64.FREADSTR(A)
|
||||||
A, Y = c64flt.GETADRAY()
|
A, Y = c64flt.GETADRAY() ; @todo fix return value type check
|
||||||
if(A==secretnumber) {
|
if(A==secretnumber) {
|
||||||
c64scr.print_string("\nThat's my number, impressive!\n")
|
c64scr.print_string("\nThat's my number, impressive!\n")
|
||||||
goto goodbye
|
goto goodbye
|
||||||
@ -68,7 +72,7 @@ ask_guess:
|
|||||||
; game over.
|
; game over.
|
||||||
c64scr.print_string("\nToo bad! It was: ")
|
c64scr.print_string("\nToo bad! It was: ")
|
||||||
c64scr.print_byte_decimal(secretnumber)
|
c64scr.print_byte_decimal(secretnumber)
|
||||||
c64.CHROUT("\n")
|
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
|
||||||
|
|
||||||
goodbye:
|
goodbye:
|
||||||
c64scr.print_string("\nThanks for playing. Bye!\n")
|
c64scr.print_string("\nThanks for playing. Bye!\n")
|
||||||
|
@ -16,6 +16,27 @@ sub start() {
|
|||||||
byte b1
|
byte b1
|
||||||
|
|
||||||
|
|
||||||
|
str stringvar = "??????????"
|
||||||
|
ubyte secretnumber = 0
|
||||||
|
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
||||||
|
uword testword
|
||||||
|
ubyte char1 = "@"
|
||||||
|
ubyte char2 = "\n" ; @todo escapechar
|
||||||
|
ubyte char3 = "\t" ; @todo escapechar
|
||||||
|
|
||||||
|
;testword = stringvar ; @todo fix str address
|
||||||
|
;testword = "sadfsafsdf" ; @todo fix str address
|
||||||
|
testword = "@" ; @todo fix argument conversion to UBYTE
|
||||||
|
testword = "\n" ; @todo fix argument conversion to UBYTE (escapechar)
|
||||||
|
;freadstr_arg = stringvar
|
||||||
|
;freadstr_arg = "asdfasdfasdfasdf"
|
||||||
|
freadstr_arg = "@" ; @todo fix argument conversion to UBYTE
|
||||||
|
freadstr_arg = "\n" ; @todo fix argument conversion to UBYTE (escapechar)
|
||||||
|
secretnumber = "@" ; @todo fix argument conversion to UBYTE
|
||||||
|
secretnumber = "\n" ; @todo fix argument conversion to UBYTE (escapechar)
|
||||||
|
;secretnumber = "asdfsdf"
|
||||||
|
|
||||||
|
|
||||||
address =c64.MEMBOT(1, 40000.w) ; ok!
|
address =c64.MEMBOT(1, 40000.w) ; ok!
|
||||||
address =c64.MEMBOT(1, address) ; ok!
|
address =c64.MEMBOT(1, address) ; ok!
|
||||||
address =c64.MEMBOT(1, memaddr) ; ok!
|
address =c64.MEMBOT(1, memaddr) ; ok!
|
||||||
|
@ -30,7 +30,25 @@ enum class DataType {
|
|||||||
ARRAY_B,
|
ARRAY_B,
|
||||||
ARRAY_UW,
|
ARRAY_UW,
|
||||||
ARRAY_W,
|
ARRAY_W,
|
||||||
ARRAY_F
|
ARRAY_F;
|
||||||
|
|
||||||
|
fun assignableTo(type: DataType) =
|
||||||
|
when(this) {
|
||||||
|
UBYTE -> type in NumericDatatypes
|
||||||
|
BYTE -> type in NumericDatatypes
|
||||||
|
UWORD -> type in NumericDatatypes
|
||||||
|
WORD -> type in NumericDatatypes
|
||||||
|
FLOAT -> type in NumericDatatypes
|
||||||
|
STR -> type == STR || type==STR_S || type == UWORD
|
||||||
|
STR_P -> type == STR_P || type==STR_PS || type == UWORD
|
||||||
|
STR_S -> type == STR || type==STR_S || type == UWORD
|
||||||
|
STR_PS -> type == STR_P || type==STR_PS || type == UWORD
|
||||||
|
ARRAY_UB -> type == UWORD
|
||||||
|
ARRAY_B -> type == UWORD
|
||||||
|
ARRAY_UW -> type == UWORD
|
||||||
|
ARRAY_W -> type == UWORD
|
||||||
|
ARRAY_F -> type == UWORD
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Register {
|
enum class Register {
|
||||||
@ -948,11 +966,12 @@ class LiteralValue(val type: DataType,
|
|||||||
val bytevalue: Short? = null,
|
val bytevalue: Short? = null,
|
||||||
val wordvalue: Int? = null,
|
val wordvalue: Int? = null,
|
||||||
val floatvalue: Double? = null,
|
val floatvalue: Double? = null,
|
||||||
val strvalue: String? = null,
|
strvalue: String? = null,
|
||||||
val arrayvalue: Array<IExpression>? = null,
|
val arrayvalue: Array<IExpression>? = null,
|
||||||
val heapId: Int? =null,
|
val heapId: Int? =null,
|
||||||
override val position: Position) : IExpression {
|
override val position: Position) : IExpression {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
private val initialstrvalue = strvalue
|
||||||
|
|
||||||
override fun referencesIdentifier(name: String) = arrayvalue?.any { it.referencesIdentifier(name) } ?: false
|
override fun referencesIdentifier(name: String) = arrayvalue?.any { it.referencesIdentifier(name) } ?: false
|
||||||
|
|
||||||
@ -1004,12 +1023,12 @@ class LiteralValue(val type: DataType,
|
|||||||
DataType.UWORD, DataType.WORD -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
|
DataType.UWORD, DataType.WORD -> 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(strvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
||||||
in ArrayDatatypes ->
|
in ArrayDatatypes ->
|
||||||
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
||||||
else -> throw FatalAstException("invalid type $type")
|
else -> throw FatalAstException("invalid type $type")
|
||||||
}
|
}
|
||||||
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && strvalue==null && heapId==null)
|
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && initialstrvalue==null && heapId==null)
|
||||||
throw FatalAstException("literal value without actual value")
|
throw FatalAstException("literal value without actual value")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,7 +1050,7 @@ class LiteralValue(val type: DataType,
|
|||||||
(floatvalue!=null && floatvalue != 0.0) ||
|
(floatvalue!=null && floatvalue != 0.0) ||
|
||||||
(bytevalue!=null && bytevalue != 0.toShort()) ||
|
(bytevalue!=null && bytevalue != 0.toShort()) ||
|
||||||
(wordvalue!=null && wordvalue != 0) ||
|
(wordvalue!=null && wordvalue != 0) ||
|
||||||
(strvalue!=null && strvalue.isNotEmpty()) ||
|
(initialstrvalue!=null && initialstrvalue.isNotEmpty()) ||
|
||||||
(arrayvalue != null && arrayvalue.isNotEmpty())
|
(arrayvalue != null && arrayvalue.isNotEmpty())
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
@ -1051,7 +1070,7 @@ class LiteralValue(val type: DataType,
|
|||||||
DataType.FLOAT -> "float:$floatvalue"
|
DataType.FLOAT -> "float:$floatvalue"
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS-> {
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS-> {
|
||||||
if(heapId!=null) "str:#$heapId"
|
if(heapId!=null) "str:#$heapId"
|
||||||
else "str:$strvalue"
|
else "str:$initialstrvalue"
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> {
|
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> {
|
||||||
if(heapId!=null) "arrayspec:#$heapId"
|
if(heapId!=null) "arrayspec:#$heapId"
|
||||||
@ -1069,7 +1088,7 @@ class LiteralValue(val type: DataType,
|
|||||||
val bh = bytevalue?.hashCode() ?: 0x10001234
|
val bh = bytevalue?.hashCode() ?: 0x10001234
|
||||||
val wh = wordvalue?.hashCode() ?: 0x01002345
|
val wh = wordvalue?.hashCode() ?: 0x01002345
|
||||||
val fh = floatvalue?.hashCode() ?: 0x00103456
|
val fh = floatvalue?.hashCode() ?: 0x00103456
|
||||||
val sh = strvalue?.hashCode() ?: 0x00014567
|
val sh = initialstrvalue?.hashCode() ?: 0x00014567
|
||||||
val ah = arrayvalue?.hashCode() ?: 0x11119876
|
val ah = arrayvalue?.hashCode() ?: 0x11119876
|
||||||
var hash = bh * 31 xor wh
|
var hash = bh * 31 xor wh
|
||||||
hash = hash*31 xor fh
|
hash = hash*31 xor fh
|
||||||
@ -1091,8 +1110,8 @@ class LiteralValue(val type: DataType,
|
|||||||
if(numLeft!=null && numRight!=null)
|
if(numLeft!=null && numRight!=null)
|
||||||
return numLeft.compareTo(numRight)
|
return numLeft.compareTo(numRight)
|
||||||
|
|
||||||
if(strvalue!=null && other.strvalue!=null)
|
if(initialstrvalue!=null && other.initialstrvalue!=null)
|
||||||
return strvalue.compareTo(other.strvalue)
|
return initialstrvalue.compareTo(other.initialstrvalue)
|
||||||
|
|
||||||
throw ExpressionError("cannot compare type $type with ${other.type}", other.position)
|
throw ExpressionError("cannot compare type $type with ${other.type}", other.position)
|
||||||
}
|
}
|
||||||
@ -1160,6 +1179,12 @@ class LiteralValue(val type: DataType,
|
|||||||
}
|
}
|
||||||
return null // invalid type conversion from $this to $targettype
|
return null // invalid type conversion from $this to $targettype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun strvalue(heap: HeapValues): String {
|
||||||
|
if(initialstrvalue!=null)
|
||||||
|
return initialstrvalue
|
||||||
|
return heap.get(heapId!!).str!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1200,15 +1225,15 @@ class RangeExpr(var from: IExpression,
|
|||||||
return "RangeExpr(from $from, to $to, step $step, pos=$position)"
|
return "RangeExpr(from $from, to $to, step $step, pos=$position)"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun size(): Int? {
|
fun size(heap: HeapValues): Int? {
|
||||||
val fromLv = (from as? LiteralValue)
|
val fromLv = (from as? LiteralValue)
|
||||||
val toLv = (to as? LiteralValue)
|
val toLv = (to as? LiteralValue)
|
||||||
if(fromLv==null || toLv==null)
|
if(fromLv==null || toLv==null)
|
||||||
return null
|
return null
|
||||||
return toConstantIntegerRange()?.count()
|
return toConstantIntegerRange(heap)?.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toConstantIntegerRange(): IntProgression? {
|
fun toConstantIntegerRange(heap: HeapValues): IntProgression? {
|
||||||
val fromLv = from as? LiteralValue
|
val fromLv = from as? LiteralValue
|
||||||
val toLv = to as? LiteralValue
|
val toLv = to as? LiteralValue
|
||||||
if(fromLv==null || toLv==null)
|
if(fromLv==null || toLv==null)
|
||||||
@ -1217,8 +1242,8 @@ class RangeExpr(var from: IExpression,
|
|||||||
val toVal: Int
|
val toVal: Int
|
||||||
if(fromLv.isString && toLv.isString) {
|
if(fromLv.isString && toLv.isString) {
|
||||||
// string range -> int range over petscii values
|
// string range -> int range over petscii values
|
||||||
fromVal = Petscii.encodePetscii(fromLv.strvalue!!, true)[0].toInt()
|
fromVal = Petscii.encodePetscii(fromLv.strvalue(heap), true)[0].toInt()
|
||||||
toVal = Petscii.encodePetscii(toLv.strvalue!!, true)[0].toInt()
|
toVal = Petscii.encodePetscii(toLv.strvalue(heap), true)[0].toInt()
|
||||||
} else {
|
} else {
|
||||||
// integer range
|
// integer range
|
||||||
fromVal = (from as LiteralValue).asIntegerValue!!
|
fromVal = (from as LiteralValue).asIntegerValue!!
|
||||||
|
@ -635,14 +635,16 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
else if(from.asIntegerValue > to.asIntegerValue && step>=0)
|
else if(from.asIntegerValue > to.asIntegerValue && step>=0)
|
||||||
err("descending range requires step < 0")
|
err("descending range requires step < 0")
|
||||||
}
|
}
|
||||||
from.strvalue!=null && to.strvalue!=null -> {
|
from.isString && to.isString -> {
|
||||||
if(from.strvalue.length!=1 || to.strvalue.length!=1)
|
val fromString = from.strvalue(heap)
|
||||||
|
val toString = to.strvalue(heap)
|
||||||
|
if(fromString.length!=1 || toString.length!=1)
|
||||||
err("range from and to must be a single character")
|
err("range from and to must be a single character")
|
||||||
if(from.strvalue[0] == to.strvalue[0])
|
if(fromString[0] == toString[0])
|
||||||
printWarning("range contains just a single character", range.position)
|
printWarning("range contains just a single character", range.position)
|
||||||
else if(from.strvalue[0] < to.strvalue[0] && step<=0)
|
else if(fromString[0] < toString[0] && step<=0)
|
||||||
err("ascending range requires step > 0")
|
err("ascending range requires step > 0")
|
||||||
else if(from.strvalue[0] > to.strvalue[0] && step>=0)
|
else if(fromString[0] > toString[0] && step>=0)
|
||||||
err("descending range requires step < 0")
|
err("descending range requires step < 0")
|
||||||
}
|
}
|
||||||
else -> err("range expression must be over integers or over characters")
|
else -> err("range expression must be over integers or over characters")
|
||||||
@ -683,7 +685,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
else {
|
else {
|
||||||
for (arg in args.withIndex().zip(func.parameters)) {
|
for (arg in args.withIndex().zip(func.parameters)) {
|
||||||
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
|
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
|
||||||
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
|
checkResult.add(ExpressionError("builtin function argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(target is Subroutine) {
|
} else if(target is Subroutine) {
|
||||||
@ -691,8 +693,9 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
checkResult.add(SyntaxError("invalid number of arguments", position))
|
checkResult.add(SyntaxError("invalid number of arguments", position))
|
||||||
else {
|
else {
|
||||||
for (arg in args.withIndex().zip(target.parameters)) {
|
for (arg in args.withIndex().zip(target.parameters)) {
|
||||||
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)
|
val argDt = arg.first.value.resultingDatatype(namespace, heap)
|
||||||
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
|
if(argDt!=null && !argDt.assignableTo(arg.second.type))
|
||||||
|
checkResult.add(ExpressionError("subroutine argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
|
||||||
|
|
||||||
if(target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {
|
if(target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {
|
||||||
if(arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
|
if(arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
|
||||||
@ -787,7 +790,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
checkResult.add(ExpressionError("range for string must have single characters from and to values", range.position))
|
checkResult.add(ExpressionError("range for string must have single characters from and to values", range.position))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
val rangeSize=range.size()
|
val rangeSize=range.size(heap)
|
||||||
if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
|
if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
|
||||||
checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
|
checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
|
||||||
return false
|
return false
|
||||||
@ -797,7 +800,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
in ArrayDatatypes -> {
|
in ArrayDatatypes -> {
|
||||||
// range and length check bytes
|
// range and length check bytes
|
||||||
val expectedSize = arrayspec!!.size()
|
val expectedSize = arrayspec!!.size()
|
||||||
val rangeSize=range.size()
|
val rangeSize=range.size(heap)
|
||||||
if(rangeSize!=null && rangeSize != expectedSize) {
|
if(rangeSize!=null && rangeSize != expectedSize) {
|
||||||
checkResult.add(ExpressionError("range size doesn't match array size, expected $expectedSize found $rangeSize", range.position))
|
checkResult.add(ExpressionError("range size doesn't match array size, expected $expectedSize found $rangeSize", range.position))
|
||||||
return false
|
return false
|
||||||
@ -859,7 +862,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||||
if(!value.isString)
|
if(!value.isString)
|
||||||
return err("string value expected")
|
return err("string value expected")
|
||||||
val str = value.strvalue ?: heap.get(value.heapId!!).str!!
|
val str = value.strvalue(heap)
|
||||||
if (str.length > 255)
|
if (str.length > 255)
|
||||||
return err("string length must be 0-255")
|
return err("string length must be 0-255")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package prog8.compiler
|
package prog8.compiler
|
||||||
|
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.ast.RegisterOrPair.*
|
import prog8.ast.RegisterOrPair.*
|
||||||
import prog8.compiler.intermediate.IntermediateProgram
|
import prog8.compiler.intermediate.IntermediateProgram
|
||||||
@ -1470,7 +1469,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(loop.iterable is RangeExpr) {
|
if(loop.iterable is RangeExpr) {
|
||||||
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
|
val range = (loop.iterable as RangeExpr).toConstantIntegerRange(heap)
|
||||||
if(range!=null) {
|
if(range!=null) {
|
||||||
// loop over a range with constant start, last and step values
|
// loop over a range with constant start, last and step values
|
||||||
if (range.isEmpty())
|
if (range.isEmpty())
|
||||||
@ -1536,7 +1535,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
DataType.STR_P,
|
DataType.STR_P,
|
||||||
DataType.STR_S,
|
DataType.STR_S,
|
||||||
DataType.STR_PS -> {
|
DataType.STR_PS -> {
|
||||||
numElements = iterableValue.strvalue?.length ?: heap.get(iterableValue.heapId!!).str!!.length
|
numElements = iterableValue.strvalue(heap).length
|
||||||
if(numElements>255) throw CompilerException("string length > 255")
|
if(numElements>255) throw CompilerException("string length > 255")
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B,
|
DataType.ARRAY_UB, DataType.ARRAY_B,
|
||||||
|
@ -345,7 +345,7 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
|
|||||||
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position)
|
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position)
|
||||||
}
|
}
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||||
val str = argument.strvalue ?: heap.get(argument.heapId!!).str!!
|
val str = argument.strvalue(heap)
|
||||||
LiteralValue(DataType.UWORD, wordvalue=str.length, position=args[0].position)
|
LiteralValue(DataType.UWORD, wordvalue=str.length, position=args[0].position)
|
||||||
}
|
}
|
||||||
DataType.UBYTE, DataType.BYTE,
|
DataType.UBYTE, DataType.BYTE,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package prog8.optimizing
|
package prog8.optimizing
|
||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
|
import prog8.compiler.HeapValues
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
|
||||||
@ -9,11 +10,11 @@ val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "=
|
|||||||
|
|
||||||
class ConstExprEvaluator {
|
class ConstExprEvaluator {
|
||||||
|
|
||||||
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression {
|
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue, heap: HeapValues): IExpression {
|
||||||
return when(operator) {
|
return when(operator) {
|
||||||
"+" -> plus(left, right)
|
"+" -> plus(left, right, heap)
|
||||||
"-" -> minus(left, right)
|
"-" -> minus(left, right)
|
||||||
"*" -> multiply(left, right)
|
"*" -> multiply(left, right, heap)
|
||||||
"/" -> divide(left, right)
|
"/" -> divide(left, right)
|
||||||
"//" -> floordivide(left, right)
|
"//" -> floordivide(left, right)
|
||||||
"%" -> remainder(left, right)
|
"%" -> remainder(left, right)
|
||||||
@ -141,7 +142,7 @@ class ConstExprEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun plus(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun plus(left: LiteralValue, right: LiteralValue, heap: HeapValues): LiteralValue {
|
||||||
val error = "cannot add $left and $right"
|
val error = "cannot add $left and $right"
|
||||||
return when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
@ -154,9 +155,9 @@ class ConstExprEvaluator {
|
|||||||
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue + right.floatvalue, position = left.position)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue + right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.strvalue!=null -> when {
|
left.isString -> when {
|
||||||
right.strvalue!=null -> {
|
right.isString -> {
|
||||||
val newStr = left.strvalue + right.strvalue
|
val newStr = left.strvalue(heap) + right.strvalue(heap)
|
||||||
if(newStr.length > 255) throw ExpressionError("string too long", left.position)
|
if(newStr.length > 255) throw ExpressionError("string too long", left.position)
|
||||||
LiteralValue(DataType.STR, strvalue = newStr, position = left.position)
|
LiteralValue(DataType.STR, strvalue = newStr, position = left.position)
|
||||||
}
|
}
|
||||||
@ -183,15 +184,15 @@ class ConstExprEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun multiply(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun multiply(left: LiteralValue, right: LiteralValue, heap: HeapValues): LiteralValue {
|
||||||
val error = "cannot multiply ${left.type} and ${right.type}"
|
val error = "cannot multiply ${left.type} and ${right.type}"
|
||||||
return when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue * right.asIntegerValue, left.position)
|
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue * right.asIntegerValue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue * right.floatvalue, position = left.position)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue * right.floatvalue, position = left.position)
|
||||||
right.strvalue!=null -> {
|
right.isString -> {
|
||||||
if(right.strvalue.length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
|
if(right.strvalue(heap).length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
|
||||||
LiteralValue(DataType.STR, strvalue = right.strvalue.repeat(left.asIntegerValue), position = left.position)
|
LiteralValue(DataType.STR, strvalue = right.strvalue(heap).repeat(left.asIntegerValue), position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
in IntegerDatatypes -> {
|
in IntegerDatatypes -> {
|
||||||
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to ubyte integer
|
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to ubyte integer
|
||||||
val literal = decl.value as? LiteralValue
|
val literal = decl.value as? LiteralValue
|
||||||
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
|
if (literal != null && literal.isString && literal.strvalue(heap).length == 1) {
|
||||||
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
|
val petscii = Petscii.encodePetscii(literal.strvalue(heap))[0]
|
||||||
val newValue = LiteralValue(DataType.UBYTE, bytevalue = petscii, position = literal.position)
|
val newValue = LiteralValue(DataType.UBYTE, bytevalue = petscii, position = literal.position)
|
||||||
decl.value = newValue
|
decl.value = newValue
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
return try {
|
return try {
|
||||||
val cval = identifier.constValue(namespace, heap) ?: return identifier
|
val cval = identifier.constValue(namespace, heap) ?: return identifier
|
||||||
return if(cval.isNumeric) {
|
return if(cval.isNumeric) {
|
||||||
val copy = LiteralValue(cval.type, cval.bytevalue, cval.wordvalue, cval.floatvalue, cval.strvalue, cval.arrayvalue, position = identifier.position)
|
val copy = LiteralValue(cval.type, cval.bytevalue, cval.wordvalue, cval.floatvalue, null, cval.arrayvalue, position = identifier.position)
|
||||||
copy.parent = identifier.parent
|
copy.parent = identifier.parent
|
||||||
copy
|
copy
|
||||||
} else
|
} else
|
||||||
@ -256,7 +256,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
return when {
|
return when {
|
||||||
leftconst != null && rightconst != null -> {
|
leftconst != null && rightconst != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
evaluator.evaluate(leftconst, expr.operator, rightconst)
|
evaluator.evaluate(leftconst, expr.operator, rightconst, heap)
|
||||||
}
|
}
|
||||||
else -> expr
|
else -> expr
|
||||||
}
|
}
|
||||||
@ -467,12 +467,12 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun process(literalValue: LiteralValue): LiteralValue {
|
override fun process(literalValue: LiteralValue): LiteralValue {
|
||||||
if(literalValue.strvalue!=null) {
|
if(literalValue.isString) {
|
||||||
// intern the string; move it into the heap
|
// intern the string; move it into the heap
|
||||||
if(literalValue.strvalue.length !in 1..255)
|
if(literalValue.strvalue(heap).length !in 1..255)
|
||||||
addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position))
|
addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position))
|
||||||
else {
|
else {
|
||||||
val heapId = heap.add(literalValue.type, literalValue.strvalue) // TODO: we don't know the actual string type yet, STR != STR_P etc...
|
val heapId = heap.add(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_P etc...
|
||||||
val newValue = LiteralValue(literalValue.type, heapId = heapId, position = literalValue.position)
|
val newValue = LiteralValue(literalValue.type, heapId = heapId, position = literalValue.position)
|
||||||
return super.process(newValue)
|
return super.process(newValue)
|
||||||
}
|
}
|
||||||
@ -540,7 +540,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
// see if we can promote/convert a literal value to the required datatype
|
// see if we can promote/convert a literal value to the required datatype
|
||||||
when(targetDt) {
|
when(targetDt) {
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
// we can convert to UWORD: any UBYTE, BYTE/WORD that are >=0, FLOAT that's an integer 0..65535
|
// we can convert to UWORD: any UBYTE, BYTE/WORD that are >=0, FLOAT that's an integer 0..65535,
|
||||||
|
// STR of length 1 (take the character's byte value)
|
||||||
if(lv.type==DataType.UBYTE)
|
if(lv.type==DataType.UBYTE)
|
||||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
|
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
|
||||||
else if(lv.type==DataType.BYTE && lv.bytevalue!!>=0)
|
else if(lv.type==DataType.BYTE && lv.bytevalue!!>=0)
|
||||||
@ -552,9 +553,17 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
if(floor(d)==d && d>=0 && d<=65535)
|
if(floor(d)==d && d>=0 && d<=65535)
|
||||||
assignment.value = LiteralValue(DataType.UWORD, wordvalue=floor(d).toInt(), position=lv.position)
|
assignment.value = LiteralValue(DataType.UWORD, wordvalue=floor(d).toInt(), position=lv.position)
|
||||||
}
|
}
|
||||||
|
else if(lv.type in StringDatatypes) {
|
||||||
|
val str = lv.strvalue(heap)
|
||||||
|
if(str.length==1) {
|
||||||
|
val petscii = Petscii.encodePetscii(str)[0]
|
||||||
|
assignment.value = LiteralValue(DataType.UWORD, wordvalue = petscii.toInt(), position = lv.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
// we can convert to UBYTE: UWORD <=255, BYTE >=0, FLOAT that's an integer 0..255
|
// we can convert to UBYTE: UWORD <=255, BYTE >=0, FLOAT that's an integer 0..255,
|
||||||
|
// STR of length 1 (take the character's byte value)
|
||||||
if(lv.type==DataType.UWORD && lv.wordvalue!! <= 255)
|
if(lv.type==DataType.UWORD && lv.wordvalue!! <= 255)
|
||||||
assignment.value = LiteralValue(DataType.UBYTE, lv.wordvalue.toShort(), position=lv.position)
|
assignment.value = LiteralValue(DataType.UBYTE, lv.wordvalue.toShort(), position=lv.position)
|
||||||
else if(lv.type==DataType.BYTE && lv.bytevalue!! >=0)
|
else if(lv.type==DataType.BYTE && lv.bytevalue!! >=0)
|
||||||
@ -564,6 +573,13 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
if(floor(d)==d && d >=0 && d<=255)
|
if(floor(d)==d && d >=0 && d<=255)
|
||||||
assignment.value = LiteralValue(DataType.UBYTE, floor(d).toShort(), position=lv.position)
|
assignment.value = LiteralValue(DataType.UBYTE, floor(d).toShort(), position=lv.position)
|
||||||
}
|
}
|
||||||
|
else if(lv.type in StringDatatypes) {
|
||||||
|
val str = lv.strvalue(heap)
|
||||||
|
if(str.length==1) {
|
||||||
|
val petscii = Petscii.encodePetscii(str)[0]
|
||||||
|
assignment.value = LiteralValue(DataType.UBYTE, bytevalue = petscii, position = lv.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
// we can convert to BYTE: UWORD/UBYTE <= 127, FLOAT that's an integer 0..127
|
// we can convert to BYTE: UWORD/UBYTE <= 127, FLOAT that's an integer 0..127
|
||||||
@ -578,7 +594,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
// we can convert to WORD: any UBYTE/BYTE, UWORD <= 32767, FLOAT that's an integer -32768..32767
|
// we can convert to WORD: any UBYTE/BYTE, UWORD <= 32767, FLOAT that's an integer -32768..32767,
|
||||||
|
// STR of length 1 (take the character's byte value)
|
||||||
if(lv.type==DataType.UBYTE || lv.type==DataType.BYTE)
|
if(lv.type==DataType.UBYTE || lv.type==DataType.BYTE)
|
||||||
assignment.value = LiteralValue(DataType.WORD, wordvalue=lv.bytevalue!!.toInt(), position=lv.position)
|
assignment.value = LiteralValue(DataType.WORD, wordvalue=lv.bytevalue!!.toInt(), position=lv.position)
|
||||||
else if(lv.type==DataType.UWORD && lv.wordvalue!! <= 32767)
|
else if(lv.type==DataType.UWORD && lv.wordvalue!! <= 32767)
|
||||||
@ -588,6 +605,13 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
if(floor(d)==d && d>=-32768 && d<=32767)
|
if(floor(d)==d && d>=-32768 && d<=32767)
|
||||||
assignment.value = LiteralValue(DataType.BYTE, floor(d).toShort(), position=lv.position)
|
assignment.value = LiteralValue(DataType.BYTE, floor(d).toShort(), position=lv.position)
|
||||||
}
|
}
|
||||||
|
else if(lv.type in StringDatatypes) {
|
||||||
|
val str = lv.strvalue(heap)
|
||||||
|
if(str.length==1) {
|
||||||
|
val petscii = Petscii.encodePetscii(str)[0]
|
||||||
|
assignment.value = LiteralValue(DataType.WORD, wordvalue= petscii.toInt(), position = lv.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
if(lv.isNumeric)
|
if(lv.isNumeric)
|
||||||
|
@ -102,7 +102,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
super.process(forLoop)
|
super.process(forLoop)
|
||||||
val range = forLoop.iterable as? RangeExpr
|
val range = forLoop.iterable as? RangeExpr
|
||||||
if(range!=null) {
|
if(range!=null) {
|
||||||
if(range.size()==1) {
|
if(range.size(heap)==1) {
|
||||||
// for loop over a (constant) range of just a single value-- optimize the loop away
|
// for loop over a (constant) range of just a single value-- optimize the loop away
|
||||||
// loopvar/reg = range value , follow by block
|
// loopvar/reg = range value , follow by block
|
||||||
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position)
|
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position)
|
||||||
|
Loading…
Reference in New Issue
Block a user