improve datatype assignment checks

This commit is contained in:
Irmen de Jong 2018-11-22 00:01:41 +01:00
parent c40fc584d6
commit 48a6a05109
9 changed files with 139 additions and 62 deletions

View File

@ -10,19 +10,23 @@
ubyte secretnumber = 0
ubyte attempts_left = 10
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()
c64.VMCSB |= 2 ; activate lowercase charset
; greeting
c64scr.print_string("Enter your name: ")
Y = c64scr.input_chars(name) ; @todo fix argument type check
c64.CHROUT("\n") ; @todo fix argument type check
c64.CHROUT("\n")
Y = c64scr.input_chars(name)
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
c64scr.print_string("Hello, ")
c64scr.print_string(name)
c64.CHROUT(".")
c64.CHROUT("\n")
c64.CHROUT(".") ; @todo fix argument conversion to UBYTE
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
; create a secret random number from 1-100
c64.RNDA(0) ; fac = rnd(0)
@ -30,7 +34,7 @@
c64.MUL10() ; .. and now *100
c64.FADDH() ; add 0.5..
c64.FADDH() ; and again, so +1 total
A, Y = c64flt.GETADRAY()
A, Y = c64flt.GETADRAY() ; @todo fix return value type check
secretnumber = A
;A=math.randbyte()
;A+=c64.RASTER
@ -47,10 +51,10 @@ ask_guess:
c64scr.print_string(" left.\nWhat is your next guess? ")
Y = c64scr.input_chars(guess)
c64.CHROUT("\n")
freadstr_arg = guess
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
freadstr_arg = guess ; @todo put string's adress in uword variable
c64.FREADSTR(A)
A, Y = c64flt.GETADRAY()
A, Y = c64flt.GETADRAY() ; @todo fix return value type check
if(A==secretnumber) {
c64scr.print_string("\nThat's my number, impressive!\n")
goto goodbye
@ -68,7 +72,7 @@ ask_guess:
; game over.
c64scr.print_string("\nToo bad! It was: ")
c64scr.print_byte_decimal(secretnumber)
c64.CHROUT("\n")
c64.CHROUT("\n") ; @todo fix argument conversion to UBYTE
goodbye:
c64scr.print_string("\nThanks for playing. Bye!\n")

View File

@ -16,6 +16,27 @@ sub start() {
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, address) ; ok!
address =c64.MEMBOT(1, memaddr) ; ok!

View File

@ -30,7 +30,25 @@ enum class DataType {
ARRAY_B,
ARRAY_UW,
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 {
@ -948,11 +966,12 @@ class LiteralValue(val type: DataType,
val bytevalue: Short? = null,
val wordvalue: Int? = null,
val floatvalue: Double? = null,
val strvalue: String? = null,
strvalue: String? = null,
val arrayvalue: Array<IExpression>? = null,
val heapId: Int? =null,
override val position: Position) : IExpression {
override lateinit var parent: Node
private val initialstrvalue = strvalue
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.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
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 ->
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
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")
}
@ -1031,7 +1050,7 @@ class LiteralValue(val type: DataType,
(floatvalue!=null && floatvalue != 0.0) ||
(bytevalue!=null && bytevalue != 0.toShort()) ||
(wordvalue!=null && wordvalue != 0) ||
(strvalue!=null && strvalue.isNotEmpty()) ||
(initialstrvalue!=null && initialstrvalue.isNotEmpty()) ||
(arrayvalue != null && arrayvalue.isNotEmpty())
override fun linkParents(parent: Node) {
@ -1051,7 +1070,7 @@ class LiteralValue(val type: DataType,
DataType.FLOAT -> "float:$floatvalue"
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS-> {
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 -> {
if(heapId!=null) "arrayspec:#$heapId"
@ -1069,7 +1088,7 @@ class LiteralValue(val type: DataType,
val bh = bytevalue?.hashCode() ?: 0x10001234
val wh = wordvalue?.hashCode() ?: 0x01002345
val fh = floatvalue?.hashCode() ?: 0x00103456
val sh = strvalue?.hashCode() ?: 0x00014567
val sh = initialstrvalue?.hashCode() ?: 0x00014567
val ah = arrayvalue?.hashCode() ?: 0x11119876
var hash = bh * 31 xor wh
hash = hash*31 xor fh
@ -1091,8 +1110,8 @@ class LiteralValue(val type: DataType,
if(numLeft!=null && numRight!=null)
return numLeft.compareTo(numRight)
if(strvalue!=null && other.strvalue!=null)
return strvalue.compareTo(other.strvalue)
if(initialstrvalue!=null && other.initialstrvalue!=null)
return initialstrvalue.compareTo(other.initialstrvalue)
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
}
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)"
}
fun size(): Int? {
fun size(heap: HeapValues): Int? {
val fromLv = (from as? LiteralValue)
val toLv = (to as? LiteralValue)
if(fromLv==null || toLv==null)
return null
return toConstantIntegerRange()?.count()
return toConstantIntegerRange(heap)?.count()
}
fun toConstantIntegerRange(): IntProgression? {
fun toConstantIntegerRange(heap: HeapValues): IntProgression? {
val fromLv = from as? LiteralValue
val toLv = to as? LiteralValue
if(fromLv==null || toLv==null)
@ -1217,8 +1242,8 @@ class RangeExpr(var from: IExpression,
val toVal: Int
if(fromLv.isString && toLv.isString) {
// string range -> int range over petscii values
fromVal = Petscii.encodePetscii(fromLv.strvalue!!, true)[0].toInt()
toVal = Petscii.encodePetscii(toLv.strvalue!!, true)[0].toInt()
fromVal = Petscii.encodePetscii(fromLv.strvalue(heap), true)[0].toInt()
toVal = Petscii.encodePetscii(toLv.strvalue(heap), true)[0].toInt()
} else {
// integer range
fromVal = (from as LiteralValue).asIntegerValue!!

View File

@ -635,14 +635,16 @@ class AstChecker(private val namespace: INameScope,
else if(from.asIntegerValue > to.asIntegerValue && step>=0)
err("descending range requires step < 0")
}
from.strvalue!=null && to.strvalue!=null -> {
if(from.strvalue.length!=1 || to.strvalue.length!=1)
from.isString && to.isString -> {
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")
if(from.strvalue[0] == to.strvalue[0])
if(fromString[0] == toString[0])
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")
else if(from.strvalue[0] > to.strvalue[0] && step>=0)
else if(fromString[0] > toString[0] && step>=0)
err("descending range requires step < 0")
}
else -> err("range expression must be over integers or over characters")
@ -683,7 +685,7 @@ class AstChecker(private val namespace: INameScope,
else {
for (arg in args.withIndex().zip(func.parameters)) {
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) {
@ -691,8 +693,9 @@ class AstChecker(private val namespace: INameScope,
checkResult.add(SyntaxError("invalid number of arguments", position))
else {
for (arg in args.withIndex().zip(target.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
val argDt = arg.first.value.resultingDatatype(namespace, heap)
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(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))
return false
}
val rangeSize=range.size()
val rangeSize=range.size(heap)
if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
return false
@ -797,7 +800,7 @@ class AstChecker(private val namespace: INameScope,
in ArrayDatatypes -> {
// range and length check bytes
val expectedSize = arrayspec!!.size()
val rangeSize=range.size()
val rangeSize=range.size(heap)
if(rangeSize!=null && rangeSize != expectedSize) {
checkResult.add(ExpressionError("range size doesn't match array size, expected $expectedSize found $rangeSize", range.position))
return false
@ -859,7 +862,7 @@ class AstChecker(private val namespace: INameScope,
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
if(!value.isString)
return err("string value expected")
val str = value.strvalue ?: heap.get(value.heapId!!).str!!
val str = value.strvalue(heap)
if (str.length > 255)
return err("string length must be 0-255")
}

View File

@ -1,6 +1,5 @@
package prog8.compiler
import com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile
import prog8.ast.*
import prog8.ast.RegisterOrPair.*
import prog8.compiler.intermediate.IntermediateProgram
@ -1470,7 +1469,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
if(loop.iterable is RangeExpr) {
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
val range = (loop.iterable as RangeExpr).toConstantIntegerRange(heap)
if(range!=null) {
// loop over a range with constant start, last and step values
if (range.isEmpty())
@ -1536,7 +1535,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
DataType.STR_P,
DataType.STR_S,
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")
}
DataType.ARRAY_UB, DataType.ARRAY_B,

View File

@ -345,7 +345,7 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position)
}
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)
}
DataType.UBYTE, DataType.BYTE,

View File

@ -1,6 +1,7 @@
package prog8.optimizing
import prog8.ast.*
import prog8.compiler.HeapValues
import kotlin.math.pow
@ -9,11 +10,11 @@ val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "=
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) {
"+" -> plus(left, right)
"+" -> plus(left, right, heap)
"-" -> minus(left, right)
"*" -> multiply(left, right)
"*" -> multiply(left, right, heap)
"/" -> divide(left, right)
"//" -> floordivide(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"
return 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)
else -> throw ExpressionError(error, left.position)
}
left.strvalue!=null -> when {
right.strvalue!=null -> {
val newStr = left.strvalue + right.strvalue
left.isString -> when {
right.isString -> {
val newStr = left.strvalue(heap) + right.strvalue(heap)
if(newStr.length > 255) throw ExpressionError("string too long", 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}"
return when {
left.asIntegerValue!=null -> when {
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.strvalue!=null -> {
if(right.strvalue.length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
LiteralValue(DataType.STR, strvalue = right.strvalue.repeat(left.asIntegerValue), position = left.position)
right.isString -> {
if(right.strvalue(heap).length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
LiteralValue(DataType.STR, strvalue = right.strvalue(heap).repeat(left.asIntegerValue), position = left.position)
}
else -> throw ExpressionError(error, left.position)
}
@ -294,4 +295,4 @@ class ConstExprEvaluator {
else -> throw ExpressionError(error, left.position)
}
}
}
}

View File

@ -45,8 +45,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
in IntegerDatatypes -> {
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to ubyte integer
val literal = decl.value as? LiteralValue
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
if (literal != null && literal.isString && literal.strvalue(heap).length == 1) {
val petscii = Petscii.encodePetscii(literal.strvalue(heap))[0]
val newValue = LiteralValue(DataType.UBYTE, bytevalue = petscii, position = literal.position)
decl.value = newValue
}
@ -138,7 +138,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
return try {
val cval = identifier.constValue(namespace, heap) ?: return identifier
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
} else
@ -256,7 +256,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
return when {
leftconst != null && rightconst != null -> {
optimizationsDone++
evaluator.evaluate(leftconst, expr.operator, rightconst)
evaluator.evaluate(leftconst, expr.operator, rightconst, heap)
}
else -> expr
}
@ -467,12 +467,12 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
override fun process(literalValue: LiteralValue): LiteralValue {
if(literalValue.strvalue!=null) {
if(literalValue.isString) {
// 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))
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)
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
when(targetDt) {
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)
assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position)
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)
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 -> {
// 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)
assignment.value = LiteralValue(DataType.UBYTE, lv.wordvalue.toShort(), position=lv.position)
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)
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 -> {
// 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 -> {
// 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)
assignment.value = LiteralValue(DataType.WORD, wordvalue=lv.bytevalue!!.toInt(), position=lv.position)
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)
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 -> {
if(lv.isNumeric)

View File

@ -102,7 +102,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
super.process(forLoop)
val range = forLoop.iterable as? RangeExpr
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
// loopvar/reg = range value , follow by block
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position)