mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 05:29:38 +00:00
153 lines
8.8 KiB
Kotlin
153 lines
8.8 KiB
Kotlin
package prog8tests.asmgen
|
|
|
|
import io.kotest.assertions.withClue
|
|
import io.kotest.core.spec.style.StringSpec
|
|
import io.kotest.matchers.shouldBe
|
|
import prog8.ast.Module
|
|
import prog8.ast.Program
|
|
import prog8.ast.base.DataType
|
|
import prog8.ast.base.Position
|
|
import prog8.ast.base.RegisterOrPair
|
|
import prog8.ast.base.VarDeclType
|
|
import prog8.ast.expressions.AddressOf
|
|
import prog8.ast.expressions.IdentifierReference
|
|
import prog8.ast.expressions.NumericLiteralValue
|
|
import prog8.ast.statements.*
|
|
import prog8.compiler.target.C64Target
|
|
import prog8.compiler.target.c64.C64MachineDefinition
|
|
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
|
import prog8.compilerinterface.*
|
|
import prog8.parser.SourceCode
|
|
import prog8tests.asmgen.helpers.DummyFunctions
|
|
import prog8tests.asmgen.helpers.DummyMemsizer
|
|
import prog8tests.asmgen.helpers.DummyStringEncoder
|
|
import prog8tests.asmgen.helpers.ErrorReporterForTests
|
|
import java.nio.file.Path
|
|
|
|
class AsmGenSymbolsTests: StringSpec({
|
|
fun createTestProgram(): Program {
|
|
/*
|
|
main {
|
|
|
|
label_outside:
|
|
uword var_outside
|
|
|
|
sub start () {
|
|
uword localvar = 1234
|
|
uword tgt
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
*/
|
|
val varInSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteralValue.optimalInteger(1234, Position.DUMMY), false, false, false, Position.DUMMY)
|
|
val var2InSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, false, Position.DUMMY)
|
|
val labelInSub = Label("locallabel", Position.DUMMY)
|
|
|
|
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
|
|
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), Position.DUMMY)
|
|
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
|
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), 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)
|
|
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY)
|
|
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
|
|
|
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
|
|
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
.addModule(module)
|
|
module.linkIntoProgram(program)
|
|
return program
|
|
}
|
|
|
|
fun createTestAsmGen(program: Program): AsmGen {
|
|
val errors = ErrorReporterForTests()
|
|
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target)
|
|
val zp = C64MachineDefinition.C64Zeropage(options)
|
|
val asmgen = AsmGen(program, errors, zp, options, C64Target, Path.of(""))
|
|
return asmgen
|
|
}
|
|
|
|
"symbol names from strings" {
|
|
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"
|
|
}
|
|
|
|
"symbol names from variable identifiers" {
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen(program)
|
|
val sub = program.entrypoint
|
|
|
|
// local variable
|
|
val localvarIdent = sub.statements.filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference
|
|
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
|
|
asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
|
|
val localvarIdentScoped = (sub.statements.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"
|
|
|
|
// variable from outer scope (note that for Variables, no scoping prefix symbols are required,
|
|
// because they're not outputted as locally scoped symbols for the assembler
|
|
val scopedVarIdent = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("var_outside") }.value as AddressOf).identifier
|
|
asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside"
|
|
asmgen.asmVariableName(scopedVarIdent) shouldBe "var_outside"
|
|
val scopedVarIdentScoped = (sub.statements.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"
|
|
}
|
|
|
|
"symbol names from label identifiers" {
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen(program)
|
|
val sub = program.entrypoint
|
|
|
|
// local label
|
|
val localLabelIdent = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier
|
|
asmgen.asmSymbolName(localLabelIdent) shouldBe "_locallabel"
|
|
withClue("as a variable it uses different naming rules (no underscore prefix)") {
|
|
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
|
|
}
|
|
val localLabelIdentScoped = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","start","locallabel") }.value as AddressOf).identifier
|
|
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "main.start._locallabel"
|
|
withClue("as a variable it uses different naming rules (no underscore prefix)") {
|
|
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "main.start.locallabel"
|
|
}
|
|
|
|
// label from outer scope needs sope prefixes because it is outputted as a locally scoped symbol for the assembler
|
|
val scopedLabelIdent = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("label_outside") }.value as AddressOf).identifier
|
|
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main._label_outside"
|
|
withClue("as a variable it uses different naming rules (no underscore prefix)") {
|
|
asmgen.asmVariableName(scopedLabelIdent) shouldBe "label_outside"
|
|
}
|
|
val scopedLabelIdentScoped = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","label_outside") }.value as AddressOf).identifier
|
|
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main._label_outside"
|
|
withClue("as a variable it uses different naming rules (no underscore prefix)") {
|
|
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"
|
|
}
|
|
}
|
|
})
|