2021-11-07 16:25:53 +00:00
|
|
|
package prog8tests.ast
|
|
|
|
|
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
|
|
|
import io.kotest.assertions.withClue
|
|
|
|
import io.kotest.core.spec.style.FunSpec
|
|
|
|
import io.kotest.matchers.collections.shouldBeIn
|
|
|
|
import io.kotest.matchers.shouldBe
|
2024-10-29 21:57:54 +00:00
|
|
|
import io.kotest.matchers.shouldNotBe
|
2021-11-07 16:25:53 +00:00
|
|
|
import io.kotest.matchers.string.shouldContain
|
|
|
|
import io.kotest.matchers.types.shouldBeSameInstanceAs
|
|
|
|
import prog8.ast.Module
|
|
|
|
import prog8.ast.Program
|
2022-03-10 21:38:16 +00:00
|
|
|
import prog8.code.core.Position
|
2022-03-21 00:01:21 +00:00
|
|
|
import prog8.code.core.SourceCode
|
|
|
|
import prog8.code.core.internedStringsModuleName
|
2024-10-29 21:57:54 +00:00
|
|
|
import prog8.code.target.C64Target
|
2024-10-29 23:37:45 +00:00
|
|
|
import prog8.code.target.VMTarget
|
|
|
|
import prog8tests.helpers.*
|
2021-11-07 16:25:53 +00:00
|
|
|
|
|
|
|
class TestProgram: FunSpec({
|
|
|
|
|
|
|
|
context("Constructor") {
|
|
|
|
test("withNameBuiltinsAndMemsizer") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
program.modules.size shouldBe 1
|
|
|
|
program.modules[0].name shouldBe internedStringsModuleName
|
|
|
|
program.modules[0].program shouldBeSameInstanceAs program
|
|
|
|
program.modules[0].parent shouldBeSameInstanceAs program.namespace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context("AddModule") {
|
|
|
|
test("withEmptyModule") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
|
|
|
|
|
|
|
|
val retVal = program.addModule(m1)
|
|
|
|
|
|
|
|
retVal shouldBeSameInstanceAs program
|
|
|
|
program.modules.size shouldBe 2
|
|
|
|
m1 shouldBeIn program.modules
|
|
|
|
m1.program shouldBeSameInstanceAs program
|
|
|
|
m1.parent shouldBeSameInstanceAs program.namespace
|
|
|
|
|
|
|
|
withClue("module may not occur multiple times") {
|
|
|
|
val ex = shouldThrow<IllegalArgumentException> { program.addModule(m1) }
|
|
|
|
ex.message shouldContain m1.name
|
|
|
|
}
|
|
|
|
|
|
|
|
val m2 = Module(mutableListOf(), m1.position, m1.source)
|
|
|
|
withClue("other module but with same name may not occur multiple times") {
|
|
|
|
val ex = shouldThrow<IllegalArgumentException> { program.addModule(m2) }
|
|
|
|
ex.message shouldContain m1.name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context("MoveModuleToFront") {
|
|
|
|
test("withInternedStringsModule") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
val m = program.modules[0]
|
|
|
|
m.name shouldBe internedStringsModuleName
|
|
|
|
|
|
|
|
val retVal = program.moveModuleToFront(m)
|
|
|
|
retVal shouldBeSameInstanceAs program
|
|
|
|
program.modules[0] shouldBeSameInstanceAs m
|
|
|
|
}
|
|
|
|
|
|
|
|
test("withForeignModule") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
val m = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
|
|
|
|
|
|
|
|
shouldThrow<IllegalArgumentException> { program.moveModuleToFront(m) }
|
|
|
|
}
|
|
|
|
|
|
|
|
test("withFirstOfPreviouslyAddedModules") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
|
|
|
|
val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl"))
|
|
|
|
program.addModule(m1)
|
|
|
|
program.addModule(m2)
|
|
|
|
|
|
|
|
val retVal = program.moveModuleToFront(m1)
|
|
|
|
retVal shouldBeSameInstanceAs program
|
|
|
|
program.modules.indexOf(m1) shouldBe 0
|
|
|
|
}
|
|
|
|
|
|
|
|
test("withSecondOfPreviouslyAddedModules") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
|
|
|
|
val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl"))
|
|
|
|
program.addModule(m1)
|
|
|
|
program.addModule(m2)
|
|
|
|
|
|
|
|
val retVal = program.moveModuleToFront(m2)
|
|
|
|
retVal shouldBeSameInstanceAs program
|
|
|
|
program.modules.indexOf(m2) shouldBe 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context("Properties") {
|
|
|
|
test("modules") {
|
|
|
|
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
|
|
|
|
|
|
|
val ms1 = program.modules
|
|
|
|
val ms2 = program.modules
|
|
|
|
ms2 shouldBeSameInstanceAs ms1
|
|
|
|
}
|
|
|
|
}
|
2024-10-29 21:57:54 +00:00
|
|
|
|
|
|
|
context("block 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, writeAssembly=false) shouldNotBe null
|
|
|
|
}
|
2024-10-29 23:37:45 +00:00
|
|
|
|
|
|
|
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, 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, writeAssembly=false, errors = errors) shouldBe null
|
|
|
|
errors.errors.size shouldBe 1
|
|
|
|
errors.errors[0] shouldContain "name conflict"
|
|
|
|
}
|
2024-10-29 21:57:54 +00:00
|
|
|
}
|
2021-11-07 16:25:53 +00:00
|
|
|
})
|