mirror of
https://github.com/irmen/prog8.git
synced 2025-08-09 19:25:22 +00:00
fix an array literal assignment type error for word arrays
This commit is contained in:
@@ -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)
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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),
|
||||||
|
@@ -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())
|
||||||
|
@@ -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()
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user