mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 20:33:39 +00:00
b7a622c68e
fix alignment of uninitialized arrays in aligned blocks (make them initialized with zeros so they don't end up in the BSS section)
249 lines
11 KiB
Kotlin
249 lines
11 KiB
Kotlin
package prog8tests.codegeneration
|
|
|
|
import io.kotest.core.spec.style.StringSpec
|
|
import io.kotest.matchers.shouldBe
|
|
import io.kotest.matchers.shouldNotBe
|
|
import prog8.ast.Module
|
|
import prog8.ast.Program
|
|
import prog8.ast.expressions.AddressOf
|
|
import prog8.ast.expressions.IdentifierReference
|
|
import prog8.ast.expressions.NumericLiteral
|
|
import prog8.ast.statements.*
|
|
import prog8.code.SymbolTableMaker
|
|
import prog8.code.ast.PtAddressOf
|
|
import prog8.code.ast.PtAssignment
|
|
import prog8.code.ast.PtIdentifier
|
|
import prog8.code.ast.PtProgram
|
|
import prog8.code.core.*
|
|
import prog8.code.target.C64Target
|
|
import prog8.code.target.VMTarget
|
|
import prog8.codegen.cpu6502.AsmGen6502Internal
|
|
import prog8.compiler.astprocessing.IntermediateAstMaker
|
|
import prog8tests.helpers.*
|
|
|
|
class TestAsmGenSymbols: 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, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, false, Position.DUMMY)
|
|
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, 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), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
|
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, 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, false, statements, Position.DUMMY)
|
|
val labelInBlock = Label("label_outside", Position.DUMMY)
|
|
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, 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)
|
|
|
|
return program
|
|
}
|
|
|
|
fun createTestAsmGen6502(program: Program): AsmGen6502Internal {
|
|
val errors = ErrorReporterForTests()
|
|
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
|
|
val ptProgram = IntermediateAstMaker(program, errors).transform()
|
|
val st = SymbolTableMaker(ptProgram, options).make()
|
|
return AsmGen6502Internal(ptProgram, st, options, errors)
|
|
}
|
|
|
|
"symbol and variable names from strings" {
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen6502(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 and variable names from variable identifiers" {
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen6502(program)
|
|
val sub = asmgen.program.entrypoint()!!
|
|
|
|
val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier
|
|
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
|
|
asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
|
|
val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(localvarIdentScoped) shouldBe "localvar"
|
|
asmgen.asmVariableName(localvarIdentScoped) shouldBe "localvar"
|
|
|
|
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside"
|
|
asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside"
|
|
val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside"
|
|
asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside"
|
|
}
|
|
|
|
"symbol and variable names from label identifiers" {
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen6502(program)
|
|
val sub = asmgen.program.entrypoint()!!
|
|
|
|
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel"
|
|
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
|
|
val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "locallabel"
|
|
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "locallabel"
|
|
|
|
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside"
|
|
asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside"
|
|
val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
|
|
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside"
|
|
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"
|
|
}
|
|
|
|
"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
|
|
*/
|
|
val program = createTestProgram()
|
|
val asmgen = createTestAsmGen6502(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 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_REG", DataType.UBYTE, Position.DUMMY)
|
|
val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataType.UWORD, Position.DUMMY)
|
|
id1.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
|
id2.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
|
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
|
|
}
|
|
|
|
"identifiers can have the names of cpu instructions" {
|
|
val text="""
|
|
%import textio
|
|
|
|
nop {
|
|
sub lda(ubyte sec) -> ubyte {
|
|
asl:
|
|
ubyte brk = sec
|
|
sec++
|
|
brk += sec
|
|
return brk
|
|
}
|
|
}
|
|
|
|
main {
|
|
|
|
sub ffalse(ubyte arg) -> ubyte {
|
|
arg++
|
|
return 0
|
|
}
|
|
sub ftrue(ubyte arg) -> ubyte {
|
|
arg++
|
|
return 128
|
|
}
|
|
|
|
sub start() {
|
|
ubyte col = 10
|
|
ubyte row = 20
|
|
txt.print_ub(nop.lda(42))
|
|
txt.nl()
|
|
txt.print_uw(nop.lda.asl)
|
|
|
|
void ffalse(99)
|
|
void ftrue(99)
|
|
}
|
|
}
|
|
"""
|
|
val result = compileText(C64Target(), false, text, writeAssembly = true)
|
|
result shouldNotBe null
|
|
val result2 = compileText(VMTarget(), false, text, writeAssembly = true)
|
|
result2 shouldNotBe null
|
|
|
|
}
|
|
|
|
"3 letter names not prefixed too aggressively" {
|
|
val text = """
|
|
%import math
|
|
main {
|
|
|
|
sub start() {
|
|
ubyte lda = getrandom()
|
|
lda++
|
|
cx16.r0 = (math.rnd() % 20) * ${'$'}0010
|
|
lda = math.rnd() % 5
|
|
lda++
|
|
}
|
|
|
|
sub getrandom() -> ubyte {
|
|
return cx16.r0L
|
|
}
|
|
}"""
|
|
val result = compileText(C64Target(), false, text, writeAssembly = true)
|
|
result shouldNotBe null
|
|
val result2 = compileText(VMTarget(), false, text, writeAssembly = true)
|
|
result2 shouldNotBe null
|
|
}
|
|
})
|