mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
simplified heapId for arrayvalues
This commit is contained in:
parent
14a13da7ec
commit
11de3db25f
@ -435,12 +435,10 @@ class StringLiteralValue(val value: String,
|
||||
|
||||
class ArrayLiteralValue(val type: DataType, // only array types
|
||||
val value: Array<Expression>,
|
||||
initHeapId: Int? =null,
|
||||
override val position: Position) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
var heapId = initHeapId
|
||||
private set
|
||||
val heapId = ++heapIdSequence
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -468,9 +466,9 @@ class ArrayLiteralValue(val type: DataType, // only array types
|
||||
val castArray = value.map{
|
||||
val num = it as? NumericLiteralValue
|
||||
if(num==null) {
|
||||
// an array of UWORDs could possibly also contain AddressOfs
|
||||
// an array of UWORDs could possibly also contain AddressOfs, other stuff can't be casted
|
||||
if (elementType != DataType.UWORD || it !is AddressOf)
|
||||
throw FatalAstException("weird array element $it")
|
||||
return null
|
||||
it
|
||||
} else {
|
||||
try {
|
||||
@ -484,11 +482,6 @@ class ArrayLiteralValue(val type: DataType, // only array types
|
||||
}
|
||||
return null // invalid type conversion from $this to $targettype
|
||||
}
|
||||
|
||||
fun addToHeap() {
|
||||
if(heapId==null)
|
||||
heapId = ++heapIdSequence
|
||||
}
|
||||
}
|
||||
|
||||
class RangeExpr(var from: Expression,
|
||||
@ -642,7 +635,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
return when (value) {
|
||||
is IdentifierReference -> value.heapId(namespace)
|
||||
is StringLiteralValue -> value.heapId
|
||||
is ArrayLiteralValue -> value.heapId ?: throw FatalAstException("array is not on the heap: $value")
|
||||
is ArrayLiteralValue -> value.heapId
|
||||
else -> throw FatalAstException("requires a reference value")
|
||||
}
|
||||
}
|
||||
|
@ -694,9 +694,6 @@ internal class AstChecker(private val program: Program,
|
||||
checkValueTypeAndRangeArray(array.type, null, arrayspec, array)
|
||||
|
||||
super.visit(array)
|
||||
|
||||
if(array.heapId==null && array.parent !is IFunctionCall)
|
||||
throw FatalAstException("array should have been moved to heap at ${array.position}")
|
||||
}
|
||||
|
||||
override fun visit(string: StringLiteralValue) {
|
||||
@ -824,6 +821,7 @@ internal class AstChecker(private val program: Program,
|
||||
if(targetStatement!=null)
|
||||
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
|
||||
if(targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
|
||||
// TODO add 'void' keyword to make this explicit
|
||||
if(targetStatement.returntypes.size==1)
|
||||
printWarning("result value of subroutine call is discarded", functionCallStatement.position)
|
||||
else
|
||||
@ -1198,31 +1196,6 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
private fun checkArrayValues(value: ArrayLiteralValue, type: DataType): Boolean {
|
||||
if (value.heapId == null) {
|
||||
// hmm weird, array literal that hasn't been moved to the heap yet?
|
||||
val array = value.value.mapNotNull { it.constValue(program) }
|
||||
val correct: Boolean
|
||||
when (type) {
|
||||
DataType.ARRAY_UB -> {
|
||||
correct = array.all { it.type == DataType.UBYTE && it.number.toInt() in 0..255 }
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
correct = array.all { it.type == DataType.BYTE && it.number.toInt() in -128..127 }
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
correct = array.all { it.type == DataType.UWORD && it.number.toInt() in 0..65535 }
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
correct = array.all { it.type == DataType.WORD && it.number.toInt() in -32768..32767 }
|
||||
}
|
||||
DataType.ARRAY_F -> correct = true
|
||||
else -> throw AstException("invalid array type $type")
|
||||
}
|
||||
if (!correct)
|
||||
checkResult.add(ExpressionError("array value out of range for type $type", value.position))
|
||||
return correct
|
||||
}
|
||||
|
||||
val array = value.value.map {
|
||||
when (it) {
|
||||
is NumericLiteralValue -> it.number.toInt()
|
||||
|
@ -229,9 +229,9 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
val array = super.visit(arrayLiteral)
|
||||
if(array is ArrayLiteralValue) {
|
||||
val vardecl = array.parent as? VarDecl
|
||||
return when {
|
||||
vardecl!=null -> fixupArrayDatatype(array, vardecl, program)
|
||||
array.heapId!=null -> {
|
||||
return if(vardecl!=null)
|
||||
fixupArrayEltDatatypesFromVardecl(array, vardecl)
|
||||
else {
|
||||
// fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array
|
||||
// (we don't know the desired datatype here exactly so we guess)
|
||||
val datatype = determineArrayDt(array.value)
|
||||
@ -240,8 +240,6 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
// finally, replace the literal array by a identifier reference.
|
||||
makeIdentifierFromRefLv(litval2)
|
||||
}
|
||||
else -> array
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
@ -279,7 +277,6 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
// a referencetype literal value that's not declared as a variable
|
||||
// we need to introduce an auto-generated variable for this to be able to refer to the value
|
||||
// note: if the var references the same literal value, it is not yet de-duplicated here.
|
||||
array.addToHeap()
|
||||
val scope = array.definingScope()
|
||||
val variable = VarDecl.createAuto(array)
|
||||
return replaceWithIdentifier(variable, scope, array.parent)
|
||||
@ -352,7 +349,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
|
||||
}
|
||||
|
||||
internal fun fixupArrayDatatype(array: ArrayLiteralValue, program: Program): ArrayLiteralValue {
|
||||
internal fun fixupArrayEltDatatypes(array: ArrayLiteralValue, program: Program): ArrayLiteralValue {
|
||||
val dts = array.value.map {it.inferType(program).typeOrElse(DataType.STRUCT)}.toSet()
|
||||
if(dts.any { it !in NumericDatatypes }) {
|
||||
return array
|
||||
@ -370,50 +367,22 @@ internal fun fixupArrayDatatype(array: ArrayLiteralValue, program: Program): Arr
|
||||
// convert values and array type
|
||||
val elementType = ArrayElementTypes.getValue(dt)
|
||||
val values = array.value.map { (it as NumericLiteralValue).cast(elementType) as Expression}.toTypedArray()
|
||||
val array2 = ArrayLiteralValue(dt, values, array.heapId, array.position)
|
||||
val array2 = ArrayLiteralValue(dt, values, array.position)
|
||||
array2.linkParents(array.parent)
|
||||
return array2
|
||||
}
|
||||
|
||||
internal fun fixupArrayDatatype(array: ArrayLiteralValue, vardecl: VarDecl, program: Program): ArrayLiteralValue {
|
||||
if(array.heapId!=null) {
|
||||
internal fun fixupArrayEltDatatypesFromVardecl(array: ArrayLiteralValue, vardecl: VarDecl): ArrayLiteralValue {
|
||||
val arrayDt = array.type
|
||||
if(arrayDt!=vardecl.datatype) {
|
||||
// fix the datatype of the array (also on the heap) to match the vardecl
|
||||
val litval2 =
|
||||
try {
|
||||
val result = array.cast(vardecl.datatype)
|
||||
if(result==null) {
|
||||
val constElements = array.value.mapNotNull { it.constValue(program) }
|
||||
val elementDts = constElements.map { it.type }
|
||||
if(DataType.FLOAT in elementDts) {
|
||||
array.cast(DataType.ARRAY_F) ?: ArrayLiteralValue(DataType.ARRAY_F, array.value, array.heapId, array.position)
|
||||
} else {
|
||||
val numbers = constElements.map { it.number.toInt() }
|
||||
val minValue = numbers.min()!!
|
||||
val maxValue = numbers.max()!!
|
||||
if (minValue >= 0) {
|
||||
// only positive values, so uword or ubyte
|
||||
val dt = if(maxValue<256) DataType.ARRAY_UB else DataType.ARRAY_UW
|
||||
array.cast(dt) ?: ArrayLiteralValue(dt, array.value, array.heapId, array.position)
|
||||
} else {
|
||||
// negative value present, so word or byte
|
||||
val dt = if(minValue >= -128 && maxValue<=127) DataType.ARRAY_B else DataType.ARRAY_W
|
||||
array.cast(dt) ?: ArrayLiteralValue(dt, array.value, array.heapId, array.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
else result
|
||||
} catch(x: ExpressionError) {
|
||||
// couldn't cast permanently.
|
||||
// instead, simply adjust the array type and trust the AstChecker to report the exact error
|
||||
ArrayLiteralValue(vardecl.datatype, array.value, array.heapId, array.position)
|
||||
}
|
||||
vardecl.value = litval2
|
||||
litval2.linkParents(vardecl)
|
||||
litval2.addToHeap()
|
||||
return litval2
|
||||
val cast = array.cast(vardecl.datatype)
|
||||
if (cast != null) {
|
||||
vardecl.value = cast
|
||||
cast.linkParents(vardecl)
|
||||
return cast
|
||||
}
|
||||
// can't be casted yet, attempt again later
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
@ -44,8 +44,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
|
||||
val arraysize = decl.arraysize!!.size()!!
|
||||
val array = ArrayLiteralValue(decl.datatype,
|
||||
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
||||
null, decl.position)
|
||||
array.addToHeap()
|
||||
decl.position)
|
||||
decl.value = array
|
||||
}
|
||||
|
||||
|
@ -198,9 +198,6 @@ class VarDecl(val type: VarDeclType,
|
||||
}
|
||||
|
||||
fun createAuto(array: ArrayLiteralValue): VarDecl {
|
||||
if(array.heapId==null)
|
||||
throw FatalAstException("can only create autovar for an array that has a heapid $array")
|
||||
|
||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||
val declaredType = ArrayElementTypes.getValue(array.type)
|
||||
val arraysize = ArrayIndex.forArray(array)
|
||||
|
@ -5,7 +5,8 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.processing.IAstModifyingVisitor
|
||||
import prog8.ast.processing.fixupArrayDatatype
|
||||
import prog8.ast.processing.fixupArrayEltDatatypesFromVardecl
|
||||
import prog8.ast.processing.fixupArrayEltDatatypes
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.functions.BuiltinFunctions
|
||||
@ -116,7 +117,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
// create the array itself, filled with the fillvalue.
|
||||
val array = Array(size) {fillvalue}.map { NumericLiteralValue.optimalInteger(it, numericLv.position) as Expression}.toTypedArray()
|
||||
val refValue = ArrayLiteralValue(decl.datatype, array, position = numericLv.position)
|
||||
refValue.addToHeap()
|
||||
decl.value = refValue
|
||||
refValue.parent=decl
|
||||
optimizationsDone++
|
||||
@ -138,7 +138,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
// create the array itself, filled with the fillvalue.
|
||||
val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray()
|
||||
val refValue = ArrayLiteralValue(DataType.ARRAY_F, array, position = litval.position)
|
||||
refValue.addToHeap()
|
||||
decl.value = refValue
|
||||
refValue.parent=decl
|
||||
optimizationsDone++
|
||||
@ -586,7 +585,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
if(array2!=null && array2!==array) {
|
||||
forLoop2.iterable = array2
|
||||
array2.linkParents(forLoop2)
|
||||
array2.addToHeap()
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,13 +631,12 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
|
||||
val array = super.visit(arrayLiteral)
|
||||
if(array is ArrayLiteralValue) {
|
||||
array.addToHeap()
|
||||
val vardecl = array.parent as? VarDecl
|
||||
return if (vardecl!=null) {
|
||||
fixupArrayDatatype(array, vardecl, program)
|
||||
fixupArrayEltDatatypesFromVardecl(array, vardecl)
|
||||
} else {
|
||||
// it's not an array associated with a vardecl, attempt to guess the data type from the array values
|
||||
fixupArrayDatatype(array, program)
|
||||
fixupArrayEltDatatypes(array, program)
|
||||
}
|
||||
}
|
||||
return array
|
||||
|
@ -261,7 +261,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
// always true -> keep only if-part
|
||||
printWarning("condition is always true", ifStatement.position)
|
||||
printWarning("condition is always true", ifStatement.position) // TODO don't warn this if the condition is just the single value 'true'
|
||||
optimizationsDone++
|
||||
ifStatement.truepart
|
||||
} else {
|
||||
@ -310,7 +310,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
// always true -> print a warning, and optimize into body + jump (if there are no continue and break statements)
|
||||
printWarning("condition is always true", whileLoop.position)
|
||||
printWarning("condition is always true", whileLoop.position) // TODO don't warn this if the condition is just the single value 'true'
|
||||
if(hasContinueOrBreak(whileLoop.body))
|
||||
return whileLoop
|
||||
val label = Label("_prog8_back", whileLoop.condition.position)
|
||||
@ -336,7 +336,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
// always true -> keep only the statement block (if there are no continue and break statements)
|
||||
printWarning("condition is always true", repeatLoop.position)
|
||||
printWarning("condition is always true", repeatLoop.position) // TODO don't warn this if the condition is just the single value 'true'
|
||||
if(hasContinueOrBreak(repeatLoop.body))
|
||||
repeatLoop
|
||||
else {
|
||||
|
@ -605,7 +605,7 @@ open class RuntimeValueArray(type: DataType, val array: Array<Number>, val heapI
|
||||
fun fromLv(array: ArrayLiteralValue): RuntimeValueArray {
|
||||
return if (array.type == DataType.ARRAY_F) {
|
||||
val doubleArray = array.value.map { (it as NumericLiteralValue).number }.toTypedArray()
|
||||
RuntimeValueArray(array.type, doubleArray, array.heapId!!)
|
||||
RuntimeValueArray(array.type, doubleArray, array.heapId)
|
||||
} else {
|
||||
val resultArray = mutableListOf<Number>()
|
||||
for (elt in array.value.withIndex()) {
|
||||
@ -615,7 +615,7 @@ open class RuntimeValueArray(type: DataType, val array: Array<Number>, val heapI
|
||||
resultArray.add((elt.hashCode())) // ...poor man's implementation of ADDRESSOF(array), it probably won't work very well
|
||||
}
|
||||
}
|
||||
RuntimeValueArray(array.type, resultArray.toTypedArray(), array.heapId!!)
|
||||
RuntimeValueArray(array.type, resultArray.toTypedArray(), array.heapId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ class TestParserNumericLiteralValue {
|
||||
val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
|
||||
val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos)
|
||||
val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos)
|
||||
val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), null, dummyPos)
|
||||
val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), null, dummyPos)
|
||||
val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), null, dummyPos)
|
||||
val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), dummyPos)
|
||||
val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos)
|
||||
val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), dummyPos)
|
||||
assertEquals(lv1, lv2)
|
||||
assertNotEquals(lv1, lv3)
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ main {
|
||||
|
||||
c64.VMCSB |= 2 ; switch to lowercase charset
|
||||
|
||||
str s1 = "HELLO hello 1234 @[/]\n"
|
||||
str s2 = c64scr("HELLO hello 1234 @[/]\n")
|
||||
str s1 = "HELLO hello 1234 @[/]\n" ; regular strings have default encoding (petscii on c64)
|
||||
str s2 = @"HELLO hello 1234 @[/]\n" ; TODO @-strings for alternate encoding (screencode on c64)
|
||||
|
||||
c64scr.print("\n\n\n\nString output via print:\n")
|
||||
c64scr.print(s1)
|
||||
|
Loading…
Reference in New Issue
Block a user