diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 8469926c7..f07778178 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -120,16 +120,19 @@ class AstPreprocessor(val program: Program, movements.add(IAstModification.InsertFirst(decl, parentscope)) replacements.add(IAstModification.Remove(decl, scope)) } else { + val declToInsert: VarDecl if(decl.value!=null && decl.datatype in NumericDatatypes) { val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position) val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position) replacements.add(IAstModification.ReplaceNode(decl, assign, scope)) decl.value = null decl.allowInitializeWithZero = false + declToInsert = decl.copy() } else { replacements.add(IAstModification.Remove(decl, scope)) + declToInsert = decl } - movements.add(IAstModification.InsertFirst(decl, parentscope)) + movements.add(IAstModification.InsertFirst(declToInsert, parentscope)) } } return movements + replacements @@ -138,12 +141,10 @@ class AstPreprocessor(val program: Program, } override fun after(expr: BinaryExpression, parent: Node): Iterable { - // this has to be done here becuse otherwise the string / range literal values will have been replaced by variables if(expr.operator=="in") { val containment = ContainmentCheck(expr.left, expr.right, expr.position) return listOf(IAstModification.ReplaceNode(expr, containment, parent)) } - return noModifications } diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index c71ec5d1d..5ed3c5578 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -163,4 +163,12 @@ _after: } return noModifications } + + override fun after(expr: BinaryExpression, parent: Node): Iterable { + if(expr.operator=="in") { + val containment = ContainmentCheck(expr.left, expr.right, expr.position) + return listOf(IAstModification.ReplaceNode(expr, containment, parent)) + } + return noModifications + } } diff --git a/compiler/test/ast/TestProg8Parser.kt b/compiler/test/ast/TestProg8Parser.kt index fc4c8eea2..044a00426 100644 --- a/compiler/test/ast/TestProg8Parser.kt +++ b/compiler/test/ast/TestProg8Parser.kt @@ -913,7 +913,7 @@ class TestProg8Parser: FunSpec( { val text=""" main { sub start() { - ubyte cc + ubyte @shared cc ubyte[] array = [1,2,3] cc = 99 in 12345 cc = 9999 in array diff --git a/compiler/test/ast/TestVarious.kt b/compiler/test/ast/TestVarious.kt index 4057e7e72..d0a1595c2 100644 --- a/compiler/test/ast/TestVarious.kt +++ b/compiler/test/ast/TestVarious.kt @@ -3,11 +3,9 @@ package prog8tests.ast import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe -import io.kotest.matchers.types.instanceOf import prog8.ast.IFunctionCall import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.StringLiteral import prog8.ast.statements.Assignment import prog8.ast.statements.InlineAssembly @@ -15,7 +13,6 @@ import prog8.ast.statements.VarDecl import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target -import prog8.compiler.printProgram import prog8tests.helpers.compileText class TestVarious: FunSpec({ @@ -148,7 +145,6 @@ main { } }""" val result = compileText(C64Target(), optimize=false, src, writeAssembly=false)!! - printProgram(result.program) val stmts = result.program.entrypoint.statements stmts.size shouldBe 7 val assign1expr = (stmts[3] as Assignment).value as BinaryExpression @@ -161,5 +157,27 @@ main { leftval2.type shouldBe DataType.UWORD leftval2.number shouldBe 1.0 } + + test("hoisting vars with complex initializer expressions to outer scope") { + val src=""" +main { + sub pget(uword @zp x, uword y) -> ubyte { + return lsb(x+y) + } + + sub start() { + uword[128] YY + ubyte[] ARRAY = [1, 5, 2] + repeat { + ubyte pixel_side1 = pget(2, YY[2]+1) in ARRAY + ubyte pixel_side2 = pget(2, 2) in ARRAY + ubyte[] array2 = [1,2,3] + } + } +}""" + val result = compileText(C64Target(), optimize=false, src, writeAssembly=false)!! + val stmts = result.program.entrypoint.statements + stmts.size shouldBe 9 + } }) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 9d6b20656..83e447960 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- fix compiler crash on : bool bb = gfx2.pget(pilex1, flakes1_yy[idx]+1) in PILED_SNOW_COLORS - bool bb = not bb -> larger code than bool bb ^= 1 - bool xx = ~xx -> larger code than xx ^= 1 - ubyte xx = not xx -> much larger code than xx ^= 1