prog8/compiler/test/TestScoping.kt

113 lines
4.5 KiB
Kotlin
Raw Normal View History

package prog8tests
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.*
import prog8.compiler.target.C64Target
import prog8tests.helpers.assertSuccess
import prog8tests.helpers.compileText
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestScoping {
@Test
fun testAnonScopeVarsMovedIntoSubroutineScope() {
val src = """
main {
sub start() {
repeat {
ubyte xx = 99
xx++
}
}
}
"""
val result = compileText(C64Target, false, src, writeAssembly = false).assertSuccess()
val module = result.programAst.toplevelModule
val mainBlock = module.statements.single() as Block
val start = mainBlock.statements.single() as Subroutine
val repeatbody = start.statements.filterIsInstance<RepeatLoop>().single().body
assertFalse(mainBlock.statements.any { it is VarDecl }, "no vars moved to main block")
val subroutineVars = start.statements.filterIsInstance<VarDecl>()
assertEquals(1, subroutineVars.size, "var from repeat anonscope must be moved up to subroutine")
assertEquals("xx", subroutineVars[0].name)
assertFalse(repeatbody.statements.any { it is VarDecl }, "var should have been removed from repeat anonscope")
val initassign = repeatbody.statements[0] as? Assignment
assertEquals(listOf("xx"), initassign?.target?.identifier?.nameInSource, "vardecl in repeat should be replaced by init assignment")
assertEquals(99, (initassign?.value as? NumericLiteralValue)?.number?.toInt(), "vardecl in repeat should be replaced by init assignment")
assertTrue(repeatbody.statements[1] is PostIncrDecr)
}
@Test
fun testLabelsWithAnonScopes() {
val src = """
main {
sub start() {
uword addr
goto labeloutside
if true {
if true {
addr = &iflabel
addr = &labelinside
addr = &labeloutside
addr = &main.start.nested.nestedlabel
; addr = &nested.nestedlabel ; TODO should also work!!
goto labeloutside
goto iflabel
goto main.start.nested.nestedlabel
; goto nested.nestedlabel ; TODO should also work!!
}
iflabel:
}
repeat {
addr = &iflabel
addr = &labelinside
addr = &labeloutside
addr = &main.start.nested.nestedlabel
; addr = &nested.nestedlabel ; TODO should also work!!
goto iflabel
goto labelinside
goto main.start.nested.nestedlabel
; goto nested.nestedlabel ; TODO should also work!!
labelinside:
}
sub nested () {
nestedlabel:
addr = &nestedlabel
goto nestedlabel
goto main.start.nested.nestedlabel
}
labeloutside:
addr = &iflabel
addr = &labelinside
addr = &labeloutside
addr = &main.start.nested.nestedlabel
; addr = &nested.nestedlabel ; TODO should also work!!
goto main.start.nested.nestedlabel
; goto nested.nestedlabel ; TODO should also work!!
}
}
"""
val result = compileText(C64Target, false, src, writeAssembly = true).assertSuccess()
val module = result.programAst.toplevelModule
val mainBlock = module.statements.single() as Block
val start = mainBlock.statements.single() as Subroutine
val labels = start.statements.filterIsInstance<Label>()
assertEquals(1, labels.size, "only one label in subroutine scope")
TODO("fix the partial scoped lookups above as well")
}
}