mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
fix array value initialization type conversions
This commit is contained in:
parent
3a7b341f47
commit
00ad285d3f
@ -1,5 +1,6 @@
|
||||
package prog8.ast
|
||||
|
||||
import com.sun.org.apache.xpath.internal.operations.Bool
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
|
||||
@ -906,6 +907,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
// value may be either a single byte, or a byte arrayspec (of all constant values)
|
||||
if(value.type==targetDt) {
|
||||
if(!checkArrayValues(value, targetDt))
|
||||
return false
|
||||
val arraySpecSize = arrayspec.size()
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
@ -926,6 +929,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
// value may be either a single word, or a word arrayspec
|
||||
if(value.type==targetDt) {
|
||||
if(!checkArrayValues(value, targetDt))
|
||||
return false
|
||||
val arraySpecSize = arrayspec.size()
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
@ -946,6 +951,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
DataType.ARRAY_F -> {
|
||||
// value may be either a single float, or a float arrayspec
|
||||
if(value.type==targetDt) {
|
||||
if(!checkArrayValues(value, targetDt))
|
||||
return false
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size
|
||||
val arraySpecSize = arrayspec.size()
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
@ -975,6 +982,30 @@ class AstChecker(private val namespace: INameScope,
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkArrayValues(value: LiteralValue, type: DataType): Boolean {
|
||||
val array = heap.get(value.heapId!!)
|
||||
val correct: Boolean
|
||||
when(type) {
|
||||
DataType.ARRAY_UB -> {
|
||||
correct=array.array!=null && array.array.all { it in 0..255 }
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
correct=array.array!=null && array.array.all { it in -128..127 }
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
correct=array.array!=null && array.array.all { it in 0..65535 }
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
correct=array.array!=null && array.array.all { it in -32768..32767 }
|
||||
}
|
||||
DataType.ARRAY_F -> correct = array.doubleArray!=null
|
||||
else -> throw AstException("invalid array type $type")
|
||||
}
|
||||
if(!correct)
|
||||
checkResult.add(ExpressionError("array value out of range for type $type", value.position))
|
||||
return correct
|
||||
}
|
||||
|
||||
private fun checkAssignmentCompatible(targetDatatype: DataType,
|
||||
sourceDatatype: DataType,
|
||||
sourceValue: IExpression,
|
||||
|
@ -32,38 +32,22 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val result = super.process(decl)
|
||||
|
||||
if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) {
|
||||
val litval = decl.value as? LiteralValue
|
||||
if(litval!=null && litval.isArray)
|
||||
fixupArrayTypeOnHeap(decl, litval)
|
||||
when(decl.datatype) {
|
||||
DataType.FLOAT -> {
|
||||
// vardecl: for float vars, promote constant integer initialization values to floats
|
||||
val literal = decl.value as? LiteralValue
|
||||
if (literal != null && literal.type in IntegerDatatypes) {
|
||||
val newValue = LiteralValue(DataType.FLOAT, floatvalue = literal.asNumericValue!!.toDouble(), position = literal.position)
|
||||
// vardecl: for scalar float vars, promote constant integer initialization values to floats
|
||||
if (litval != null && litval.type in IntegerDatatypes) {
|
||||
val newValue = LiteralValue(DataType.FLOAT, floatvalue = litval.asNumericValue!!.toDouble(), position = litval.position)
|
||||
decl.value = newValue
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
val litval = decl.value as? LiteralValue
|
||||
if(litval?.type==DataType.FLOAT)
|
||||
errors.add(ExpressionError("arrayspec requires only integers here", litval.position))
|
||||
val size = decl.arrayspec!!.size()
|
||||
if(litval!=null && litval.isArray) {
|
||||
// arrayspec initializer value is an arrayspec already, keep as-is (or convert to WORDs if needed)
|
||||
if(litval.heapId!=null) {
|
||||
if(decl.datatype==DataType.ARRAY_UW && litval.type == DataType.ARRAY_UB) {
|
||||
val array = heap.get(litval.heapId)
|
||||
if(array.array!=null) {
|
||||
heap.update(litval.heapId, HeapValues.HeapValue(DataType.ARRAY_UW, null, array.array, null))
|
||||
decl.value = LiteralValue(decl.datatype, heapId = litval.heapId, position = litval.position)
|
||||
}
|
||||
} else if(decl.datatype==DataType.ARRAY_W && litval.type == DataType.ARRAY_B) {
|
||||
val array = heap.get(litval.heapId)
|
||||
if(array.array!=null) {
|
||||
heap.update(litval.heapId, HeapValues.HeapValue(DataType.ARRAY_W, null, array.array, null))
|
||||
decl.value = LiteralValue(decl.datatype, heapId = litval.heapId, position = litval.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
if ((litval==null || !litval.isArray) && size != null) {
|
||||
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
|
||||
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
|
||||
when(decl.datatype){
|
||||
@ -91,19 +75,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val litval = decl.value as? LiteralValue
|
||||
val size = decl.arrayspec!!.size()
|
||||
if(litval!=null && litval.isArray) {
|
||||
// arrayspec initializer value is an arrayspec already, make sure to convert to floats
|
||||
if(litval.heapId!=null) {
|
||||
val array = heap.get(litval.heapId)
|
||||
if (array.doubleArray == null) {
|
||||
val doubleArray = array.array!!.map { it.toDouble() }.toDoubleArray()
|
||||
heap.update(litval.heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
|
||||
decl.value = LiteralValue(decl.datatype, heapId = litval.heapId, position = litval.position)
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
if ((litval==null || !litval.isArray) && size != null) {
|
||||
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
|
||||
val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0
|
||||
if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE)
|
||||
@ -121,6 +94,32 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
return result
|
||||
}
|
||||
|
||||
private fun fixupArrayTypeOnHeap(decl: VarDecl, litval: LiteralValue) {
|
||||
// fix the type of the array value that's on the heap, to match the vardecl.
|
||||
// notice that checking the bounds of the actual values is not done here, but in the AstChecker later.
|
||||
if(decl.datatype==litval.type)
|
||||
return // already correct datatype
|
||||
val heapId = litval.heapId!!
|
||||
val array=heap.get(heapId)
|
||||
when(decl.datatype) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
if(array.array!=null) {
|
||||
heap.update(heapId, HeapValues.HeapValue(decl.datatype, null, array.array, null))
|
||||
decl.value = LiteralValue(decl.datatype, heapId=heapId, position = litval.position)
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
if(array.array!=null) {
|
||||
// convert a non-float array to floats
|
||||
val doubleArray = array.array.map { it.toDouble() }.toDoubleArray()
|
||||
heap.update(heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
|
||||
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval.position)
|
||||
}
|
||||
}
|
||||
else -> throw AstException("invalid array vardecl type")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* replace identifiers that refer to const value, with the value itself (if it's a simple type)
|
||||
*/
|
||||
@ -484,14 +483,15 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val integerArray = valuesInArray.map{it.toInt()}.toIntArray()
|
||||
val doubleArray = valuesInArray.map{it.toDouble()}.toDoubleArray()
|
||||
val typesInArray: Set<DataType> = array.mapNotNull { it.resultingDatatype(namespace, heap) }.toSet()
|
||||
|
||||
// Take an educated guess about the array type.
|
||||
// This may be altered (if needed & if possible) to suit an array declaration type later!
|
||||
// Also, the check if all values are valid for the given datatype is done later, in the AstChecker.
|
||||
val arrayDt =
|
||||
if(DataType.FLOAT in typesInArray)
|
||||
DataType.ARRAY_F
|
||||
else if(DataType.WORD in typesInArray) {
|
||||
if(DataType.UWORD in typesInArray)
|
||||
DataType.ARRAY_F
|
||||
else
|
||||
DataType.ARRAY_W
|
||||
DataType.ARRAY_W
|
||||
} else {
|
||||
val maxValue = integerArray.max()!!
|
||||
val minValue = integerArray.min()!!
|
||||
|
@ -290,7 +290,7 @@ dec_var_f .proc
|
||||
.pend
|
||||
|
||||
pop_2_floats_f2_in_fac1 .proc
|
||||
; -- pop 2 floats from stack, load the second one in FAC1
|
||||
; -- pop 2 floats from stack, load the second one in FAC1 as well
|
||||
lda #<fmath_float2
|
||||
ldy #>fmath_float2
|
||||
jsr pop_float
|
||||
@ -1100,6 +1100,67 @@ _cmp_mod cpy #255 ; modified
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_ub .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_max_ub"
|
||||
.pend
|
||||
|
||||
func_max_b .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_max_b"
|
||||
.pend
|
||||
|
||||
func_max_uw .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_max_uw"
|
||||
.pend
|
||||
|
||||
func_max_w .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_max_w"
|
||||
.pend
|
||||
|
||||
func_max_f .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_max_f"
|
||||
.pend
|
||||
|
||||
func_min_ub .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_min_ub"
|
||||
.pend
|
||||
|
||||
func_min_b .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_min_b"
|
||||
.pend
|
||||
|
||||
func_min_uw .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_min_uw"
|
||||
.pend
|
||||
|
||||
func_min_w .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_min_w"
|
||||
.pend
|
||||
|
||||
func_min_f .proc
|
||||
inx
|
||||
rts
|
||||
.warn "todo func_min_f"
|
||||
.pend
|
||||
|
||||
|
||||
func_len_str .proc
|
||||
; -- push length of 0-terminated string on stack
|
||||
jsr peek_address
|
||||
|
Loading…
Reference in New Issue
Block a user