diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index e958ffe45..da8afea41 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -1539,6 +1539,7 @@ internal class AstChecker(private val program: Program, when (it) { is NumericLiteral -> it.number.toInt() is AddressOf -> it.identifier.hashCode() and 0xffff + is IdentifierReference -> it.hashCode() and 0xffff is TypecastExpression -> { val constVal = it.expression.constValue(program) val cast = constVal?.cast(it.type) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 432e88a2c..ff4c4e6d1 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -433,7 +433,12 @@ class IntermediateAstMaker(private val program: Program, private val options: Co private fun transform(src: AddressOf): PtAddressOf { val addr = PtAddressOf(src.position) - addr.add(transform(src.identifier)) + val (name, dt) = src.identifier.targetNameAndType(program) + if(dt in SplitWordArrayTypes) { + addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) + } else { + addr.add(transform(src.identifier)) + } return addr } diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt index 530ab7145..8f1c0407e 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt @@ -7,14 +7,12 @@ import prog8.ast.expressions.ArrayLiteral import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.StringLiteral +import prog8.ast.statements.Assignment import prog8.ast.statements.VarDecl import prog8.ast.statements.WhenChoice import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.DataType -import prog8.code.core.Encoding -import prog8.code.core.ICompilationTarget -import prog8.code.core.IErrorReporter +import prog8.code.core.* internal class LiteralsToAutoVars(private val program: Program, @@ -60,10 +58,12 @@ internal class LiteralsToAutoVars(private val program: Program, } else { val arrayDt = array.guessDatatype(program) if(arrayDt.isKnown) { + val parentAssign = parent as? Assignment + val targetDt = parentAssign?.target?.inferType(program) ?: arrayDt // turn the array literal it into an identifier reference - val litval2 = array.cast(arrayDt.getOr(DataType.UNDEFINED)) + val litval2 = array.cast(targetDt.getOr(DataType.UNDEFINED)) if(litval2!=null) { - val vardecl2 = VarDecl.createAuto(litval2) + val vardecl2 = VarDecl.createAuto(litval2, targetDt.getOr(DataType.UNDEFINED) in SplitWordArrayTypes) val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position) return listOf( IAstModification.ReplaceNode(array, identifier, parent), diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index d8359bab9..7cd4e7c1c 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -291,8 +291,10 @@ internal class StatementReorderer(val program: Program, } else { if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex()) errors.err("element count mismatch", assign.position) - if (sourceVar.datatype != targetVar.datatype) - errors.err("element type mismatch", assign.position) + if (sourceVar.datatype != targetVar.datatype) { + if(!targetVar.splitArray || (sourceVar.datatype!=DataType.ARRAY_W && sourceVar.datatype!=DataType.ARRAY_UW)) + errors.err("element type mismatch", assign.position) + } } if(!errors.noErrors()) diff --git a/compiler/test/TestSubroutines.kt b/compiler/test/TestSubroutines.kt index ae78d4935..682fbf177 100644 --- a/compiler/test/TestSubroutines.kt +++ b/compiler/test/TestSubroutines.kt @@ -26,7 +26,7 @@ class TestSubroutines: FunSpec({ sub start() { func("abc") - uword[] commands = ["abc", func] + uword[] commands = ["abc", 1.234] } }""" val errors = ErrorReporterForTests() diff --git a/compiler/test/codegeneration/TestArrayInplaceAssign.kt b/compiler/test/codegeneration/TestArrayThings.kt similarity index 83% rename from compiler/test/codegeneration/TestArrayInplaceAssign.kt rename to compiler/test/codegeneration/TestArrayThings.kt index 5a904d100..0486bcedf 100644 --- a/compiler/test/codegeneration/TestArrayInplaceAssign.kt +++ b/compiler/test/codegeneration/TestArrayThings.kt @@ -4,7 +4,6 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain -import prog8.code.ast.printAst import prog8.code.target.C64Target import prog8.code.target.VMTarget import prog8tests.helpers.ErrorReporterForTests @@ -130,10 +129,23 @@ main { }} } }""" - val result6502 = compileText(C64Target(), false, text, writeAssembly = true)!!.codegenAst!! - val resultVm = compileText(VMTarget(), false, text, writeAssembly = true)!!.codegenAst!! - printAst(result6502, true, ::println) - printAst(resultVm, true, ::println) + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null + } + + test("split array assignments") { + val text = """ +main { + sub start() { + str name1 = "name1" + str name2 = "name2" + uword[] @split names = [name1, name2, "name3"] + cx16.r0++ + names = [1111,2222,3333] + } +}""" + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null } }) diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 0f33326e3..b4a74d5d8 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -782,22 +782,42 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because return this if(targettype in ArrayDatatypes) { val elementType = ArrayToElementTypes.getValue(targettype) - val castArray = value.map{ - val num = it as? NumericLiteral - if(num==null) { - // an array of UWORDs could possibly also contain AddressOfs, other stuff can't be typecasted - if (elementType != DataType.UWORD || it !is AddressOf) - return null // can't cast a value of the array, abort - it - } else { - val cast = num.cast(elementType) + + // if all values are numeric literals, just do the cast. + // if not: + // if all values are numeric literals OR addressof OR identifiers, and the target type is WORD or UWORD, + // do the cast for the numeric literals and leave the rest. + // otherwise: return null (cast cannot be done) + + if(value.all { it is NumericLiteral }) { + val castArray = value.map { + val cast = (it as NumericLiteral).cast(elementType) if(cast.isValid) - cast.valueOrZero() + cast.valueOrZero() as Expression else - return null // can't cast a value of the array, abort - } - }.toTypedArray() - return ArrayLiteral(InferredTypes.InferredType.known(targettype), castArray, position = position) + return null // abort + }.toTypedArray() + return ArrayLiteral(InferredTypes.InferredType.known(targettype), castArray, position = position) + } + else if(elementType in WordDatatypes && value.all { it is NumericLiteral || it is AddressOf || it is IdentifierReference}) { + val castArray = value.map { + when(it) { + is AddressOf -> it as Expression + is IdentifierReference -> it as Expression + is NumericLiteral -> { + val numcast = it.cast(elementType) + if(numcast.isValid) + numcast.valueOrZero() as Expression + else + return null // abort + } + else -> return null // abort + } + }.toTypedArray() + return ArrayLiteral(InferredTypes.InferredType.known(targettype), castArray, position = position) + } + else + return null } return null // invalid type conversion from $this to $targettype } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 6cd314254..5b4b0a88f 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -216,13 +216,13 @@ class VarDecl(val type: VarDeclType, ) } - fun createAuto(array: ArrayLiteral): VarDecl { + fun createAuto(array: ArrayLiteral, splitArray: Boolean): VarDecl { val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}" val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") } val declaredType = ArrayToElementTypes.getValue(arrayDt) val arraysize = ArrayIndex.forArray(array) return VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array, - isArray = true, sharedWithAsm = false, splitArray = false, position = array.position) + isArray = true, sharedWithAsm = false, splitArray = splitArray, position = array.position) } } diff --git a/examples/test.p8 b/examples/test.p8 index 5ae6f9cd6..439224db0 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,3 @@ -%import floats %import textio %zeropage basicsafe %option no_sysinit @@ -6,29 +5,11 @@ main { sub start() { - uword[] split_uwords = [12345, 60000, 4096] - word[] split_words = [12345, -6000, 4096] - float[] floats = [1.1,2.2,3.3] - reverse(split_uwords) - reverse(split_words) - reverse(floats) - uword ww - for ww in split_uwords { - txt.print_uw(ww) - txt.spc() - } - txt.nl() - word sw - for sw in split_words { - txt.print_w(sw) - txt.spc() - } - txt.nl() - ubyte ix - for ix in 0 to len(floats)-1 { - floats.print_f(floats[ix]) - txt.spc() - } + str name1 = "name1" + str name2 = "name2" + uword[] @split names = [name1, name2, "name3"] + cx16.r0++ + names = [1111,2222,3333] } } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 3c98caf37..2529be290 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -326,9 +326,16 @@ class VmProgramLoader { } in SplitWordArrayTypes -> { for(elt in it) { - val number = elt.number!!.toInt().toUInt() + val number = if(elt.addressOfSymbol!=null) { + val name = elt.addressOfSymbol!! + val symbolAddress = symbolAddresses[name] + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") // TODO + symbolAddress.toUInt() + } else { + elt.number!!.toInt().toUInt() + } memory.setUB(addr, (number and 255u).toUByte()) - memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) + memory.setUB(addr + variable.length!!, (number shr 8).toUByte()) addr++ } }