diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 83879de81..fcb1e14b7 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -146,7 +146,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private // convert the initializer range expression to an actual array val declArraySize = decl.arraysize?.constIndex() if(declArraySize!=null && declArraySize!=rangeExpr.size()) - errors.err("range expression size doesn't match declared array size", decl.value?.position!!) + errors.err("range expression size (${rangeExpr.size()}) doesn't match declared array size ($declArraySize)", decl.value?.position!!) val constRange = rangeExpr.toConstantIntegerRange() if(constRange!=null) { val eltType = rangeExpr.inferType(program).getOr(DataType.UBYTE) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index a03e8d06f..5332024d8 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -255,7 +255,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget private fun processAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { // perform initial syntax checks and processings println("Processing for target ${compilerOptions.compTarget.name}...") - program.preprocessAst() + program.preprocessAst(program) program.checkIdentifiers(errors, compilerOptions) errors.report() // TODO: turning char literals into UBYTEs via an encoding should really happen in code gen - but for that we'd need DataType.CHAR diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 14e5f0481..12c9fd33f 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -65,8 +65,8 @@ internal fun Program.verifyFunctionArgTypes() { fixer.visit(this) } -internal fun Program.preprocessAst() { - val transforms = AstPreprocessor() +internal fun Program.preprocessAst(program: Program) { + val transforms = AstPreprocessor(program) transforms.visit(this) var mods = transforms.applyModifications() while(mods>0) diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index cf987b60d..416269692 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -1,9 +1,12 @@ package prog8.compiler.astprocessing import prog8.ast.Node +import prog8.ast.Program import prog8.ast.base.NumericDatatypes import prog8.ast.base.VarDeclType import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.NumericLiteralValue +import prog8.ast.expressions.RangeExpr import prog8.ast.statements.AnonymousScope import prog8.ast.statements.AssignTarget import prog8.ast.statements.Assignment @@ -12,7 +15,28 @@ import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -class AstPreprocessor : AstWalker() { +class AstPreprocessor(val program: Program) : AstWalker() { + + override fun after(range: RangeExpr, parent: Node): Iterable { + // has to be done before the constant folding, otherwise certain checks there will fail on invalid range sizes + val modifications = mutableListOf() + if(range.from !is NumericLiteralValue) { + val constval = range.from.constValue(program) + if(constval!=null) + modifications += IAstModification.ReplaceNode(range.from, constval, range) + } + if(range.to !is NumericLiteralValue) { + val constval = range.to.constValue(program) + if(constval!=null) + modifications += IAstModification.ReplaceNode(range.to, constval, range) + } + if(range.step !is NumericLiteralValue) { + val constval = range.step.constValue(program) + if(constval!=null) + modifications += IAstModification.ReplaceNode(range.step, constval, range) + } + return modifications + } override fun before(scope: AnonymousScope, parent: Node): Iterable { diff --git a/compilerInterfaces/src/prog8/compilerinterface/AstExtensions.kt b/compilerInterfaces/src/prog8/compilerinterface/AstExtensions.kt index 49b2bca24..b64f46f80 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/AstExtensions.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/AstExtensions.kt @@ -69,11 +69,12 @@ fun RangeExpr.toConstantIntegerRange(): IntProgression? { val fromLv = from as? NumericLiteralValue val toLv = to as? NumericLiteralValue - if(fromLv==null || toLv==null) + val stepLv = step as? NumericLiteralValue + if(fromLv==null || toLv==null || stepLv==null) return null val fromVal = fromLv.number.toInt() val toVal = toLv.number.toInt() - val stepVal = (step as? NumericLiteralValue)?.number?.toInt() ?: 1 + val stepVal = stepLv.number.toInt() return makeRange(fromVal, toVal, stepVal) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ad6290ab3..13874a95e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -5,6 +5,10 @@ For next compiler release (7.4) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BUG: balls example crashes / animates wrong! + caused by c83882161521378f20dc0076c01e18e8556e363e 'refactor function arguments codegen a bit' + on the lines that call txt.setclr(BX[lp], BY[lp], BC[lp]) - they work with regular vars as args + so, something wrong with clobber/arg order when passing array lookups?? + Add unit test to avoid this in the future? Use GoSub to call subroutines (statements): diff --git a/examples/test.p8 b/examples/test.p8 index abc4d6f1a..bd037bda3 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,6 +6,17 @@ main { sub start() { test_stack.test() + ubyte[50] xpos = 49 to 0 step -1 + ubyte[50] ypos = 49 to 0 step -1 + + ubyte ball + for ball in 0 to len(xpos)-1 { + txt.print_ub(xpos[ball]) + txt.spc() + txt.print_ub(ypos[ball]) + txt.nl() + } + ubyte @shared x1 = 10 ubyte @shared x2 = 20 ubyte @shared x3 = 30