From bd295ffc9968d4bfed80ad1e4bd0c4e8bd987a48 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 22 Mar 2021 19:33:57 +0100 Subject: [PATCH] array indexer complexity is now dealt with in the asm-generator only --- .../compiler/BeforeAsmGenerationAstChanger.kt | 41 +++++++++++++ .../compiler/astprocessing/AstChecker.kt | 13 +---- .../astprocessing/StatementReorderer.kt | 58 ++----------------- .../compiler/target/cpu6502/codegen/AsmGen.kt | 4 +- .../cpu6502/codegen/BuiltinFunctionsAsmGen.kt | 16 ++--- .../cpu6502/codegen/ExpressionsAsmGen.kt | 13 ++--- .../cpu6502/codegen/PostIncrDecrAsmGen.kt | 5 +- .../codegen/assignment/AsmAssignment.kt | 8 +-- .../codegen/assignment/AssignmentAsmGen.kt | 46 ++++++++------- .../assignment/AugmentableAssignmentAsmGen.kt | 4 +- .../optimizer/ConstantIdentifierReplacer.kt | 15 +---- compilerAst/src/prog8/ast/AstToSourceCode.kt | 6 +- .../src/prog8/ast/statements/AstStatements.kt | 58 +++---------------- 13 files changed, 104 insertions(+), 183 deletions(-) diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index e7160c226..853b8cf7a 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -228,4 +228,45 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I } return noModifications } + + override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { + val index = arrayIndexedExpression.indexer.indexExpr + if(index !is NumericLiteralValue && index !is IdentifierReference) { + // replace complex indexing expression with a temp variable to hold the computed index first + return getAutoIndexerVarFor(arrayIndexedExpression) + } + + return noModifications + } + + private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList { + val modifications = mutableListOf() + val subroutine = expr.definingSubroutine()!! + val statement = expr.containingStatement() + val indexerVarPrefix = "prog8_autovar_index_" + val repo = subroutine.asmGenInfo.usedAutoArrayIndexerForStatements + + // TODO [codegen] make this a bit smarter so it can reuse indexer variables. BUT BEWARE of scoping+initialization problems then + // for instance when dealing with multiple complex array indices in a single statement... + // ... use cx16's virtual registers for this instead of adding new variables? + + // add another loop index var to be used for this expression + val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}" + val indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer) + repo.add(indexerVar) + // create the indexer var at block level scope + val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, + null, indexerVarName, null, null, isArray = false, autogeneratedDontRemove = true, position = expr.position) + modifications.add(IAstModification.InsertFirst(vardecl, subroutine)) + + // replace the indexer with just the variable + // assign the indexing expression to the helper variable, but only if that hasn't been done already + val target = AssignTarget(IdentifierReference(listOf(indexerVar.name), expr.indexer.position), null, null, expr.indexer.position) + val assign = Assignment(target, expr.indexer.indexExpr, expr.indexer.position) + modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope())) + modifications.add(IAstModification.ReplaceNode(expr.indexer.indexExpr, target.identifier!!.copy(), expr.indexer)) // TODO is this ok now? + + return modifications + } + } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 2a9ae76f8..7dd0fe931 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -493,7 +493,7 @@ internal class AstChecker(private val program: Program, fun err(msg: String, position: Position?=null) = errors.err(msg, position ?: decl.position) // the initializer value can't refer to the variable itself (recursive definition) - if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexVar?.referencesIdentifier(decl.name) == true) + if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexExpr?.referencesIdentifier(decl.name) == true) err("recursive var declaration") // CONST can only occur on simple types (byte, word, float) @@ -1125,16 +1125,9 @@ internal class AstChecker(private val program: Program, errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position) // check index value 0..255 - val dtxNum = arrayIndexedExpression.indexer.indexNum?.inferType(program)?.typeOrElse(DataType.STRUCT) - if(dtxNum!=null && dtxNum != DataType.UBYTE && dtxNum != DataType.BYTE) + val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) + if(!dtxNum.istype(DataType.UBYTE) && !dtxNum.istype(DataType.BYTE)) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) - val dtxVar = arrayIndexedExpression.indexer.indexVar?.inferType(program)?.typeOrElse(DataType.STRUCT) - if(dtxVar!=null && dtxVar != DataType.UBYTE && dtxVar != DataType.BYTE) - errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) - - // TODO remove this once this rewriter is moved to BeforeAsmGen - if(arrayIndexedExpression.indexer.origExpression!=null) - throw FatalAstException("array indexer should have been replaced with a temp var @ ${arrayIndexedExpression.indexer.position}") super.visit(arrayIndexedExpression) } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index c89419fd8..02ad6ca79 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -1,6 +1,9 @@ package prog8.compiler.astprocessing -import prog8.ast.* +import prog8.ast.IFunctionCall +import prog8.ast.Module +import prog8.ast.Node +import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* @@ -89,8 +92,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport if(arrayVar!=null && arrayVar.datatype == DataType.UWORD) { // rewrite pointervar[index] into @(pointervar+index) val indexer = arrayIndexedExpression.indexer - val index = (indexer.indexNum ?: indexer.indexVar)!! - val add = BinaryExpression(arrayIndexedExpression.arrayvar, "+", index, arrayIndexedExpression.position) + val add = BinaryExpression(arrayIndexedExpression.arrayvar, "+", indexer.indexExpr, arrayIndexedExpression.position) return if(parent is AssignTarget) { // we're part of the target of an assignment, we have to actually change the assign target itself val memwrite = DirectMemoryWrite(add, arrayIndexedExpression.position) @@ -102,23 +104,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport } } - when (val expr2 = arrayIndexedExpression.indexer.origExpression) { - is NumericLiteralValue -> { - arrayIndexedExpression.indexer.indexNum = expr2 - arrayIndexedExpression.indexer.origExpression = null - return noModifications - } - is IdentifierReference -> { - arrayIndexedExpression.indexer.indexVar = expr2 - arrayIndexedExpression.indexer.origExpression = null - return noModifications - } - is Expression -> { - // replace complex indexing with a temp variable TODO move this to BeforeAsmGeneration transformer, get rid of indexNum/indexVar/origExpression differentiation? (just use 'is Identifier' etc)? - return getAutoIndexerVarFor(arrayIndexedExpression) - } - else -> return noModifications - } + return noModifications } override fun after(expr: BinaryExpression, parent: Node): Iterable { @@ -202,38 +188,6 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport return noModifications } - private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList { - val modifications = mutableListOf() - val subroutine = expr.definingSubroutine()!! - val statement = expr.containingStatement() - val indexerVarPrefix = "prog8_autovar_index_" - val repo = subroutine.asmGenInfo.usedAutoArrayIndexerForStatements - - // TODO [codegen] make this a bit smarter so it can reuse indexer variables. BUT BEWARE of scoping+initialization problems then - // add another loop index var to be used for this expression - val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}" - val indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer) - repo.add(indexerVar) - // create the indexer var at block level scope - val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, - null, indexerVarName, null, null, isArray = false, autogeneratedDontRemove = true, position = expr.position) - modifications.add(IAstModification.InsertFirst(vardecl, subroutine)) - - // replace the indexer with just the variable - // assign the indexing expression to the helper variable, but only if that hasn't been done already - val indexerExpression = expr.indexer.origExpression!! - val target = AssignTarget(IdentifierReference(listOf(indexerVar.name), indexerExpression.position), null, null, indexerExpression.position) - val assign = Assignment(target, indexerExpression, indexerExpression.position) - modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope())) - modifications.add(IAstModification.SetExpression( { - expr.indexer.indexVar = it as IdentifierReference - expr.indexer.indexNum = null - expr.indexer.origExpression = null - }, target.identifier!!.copy(), expr.indexer)) - - return modifications - } - override fun after(whenStatement: WhenStatement, parent: Node): Iterable { val choices = whenStatement.choiceValues(program).sortedBy { it.first?.first() ?: Int.MAX_VALUE diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 1d187a938..744fa7188 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -720,11 +720,9 @@ internal class AsmGen(private val program: Program, return } - val indexVar = expr.indexer.indexVar + val indexVar = expr.indexer.indexExpr as? IdentifierReference ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.indexer.position}") - // must be indexed via variable (arbitrary expression is already replaced out) - val indexName = asmVariableName(indexVar) if(addOneExtra) { // add 1 to the result diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index 2fb50002f..a9aebacd7 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -14,11 +14,6 @@ import prog8.compiler.AssemblyError import prog8.compiler.functions.FSignature import prog8.compiler.target.CpuType import prog8.compiler.target.cpu6502.codegen.assignment.* -import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignSource -import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget -import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment -import prog8.compiler.target.cpu6502.codegen.assignment.SourceStorageKind -import prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind import prog8.compiler.target.subroutineFloatEvalResultVar2 internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) { @@ -469,8 +464,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val private fun translateRolRorArrayArgs(arrayvar: IdentifierReference, indexer: ArrayIndex, operation: String, dt: Char) { asmgen.assignExpressionToVariable(AddressOf(arrayvar, arrayvar.position), "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null) - val indexerExpr = if(indexer.indexVar!=null) indexer.indexVar!! else indexer.indexNum!! - asmgen.assignExpressionToVariable(indexerExpr, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null) + asmgen.assignExpressionToVariable(indexer.indexExpr, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null) } private fun funcVariousFloatFuncs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { @@ -685,10 +679,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val throw AssemblyError("unknown dt") val elementDt = elementIDt.typeOrElse(DataType.STRUCT) - val firstNum = first.indexer.indexNum - val firstVar = first.indexer.indexVar - val secondNum = second.indexer.indexNum - val secondVar = second.indexer.indexVar + val firstNum = first.indexer.indexExpr as? NumericLiteralValue + val firstVar = first.indexer.indexExpr as? IdentifierReference + val secondNum = second.indexer.indexExpr as? NumericLiteralValue + val secondVar = second.indexer.indexExpr as? IdentifierReference if(firstNum!=null && secondNum!=null) { swapArrayValues(elementDt, arrayVarName1, firstNum, arrayVarName2, secondNum) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt index bddfeb706..b8a5872ca 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt @@ -2055,8 +2055,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge throw AssemblyError("unknown dt") val elementDt = elementIDt.typeOrElse(DataType.STRUCT) val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar) - if(arrayExpr.indexer.indexNum!=null) { - val indexValue = arrayExpr.indexer.constIndex()!! * program.memsizer.memorySize(elementDt) + val constIndexNum = arrayExpr.indexer.constIndex() + if(constIndexNum!=null) { + val indexValue = constIndexNum * program.memsizer.memorySize(elementDt) when(elementDt) { in ByteDatatypes -> { asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | dex") @@ -2095,13 +2096,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } } - fun translateExpression(indexer: ArrayIndex) { - // it is either a number, or a variable - val indexNum = indexer.indexNum - val indexVar = indexer.indexVar - indexNum?.let { asmgen.translateExpression(indexNum) } - indexVar?.let { asmgen.translateExpression(indexVar) } - } + fun translateExpression(indexer: ArrayIndex) = asmgen.translateExpression(indexer.indexExpr) private fun translateBinaryOperatorBytes(operator: String, types: DataType) { when(operator) { diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/PostIncrDecrAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/PostIncrDecrAsmGen.kt index 939aacc10..7b689fc31 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/PostIncrDecrAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/PostIncrDecrAsmGen.kt @@ -66,8 +66,9 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg targetArrayIdx!=null -> { val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.arrayvar) val elementDt = targetArrayIdx.inferType(program).typeOrElse(DataType.STRUCT) - if(targetArrayIdx.indexer.indexNum!=null) { - val indexValue = targetArrayIdx.indexer.constIndex()!! * program.memsizer.memorySize(elementDt) + val constIndex = targetArrayIdx.indexer.constIndex() + if(constIndex!=null) { + val indexValue = constIndex * program.memsizer.memorySize(elementDt) when(elementDt) { in ByteDatatypes -> asmgen.out(if (incr) " inc $asmArrayvarname+$indexValue" else " dec $asmArrayvarname+$indexValue") in WordDatatypes -> { diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt index fea8ca3ee..536e2bb8c 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt @@ -120,13 +120,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, asmgen.asmVariableName(array.arrayvar) companion object { - fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen): AsmAssignSource { - return when { - indexer.indexNum!=null -> fromAstSource(indexer.indexNum!!, program, asmgen) - indexer.indexVar!=null -> fromAstSource(indexer.indexVar!!, program, asmgen) - else -> throw AssemblyError("weird indexer") - } - } + fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen): AsmAssignSource = fromAstSource(indexer.indexExpr, program, asmgen) fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen): AsmAssignSource { val cv = value.constValue(program) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt index 5d27a942a..f905e4d34 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt @@ -65,9 +65,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val value = assign.source.array!! val elementDt = assign.source.datatype val arrayVarName = asmgen.asmVariableName(value.arrayvar) - if (value.indexer.indexNum!=null) { + val constIndex = value.indexer.constIndex() + if (constIndex!=null) { // constant array index value - val indexValue = value.indexer.constIndex()!! * program.memsizer.memorySize(elementDt) + val indexValue = constIndex * program.memsizer.memorySize(elementDt) when (elementDt) { in ByteDatatypes -> { asmgen.out(" lda $arrayVarName+$indexValue") @@ -1074,11 +1075,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1""") - if(target.array!!.indexer.indexNum!=null) { - val index = target.array.indexer.constIndex()!! - asmgen.out(" lda #$index") + val constIndex = target.array!!.indexer.constIndex() + if(constIndex!=null) { + asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!) + val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float_from_fac1") @@ -1110,11 +1111,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1""") - if(target.array!!.indexer.indexNum!=null) { - val index = target.array.indexer.constIndex()!! - asmgen.out(" lda #$index") + val constIndex = target.array!!.indexer.constIndex() + if(constIndex!=null) { + asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!) + val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float") @@ -1157,11 +1158,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1""") - if(target.array!!.indexer.indexNum!=null) { - val index = target.array.indexer.constIndex()!! - asmgen.out(" lda #$index") + val constIndex = target.array!!.indexer.constIndex() + if(constIndex!=null) { + asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!) + val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float") @@ -1369,7 +1370,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen CpuRegister.X -> asmgen.out(" txa") CpuRegister.Y -> asmgen.out(" tya") } - asmgen.out(" ldy ${asmgen.asmVariableName(target.array!!.indexer.indexVar!!)} | sta ${target.asmVarname},y") + val indexVar = target.array!!.indexer.indexExpr as IdentifierReference + asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y") } } TargetStorageKind.REGISTER -> { @@ -1777,8 +1779,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen """) } TargetStorageKind.ARRAY -> { - if (target.array!!.indexer.indexNum!=null) { - val indexValue = target.array.indexer.constIndex()!! * program.memsizer.memorySize(DataType.FLOAT) + val constIndex = target.array!!.indexer.constIndex() + if (constIndex!=null) { + val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT) if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(""" stz ${target.asmVarname}+$indexValue @@ -1797,7 +1800,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen sta ${target.asmVarname}+$indexValue+4 """) } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!) + val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) asmgen.out(""" lda #<${target.asmVarname} sta P8ZP_SCRATCH_W1 @@ -1842,8 +1845,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } TargetStorageKind.ARRAY -> { val arrayVarName = target.asmVarname - if (target.array!!.indexer.indexNum!=null) { - val indexValue = target.array.indexer.constIndex()!! * program.memsizer.memorySize(DataType.FLOAT) + val constIndex = target.array!!.indexer.constIndex() + if (constIndex!=null) { + val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT) asmgen.out(""" lda $constFloat sta $arrayVarName+$indexValue @@ -1857,7 +1861,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen sta $arrayVarName+$indexValue+4 """) } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!) + val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) asmgen.out(""" lda #<${constFloat} sta P8ZP_SCRATCH_W1 diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AugmentableAssignmentAsmGen.kt index 815fb105f..aaf539299 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -199,9 +199,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } TargetStorageKind.ARRAY -> { with(target.array!!.indexer) { + val indexNum = indexExpr as? NumericLiteralValue + val indexVar = indexExpr as? IdentifierReference when { indexNum!=null -> { - val targetVarName = "${target.asmVarname} + ${indexNum!!.number.toInt()*program.memsizer.memorySize(target.datatype)}" + val targetVarName = "${target.asmVarname} + ${indexNum.number.toInt()*program.memsizer.memorySize(target.datatype)}" when(target.datatype) { in ByteDatatypes -> { when { diff --git a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt index e46fd5c08..a9c640d01 100644 --- a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -75,7 +75,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private override fun before(decl: VarDecl, parent: Node): Iterable { // the initializer value can't refer to the variable itself (recursive definition) // TODO: use call graph for this? - if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexVar?.referencesIdentifier(decl.name) == true) { + if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexExpr?.referencesIdentifier(decl.name) == true) { errors.err("recursive var declaration", decl.position) return noModifications } @@ -93,19 +93,6 @@ internal class ConstantIdentifierReplacer(private val program: Program, private decl )) } - } else if(arraysize.constIndex()==null) { - // see if we can calculate the size from other fields - try { - val cval = arraysize.indexVar?.constValue(program) ?: arraysize.origExpression?.constValue(program) - if (cval != null) { - arraysize.indexVar = null - arraysize.origExpression = null - arraysize.indexNum = cval - } - } catch (x: UndefinedSymbolError) { - errors.err(x.message, x.position) - return noModifications - } } } diff --git a/compilerAst/src/prog8/ast/AstToSourceCode.kt b/compilerAst/src/prog8/ast/AstToSourceCode.kt index 25372e9aa..c5eb01615 100644 --- a/compilerAst/src/prog8/ast/AstToSourceCode.kt +++ b/compilerAst/src/prog8/ast/AstToSourceCode.kt @@ -121,8 +121,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): output(datatypeString(decl.datatype)) if(decl.arraysize!=null) { - decl.arraysize!!.indexNum?.accept(this) - decl.arraysize!!.indexVar?.accept(this) + decl.arraysize!!.indexExpr.accept(this) } if(decl.isArray) output("]") @@ -365,8 +364,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { arrayIndexedExpression.arrayvar.accept(this) output("[") - arrayIndexedExpression.indexer.indexNum?.accept(this) - arrayIndexedExpression.indexer.indexVar?.accept(this) + arrayIndexedExpression.indexer.indexExpr.accept(this) output("]") } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 800072f2b..c4d532747 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -275,46 +275,19 @@ class ParameterVarDecl(name: String, declaredDatatype: DataType, position: Posit : VarDecl(VarDeclType.VAR, declaredDatatype, ZeropageWish.DONTCARE, null, name, null, null, false, true, position) -class ArrayIndex(var origExpression: Expression?, // will be replaced later by either the number or the identifier +class ArrayIndex(var indexExpr: Expression, override val position: Position) : Node { - // for code simplicity, either indexed via a constant number or via a variable (no arbitrary expressions) override lateinit var parent: Node - var indexNum: NumericLiteralValue? = origExpression as? NumericLiteralValue - var indexVar: IdentifierReference? = origExpression as? IdentifierReference - - init { - if(indexNum!=null || indexVar!=null) - origExpression = null - } override fun linkParents(parent: Node) { this.parent = parent - origExpression?.linkParents(this) - indexNum?.linkParents(this) - indexVar?.linkParents(this) + indexExpr.linkParents(this) } override fun replaceChildNode(node: Node, replacement: Node) { require(replacement is Expression) - when { - node===origExpression -> origExpression = replacement - node===indexVar -> { - when (replacement) { - is NumericLiteralValue -> { - indexVar = null - indexNum = replacement - } - is IdentifierReference -> { - indexVar = replacement - indexNum = null - } - else -> { - throw FatalAstException("invalid replace") - } - } - } - else -> throw FatalAstException("invalid replace") - } + if (node===indexExpr) indexExpr = replacement + else throw FatalAstException("invalid replace") } companion object { @@ -324,29 +297,16 @@ class ArrayIndex(var origExpression: Expression?, // will be replaced } } - fun accept(visitor: IAstVisitor) { - origExpression?.accept(visitor) - indexNum?.accept(visitor) - indexVar?.accept(visitor) - } - fun accept(visitor: AstWalker, parent: Node) { - origExpression?.accept(visitor, this) - indexNum?.accept(visitor, this) - indexVar?.accept(visitor, this) - } + fun accept(visitor: IAstVisitor) = indexExpr.accept(visitor) + fun accept(visitor: AstWalker, parent: Node) = indexExpr.accept(visitor, this) override fun toString(): String { - return("ArrayIndex($indexNum, $indexVar, pos=$position)") + return("ArrayIndex($indexExpr, pos=$position)") } - fun constIndex() = indexNum?.number?.toInt() + fun constIndex() = (indexExpr as? NumericLiteralValue)?.number?.toInt() - infix fun isSameAs(other: ArrayIndex): Boolean { - return if(indexNum!=null || indexVar!=null) - indexNum==other.indexNum && indexVar == other.indexVar - else - other.origExpression!=null && origExpression!! isSameAs other.origExpression!! - } + infix fun isSameAs(other: ArrayIndex): Boolean = indexExpr isSameAs other.indexExpr } open class Assignment(var target: AssignTarget, var value: Expression, override val position: Position) : Statement() {