fix an array literal assignment type error for word arrays

This commit is contained in:
Irmen de Jong 2023-05-30 21:54:19 +02:00
parent b9d8ec1463
commit bb9d29b061
10 changed files with 85 additions and 57 deletions

View File

@ -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)

View File

@ -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
}

View File

@ -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),

View File

@ -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())

View File

@ -26,7 +26,7 @@ class TestSubroutines: FunSpec({
sub start() {
func("abc")
uword[] commands = ["abc", func]
uword[] commands = ["abc", 1.234]
}
}"""
val errors = ErrorReporterForTests()

View File

@ -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
}
})

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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]
}
}

View File

@ -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++
}
}