mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
improved array literal datatype handling, fixed some datatype compiler errors related to this
This commit is contained in:
parent
fbecedaf41
commit
5f1ec80ae0
@ -476,7 +476,7 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
|
|||||||
val array = litval.arrayliteral().toAst()
|
val array = litval.arrayliteral().toAst()
|
||||||
// the actual type of the arraysize can not yet be determined here (missing namespace & heap)
|
// the actual type of the arraysize can not yet be determined here (missing namespace & heap)
|
||||||
// the ConstantFold takes care of that and converts the type if needed.
|
// the ConstantFold takes care of that and converts the type if needed.
|
||||||
ArrayLiteralValue(DataType.ARRAY_UB, array, position = litval.toPosition())
|
ArrayLiteralValue(InferredTypes.InferredType.unknown(), array, position = litval.toPosition())
|
||||||
}
|
}
|
||||||
litval.structliteral()!=null -> {
|
litval.structliteral()!=null -> {
|
||||||
val values = litval.structliteral().expression().map { it.toAst() }
|
val values = litval.structliteral().expression().map { it.toAst() }
|
||||||
|
@ -126,6 +126,13 @@ val ArrayElementTypes = mapOf(
|
|||||||
DataType.ARRAY_W to DataType.WORD,
|
DataType.ARRAY_W to DataType.WORD,
|
||||||
DataType.ARRAY_UW to DataType.UWORD,
|
DataType.ARRAY_UW to DataType.UWORD,
|
||||||
DataType.ARRAY_F to DataType.FLOAT)
|
DataType.ARRAY_F to DataType.FLOAT)
|
||||||
|
val ElementArrayTypes = mapOf(
|
||||||
|
DataType.BYTE to DataType.ARRAY_B,
|
||||||
|
DataType.UBYTE to DataType.ARRAY_UB,
|
||||||
|
DataType.WORD to DataType.ARRAY_W,
|
||||||
|
DataType.UWORD to DataType.ARRAY_UW,
|
||||||
|
DataType.FLOAT to DataType.ARRAY_F
|
||||||
|
)
|
||||||
|
|
||||||
// find the parent node of a specific type or interface
|
// find the parent node of a specific type or interface
|
||||||
// (useful to figure out in what namespace/block something is defined, etc)
|
// (useful to figure out in what namespace/block something is defined, etc)
|
||||||
|
@ -5,10 +5,7 @@ import prog8.ast.antlr.escape
|
|||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.processing.IAstModifyingVisitor
|
import prog8.ast.processing.IAstModifyingVisitor
|
||||||
import prog8.ast.processing.IAstVisitor
|
import prog8.ast.processing.IAstVisitor
|
||||||
import prog8.ast.statements.ArrayIndex
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
|
|
||||||
import prog8.ast.statements.Subroutine
|
|
||||||
import prog8.ast.statements.VarDecl
|
|
||||||
import prog8.compiler.target.CompilationTarget
|
import prog8.compiler.target.CompilationTarget
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import prog8.functions.NotConstArgumentException
|
import prog8.functions.NotConstArgumentException
|
||||||
@ -454,7 +451,7 @@ class StringLiteralValue(val value: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArrayLiteralValue(val type: DataType, // only array types
|
class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred because not all array literals hava a known type yet
|
||||||
val value: Array<Expression>,
|
val value: Array<Expression>,
|
||||||
override val position: Position) : Expression() {
|
override val position: Position) : Expression() {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
@ -470,7 +467,8 @@ class ArrayLiteralValue(val type: DataType, // only array types
|
|||||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
override fun toString(): String = "$value"
|
override fun toString(): String = "$value"
|
||||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(type)
|
override fun inferType(program: Program): InferredTypes.InferredType = if(type.isUnknown) type else guessDatatype(program)
|
||||||
|
|
||||||
operator fun compareTo(other: ArrayLiteralValue): Int = throw ExpressionError("cannot order compare arrays", position)
|
operator fun compareTo(other: ArrayLiteralValue): Int = throw ExpressionError("cannot order compare arrays", position)
|
||||||
override fun hashCode(): Int = Objects.hash(value, type)
|
override fun hashCode(): Int = Objects.hash(value, type)
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -479,8 +477,36 @@ class ArrayLiteralValue(val type: DataType, // only array types
|
|||||||
return type==other.type && value.contentEquals(other.value)
|
return type==other.type && value.contentEquals(other.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun guessDatatype(program: Program): InferredTypes.InferredType {
|
||||||
|
// Educated guess of the desired array literal's datatype.
|
||||||
|
// If it's inside a for loop, assume the data type of the loop variable is what we want.
|
||||||
|
val forloop = parent as? ForLoop
|
||||||
|
if(forloop != null) {
|
||||||
|
val loopvarDt = forloop.loopVarDt(program)
|
||||||
|
if(loopvarDt.isKnown) {
|
||||||
|
return if(loopvarDt.typeOrElse(DataType.STRUCT) !in ElementArrayTypes)
|
||||||
|
InferredTypes.InferredType.unknown()
|
||||||
|
else
|
||||||
|
InferredTypes.InferredType.known(ElementArrayTypes.getValue(loopvarDt.typeOrElse(DataType.STRUCT)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, select the "biggegst" datatype based on the elements in the array.
|
||||||
|
val datatypesInArray = value.map { it.inferType(program) }
|
||||||
|
require(datatypesInArray.isNotEmpty() && datatypesInArray.all { it.isKnown }) { "can't determine type of empty array" }
|
||||||
|
val dts = datatypesInArray.map { it.typeOrElse(DataType.STRUCT) }
|
||||||
|
return when {
|
||||||
|
DataType.FLOAT in dts -> InferredTypes.InferredType.known(DataType.ARRAY_F)
|
||||||
|
DataType.WORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_W)
|
||||||
|
DataType.UWORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW)
|
||||||
|
DataType.BYTE in dts -> InferredTypes.InferredType.known(DataType.ARRAY_B)
|
||||||
|
DataType.UBYTE in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UB)
|
||||||
|
else -> InferredTypes.InferredType.unknown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun cast(targettype: DataType): ArrayLiteralValue? {
|
fun cast(targettype: DataType): ArrayLiteralValue? {
|
||||||
if(type==targettype)
|
if(type.istype(targettype))
|
||||||
return this
|
return this
|
||||||
if(targettype in ArrayDatatypes) {
|
if(targettype in ArrayDatatypes) {
|
||||||
val elementType = ArrayElementTypes.getValue(targettype)
|
val elementType = ArrayElementTypes.getValue(targettype)
|
||||||
@ -499,7 +525,7 @@ class ArrayLiteralValue(val type: DataType, // only array types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
return ArrayLiteralValue(targettype, castArray, position = position)
|
return ArrayLiteralValue(InferredTypes.InferredType.known(targettype), castArray, position = position)
|
||||||
}
|
}
|
||||||
return null // invalid type conversion from $this to $targettype
|
return null // invalid type conversion from $this to $targettype
|
||||||
}
|
}
|
||||||
|
@ -686,11 +686,13 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(array: ArrayLiteralValue) {
|
override fun visit(array: ArrayLiteralValue) {
|
||||||
if(!compilerOptions.floats && array.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) {
|
if(array.type.isKnown) {
|
||||||
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", array.position))
|
if (!compilerOptions.floats && array.type.typeOrElse(DataType.STRUCT) in setOf(DataType.FLOAT, DataType.ARRAY_F)) {
|
||||||
|
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", array.position))
|
||||||
|
}
|
||||||
|
val arrayspec = ArrayIndex.forArray(array)
|
||||||
|
checkValueTypeAndRangeArray(array.type.typeOrElse(DataType.STRUCT), null, arrayspec, array)
|
||||||
}
|
}
|
||||||
val arrayspec = ArrayIndex.forArray(array)
|
|
||||||
checkValueTypeAndRangeArray(array.type, null, arrayspec, array)
|
|
||||||
|
|
||||||
super.visit(array)
|
super.visit(array)
|
||||||
}
|
}
|
||||||
@ -1064,11 +1066,15 @@ internal class AstChecker(private val program: Program,
|
|||||||
checkResult.add(ExpressionError(msg, value.position))
|
checkResult.add(ExpressionError(msg, value.position))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(value.type.isUnknown)
|
||||||
|
return err("attempt to check values of array with as yet unknown datatype")
|
||||||
|
|
||||||
when (targetDt) {
|
when (targetDt) {
|
||||||
DataType.STR -> return err("string value expected")
|
DataType.STR -> return err("string value expected")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
// value may be either a single byte, or a byte arraysize (of all constant values), or a range
|
// value may be either a single byte, or a byte arraysize (of all constant values), or a range
|
||||||
if(value.type==targetDt) {
|
if(value.type.istype(targetDt)) {
|
||||||
if(!checkArrayValues(value, targetDt))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySpecSize = arrayspec.size()
|
val arraySpecSize = arrayspec.size()
|
||||||
@ -1090,7 +1096,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||||
// value may be either a single word, or a word arraysize, or a range
|
// value may be either a single word, or a word arraysize, or a range
|
||||||
if(value.type==targetDt) {
|
if(value.type.istype(targetDt)) {
|
||||||
if(!checkArrayValues(value, targetDt))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySpecSize = arrayspec.size()
|
val arraySpecSize = arrayspec.size()
|
||||||
@ -1112,7 +1118,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
DataType.ARRAY_F -> {
|
DataType.ARRAY_F -> {
|
||||||
// value may be either a single float, or a float arraysize
|
// value may be either a single float, or a float arraysize
|
||||||
if(value.type==targetDt) {
|
if(value.type.istype(targetDt)) {
|
||||||
if(!checkArrayValues(value, targetDt))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySize = value.value.size
|
val arraySize = value.value.size
|
||||||
@ -1138,7 +1144,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
return err("invalid float array initialization value ${value.type}, expected $targetDt")
|
return err("invalid float array initialization value ${value.type}, expected $targetDt")
|
||||||
}
|
}
|
||||||
DataType.STRUCT -> {
|
DataType.STRUCT -> {
|
||||||
if(value.type in ArrayDatatypes) {
|
if(value.type.typeOrElse(DataType.STRUCT) in ArrayDatatypes) {
|
||||||
if(value.value.size != struct!!.numberOfElements)
|
if(value.value.size != struct!!.numberOfElements)
|
||||||
return err("number of values is not the same as the number of members in the struct")
|
return err("number of values is not the same as the number of members in the struct")
|
||||||
for(elt in value.value.zip(struct.statements)) {
|
for(elt in value.value.zip(struct.statements)) {
|
||||||
|
@ -225,22 +225,34 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
return super.visit(returnStmt)
|
return super.visit(returnStmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
val vardecl = array.parent as? VarDecl
|
val vardecl = array.parent as? VarDecl
|
||||||
return if(vardecl!=null)
|
// adjust the datatype of the array (to an educated guess)
|
||||||
fixupArrayEltDatatypesFromVardecl(array, vardecl)
|
if(vardecl!=null) {
|
||||||
|
val arrayDt = array.type
|
||||||
|
if(!arrayDt.istype(vardecl.datatype)) {
|
||||||
|
val cast = array.cast(vardecl.datatype)
|
||||||
|
if (cast != null) {
|
||||||
|
vardecl.value = cast
|
||||||
|
cast.linkParents(vardecl)
|
||||||
|
return cast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array
|
val arrayDt = array.guessDatatype(program)
|
||||||
// (we don't know the desired datatype here exactly so we guess)
|
if(arrayDt.isKnown) {
|
||||||
val datatype = determineArrayDt(array.value)
|
// this array literal is part of an expression, turn it into an identifier reference
|
||||||
val litval2 = array.cast(datatype)
|
val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT))
|
||||||
if(litval2!=null) {
|
return if (litval2 != null) {
|
||||||
litval2.parent = array.parent
|
litval2.parent = array.parent
|
||||||
// finally, replace the literal array by a identifier reference.
|
makeIdentifierFromRefLv(litval2)
|
||||||
makeIdentifierFromRefLv(litval2)
|
} else array
|
||||||
} else array
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array
|
return array
|
||||||
@ -261,20 +273,6 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun determineArrayDt(array: Array<Expression>): DataType {
|
|
||||||
val datatypesInArray = array.map { it.inferType(program) }
|
|
||||||
require(datatypesInArray.isNotEmpty() && datatypesInArray.all { it.isKnown }) { "can't determine type of empty array" }
|
|
||||||
val dts = datatypesInArray.map { it.typeOrElse(DataType.STRUCT) }
|
|
||||||
return when {
|
|
||||||
DataType.FLOAT in dts -> DataType.ARRAY_F
|
|
||||||
DataType.WORD in dts -> DataType.ARRAY_W
|
|
||||||
DataType.UWORD in dts -> DataType.ARRAY_UW
|
|
||||||
DataType.BYTE in dts -> DataType.ARRAY_B
|
|
||||||
DataType.UBYTE in dts -> DataType.ARRAY_UB
|
|
||||||
else -> throw IllegalArgumentException("can't determine type of array")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeIdentifierFromRefLv(array: ArrayLiteralValue): IdentifierReference {
|
private fun makeIdentifierFromRefLv(array: ArrayLiteralValue): IdentifierReference {
|
||||||
// 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
|
||||||
@ -350,46 +348,3 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
val dt = when {
|
|
||||||
DataType.FLOAT in dts -> DataType.ARRAY_F
|
|
||||||
DataType.WORD in dts -> DataType.ARRAY_W
|
|
||||||
DataType.UWORD in dts -> DataType.ARRAY_UW
|
|
||||||
DataType.BYTE in dts -> DataType.ARRAY_B
|
|
||||||
else -> DataType.ARRAY_UB
|
|
||||||
}
|
|
||||||
if(dt==array.type)
|
|
||||||
return array
|
|
||||||
|
|
||||||
// convert values and array type
|
|
||||||
val elementType = ArrayElementTypes.getValue(dt)
|
|
||||||
val allNumerics = array.value.all { it is NumericLiteralValue }
|
|
||||||
if(allNumerics) {
|
|
||||||
val values = array.value.map { (it as NumericLiteralValue).cast(elementType) as Expression }.toTypedArray()
|
|
||||||
val array2 = ArrayLiteralValue(dt, values, array.position)
|
|
||||||
array2.linkParents(array.parent)
|
|
||||||
return array2
|
|
||||||
}
|
|
||||||
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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
|
|
||||||
}
|
|
||||||
|
@ -42,7 +42,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
|
|||||||
if(decl.isArray && decl.value==null) {
|
if(decl.isArray && decl.value==null) {
|
||||||
// array datatype without initialization value, add list of zeros
|
// array datatype without initialization value, add list of zeros
|
||||||
val arraysize = decl.arraysize!!.size()!!
|
val arraysize = decl.arraysize!!.size()!!
|
||||||
val array = ArrayLiteralValue(decl.datatype,
|
val array = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
|
||||||
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
||||||
decl.position)
|
decl.position)
|
||||||
decl.value = array
|
decl.value = array
|
||||||
|
@ -199,7 +199,7 @@ class VarDecl(val type: VarDeclType,
|
|||||||
|
|
||||||
fun createAuto(array: ArrayLiteralValue): VarDecl {
|
fun createAuto(array: ArrayLiteralValue): VarDecl {
|
||||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||||
val declaredType = ArrayElementTypes.getValue(array.type)
|
val declaredType = ArrayElementTypes.getValue(array.type.typeOrElse(DataType.STRUCT))
|
||||||
val arraysize = ArrayIndex.forArray(array)
|
val arraysize = ArrayIndex.forArray(array)
|
||||||
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
|
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
|
||||||
isArray = true, autogeneratedDontRemove = true, position = array.position)
|
isArray = true, autogeneratedDontRemove = true, position = array.position)
|
||||||
@ -663,6 +663,12 @@ class ForLoop(val loopRegister: Register?,
|
|||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ForLoop(loopVar: $loopVar, loopReg: $loopRegister, iterable: $iterable, pos=$position)"
|
return "ForLoop(loopVar: $loopVar, loopReg: $loopRegister, iterable: $iterable, pos=$position)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun loopVarDt(program: Program): InferredTypes.InferredType {
|
||||||
|
val lv = loopVar
|
||||||
|
return if(loopRegister!=null) InferredTypes.InferredType.known(DataType.UBYTE)
|
||||||
|
else lv?.inferType(program) ?: InferredTypes.InferredType.unknown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WhileLoop(var condition: Expression,
|
class WhileLoop(var condition: Expression,
|
||||||
|
@ -5,8 +5,6 @@ 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.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
|
||||||
@ -76,11 +74,11 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
if(constRange!=null) {
|
if(constRange!=null) {
|
||||||
val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE)
|
val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE)
|
||||||
if(eltType in ByteDatatypes) {
|
if(eltType in ByteDatatypes) {
|
||||||
decl.value = ArrayLiteralValue(decl.datatype,
|
decl.value = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
|
||||||
constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(),
|
constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(),
|
||||||
position = decl.value!!.position)
|
position = decl.value!!.position)
|
||||||
} else {
|
} else {
|
||||||
decl.value = ArrayLiteralValue(decl.datatype,
|
decl.value = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
|
||||||
constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(),
|
constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(),
|
||||||
position = decl.value!!.position)
|
position = decl.value!!.position)
|
||||||
}
|
}
|
||||||
@ -116,7 +114,7 @@ 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(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position)
|
||||||
decl.value = refValue
|
decl.value = refValue
|
||||||
refValue.parent=decl
|
refValue.parent=decl
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
@ -137,7 +135,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
else {
|
else {
|
||||||
// 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(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = litval.position)
|
||||||
decl.value = refValue
|
decl.value = refValue
|
||||||
refValue.parent=decl
|
refValue.parent=decl
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
@ -629,14 +627,18 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
|
override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
|
||||||
|
// because constant folding can result in arrays that are now suddenly capable
|
||||||
|
// of telling the type of all their elements (for instance, when they contained -2 which
|
||||||
|
// was a prefix expression earlier), we recalculate the array's datatype.
|
||||||
val array = super.visit(arrayLiteral)
|
val array = super.visit(arrayLiteral)
|
||||||
if(array is ArrayLiteralValue) {
|
if(array is ArrayLiteralValue) {
|
||||||
val vardecl = array.parent as? VarDecl
|
if(array.type.isKnown)
|
||||||
return if (vardecl!=null) {
|
return array
|
||||||
fixupArrayEltDatatypesFromVardecl(array, vardecl)
|
val arrayDt = array.guessDatatype(program)
|
||||||
} else {
|
if(arrayDt.isKnown) {
|
||||||
// it's not an array associated with a vardecl, attempt to guess the data type from the array values
|
val newArray = arrayLiteral.cast(arrayDt.typeOrElse(DataType.STRUCT))
|
||||||
fixupArrayEltDatatypes(array, program)
|
if(newArray!=null)
|
||||||
|
return newArray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array
|
return array
|
||||||
|
@ -22,7 +22,7 @@ internal class SimplifyExpressions(private val program: Program) : IAstModifying
|
|||||||
|
|
||||||
override fun visit(assignment: Assignment): Statement {
|
override fun visit(assignment: Assignment): Statement {
|
||||||
if (assignment.aug_op != null)
|
if (assignment.aug_op != null)
|
||||||
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer")
|
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer: $assignment")
|
||||||
return super.visit(assignment)
|
return super.visit(assignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ internal class StatementOptimizer(private val program: Program) : IAstModifyingV
|
|||||||
|
|
||||||
override fun visit(assignment: Assignment): Statement {
|
override fun visit(assignment: Assignment): Statement {
|
||||||
if(assignment.aug_op!=null)
|
if(assignment.aug_op!=null)
|
||||||
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer")
|
throw AstException("augmented assignments should have been converted to normal assignments before this optimizer: $assignment")
|
||||||
|
|
||||||
if(assignment.target isSameAs assignment.value) {
|
if(assignment.target isSameAs assignment.value) {
|
||||||
if(assignment.target.isNotMemory(program.namespace)) {
|
if(assignment.target.isNotMemory(program.namespace)) {
|
||||||
|
@ -603,9 +603,9 @@ open class RuntimeValueArray(type: DataType, val array: Array<Number>, val heapI
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromLv(array: ArrayLiteralValue): RuntimeValueArray {
|
fun fromLv(array: ArrayLiteralValue): RuntimeValueArray {
|
||||||
return if (array.type == DataType.ARRAY_F) {
|
return if (array.type.istype(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(DataType.ARRAY_F, 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.typeOrElse(DataType.STRUCT), resultArray.toTypedArray(), array.heapId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.ArrayLiteralValue
|
import prog8.ast.expressions.ArrayLiteralValue
|
||||||
|
import prog8.ast.expressions.InferredTypes
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.StringLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -96,9 +97,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), dummyPos)
|
val lv1 = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOne, lvTwo, lvThree), dummyPos)
|
||||||
val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos)
|
val lv2 = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos)
|
||||||
val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), dummyPos)
|
val lv3 = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvFour), dummyPos)
|
||||||
assertEquals(lv1, lv2)
|
assertEquals(lv1, lv2)
|
||||||
assertNotEquals(lv1, lv3)
|
assertNotEquals(lv1, lv3)
|
||||||
}
|
}
|
||||||
|
120
examples/test.p8
120
examples/test.p8
@ -5,125 +5,7 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
ubyte[] uba = [1,2,3]
|
byte[] barr = [22,-33,-44,55,66]
|
||||||
byte[] bba = [1,2,3]
|
|
||||||
uword[] uwa = [1111,2222,3333]
|
|
||||||
word[] wwa = [1111,2222,3333]
|
|
||||||
|
|
||||||
ubyte ub
|
|
||||||
byte bb
|
|
||||||
uword uw
|
|
||||||
word ww
|
|
||||||
|
|
||||||
for ub in uba {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for bb in bba {
|
|
||||||
c64scr.print_b(bb)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in uwa {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for ww in wwa {
|
|
||||||
c64scr.print_w(ww)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
|
|
||||||
for ub in [1,2,3] {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
; c64scr.print("\n")
|
|
||||||
; for bb in [1,2,3] { ; TODO fix array literal conversion error
|
|
||||||
; c64scr.print_b(bb)
|
|
||||||
; c64scr.print(",")
|
|
||||||
; }
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in [1111,2222,3333] {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
; c64scr.print("\n")
|
|
||||||
; for ww in [1111,2222,3333] { ; TODO fix array literal conversion error
|
|
||||||
; c64scr.print_w(ww)
|
|
||||||
; c64scr.print(",")
|
|
||||||
; }
|
|
||||||
c64scr.print("\n")
|
|
||||||
|
|
||||||
ubyte[] ubb1 = [ 1 ]
|
|
||||||
ubyte[] ubb2 = [ 1, 2]
|
|
||||||
ubyte[] ubb3 = [ 1,2,3 ]
|
|
||||||
ubyte[] ubb4 = [ 1,2,3,4 ]
|
|
||||||
uword[] uww1 = [111]
|
|
||||||
uword[] uww2 = [111,222]
|
|
||||||
uword[] uww3 = [111,222,333]
|
|
||||||
uword[] uww4 = [111,222,333,444]
|
|
||||||
|
|
||||||
reverse(ubb1)
|
|
||||||
reverse(ubb2)
|
|
||||||
reverse(ubb3)
|
|
||||||
reverse(ubb4)
|
|
||||||
reverse(uww1)
|
|
||||||
reverse(uww2)
|
|
||||||
reverse(uww3)
|
|
||||||
reverse(uww4)
|
|
||||||
for ub in ubb1 {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for ub in ubb2 {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for ub in ubb3 {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for ub in ubb4 {
|
|
||||||
c64scr.print_ub(ub)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in uww1 {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in uww2 {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in uww3 {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
for uw in uww4 {
|
|
||||||
c64scr.print_uw(uw)
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
|
|
||||||
float[] fa = [1.1, 2.2, 3.3, 4.4, 5.5]
|
|
||||||
reverse(fa)
|
|
||||||
sort(uww3)
|
|
||||||
sort(fa)
|
|
||||||
for ub in 0 to len(fa)-1 {
|
|
||||||
c64flt.print_f(fa[ub])
|
|
||||||
c64scr.print(",")
|
|
||||||
}
|
|
||||||
c64scr.print("\n")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ main {
|
|||||||
return
|
return
|
||||||
|
|
||||||
str s1 = "hello"
|
str s1 = "hello"
|
||||||
str s2 = "screencodes" ; TODO as c64sc
|
str s2 = @"screencodes"
|
||||||
|
|
||||||
&str ms1 = $c000
|
&str ms1 = $c000
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ main {
|
|||||||
count = 0
|
count = 0
|
||||||
total = 0
|
total = 0
|
||||||
c64scr.print("byte var in arrayliteral: ")
|
c64scr.print("byte var in arrayliteral: ")
|
||||||
for bb in [1,3,5,99] { ; TODO now gives compiler error, fix byte var array literal conversion
|
for bb in [1,3,5,99] {
|
||||||
count++
|
count++
|
||||||
total += bb
|
total += bb
|
||||||
}
|
}
|
||||||
@ -790,7 +790,7 @@ main {
|
|||||||
count = 0
|
count = 0
|
||||||
total = 0
|
total = 0
|
||||||
c64scr.print("word var in arrayliteral: ")
|
c64scr.print("word var in arrayliteral: ")
|
||||||
for ww in [1111,3333,555,999] { ; TODO now compiler error, fix word var array literal conversion
|
for ww in [1111,3333,555,999] {
|
||||||
count++
|
count++
|
||||||
total += ww
|
total += ww
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user