simplified heapId for arrayvalues

This commit is contained in:
Irmen de Jong 2020-02-08 17:38:41 +01:00
parent 14a13da7ec
commit 11de3db25f
10 changed files with 42 additions and 114 deletions

View File

@ -435,12 +435,10 @@ class StringLiteralValue(val value: String,
class ArrayLiteralValue(val type: DataType, // only array types class ArrayLiteralValue(val type: DataType, // only array types
val value: Array<Expression>, val value: Array<Expression>,
initHeapId: Int? =null,
override val position: Position) : Expression() { override val position: Position) : Expression() {
override lateinit var parent: Node override lateinit var parent: Node
var heapId = initHeapId val heapId = ++heapIdSequence
private set
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
@ -468,9 +466,9 @@ class ArrayLiteralValue(val type: DataType, // only array types
val castArray = value.map{ val castArray = value.map{
val num = it as? NumericLiteralValue val num = it as? NumericLiteralValue
if(num==null) { 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) if (elementType != DataType.UWORD || it !is AddressOf)
throw FatalAstException("weird array element $it") return null
it it
} else { } else {
try { try {
@ -484,11 +482,6 @@ class ArrayLiteralValue(val type: DataType, // only array types
} }
return null // invalid type conversion from $this to $targettype return null // invalid type conversion from $this to $targettype
} }
fun addToHeap() {
if(heapId==null)
heapId = ++heapIdSequence
}
} }
class RangeExpr(var from: Expression, class RangeExpr(var from: Expression,
@ -642,7 +635,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
return when (value) { return when (value) {
is IdentifierReference -> value.heapId(namespace) is IdentifierReference -> value.heapId(namespace)
is StringLiteralValue -> value.heapId 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") else -> throw FatalAstException("requires a reference value")
} }
} }

View File

@ -694,9 +694,6 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRangeArray(array.type, null, arrayspec, array) checkValueTypeAndRangeArray(array.type, null, arrayspec, array)
super.visit(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) { override fun visit(string: StringLiteralValue) {
@ -824,6 +821,7 @@ internal class AstChecker(private val program: Program,
if(targetStatement!=null) if(targetStatement!=null)
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position) checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
if(targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) { if(targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
// TODO add 'void' keyword to make this explicit
if(targetStatement.returntypes.size==1) if(targetStatement.returntypes.size==1)
printWarning("result value of subroutine call is discarded", functionCallStatement.position) printWarning("result value of subroutine call is discarded", functionCallStatement.position)
else else
@ -1198,31 +1196,6 @@ internal class AstChecker(private val program: Program,
} }
private fun checkArrayValues(value: ArrayLiteralValue, type: DataType): Boolean { 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 { val array = value.value.map {
when (it) { when (it) {
is NumericLiteralValue -> it.number.toInt() is NumericLiteralValue -> it.number.toInt()

View File

@ -229,18 +229,16 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
val array = super.visit(arrayLiteral) val array = super.visit(arrayLiteral)
if(array is ArrayLiteralValue) { if(array is ArrayLiteralValue) {
val vardecl = array.parent as? VarDecl val vardecl = array.parent as? VarDecl
return when { return if(vardecl!=null)
vardecl!=null -> fixupArrayDatatype(array, vardecl, program) fixupArrayEltDatatypesFromVardecl(array, vardecl)
array.heapId!=null -> { else {
// fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array // 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) // (we don't know the desired datatype here exactly so we guess)
val datatype = determineArrayDt(array.value) val datatype = determineArrayDt(array.value)
val litval2 = array.cast(datatype)!! val litval2 = array.cast(datatype)!!
litval2.parent = array.parent litval2.parent = array.parent
// finally, replace the literal array by a identifier reference. // finally, replace the literal array by a identifier reference.
makeIdentifierFromRefLv(litval2) makeIdentifierFromRefLv(litval2)
}
else -> array
} }
} }
return 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 // 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 // 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. // note: if the var references the same literal value, it is not yet de-duplicated here.
array.addToHeap()
val scope = array.definingScope() val scope = array.definingScope()
val variable = VarDecl.createAuto(array) val variable = VarDecl.createAuto(array)
return replaceWithIdentifier(variable, scope, array.parent) 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() val dts = array.value.map {it.inferType(program).typeOrElse(DataType.STRUCT)}.toSet()
if(dts.any { it !in NumericDatatypes }) { if(dts.any { it !in NumericDatatypes }) {
return array return array
@ -370,50 +367,22 @@ internal fun fixupArrayDatatype(array: ArrayLiteralValue, program: Program): Arr
// convert values and array type // convert values and array type
val elementType = ArrayElementTypes.getValue(dt) val elementType = ArrayElementTypes.getValue(dt)
val values = array.value.map { (it as NumericLiteralValue).cast(elementType) as Expression}.toTypedArray() 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) array2.linkParents(array.parent)
return array2 return array2
} }
internal fun fixupArrayDatatype(array: ArrayLiteralValue, vardecl: VarDecl, program: Program): ArrayLiteralValue { internal fun fixupArrayEltDatatypesFromVardecl(array: ArrayLiteralValue, vardecl: VarDecl): ArrayLiteralValue {
if(array.heapId!=null) { val arrayDt = array.type
val arrayDt = array.type if(arrayDt!=vardecl.datatype) {
if(arrayDt!=vardecl.datatype) { // fix the datatype of the array (also on the heap) to match the vardecl
// fix the datatype of the array (also on the heap) to match the vardecl val cast = array.cast(vardecl.datatype)
val litval2 = if (cast != null) {
try { vardecl.value = cast
val result = array.cast(vardecl.datatype) cast.linkParents(vardecl)
if(result==null) { return cast
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
} }
// can't be casted yet, attempt again later
} }
return array return array
} }

View File

@ -44,8 +44,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
val arraysize = decl.arraysize!!.size()!! val arraysize = decl.arraysize!!.size()!!
val array = ArrayLiteralValue(decl.datatype, val array = ArrayLiteralValue(decl.datatype,
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) }, Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
null, decl.position) decl.position)
array.addToHeap()
decl.value = array decl.value = array
} }

View File

@ -198,9 +198,6 @@ class VarDecl(val type: VarDeclType,
} }
fun createAuto(array: ArrayLiteralValue): VarDecl { 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 autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
val declaredType = ArrayElementTypes.getValue(array.type) val declaredType = ArrayElementTypes.getValue(array.type)
val arraysize = ArrayIndex.forArray(array) val arraysize = ArrayIndex.forArray(array)

View File

@ -5,7 +5,8 @@ import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.processing.IAstModifyingVisitor 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.ast.statements.*
import prog8.compiler.target.CompilationTarget import prog8.compiler.target.CompilationTarget
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
@ -116,7 +117,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
// create the array itself, filled with the fillvalue. // create the array itself, filled with the fillvalue.
val array = Array(size) {fillvalue}.map { NumericLiteralValue.optimalInteger(it, numericLv.position) as Expression}.toTypedArray() val array = Array(size) {fillvalue}.map { NumericLiteralValue.optimalInteger(it, numericLv.position) as Expression}.toTypedArray()
val refValue = ArrayLiteralValue(decl.datatype, array, position = numericLv.position) val refValue = ArrayLiteralValue(decl.datatype, array, position = numericLv.position)
refValue.addToHeap()
decl.value = refValue decl.value = refValue
refValue.parent=decl refValue.parent=decl
optimizationsDone++ optimizationsDone++
@ -138,7 +138,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
// create the array itself, filled with the fillvalue. // create the array itself, filled with the fillvalue.
val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray() 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) val refValue = ArrayLiteralValue(DataType.ARRAY_F, array, position = litval.position)
refValue.addToHeap()
decl.value = refValue decl.value = refValue
refValue.parent=decl refValue.parent=decl
optimizationsDone++ optimizationsDone++
@ -586,7 +585,6 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
if(array2!=null && array2!==array) { if(array2!=null && array2!==array) {
forLoop2.iterable = array2 forLoop2.iterable = array2
array2.linkParents(forLoop2) array2.linkParents(forLoop2)
array2.addToHeap()
} }
} }
@ -633,13 +631,12 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
override fun visit(arrayLiteral: ArrayLiteralValue): Expression { override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
val array = super.visit(arrayLiteral) val array = super.visit(arrayLiteral)
if(array is ArrayLiteralValue) { if(array is ArrayLiteralValue) {
array.addToHeap()
val vardecl = array.parent as? VarDecl val vardecl = array.parent as? VarDecl
return if (vardecl!=null) { return if (vardecl!=null) {
fixupArrayDatatype(array, vardecl, program) fixupArrayEltDatatypesFromVardecl(array, vardecl)
} else { } else {
// it's not an array associated with a vardecl, attempt to guess the data type from the array values // 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 return array

View File

@ -261,7 +261,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(constvalue!=null) { if(constvalue!=null) {
return if(constvalue.asBooleanValue){ return if(constvalue.asBooleanValue){
// always true -> keep only if-part // 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++ optimizationsDone++
ifStatement.truepart ifStatement.truepart
} else { } else {
@ -310,7 +310,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(constvalue!=null) { if(constvalue!=null) {
return if(constvalue.asBooleanValue){ return if(constvalue.asBooleanValue){
// always true -> print a warning, and optimize into body + jump (if there are no continue and break statements) // 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)) if(hasContinueOrBreak(whileLoop.body))
return whileLoop return whileLoop
val label = Label("_prog8_back", whileLoop.condition.position) val label = Label("_prog8_back", whileLoop.condition.position)
@ -336,7 +336,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
if(constvalue!=null) { if(constvalue!=null) {
return if(constvalue.asBooleanValue){ return if(constvalue.asBooleanValue){
// always true -> keep only the statement block (if there are no continue and break statements) // 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)) if(hasContinueOrBreak(repeatLoop.body))
repeatLoop repeatLoop
else { else {

View File

@ -605,7 +605,7 @@ open class RuntimeValueArray(type: DataType, val array: Array<Number>, val heapI
fun fromLv(array: ArrayLiteralValue): RuntimeValueArray { fun fromLv(array: ArrayLiteralValue): RuntimeValueArray {
return if (array.type == DataType.ARRAY_F) { return if (array.type == DataType.ARRAY_F) {
val doubleArray = array.value.map { (it as NumericLiteralValue).number }.toTypedArray() val doubleArray = array.value.map { (it as NumericLiteralValue).number }.toTypedArray()
RuntimeValueArray(array.type, doubleArray, array.heapId!!) RuntimeValueArray(array.type, doubleArray, array.heapId)
} else { } else {
val resultArray = mutableListOf<Number>() val resultArray = mutableListOf<Number>()
for (elt in array.value.withIndex()) { 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 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)
} }
} }
} }

View File

@ -93,9 +93,9 @@ class TestParserNumericLiteralValue {
val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos) val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos) val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos)
val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos) val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos)
val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), null, dummyPos) val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), dummyPos)
val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), null, dummyPos) val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos)
val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), null, dummyPos) val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), dummyPos)
assertEquals(lv1, lv2) assertEquals(lv1, lv2)
assertNotEquals(lv1, lv3) assertNotEquals(lv1, lv3)
} }

View File

@ -9,8 +9,8 @@ main {
c64.VMCSB |= 2 ; switch to lowercase charset c64.VMCSB |= 2 ; switch to lowercase charset
str s1 = "HELLO hello 1234 @[/]\n" str s1 = "HELLO hello 1234 @[/]\n" ; regular strings have default encoding (petscii on c64)
str s2 = c64scr("HELLO hello 1234 @[/]\n") 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("\n\n\n\nString output via print:\n")
c64scr.print(s1) c64scr.print(s1)