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
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")
}
}

View File

@ -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()

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -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)
}

View File

@ -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)