From 925b9d845d501d9d7fc52e35d401b822e7496c36 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 1 Nov 2024 19:04:11 +0100 Subject: [PATCH] fix split array possible compiler loop (due to wrong datatype replacement) --- .../compiler/astprocessing/AstPreprocessor.kt | 19 ++++++++++++++----- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 8 +++++++- .../prog8/ast/expressions/AstExpressions.kt | 2 +- .../src/prog8/ast/statements/AstStatements.kt | 5 +++++ docs/source/todo.rst | 3 ++- examples/test.p8 | 11 +++-------- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 96b7bcc75..655823003 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -112,6 +112,8 @@ class AstPreprocessor(val program: Program, val replacements = mutableListOf() for(decl in vars) { + if(shouldSplitArray(decl)) + continue // splitting must be done first if(decl.type != VarDeclType.VAR) { movements.add(IAstModification.InsertFirst(decl, parentscope)) replacements.add(IAstModification.Remove(decl, scope)) @@ -179,9 +181,8 @@ class AstPreprocessor(val program: Program, } } - if(options.splitWordArrays && (decl.datatype==DataType.ARRAY_W || decl.datatype==DataType.ARRAY_UW)) { - if(!decl.definingBlock.isInLibrary) - return makeSplitArray(decl) + if(shouldSplitArray(decl)) { + return makeSplitArray(decl) } if(decl.datatype==DataType.ARRAY_W || decl.datatype==DataType.ARRAY_UW) { @@ -194,10 +195,18 @@ class AstPreprocessor(val program: Program, return noModifications } + private fun shouldSplitArray(decl: VarDecl): Boolean = + options.splitWordArrays && (decl.datatype==DataType.ARRAY_W || decl.datatype==DataType.ARRAY_UW) && !decl.definingBlock.isInLibrary + private fun makeSplitArray(decl: VarDecl): Iterable { + val splitDt = when(decl.datatype) { + DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> DataType.ARRAY_UW_SPLIT + DataType.ARRAY_W,DataType.ARRAY_W_SPLIT -> DataType.ARRAY_W_SPLIT + else -> throw FatalAstException("invalid dt") + } val newDecl = VarDecl( - decl.type, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, emptyList(), - decl.value, decl.sharedWithAsm, true, decl.alignment, decl.position + decl.type, decl.origin, splitDt, decl.zeropage, decl.arraysize, decl.name, emptyList(), + decl.value?.copy(), decl.sharedWithAsm, true, decl.alignment, decl.position ) return listOf(IAstModification.ReplaceNode(decl, newDecl, decl.parent)) } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 0c0df4870..60c7f2e26 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -744,9 +744,15 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl } else arrayDt } else origDt + val datatype = if(!split) dt else when(dt) { + DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> DataType.ARRAY_UW_SPLIT + DataType.ARRAY_W,DataType.ARRAY_W_SPLIT -> DataType.ARRAY_W_SPLIT + else -> dt + } + return VarDecl( type, VarDeclOrigin.USERCODE, - dt, + datatype, zp, arrayindex()?.toAst(), name, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index ae0be1c75..300725598 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -892,7 +892,7 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because value.forEach {it.linkParents(this)} } - override fun copy() = throw NotImplementedError("no support for duplicating a ArrayLiteralValue") + override fun copy(): ArrayLiteral = ArrayLiteral(type, value.map { it.copy() }.toTypedArray(), position) override val isSimple = true override fun replaceChildNode(node: Node, replacement: Node) { diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index fe3c5af06..279d39ee5 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -274,6 +274,11 @@ class VarDecl(val type: VarDeclType, } } + init { + if(datatype in SplitWordArrayTypes) + require(splitArray) + } + val isArray: Boolean get() = datatype in ArrayDatatypes diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 527039d2c..cbc9371db 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,8 @@ TODO ==== --splitarrays option gets the compiler in an infinite loop sometimes (on examples/animals.p8 for example) +"cannot take address of split word array" -> don't make this a fatal error, make it a warning and turn the array into a regular array instead +(benchmark program/textelite should then be compilable with -splitarrays) merge problem: if 2 library modules both have merge, stuff breaks (math & prog8_math where prog8_math used to have math block.... didn't work) diff --git a/examples/test.p8 b/examples/test.p8 index c858b56e6..ae1b46d11 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,3 @@ -%import math %import textio %option no_sysinit %zeropage basicsafe @@ -6,15 +5,11 @@ main { sub start() { - ubyte v1 = 100 - ubyte v2 = 200 - - for cx16.r0L in 0 to 255 step 16 { - txt.print_ub(math.lerp(v1, v2, cx16.r0L)) + if cx16.r0L==0 { + uword[] scores = [10, 25, 50, 100] ; can never clear more than 4 lines at once + txt.print_uw(scores[1]) txt.nl() } - txt.print_ub(math.lerp(v1, v2, 255)) - txt.nl() } }