prog8/compiler/test/codegeneration/TestVariables.kt

226 lines
8.5 KiB
Kotlin
Raw Normal View History

package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
2022-03-07 20:41:12 +00:00
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
2022-03-11 19:35:25 +00:00
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
}}
}
}
"""
2022-03-07 20:41:12 +00:00
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]
}
}
"""
2022-03-07 20:41:12 +00:00
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")
}
})