2021-06-01 19:21:33 +00:00
package prog8tests
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
2021-10-10 22:22:04 +00:00
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
2021-06-01 19:21:33 +00:00
import prog8.ast.Module
import prog8.ast.Program
2021-10-26 22:05:46 +00:00
import prog8.ast.base.DataType
import prog8.ast.base.Position
import prog8.ast.base.RegisterOrPair
import prog8.ast.base.VarDeclType
2021-10-10 22:22:04 +00:00
import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
2021-06-01 19:21:33 +00:00
import prog8.ast.statements.*
import prog8.compiler.*
import prog8.compiler.target.C64Target
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cpu6502.codegen.AsmGen
2021-10-29 00:42:10 +00:00
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.LauncherType
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.ZeropageType
2021-10-13 16:55:56 +00:00
import prog8.parser.SourceCode
2021-10-10 22:22:04 +00:00
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
2021-06-01 19:21:33 +00:00
import java.nio.file.Path
2021-07-11 16:18:27 +00:00
2021-06-01 19:21:33 +00:00
@TestInstance ( TestInstance . Lifecycle . PER _CLASS )
class TestAsmGen6502 {
private fun createTestProgram ( ) : Program {
/ *
2021-06-02 23:42:11 +00:00
main {
label _outside :
uword var _outside
2021-06-01 19:21:33 +00:00
2021-06-02 23:42:11 +00:00
sub start ( ) {
uword localvar = 1234
uword tgt
2021-06-01 19:21:33 +00:00
2021-06-02 23:42:11 +00:00
locallabel :
tgt = localvar
tgt = & locallabel
tgt = & var _outside
tgt = & label _outside
2021-06-04 20:42:28 +00:00
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-04 20:42:28 +00:00
2021-06-01 19:21:33 +00:00
* /
2021-06-02 23:42:11 +00:00
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 )
2021-06-04 20:42:28 +00:00
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 )
2021-06-02 23:42:11 +00:00
2021-06-04 20:42:28 +00:00
val statements = mutableListOf ( varInSub , var2InSub , labelInSub , assign1 , assign2 , assign3 , assign4 , assign5 , assign6 , assign7 , assign8 )
2021-10-24 18:57:10 +00:00
val subroutine = Subroutine ( " start " , mutableListOf ( ) , emptyList ( ) , emptyList ( ) , emptyList ( ) , emptySet ( ) , null , false , false , statements , Position . DUMMY )
2021-06-02 23:42:11 +00:00
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 )
2021-10-14 21:56:23 +00:00
val module = Module ( mutableListOf ( block ) , Position . DUMMY , SourceCode . Generated ( " test " ) )
2021-08-01 20:47:11 +00:00
val program = Program ( " test " , DummyFunctions , DummyMemsizer )
. addModule ( module )
2021-10-19 20:30:30 +00:00
module . linkIntoProgram ( program )
2021-06-01 19:21:33 +00:00
return program
}
private fun createTestAsmGen ( program : Program ) : AsmGen {
val errors = ErrorReporter ( )
val options = CompilationOptions ( OutputType . RAW , LauncherType . NONE , ZeropageType . FULL , emptyList ( ) , false , true , C64Target )
val zp = C64MachineDefinition . C64Zeropage ( options )
2021-10-16 00:43:22 +00:00
val asmgen = AsmGen ( program , errors , zp , options , C64Target , Path . of ( " " ) )
2021-06-01 19:21:33 +00:00
return asmgen
}
@Test
fun testSymbolNameFromStrings ( ) {
val program = createTestProgram ( )
val asmgen = createTestAsmGen ( program )
assertThat ( asmgen . asmSymbolName ( " name " ) , equalTo ( " name " ) )
assertThat ( asmgen . asmSymbolName ( " <name> " ) , equalTo ( " prog8_name " ) )
assertThat ( asmgen . asmSymbolName ( RegisterOrPair . R15 ) , equalTo ( " cx16.r15 " ) )
assertThat ( asmgen . asmSymbolName ( listOf ( " a " , " b " , " name " ) ) , equalTo ( " a.b.name " ) )
assertThat ( asmgen . asmVariableName ( " name " ) , equalTo ( " name " ) )
assertThat ( asmgen . asmVariableName ( " <name> " ) , equalTo ( " prog8_name " ) )
assertThat ( asmgen . asmVariableName ( listOf ( " a " , " b " , " name " ) ) , equalTo ( " a.b.name " ) )
}
@Test
fun testSymbolNameFromVarIdentifier ( ) {
val program = createTestProgram ( )
val asmgen = createTestAsmGen ( program )
2021-10-10 22:01:26 +00:00
val sub = program . entrypoint
2021-06-02 23:42:11 +00:00
// local variable
val localvarIdent = sub . statements . filterIsInstance < Assignment > ( ) . first { it . value is IdentifierReference } . value as IdentifierReference
assertThat ( asmgen . asmSymbolName ( localvarIdent ) , equalTo ( " localvar " ) )
assertThat ( asmgen . asmVariableName ( localvarIdent ) , equalTo ( " localvar " ) )
2021-06-04 20:42:28 +00:00
val localvarIdentScoped = ( sub . statements . filterIsInstance < Assignment > ( ) . first { ( it . value as ? AddressOf ) ?. identifier ?. nameInSource == listOf ( " main " , " start " , " localvar " ) } . value as AddressOf ) . identifier
assertThat ( asmgen . asmSymbolName ( localvarIdentScoped ) , equalTo ( " main.start.localvar " ) )
assertThat ( asmgen . asmVariableName ( localvarIdentScoped ) , equalTo ( " main.start.localvar " ) )
2021-06-02 23:42:11 +00:00
2021-06-04 20:42:28 +00:00
// variable from outer scope (note that for Variables, no scoping prefix symbols are required,
2021-06-02 23:42:11 +00:00
// 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
2021-06-04 20:42:28 +00:00
assertThat ( asmgen . asmSymbolName ( scopedVarIdent ) , equalTo ( " main.var_outside " ) )
2021-06-02 23:42:11 +00:00
assertThat ( asmgen . asmVariableName ( scopedVarIdent ) , equalTo ( " var_outside " ) )
2021-06-04 20:42:28 +00:00
val scopedVarIdentScoped = ( sub . statements . filterIsInstance < Assignment > ( ) . first { ( it . value as ? AddressOf ) ?. identifier ?. nameInSource == listOf ( " main " , " var_outside " ) } . value as AddressOf ) . identifier
assertThat ( asmgen . asmSymbolName ( scopedVarIdentScoped ) , equalTo ( " main.var_outside " ) )
assertThat ( asmgen . asmVariableName ( scopedVarIdentScoped ) , equalTo ( " main.var_outside " ) )
2021-06-01 19:21:33 +00:00
}
@Test
fun testSymbolNameFromLabelIdentifier ( ) {
val program = createTestProgram ( )
val asmgen = createTestAsmGen ( program )
2021-10-10 22:01:26 +00:00
val sub = program . entrypoint
2021-06-02 23:42:11 +00:00
// local label
val localLabelIdent = ( sub . statements . filterIsInstance < Assignment > ( ) . first { ( it . value as ? AddressOf ) ?. identifier ?. nameInSource == listOf ( " locallabel " ) } . value as AddressOf ) . identifier
assertThat ( asmgen . asmSymbolName ( localLabelIdent ) , equalTo ( " _locallabel " ) )
assertThat ( " as a variable it uses different naming rules (no underscore prefix) " , asmgen . asmVariableName ( localLabelIdent ) , equalTo ( " locallabel " ) )
2021-06-04 20:42:28 +00:00
val localLabelIdentScoped = ( sub . statements . filterIsInstance < Assignment > ( ) . first { ( it . value as ? AddressOf ) ?. identifier ?. nameInSource == listOf ( " main " , " start " , " locallabel " ) } . value as AddressOf ) . identifier
assertThat ( asmgen . asmSymbolName ( localLabelIdentScoped ) , equalTo ( " main.start._locallabel " ) )
assertThat ( " as a variable it uses different naming rules (no underscore prefix) " , asmgen . asmVariableName ( localLabelIdentScoped ) , equalTo ( " main.start.locallabel " ) )
2021-06-02 23:42:11 +00:00
// 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
assertThat ( asmgen . asmSymbolName ( scopedLabelIdent ) , equalTo ( " main._label_outside " ) )
2021-06-04 20:42:28 +00:00
assertThat ( " as a variable it uses different naming rules (no underscore prefix) " , asmgen . asmVariableName ( scopedLabelIdent ) , equalTo ( " label_outside " ) )
val scopedLabelIdentScoped = ( sub . statements . filterIsInstance < Assignment > ( ) . first { ( it . value as ? AddressOf ) ?. identifier ?. nameInSource == listOf ( " main " , " label_outside " ) } . value as AddressOf ) . identifier
assertThat ( asmgen . asmSymbolName ( scopedLabelIdentScoped ) , equalTo ( " main._label_outside " ) )
assertThat ( " as a variable it uses different naming rules (no underscore prefix) " , asmgen . asmVariableName ( scopedLabelIdentScoped ) , equalTo ( " main.label_outside " ) )
2021-06-01 19:21:33 +00:00
}
}