prog8/compiler/test/codegeneration/TestAsmGenSymbols.kt

177 lines
9.7 KiB
Kotlin
Raw Normal View History

package prog8tests.codegeneration
2021-06-01 19:21:33 +00:00
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
2021-06-01 19:21:33 +00:00
import prog8.ast.Module
import prog8.ast.Program
2021-10-10 22:22:04 +00:00
import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
2022-02-10 23:21:40 +00:00
import prog8.ast.expressions.NumericLiteral
2021-06-01 19:21:33 +00:00
import prog8.ast.statements.*
2022-03-10 22:08:41 +00:00
import prog8.code.core.*
2022-03-11 19:35:25 +00:00
import prog8.code.target.C64Target
import prog8.code.target.c64.C64Zeropage
2022-02-06 21:56:17 +00:00
import prog8.codegen.cpu6502.AsmGen
2022-03-04 22:25:26 +00:00
import prog8.compiler.astprocessing.SymbolTableMaker
import prog8tests.helpers.*
2021-06-01 19:21:33 +00:00
class TestAsmGenSymbols: StringSpec({
2022-03-04 22:25:26 +00:00
fun createTestProgram(): Program {
2021-06-01 19:21:33 +00:00
/*
main {
label_outside:
uword var_outside
2021-06-01 19:21:33 +00:00
sub start () {
uword localvar = 1234
uword tgt
2021-06-01 19:21:33 +00:00
locallabel:
tgt = localvar
tgt = &locallabel
tgt = &var_outside
tgt = &label_outside
tgt = &main.start.localvar
tgt = &main.start.locallabel
tgt = &main.var_outside
tgt = &main.label_outside
2021-06-01 19:21:33 +00:00
}
}
2021-06-01 19:21:33 +00:00
*/
2022-02-10 23:21:40 +00:00
val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, null, Position.DUMMY)
2022-01-10 00:48:25 +00:00
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, null, Position.DUMMY)
val labelInSub = Label("locallabel", Position.DUMMY)
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
2022-01-10 01:25:02 +00:00
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements, Position.DUMMY)
val labelInBlock = Label("label_outside", Position.DUMMY)
2022-01-10 00:48:25 +00:00
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, null, Position.DUMMY)
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
2022-02-06 21:56:17 +00:00
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
2022-03-04 22:25:26 +00:00
return program
2021-06-01 19:21:33 +00:00
}
2022-03-04 22:25:26 +00:00
fun createTestAsmGen(program: Program): AsmGen {
2021-10-29 14:46:56 +00:00
val errors = ErrorReporterForTests()
2022-03-13 11:52:12 +00:00
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
options.compTarget.machine.zeropage = C64Zeropage(options)
2022-03-04 22:25:26 +00:00
val st = SymbolTableMaker().makeFrom(program)
return AsmGen(program, st, options, errors)
2021-06-01 19:21:33 +00:00
}
"symbol and variable names from strings" {
2022-03-04 22:25:26 +00:00
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("<name>") shouldBe "prog8_name"
asmgen.asmSymbolName(RegisterOrPair.R15) shouldBe "cx16.r15"
asmgen.asmSymbolName(listOf("a", "b", "name")) shouldBe "a.b.name"
asmgen.asmVariableName("name") shouldBe "name"
asmgen.asmVariableName("<name>") shouldBe "prog8_name"
asmgen.asmVariableName(listOf("a", "b", "name")) shouldBe "a.b.name"
2021-06-01 19:21:33 +00:00
}
"symbol and variable names from variable identifiers" {
2022-03-04 22:25:26 +00:00
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val sub = program.entrypoint
val localvarIdent = sub.statements.asSequence().filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
val localvarIdentScoped = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main", "start", "localvar") }.value as AddressOf).identifier
asmgen.asmSymbolName(localvarIdentScoped) shouldBe "main.start.localvar"
asmgen.asmVariableName(localvarIdentScoped) shouldBe "main.start.localvar"
val scopedVarIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("var_outside") }.value as AddressOf).identifier
asmgen.asmSymbolName(scopedVarIdent) shouldBe "var_outside"
asmgen.asmVariableName(scopedVarIdent) shouldBe "var_outside"
val scopedVarIdentScoped = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main", "var_outside") }.value as AddressOf).identifier
asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside"
asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside"
2021-06-01 19:21:33 +00:00
}
"symbol and variable names from label identifiers" {
2022-03-04 22:25:26 +00:00
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val sub = program.entrypoint
val localLabelIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier
asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel"
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
val localLabelIdentScoped = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","start","locallabel") }.value as AddressOf).identifier
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "main.start.locallabel"
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "main.start.locallabel"
val scopedLabelIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("label_outside") }.value as AddressOf).identifier
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "label_outside"
asmgen.asmVariableName(scopedLabelIdent) shouldBe "label_outside"
val scopedLabelIdentScoped = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","label_outside") }.value as AddressOf).identifier
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside"
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"
2021-06-01 19:21:33 +00:00
}
"asm names for hooks to zp temp vars" {
/*
main {
sub start() {
prog8_lib.P8ZP_SCRATCH_REG = 1
prog8_lib.P8ZP_SCRATCH_B1 = 1
prog8_lib.P8ZP_SCRATCH_W1 = 1
prog8_lib.P8ZP_SCRATCH_W2 = 1
*/
2022-03-04 22:25:26 +00:00
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2"
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_W2")) shouldBe "P8ZP_SCRATCH_W2"
val id1 = IdentifierReference(listOf("prog8_lib","P8ZP_SCRATCH_REG"), Position.DUMMY)
id1.linkParents(program.toplevelModule)
val id2 = IdentifierReference(listOf("prog8_lib","P8ZP_SCRATCH_W2"), Position.DUMMY)
id2.linkParents(program.toplevelModule)
asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName(id2) shouldBe "P8ZP_SCRATCH_W2"
}
"no double labels with various loops" {
val text="""
main {
sub start() {
if true {
}
repeat 4 {
}
while true {
}
repeat {
}
}
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = true)
result shouldNotBe null
}
})