prog8/compiler/test/TestBuiltinFunctions.kt

118 lines
4.0 KiB
Kotlin

package prog8tests.compiler
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Assignment
import prog8.ast.statements.FunctionCallStatement
import prog8.code.core.BuiltinFunctions
import prog8.code.core.DataType
import prog8.code.core.NumericDatatypes
import prog8.code.core.RegisterOrPair
import prog8.code.target.Cx16Target
import prog8tests.helpers.compileText
class TestBuiltinFunctions: FunSpec({
test("pure func with fixed type") {
val func = BuiltinFunctions.getValue("sgn")
func.parameters.size shouldBe 1
func.parameters[0].name shouldBe "value"
func.parameters[0].possibleDatatypes shouldBe NumericDatatypes
func.pure shouldBe true
func.returnType shouldBe DataType.BYTE
val conv = func.callConvention(listOf(DataType.UBYTE))
conv.params.size shouldBe 1
conv.params[0].dt shouldBe DataType.UBYTE
conv.params[0].reg shouldBe RegisterOrPair.A
conv.params[0].variable shouldBe false
conv.returns.dt shouldBe DataType.BYTE
conv.returns.floatFac1 shouldBe false
conv.returns.reg shouldBe RegisterOrPair.A
}
test("not-pure func with varying result value type") {
val func = BuiltinFunctions.getValue("cmp")
func.parameters.size shouldBe 2
func.pure shouldBe false
func.returnType shouldBe null
val conv = func.callConvention(listOf(DataType.UWORD, DataType.UWORD))
conv.params.size shouldBe 2
conv.returns.dt shouldBe null
conv.returns.floatFac1 shouldBe false
conv.returns.reg shouldBe null
}
test("func without return type") {
val func = BuiltinFunctions.getValue("poke")
func.parameters.size shouldBe 2
func.parameters[0].name shouldBe "address"
func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UWORD)
func.parameters[1].name shouldBe "value"
func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE)
func.pure shouldBe false
func.returnType shouldBe null
val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE))
conv.params.size shouldBe 2
conv.params[0].dt shouldBe DataType.UWORD
conv.params[0].reg shouldBe null
conv.params[0].variable shouldBe true
conv.params[1].dt shouldBe DataType.UBYTE
conv.params[1].reg shouldBe null
conv.params[1].variable shouldBe true
conv.returns.dt shouldBe null
conv.returns.floatFac1 shouldBe false
conv.returns.reg shouldBe null
}
test("certain builtin functions should be compile time evaluated") {
val src="""
main {
sub start() {
uword[] array = [1,2,3]
str name = "hello"
cx16.r0L = len(array)
cx16.r1L = len(name)
cx16.r2L = sizeof(array)
cx16.r4 = mkword(200,100)
test(sizeof(array))
}
sub test(uword value) {
value++
}
}"""
val result = compileText(Cx16Target(), false, src, writeAssembly = false)
val statements = result!!.compilerAst.entrypoint.statements
statements.size shouldBe 7
val a1 = statements[2] as Assignment
val a2 = statements[3] as Assignment
val a3 = statements[4] as Assignment
val a4 = statements[5] as Assignment
val a5 = statements[6] as FunctionCallStatement
(a1.value as NumericLiteral).number shouldBe 3.0
(a2.value as NumericLiteral).number shouldBe 5.0
(a3.value as NumericLiteral).number shouldBe 6.0
(a4.value as NumericLiteral).number shouldBe 200*256+100
(a5.args[0] as NumericLiteral).number shouldBe 6.0
}
test("divmod target args should be treated as variables that are written") {
val src="""
main {
ubyte c
ubyte l
sub start() {
divmod(99, 10, c, l)
}
}"""
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
}
})