mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-04 10:16:13 +00:00 
			
		
		
		
	replace str or ubyte[] param and returnvalue type into ^^ubyte rather than uword
This commit is contained in:
		@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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<IAstModification>()
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user