mirror of
				https://github.com/irmen/prog8.git
				synced 2025-10-31 00:16:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			317 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
| package prog8tests.compiler
 | |
| 
 | |
| import io.kotest.assertions.withClue
 | |
| import io.kotest.core.spec.style.FunSpec
 | |
| import io.kotest.engine.spec.tempdir
 | |
| import io.kotest.matchers.shouldBe
 | |
| import io.kotest.matchers.shouldNotBe
 | |
| import io.kotest.matchers.string.shouldContain
 | |
| import io.kotest.matchers.string.shouldStartWith
 | |
| import prog8.code.INTERNED_STRINGS_MODULENAME
 | |
| import prog8.code.core.ZeropageType
 | |
| import prog8.code.target.C64Target
 | |
| import prog8.code.target.Cx16Target
 | |
| import prog8.code.target.VMTarget
 | |
| import prog8.compiler.determineCompilationOptions
 | |
| import prog8.compiler.parseMainModule
 | |
| import prog8tests.helpers.ErrorReporterForTests
 | |
| import prog8tests.helpers.compileText
 | |
| 
 | |
| 
 | |
| class TestImportedModulesOrderAndOptions: FunSpec({
 | |
| 
 | |
|     val outputDir = tempdir().toPath()
 | |
| 
 | |
|     test("testImportedModuleOrderAndMainModuleCorrect") {
 | |
|         val result = compileText(
 | |
|             C64Target(), false, """
 | |
| %import textio
 | |
| %import floats
 | |
| 
 | |
| main {
 | |
|     sub start() {
 | |
|         ; nothing
 | |
|     }
 | |
| }
 | |
| """, outputDir)!!
 | |
|         result.compilerAst.toplevelModule.name shouldStartWith "on_the_fly_test"
 | |
| 
 | |
|         val moduleNames = result.compilerAst.modules.map { it.name }
 | |
|         withClue("main module must be first") {
 | |
|             moduleNames[0] shouldStartWith "on_the_fly_test"
 | |
|         }
 | |
|         withClue("module order in parse tree") {
 | |
|             moduleNames.drop(1) shouldBe listOf(
 | |
|                 INTERNED_STRINGS_MODULENAME,
 | |
|                 "textio",
 | |
|                 "syslib",
 | |
|                 "conv",
 | |
|                 "shared_cbm_textio_functions",
 | |
|                 "floats",
 | |
|                 "shared_floats_functions",
 | |
|                 "prog8_math",
 | |
|                 "prog8_lib"
 | |
|             )
 | |
|         }
 | |
|         result.compilerAst.toplevelModule.name shouldStartWith "on_the_fly_test"
 | |
|     }
 | |
| 
 | |
|     test("testCompilationOptionsCorrectFromMain") {
 | |
|         val result = compileText(
 | |
|             C64Target(), false, """
 | |
| %import textio
 | |
| %import floats
 | |
| %zeropage dontuse
 | |
| %option no_sysinit
 | |
| 
 | |
| main {
 | |
|     sub start() {
 | |
|         ; nothing
 | |
|     }
 | |
| }
 | |
| """, outputDir)!!
 | |
|         result.compilerAst.toplevelModule.name shouldStartWith "on_the_fly_test"
 | |
|         val options = determineCompilationOptions(result.compilerAst, C64Target())
 | |
|         options.floats shouldBe true
 | |
|         options.zeropage shouldBe ZeropageType.DONTUSE
 | |
|         options.noSysInit shouldBe true
 | |
|     }
 | |
| 
 | |
|     test("testModuleOrderAndCompilationOptionsCorrectWithJustImports") {
 | |
|         val errors = ErrorReporterForTests()
 | |
|         val sourceText = """
 | |
| %import textio
 | |
| %import floats
 | |
| %option no_sysinit
 | |
| %zeropage dontuse            
 | |
| 
 | |
| main {
 | |
|     sub start() {
 | |
|         ; nothing
 | |
|     }
 | |
| }
 | |
| """
 | |
|         val filenameBase = "on_the_fly_test_${sourceText.hashCode().toUInt().toString(16)}"
 | |
| 
 | |
|         val filepath = outputDir.resolve("$filenameBase.p8")
 | |
|         filepath.toFile().writeText(sourceText)
 | |
|         val (program, options, importedfiles) = parseMainModule(filepath, errors, C64Target(), emptyList(), emptyList(), false)
 | |
| 
 | |
|         program.toplevelModule.name shouldBe filenameBase
 | |
|         withClue("all imports other than the test source must have been internal resources library files") {
 | |
|             importedfiles.size shouldBe 1
 | |
|         }
 | |
|         withClue("module order in parse tree") {
 | |
|             program.modules.map { it.name } shouldBe
 | |
|                 listOf(
 | |
|                     INTERNED_STRINGS_MODULENAME,
 | |
|                     filenameBase,
 | |
|                     "textio", "syslib", "conv", "shared_cbm_textio_functions", "floats", "shared_floats_functions", "prog8_math", "prog8_lib"
 | |
|                 )
 | |
|         }
 | |
|         options.floats shouldBe true
 | |
|         options.noSysInit shouldBe true
 | |
|         withClue("zeropage option must be correctly taken from main module, not from float module import logic") {
 | |
|             options.zeropage shouldBe ZeropageType.DONTUSE
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     test("merge option works on library modules") {
 | |
|         val src="""
 | |
| %zeropage basicsafe
 | |
| %import textio
 | |
| 
 | |
| txt {
 | |
|     %option merge
 | |
|     sub println(uword string) {
 | |
|         txt.print(string)
 | |
|         txt.nl()
 | |
|     }
 | |
| }
 | |
| 
 | |
| main {
 | |
|     sub start() {
 | |
|         txt.lowercase()
 | |
|         txt.println("Hello, world1")
 | |
|         txt.println("Hello, world2")
 | |
|         txt.println("Hello, world3")
 | |
|     }
 | |
| }"""
 | |
|         compileText(VMTarget(), optimize = false, src, outputDir) shouldNotBe null
 | |
|     }
 | |
| 
 | |
|     test("double merge is invalid") {
 | |
|         val src="""
 | |
| main {
 | |
| 
 | |
|     sub start() {
 | |
|         block1.sub1()
 | |
|         block1.sub2()
 | |
|     }
 | |
| }
 | |
| 
 | |
| block1 {
 | |
|     %option merge
 | |
| 
 | |
|     sub sub1() {
 | |
|         cx16.r1++
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| block1 {
 | |
|     %option merge
 | |
| 
 | |
|     sub sub2() {
 | |
|         cx16.r2++
 | |
|     }
 | |
| }"""
 | |
|         val errors=ErrorReporterForTests()
 | |
|         compileText(VMTarget(), optimize = false, src, outputDir, errors=errors) shouldBe null
 | |
|         errors.errors.size shouldBe 1
 | |
|         errors.errors[0] shouldContain "all declarations of block 'block1' have %option merge"
 | |
|     }
 | |
| 
 | |
|     test("merge works") {
 | |
|         val src = """
 | |
| %import textio
 | |
| 
 | |
| main {
 | |
| 
 | |
| sub start() {
 | |
|     blah.test()
 | |
| }
 | |
| }
 | |
| 
 | |
| txt {
 | |
| ; merges this block into the txt block coming from the textio library
 | |
| %option merge
 | |
| 
 | |
| sub schrijf(str arg) {
 | |
|     print(arg)
 | |
| }
 | |
| }
 | |
| 
 | |
| blah {
 | |
| ; merges this block into the other 'blah' one
 | |
| %option merge
 | |
| 
 | |
| sub test() {
 | |
|     printit("test merge")
 | |
| }
 | |
| }
 | |
| 
 | |
| blah {
 | |
| sub printit(str arg) {
 | |
|     txt.schrijf(arg)
 | |
| }
 | |
| }"""
 | |
|         compileText(C64Target(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
 | |
|     }
 | |
| 
 | |
|     test("merge override existing subroutine") {
 | |
|         val src="""
 | |
| %import textio
 | |
| 
 | |
| main {
 | |
| 
 | |
| sub start() {
 | |
|     txt.print("sdfdsf")
 | |
| }
 | |
| }
 | |
| 
 | |
| txt {
 | |
| %option merge
 | |
| 
 | |
| sub print(str text) {
 | |
|     cx16.r0++
 | |
|     ; just some dummy implementation to replace existing print
 | |
| }
 | |
| }"""
 | |
| 
 | |
|         val result = compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false)
 | |
|         result shouldNotBe null
 | |
|     }
 | |
| 
 | |
|     test("merge doesn't override existing subroutine if signature differs") {
 | |
|         val src="""
 | |
| %import textio
 | |
| 
 | |
| main {
 | |
| 
 | |
| sub start() {
 | |
|     txt.print("sdfdsf")
 | |
| }
 | |
| }
 | |
| 
 | |
| txt {
 | |
| %option merge
 | |
| 
 | |
| sub print(str anotherparamname) {
 | |
|     cx16.r0++
 | |
|     ; just some dummy implementation to replace existing print
 | |
| }
 | |
| }"""
 | |
|         val errors = ErrorReporterForTests()
 | |
|         compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false, errors = errors) shouldBe null
 | |
|         errors.errors.size shouldBe 1
 | |
|         errors.errors[0] shouldContain "name conflict"
 | |
|     }
 | |
| 
 | |
|     test("merge of float stuff into sys and txt - import order 1") {
 | |
|         val src="""
 | |
| %import textio
 | |
| %import floats
 | |
| 
 | |
| main {
 | |
| sub start() {
 | |
|     txt.print_b(sys.MIN_BYTE)
 | |
|     txt.print_b(sys.MAX_BYTE)
 | |
|     txt.print_ub(sys.MIN_UBYTE)
 | |
|     txt.print_ub(sys.MAX_UBYTE)
 | |
|     txt.print_w(sys.MIN_WORD)
 | |
|     txt.print_w(sys.MAX_WORD)
 | |
|     txt.print_uw(sys.MIN_UWORD)
 | |
|     txt.print_uw(sys.MAX_UWORD)
 | |
| 
 | |
|     txt.print_f(floats.EPSILON)
 | |
|     txt.print_f(sys.MIN_FLOAT)
 | |
|     txt.print_f(sys.MAX_FLOAT)
 | |
|     txt.print_f(floats.E)
 | |
|     txt.print_ub(sys.SIZEOF_FLOAT)
 | |
| }
 | |
| }"""
 | |
| 
 | |
|         compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
 | |
|         compileText(Cx16Target(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
 | |
|     }
 | |
| 
 | |
|     test("merge of float stuff into sys and txt - import order 2") {
 | |
|         val src="""
 | |
| %import floats
 | |
| %import textio
 | |
| 
 | |
| main {
 | |
| sub start() {
 | |
|     txt.print_b(sys.MIN_BYTE)
 | |
|     txt.print_b(sys.MAX_BYTE)
 | |
|     txt.print_ub(sys.MIN_UBYTE)
 | |
|     txt.print_ub(sys.MAX_UBYTE)
 | |
|     txt.print_w(sys.MIN_WORD)
 | |
|     txt.print_w(sys.MAX_WORD)
 | |
|     txt.print_uw(sys.MIN_UWORD)
 | |
|     txt.print_uw(sys.MAX_UWORD)
 | |
| 
 | |
|     txt.print_f(floats.EPSILON)
 | |
|     txt.print_f(sys.MIN_FLOAT)
 | |
|     txt.print_f(sys.MAX_FLOAT)
 | |
|     txt.print_f(floats.E)
 | |
|     txt.print_ub(sys.SIZEOF_FLOAT)
 | |
| }
 | |
| }"""
 | |
| 
 | |
|         compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
 | |
|         compileText(Cx16Target(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
 | |
|     }
 | |
| })
 |