prog8/compiler/test/codegeneration/TestVariables.kt
2024-10-17 22:51:39 +02:00

226 lines
8.5 KiB
Kotlin

package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf
import prog8.ast.statements.Assignment
import prog8.ast.statements.AssignmentOrigin
import prog8.ast.statements.ForLoop
import prog8.ast.statements.VarDecl
import prog8.code.target.C64Target
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestVariables: FunSpec({
test("shared variables without refs not removed for inlined asm") {
val text = """
main {
sub start() {
ubyte[] @shared arrayvar = [1,2,3,4]
str @shared stringvar = "test"
ubyte @shared bytevar = 0
%asm {{
lda p8v_arrayvar
lda p8v_stringvar
lda p8v_bytevar
}}
}
}
"""
compileText(C64Target(), true, text, writeAssembly = true) shouldNotBe null
}
test("array initialization with array literal") {
val text = """
main {
sub start() {
ubyte[] @shared arrayvar = [1,2,3,4]
}
}
"""
compileText(C64Target(), true, text, writeAssembly = true) shouldNotBe null
}
test("pipe character in string literal") {
val text = """
main {
sub start() {
str name = "first|second"
str name2 = "first | second"
}
}
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("negation of unsigned via casts") {
val text = """
main {
sub start() {
cx16.r0L = -(cx16.r0L as byte) as ubyte
cx16.r0 = -(cx16.r0 as word) as uword
ubyte ub
uword uw
ub = -(ub as byte) as ubyte
uw = -(uw as word) as uword
}
}
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("initialization of boolean array with array") {
val text = """
main {
sub start() {
bool[3] sieve0 = [true, false, true]
}
}
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("initialization of boolean array with wrong array type should fail") {
val text = """
main {
sub start() {
bool[] sieve0 = [true, false, 1]
bool[] sieve1 = [true, false, 42]
}
}
"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "value has incompatible type"
errors.errors[1] shouldContain "value has incompatible type"
}
test("global var init with array lookup should sometimes be const") {
val src="""
main {
bool[] barray = [true, false, true, false]
uword[] warray = [&value1, &barray, &value5, 4242]
bool @shared value1
bool @shared value2 = barray[2] ; should be const!
bool @shared value3 = true
bool @shared value4 = false
bool @shared value5 = barray[cx16.r0L] ; cannot be const
uword @shared value6 = warray[3] ; should be const!
uword @shared value7 = warray[2] ; cannot be const
sub start() {
}
}"""
val result = compileText(C64Target(), true, src, writeAssembly = true)!!.compilerAst
val main = result.allBlocks.first { it.name=="main" }
main.statements.size shouldBe 17
val assigns = main.statements.filterIsInstance<Assignment>()
assigns[0].target.identifier?.nameInSource shouldBe listOf("value1")
assigns[1].target.identifier?.nameInSource shouldBe listOf("value2")
assigns[2].target.identifier?.nameInSource shouldBe listOf("value3")
assigns[3].target.identifier?.nameInSource shouldBe listOf("value4")
assigns[4].target.identifier?.nameInSource shouldBe listOf("value5")
assigns[5].target.identifier?.nameInSource shouldBe listOf("value6")
assigns[6].target.identifier?.nameInSource shouldBe listOf("value7")
assigns[0].origin shouldBe AssignmentOrigin.VARINIT
assigns[1].origin shouldBe AssignmentOrigin.VARINIT
assigns[2].origin shouldBe AssignmentOrigin.VARINIT
assigns[3].origin shouldBe AssignmentOrigin.VARINIT
assigns[4].origin shouldBe AssignmentOrigin.VARINIT
assigns[5].origin shouldBe AssignmentOrigin.VARINIT
assigns[6].origin shouldBe AssignmentOrigin.VARINIT
assigns[0].value.constValue(result)?.number shouldBe 0
assigns[1].value.constValue(result)?.number shouldBe 1
assigns[2].value.constValue(result)?.number shouldBe 1
assigns[3].value.constValue(result)?.number shouldBe 0
assigns[4].value.constValue(result) shouldBe null
assigns[5].value.constValue(result)?.number shouldBe 4242
assigns[6].value.constValue(result) shouldBe null
}
test("scoped var init with array lookup should never be const") {
val src="""
main {
sub start() {
bool[] barray = [true, false, true, false]
uword[] warray = [&value1, &barray, &value5, 4242]
bool @shared value1
bool @shared value2 = barray[2]
bool @shared value3 = true
bool @shared value4 = false
bool @shared value5 = barray[cx16.r0L]
uword @shared value6 = warray[3]
uword @shared value7 = warray[2]
}
}"""
val result = compileText(C64Target(), true, src, writeAssembly = true)!!.compilerAst
val st = result.entrypoint.statements
st.size shouldBe 17
val assigns = st.filterIsInstance<Assignment>()
assigns[0].target.identifier?.nameInSource shouldBe listOf("value1")
assigns[1].target.identifier?.nameInSource shouldBe listOf("value2")
assigns[2].target.identifier?.nameInSource shouldBe listOf("value3")
assigns[3].target.identifier?.nameInSource shouldBe listOf("value4")
assigns[4].target.identifier?.nameInSource shouldBe listOf("value5")
assigns[5].target.identifier?.nameInSource shouldBe listOf("value6")
assigns[6].target.identifier?.nameInSource shouldBe listOf("value7")
assigns[0].origin shouldBe AssignmentOrigin.VARINIT
assigns[1].origin shouldBe AssignmentOrigin.VARINIT
assigns[2].origin shouldBe AssignmentOrigin.VARINIT
assigns[3].origin shouldBe AssignmentOrigin.VARINIT
assigns[4].origin shouldBe AssignmentOrigin.VARINIT
assigns[5].origin shouldBe AssignmentOrigin.VARINIT
assigns[6].origin shouldBe AssignmentOrigin.VARINIT
assigns[0].value.constValue(result)?.number shouldBe 0
assigns[1].value.constValue(result) shouldBe null
assigns[2].value.constValue(result)?.number shouldBe 1
assigns[3].value.constValue(result)?.number shouldBe 0
assigns[4].value.constValue(result) shouldBe null
assigns[5].value.constValue(result) shouldBe null
assigns[6].value.constValue(result) shouldBe null
}
test("not inserting redundant 0-initializations") {
val src="""
main {
sub start() {
ubyte v0
ubyte v1
ubyte v2
ubyte v3
v0 = v1 = v2 = 99
for v3 in 10 to 20 {
cx16.r0L++
}
}
}"""
val result = compileText(C64Target(), false, src, writeAssembly = false)!!.compilerAst
val st = result.entrypoint.statements
st.size shouldBe 8
st[0] shouldBe instanceOf<VarDecl>()
st[1] shouldBe instanceOf<VarDecl>()
st[2] shouldBe instanceOf<VarDecl>()
st[3] shouldBe instanceOf<VarDecl>()
st[4] shouldBe instanceOf<Assignment>()
st[5] shouldBe instanceOf<Assignment>()
st[6] shouldBe instanceOf<Assignment>()
st[7] shouldBe instanceOf<ForLoop>()
(st[4] as Assignment).target.identifier?.nameInSource shouldBe listOf("v2")
(st[5] as Assignment).target.identifier?.nameInSource shouldBe listOf("v1")
(st[6] as Assignment).target.identifier?.nameInSource shouldBe listOf("v0")
}
})