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) { when (it) {
is NumericLiteral -> it.number.toInt() is NumericLiteral -> it.number.toInt()
is AddressOf -> it.identifier.hashCode() and 0xffff is AddressOf -> it.identifier.hashCode() and 0xffff
is IdentifierReference -> it.hashCode() and 0xffff
is TypecastExpression -> { is TypecastExpression -> {
val constVal = it.expression.constValue(program) val constVal = it.expression.constValue(program)
val cast = constVal?.cast(it.type) 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 { private fun transform(src: AddressOf): PtAddressOf {
val addr = PtAddressOf(src.position) 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 return addr
} }

View File

@@ -7,14 +7,12 @@ import prog8.ast.expressions.ArrayLiteral
import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.StringLiteral import prog8.ast.expressions.StringLiteral
import prog8.ast.statements.Assignment
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.ast.statements.WhenChoice import prog8.ast.statements.WhenChoice
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification import prog8.ast.walk.IAstModification
import prog8.code.core.DataType import prog8.code.core.*
import prog8.code.core.Encoding
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter
internal class LiteralsToAutoVars(private val program: Program, internal class LiteralsToAutoVars(private val program: Program,
@@ -60,10 +58,12 @@ internal class LiteralsToAutoVars(private val program: Program,
} else { } else {
val arrayDt = array.guessDatatype(program) val arrayDt = array.guessDatatype(program)
if(arrayDt.isKnown) { if(arrayDt.isKnown) {
val parentAssign = parent as? Assignment
val targetDt = parentAssign?.target?.inferType(program) ?: arrayDt
// turn the array literal it into an identifier reference // 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) { 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) val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
return listOf( return listOf(
IAstModification.ReplaceNode(array, identifier, parent), IAstModification.ReplaceNode(array, identifier, parent),

View File

@@ -291,8 +291,10 @@ internal class StatementReorderer(val program: Program,
} else { } else {
if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex()) if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex())
errors.err("element count mismatch", assign.position) errors.err("element count mismatch", assign.position)
if (sourceVar.datatype != targetVar.datatype) if (sourceVar.datatype != targetVar.datatype) {
errors.err("element type mismatch", assign.position) if(!targetVar.splitArray || (sourceVar.datatype!=DataType.ARRAY_W && sourceVar.datatype!=DataType.ARRAY_UW))
errors.err("element type mismatch", assign.position)
}
} }
if(!errors.noErrors()) if(!errors.noErrors())

View File

@@ -26,7 +26,7 @@ class TestSubroutines: FunSpec({
sub start() { sub start() {
func("abc") func("abc")
uword[] commands = ["abc", func] uword[] commands = ["abc", 1.234]
} }
}""" }"""
val errors = ErrorReporterForTests() 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.shouldBe
import io.kotest.matchers.shouldNotBe import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldContain
import prog8.code.ast.printAst
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.VMTarget import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
@@ -130,10 +129,23 @@ main {
}} }}
} }
}""" }"""
val result6502 = compileText(C64Target(), false, text, writeAssembly = true)!!.codegenAst!! compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
val resultVm = compileText(VMTarget(), false, text, writeAssembly = true)!!.codegenAst!! compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
printAst(result6502, true, ::println) }
printAst(resultVm, true, ::println)
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 return this
if(targettype in ArrayDatatypes) { if(targettype in ArrayDatatypes) {
val elementType = ArrayToElementTypes.getValue(targettype) val elementType = ArrayToElementTypes.getValue(targettype)
val castArray = value.map{
val num = it as? NumericLiteral // if all values are numeric literals, just do the cast.
if(num==null) { // if not:
// an array of UWORDs could possibly also contain AddressOfs, other stuff can't be typecasted // if all values are numeric literals OR addressof OR identifiers, and the target type is WORD or UWORD,
if (elementType != DataType.UWORD || it !is AddressOf) // do the cast for the numeric literals and leave the rest.
return null // can't cast a value of the array, abort // otherwise: return null (cast cannot be done)
it
} else { if(value.all { it is NumericLiteral }) {
val cast = num.cast(elementType) val castArray = value.map {
val cast = (it as NumericLiteral).cast(elementType)
if(cast.isValid) if(cast.isValid)
cast.valueOrZero() cast.valueOrZero() as Expression
else else
return null // can't cast a value of the array, abort return null // abort
} }.toTypedArray()
}.toTypedArray() return ArrayLiteral(InferredTypes.InferredType.known(targettype), castArray, position = position)
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 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 autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") } val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
val declaredType = ArrayToElementTypes.getValue(arrayDt) val declaredType = ArrayToElementTypes.getValue(arrayDt)
val arraysize = ArrayIndex.forArray(array) val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, 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 %import textio
%zeropage basicsafe %zeropage basicsafe
%option no_sysinit %option no_sysinit
@@ -6,29 +5,11 @@
main { main {
sub start() { sub start() {
uword[] split_uwords = [12345, 60000, 4096] str name1 = "name1"
word[] split_words = [12345, -6000, 4096] str name2 = "name2"
float[] floats = [1.1,2.2,3.3] uword[] @split names = [name1, name2, "name3"]
reverse(split_uwords) cx16.r0++
reverse(split_words) names = [1111,2222,3333]
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()
}
} }
} }

View File

@@ -326,9 +326,16 @@ class VmProgramLoader {
} }
in SplitWordArrayTypes -> { in SplitWordArrayTypes -> {
for(elt in it) { 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, (number and 255u).toUByte())
memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) memory.setUB(addr + variable.length!!, (number shr 8).toUByte())
addr++ addr++
} }
} }