From cc9965cc961dcc1697a305ce179ddb958445477d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 30 Jul 2019 23:35:25 +0200 Subject: [PATCH] improved deduction of array datatypes --- .../prog8/ast/expressions/AstExpressions.kt | 16 +++-- .../src/prog8/ast/processing/AstChecker.kt | 1 - .../ast/processing/AstIdentifiersChecker.kt | 63 ++++++++++++++++- .../compiler/target/c64/codegen2/AsmGen2.kt | 22 +++++- .../src/prog8/optimizer/ConstantFolding.kt | 27 +------- examples/test.p8 | 67 ++++++++++++------- 6 files changed, 134 insertions(+), 62 deletions(-) diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 700a78031..3d491752b 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -600,13 +600,15 @@ class ReferenceLiteralValue(val type: DataType, // only reference types allo } heapId = heap.addIntegerArray(type, intArrayWithAddressOfs.toTypedArray()) } else { - val valuesInArray = array.map { (it as NumericLiteralValue).number } - heapId = if(type== DataType.ARRAY_F) { - val doubleArray = valuesInArray.map { it.toDouble() }.toDoubleArray() - heap.addDoublesArray(doubleArray) - } else { - val integerArray = valuesInArray.map { it.toInt() } - heap.addIntegerArray(type, integerArray.map { IntegerOrAddressOf(it, null) }.toTypedArray()) + val valuesInArray = array.map { (it as? NumericLiteralValue)?.number } + if(null !in valuesInArray) { + heapId = if (type == DataType.ARRAY_F) { + val doubleArray = valuesInArray.map { it!!.toDouble() }.toDoubleArray() + heap.addDoublesArray(doubleArray) + } else { + val integerArray = valuesInArray.map { it!!.toInt() } + heap.addIntegerArray(type, integerArray.map { IntegerOrAddressOf(it, null) }.toTypedArray()) + } } } } diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 9585ee67a..f55ec048b 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -1061,7 +1061,6 @@ internal class AstChecker(private val program: Program, } return err("invalid word array size, must be 1-128") } - TODO("${value.position}") return err("invalid word array initialization value ${value.type}, expected $targetDt") } DataType.ARRAY_F -> { diff --git a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt index 0ee8e568b..114c31a18 100644 --- a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt @@ -7,6 +7,7 @@ import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* +import prog8.compiler.HeapValues import prog8.compiler.target.c64.AssemblyProgram import prog8.functions.BuiltinFunctions @@ -233,10 +234,49 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi } override fun visit(refLiteral: ReferenceLiteralValue): Expression { - if(refLiteral.parent !is VarDecl) { - return makeIdentifierFromRefLv(refLiteral) + val litval = super.visit(refLiteral) + if(litval is ReferenceLiteralValue) { + if (litval.isString) { + // intern the string; move it into the heap + if (litval.str!!.length !in 1..255) + checkResult.add(ExpressionError("string literal length must be between 1 and 255", litval.position)) + else { + litval.addToHeap(program.heap) + } + } else if (litval.isArray) { + val vardecl = litval.parent as? VarDecl + if (vardecl!=null) { + return fixupArrayDatatype(litval, vardecl, program.heap) + } 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(litval.array!!) ?: return litval + val litval2 = litval.cast(datatype)!! + litval2.parent = litval.parent + // finally, replace the literal by a identifier reference. + return makeIdentifierFromRefLv(litval2) + } + } } - return super.visit(refLiteral) + + return litval + } + + private fun determineArrayDt(array: Array): DataType? { + val datatypesInArray = array.mapNotNull { it.inferType(program) } + if(datatypesInArray.isEmpty()) + return null + if(DataType.FLOAT in datatypesInArray) + return DataType.ARRAY_F + if(DataType.WORD in datatypesInArray) + return DataType.ARRAY_W + if(DataType.UWORD in datatypesInArray) + return DataType.ARRAY_UW + if(DataType.BYTE in datatypesInArray) + return DataType.ARRAY_B + if(DataType.UBYTE in datatypesInArray) + return DataType.ARRAY_UB + return null } private fun makeIdentifierFromRefLv(refLiteral: ReferenceLiteralValue): IdentifierReference { @@ -315,3 +355,20 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi } } + +internal fun fixupArrayDatatype(array: ReferenceLiteralValue, vardecl: VarDecl, heap: HeapValues): ReferenceLiteralValue { + if(array.heapId!=null) { + val arrayDt = array.type + if(arrayDt!=vardecl.datatype) { + // fix the datatype of the array (also on the heap) to match the vardecl + val litval2 = array.cast(vardecl.datatype)!! + vardecl.value = litval2 + litval2.linkParents(vardecl) + litval2.addToHeap(heap) // TODO is the previous array discarded from the resulting asm code? + return litval2 + } + } else { + array.addToHeap(heap) + } + return array +} diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index f075f3ba0..60fa2b45e 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -952,7 +952,27 @@ internal class AsmGen2(val program: Program, } private fun translate(stmt: ForLoop) { - TODO("forloop $stmt") + when(stmt.iterable) { + is RangeExpr -> { + println("forloop over range $stmt") + } + is IdentifierReference -> { + val iterableDt = stmt.iterable.inferType(program) + when(iterableDt) { + DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> { + println("forloop over byte array/string $stmt") + } + DataType.ARRAY_W, DataType.ARRAY_UW -> { + println("forloop over word array $stmt") + } + DataType.ARRAY_F -> { + println("forloop over float array $stmt") + } + else -> throw AssemblyError("can't iterate over $iterableDt") + } + } + else -> throw AssemblyError("can't iterate over ${stmt.iterable}") + } } private fun translate(stmt: PostIncrDecr) { diff --git a/compiler/src/prog8/optimizer/ConstantFolding.kt b/compiler/src/prog8/optimizer/ConstantFolding.kt index 3cec7f85a..b7c248d77 100644 --- a/compiler/src/prog8/optimizer/ConstantFolding.kt +++ b/compiler/src/prog8/optimizer/ConstantFolding.kt @@ -5,6 +5,7 @@ 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.statements.* import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE @@ -580,33 +581,11 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { override fun visit(refLiteral: ReferenceLiteralValue): Expression { val litval = super.visit(refLiteral) if(litval is ReferenceLiteralValue) { - if (litval.isString) { - // intern the string; move it into the heap - if (litval.str!!.length !in 1..255) - addError(ExpressionError("string literal length must be between 1 and 255", litval.position)) - else { - litval.addToHeap(program.heap) - } - } else if (litval.isArray) { + if (litval.isArray) { val vardecl = litval.parent as? VarDecl if (vardecl!=null) { - if(litval.heapId!=null) { - val arrayDt = litval.type - if(arrayDt!=vardecl.datatype) { - // fix the datatype of the array (also on the heap) to match the vardecl - val litval2 = litval.cast(vardecl.datatype)!! - vardecl.value = litval2 - litval2.linkParents(vardecl) - litval2.addToHeap(program.heap) // TODO is the previous array discarded from the resulting asm code? - return litval2 - } - } - } else { - TODO("VISIT REFLITERAL OUTSIDE OF VARDECL $litval") + return fixupArrayDatatype(litval, vardecl, program.heap) } - - if(litval.heapId==null) - litval.addToHeap(program.heap) } } return litval diff --git a/examples/test.p8 b/examples/test.p8 index 7ab98ecff..1e32d2377 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,35 +4,50 @@ main { - ubyte abc - - sub start() { +; byte bvar +; ubyte var2 +; +; for A in "hello" { +; c64scr.print_ub(A) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') +; +; for A in [1,3,5,99] { +; c64scr.print_ub(A) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') +; +; for A in 10 to 20 { +; c64scr.print_ub(A) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') - A=abc - ubyte zzz - - repeat { - uword wvar - Y=abc - Y=zzz - wvar=99 - } until 99 - - repeat { - uword wvar - Y=abc - Y=zzz - wvar=99 - } until 99 - - if A>0 { - uword wvar - Y=abc - Y=zzz - wvar=99 + for float fl in [1.1, 2.2, 5.5, 99.99] { + c64flt.print_f(fl) + c64.CHROUT(',') } + c64.CHROUT('\n') - +; for var2 in 10 to 20 { +; c64scr.print_ub(var2) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') +; +; for ubyte var3 in 10 to 20 { +; c64scr.print_ub(var3) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') +; +; for bvar in -5 to 5 { +; c64scr.print_b(bvar) +; c64.CHROUT(',') +; } +; c64.CHROUT('\n') } }