From 893e16d814df176f299dba3e149059e0b1d8bafa Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 21 Jul 2025 22:59:14 +0200 Subject: [PATCH] replace str or ubyte[] param and returnvalue type into ^^ubyte rather than uword --- compiler/src/prog8/compiler/Compiler.kt | 2 +- .../compiler/astprocessing/AstChecker.kt | 9 +++--- .../compiler/astprocessing/AstExtensions.kt | 4 +-- .../astprocessing/StatementReorderer.kt | 14 ++++----- .../astprocessing/VerifyFunctionArgTypes.kt | 3 +- compiler/test/TestPointers.kt | 30 +++++++++++++++++++ compiler/test/TestTypecasts.kt | 9 +++--- docs/source/todo.rst | 3 +- 8 files changed, 52 insertions(+), 22 deletions(-) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 6eaa33223..c2020485b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -467,7 +467,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions errors.report() program.constantFold(errors, compilerOptions) errors.report() - program.reorderStatements(errors) + program.reorderStatements(compilerOptions.compTarget, errors) errors.report() program.desugaring(errors, compilerOptions) errors.report() diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index ebe36c80a..467b1bac9 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -494,8 +494,9 @@ internal class AstChecker(private val program: Program, errors.err("parameter '${param.first.name}' should be (u)byte or bool", param.first.position) } else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { - if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray) - err("parameter '${param.first.name}' should be (u)word (an address) or str") + if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray && param.first.type!=DataType.pointer(BaseDataType.UBYTE)) { + err("parameter '${param.first.name}' should be (u)word, str or ^^ubyte") + } } else if(param.second.statusflag!=null) { if (!param.first.type.isBool) @@ -508,8 +509,8 @@ internal class AstChecker(private val program: Program, err("return type #${index + 1} should be (u)byte") } else if(pair.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { - if (!pair.first.isWord && !pair.first.isString && !pair.first.isArray) - err("return type #${index + 1} should be (u)word/address") + if (!pair.first.isWord && !pair.first.isString && !pair.first.isArray && pair.first!=DataType.pointer(BaseDataType.UBYTE)) + err("return type #${index + 1} should be (u)word/address or ^^ubyte") } else if(pair.second.statusflag!=null) { if (!pair.first.isBool) diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 97c466f79..f8930316a 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -20,8 +20,8 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila checker.visit(this) } -internal fun Program.reorderStatements(errors: IErrorReporter) { - val reorder = StatementReorderer(this, errors) +internal fun Program.reorderStatements(target: ICompilationTarget, errors: IErrorReporter) { + val reorder = StatementReorderer(this, target, errors) reorder.visit(this) if(errors.noErrors()) { reorder.applyModifications() diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 5ba1bcb36..5346ecab0 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -5,13 +5,11 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.AssociativeOperators -import prog8.code.core.BaseDataType -import prog8.code.core.DataType -import prog8.code.core.IErrorReporter +import prog8.code.core.* internal class StatementReorderer( val program: Program, + val target: ICompilationTarget, val errors: IErrorReporter ) : AstWalker() { // Reorders the statements in a way the compiler needs. @@ -215,16 +213,16 @@ internal class StatementReorderer( subs.map { IAstModification.InsertLast(it, subroutine) } } - // change 'str' and 'ubyte[]' parameters into 'uword' (just treat it as an address) + // change 'str' and 'ubyte[]' parameters or return types into ^^ubyte (TODO also for 6502 target, that is still uword for now) val stringParams = subroutine.parameters.filter { it.type.isString || it.type.isUnsignedByteArray } + val replacementForStrDt = if(target.cpu!=CpuType.VIRTUAL) DataType.UWORD else DataType.pointer(BaseDataType.UBYTE) // TODO fix this once 6502 has pointers too val parameterChanges = stringParams.map { - val uwordParam = SubroutineParameter(it.name, DataType.UWORD, it.zp, it.registerOrPair, it.position) + val uwordParam = SubroutineParameter(it.name, replacementForStrDt, it.zp, it.registerOrPair, it.position) IAstModification.ReplaceNode(it, uwordParam, subroutine) } - // change 'str' and 'ubyte[]' return types into 'uword' (just treat it as an address) subroutine.returntypes.withIndex().forEach { (index, type) -> if(type.isString || type.isUnsignedByteArray) - subroutine.returntypes[index] = DataType.UWORD + subroutine.returntypes[index] = replacementForStrDt } val varsChanges = mutableListOf() diff --git a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt index 579d63286..eac2bb958 100644 --- a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt @@ -96,7 +96,8 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila // if uword is passed, check if the parameter type is pointer to array element type if(argDt.isArray && paramDt.isPointer) { - TODO("array vs element pointer check") + if(argDt.sub==paramDt.sub) + return true } // if expected is UWORD and actual is any pointer, we allow it (uword is untyped pointer, for backwards compatibility) diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index db337e692..5ebcec571 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -458,6 +458,36 @@ thing { // TODO compileText(C64Target(), false, src, outputDir) shouldNotBe null } + test("str or ubyte array params or return type replaced by pointer to ubyte") { + val src=""" +main { + sub start() { + test1("zzz") + test2("zzz") + } + + sub test1(str arg) -> str { + cx16.r0++ + return cx16.r0 + } + + sub test2(ubyte[] arg) { + cx16.r0++ + } +}""" + + // TODO check this for C64 target too + val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!! + val main = result.compilerAst.allBlocks.first {it.name=="main"} + val test1 = main.statements[1] as Subroutine + val test2 = main.statements[2] as Subroutine + test1.name shouldBe "test1" + test1.parameters.single().type shouldBe DataType.pointer(DataType.UBYTE) + test1.returntypes.single() shouldBe DataType.pointer(DataType.UBYTE) + test2.name shouldBe "test2" + test2.parameters.single().type shouldBe DataType.pointer(DataType.UBYTE) + } + test("creating instances") { val src=""" main { diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index d042d5907..3cde2e106 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -752,7 +752,7 @@ main { errors.errors[3] shouldContain (":9:28: value type uword doesn't match target") } - test("str replaced with uword in subroutine params and return types") { + test("str replaced with uword in subroutine params and return types (6502 only until that has pointers too)") { // TODO remove this test once 6502 has pointers too val src = """ main { sub start() { @@ -773,13 +773,12 @@ main { }} } }""" - compileText(C64Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null - val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = true)!! + val result = compileText(C64Target(), true, src, outputDir, writeAssembly = true)!! val main = result.codegenAst!!.allBlocks().first() - val derp = main.children.single { it is PtSub && it.name == "main.derp" } as PtSub + val derp = main.children.single { it is PtSub && it.name == "p8s_derp" } as PtSub derp.signature.returns shouldBe listOf(DataType.UWORD) (derp.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.UWORD - val mult3 = main.children.single { it is PtAsmSub && it.name == "main.mult3" } as PtAsmSub + val mult3 = main.children.single { it is PtAsmSub && it.name == "p8s_mult3" } as PtAsmSub mult3.parameters.single().second.type shouldBe DataType.UWORD mult3.returns.single().second shouldBe DataType.UWORD } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index d047bf4c2..3e0968e31 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -60,7 +60,7 @@ STRUCTS and TYPED POINTERS - DONE: added peekbool() and pokebool() and pokebowl() boolean peek and poke, the latter is equivalent to pokebool() - DONE: fixed support for (expression) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with peek() - DONE: fixed support for (assigntarget) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with poke() -- replace str param type into ^^ubyte rather than uword +- DONE: replace str or ubyte[] param and returnvalue type into ^^ubyte rather than uword - write docs in structpointers.rst - virtual/sorting.p8 module generates slightly less efficient code than the old version with untyped uword pointers - add support for array index dereferencing as assign target "array[2]^^.value = 99" where array is struct pointers (currently a 'no support' error) @@ -71,6 +71,7 @@ STRUCTS and TYPED POINTERS - 6502 codegen: remove checks in checkForPointerTypesOn6502() - 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code" - 6502 asm symbol name prefixing should work for dereferences too. +- 6502 statementreorderer: fix todo for str -> ^^ubyte instead of uword - update structpointers.rst docs with 6502 things? - scan through 6502 library modules to change untyped uword pointers to typed pointers - scan through 6502 examples to change untyped uword pointers to typed pointers