mirror of
https://github.com/irmen/prog8.git
synced 2024-11-30 08:52:30 +00:00
210 lines
10 KiB
Kotlin
210 lines
10 KiB
Kotlin
package prog8tests
|
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
|
import io.kotest.core.spec.style.FunSpec
|
|
import io.kotest.matchers.doubles.plusOrMinus
|
|
import io.kotest.matchers.shouldBe
|
|
import io.kotest.matchers.shouldNotBe
|
|
import io.kotest.matchers.string.shouldContain
|
|
import prog8.ast.expressions.NumericLiteral
|
|
import prog8.ast.statements.Assignment
|
|
import prog8.code.core.DataType
|
|
import prog8.code.core.InternalCompilerException
|
|
import prog8.code.core.Position
|
|
import prog8.code.core.toHex
|
|
import prog8.code.target.C64Target
|
|
import prog8.code.target.cbm.Mflpt5
|
|
import prog8tests.helpers.ErrorReporterForTests
|
|
import prog8tests.helpers.compileText
|
|
|
|
|
|
class TestNumbers: FunSpec({
|
|
test("testToHex") {
|
|
0.toHex() shouldBe "0"
|
|
1.toHex() shouldBe "1"
|
|
1.234.toHex() shouldBe "1"
|
|
10.toHex() shouldBe "10"
|
|
10.99.toHex() shouldBe "10"
|
|
15.toHex() shouldBe "15"
|
|
16.toHex() shouldBe "\$10"
|
|
255.toHex() shouldBe "\$ff"
|
|
256.toHex() shouldBe "\$0100"
|
|
20060.toHex() shouldBe "\$4e5c"
|
|
50050.toHex() shouldBe "\$c382"
|
|
65535.toHex() shouldBe "\$ffff"
|
|
65535L.toHex() shouldBe "\$ffff"
|
|
0.toHex() shouldBe "0"
|
|
(-1).toHex() shouldBe "-1"
|
|
(-1.234).toHex() shouldBe "-1"
|
|
(-10).toHex() shouldBe "-10"
|
|
(-10.99).toHex() shouldBe "-10"
|
|
(-15).toHex() shouldBe "-15"
|
|
(-16).toHex() shouldBe "-\$10"
|
|
(-255).toHex() shouldBe "-\$ff"
|
|
(-256).toHex() shouldBe "-\$0100"
|
|
(-20060).toHex() shouldBe "-\$4e5c"
|
|
(-50050).toHex() shouldBe "-\$c382"
|
|
(-65535).toHex() shouldBe "-\$ffff"
|
|
(-65535L).toHex() shouldBe "-\$ffff"
|
|
shouldThrow<IllegalArgumentException> { 65536.toHex() }
|
|
shouldThrow<IllegalArgumentException> { 65536L.toHex() }
|
|
}
|
|
|
|
test("testFloatToMflpt5") {
|
|
Mflpt5.fromNumber(0) shouldBe Mflpt5(0x00u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(3.141592653) shouldBe Mflpt5(0x82u, 0x49u, 0x0Fu, 0xDAu, 0xA1u)
|
|
Mflpt5.fromNumber(3.141592653589793) shouldBe Mflpt5(0x82u, 0x49u, 0x0Fu, 0xDAu, 0xA2u)
|
|
Mflpt5.fromNumber(32768) shouldBe Mflpt5(0x90u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(-32768) shouldBe Mflpt5(0x90u, 0x80u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(1) shouldBe Mflpt5(0x81u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(0.7071067812) shouldBe Mflpt5(0x80u, 0x35u, 0x04u, 0xF3u, 0x34u)
|
|
Mflpt5.fromNumber(0.7071067811865476) shouldBe Mflpt5(0x80u, 0x35u, 0x04u, 0xF3u, 0x33u)
|
|
Mflpt5.fromNumber(1.4142135624) shouldBe Mflpt5(0x81u, 0x35u, 0x04u, 0xF3u, 0x34u)
|
|
Mflpt5.fromNumber(1.4142135623730951) shouldBe Mflpt5(0x81u, 0x35u, 0x04u, 0xF3u, 0x33u)
|
|
Mflpt5.fromNumber(-.5) shouldBe Mflpt5(0x80u, 0x80u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(0.69314718061) shouldBe Mflpt5(0x80u, 0x31u, 0x72u, 0x17u, 0xF8u)
|
|
Mflpt5.fromNumber(0.6931471805599453) shouldBe Mflpt5(0x80u, 0x31u, 0x72u, 0x17u, 0xF7u)
|
|
Mflpt5.fromNumber(10) shouldBe Mflpt5(0x84u, 0x20u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(1000000000) shouldBe Mflpt5(0x9Eu, 0x6Eu, 0x6Bu, 0x28u, 0x00u)
|
|
Mflpt5.fromNumber(.5) shouldBe Mflpt5(0x80u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(1.4426950408889634) shouldBe Mflpt5(0x81u, 0x38u, 0xAAu, 0x3Bu, 0x29u)
|
|
Mflpt5.fromNumber(1.5707963267948966) shouldBe Mflpt5(0x81u, 0x49u, 0x0Fu, 0xDAu, 0xA2u)
|
|
Mflpt5.fromNumber(6.283185307179586) shouldBe Mflpt5(0x83u, 0x49u, 0x0Fu, 0xDAu, 0xA2u)
|
|
Mflpt5.fromNumber(.25) shouldBe Mflpt5(0x7Fu, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(123.45678e22) shouldBe Mflpt5(0xd1u, 0x02u, 0xb7u, 0x06u, 0xfbu)
|
|
Mflpt5.fromNumber(-123.45678e-22) shouldBe Mflpt5(0x3eu, 0xe9u, 0x34u, 0x09u, 0x1bu)
|
|
}
|
|
|
|
test("testFloatRange") {
|
|
Mflpt5.fromNumber(Mflpt5.FLOAT_MAX_POSITIVE) shouldBe Mflpt5(0xffu, 0x7fu, 0xffu, 0xffu, 0xffu)
|
|
Mflpt5.fromNumber(Mflpt5.FLOAT_MAX_NEGATIVE) shouldBe Mflpt5(0xffu, 0xffu, 0xffu, 0xffu, 0xffu)
|
|
Mflpt5.fromNumber(1.7e-38) shouldBe Mflpt5(0x03u, 0x39u, 0x1du, 0x15u, 0x63u)
|
|
Mflpt5.fromNumber(1.7e-39) shouldBe Mflpt5(0x00u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
Mflpt5.fromNumber(-1.7e-38) shouldBe Mflpt5(0x03u, 0xb9u, 0x1du, 0x15u, 0x63u)
|
|
Mflpt5.fromNumber(-1.7e-39) shouldBe Mflpt5(0x00u, 0x00u, 0x00u, 0x00u, 0x00u)
|
|
shouldThrow<InternalCompilerException> { Mflpt5.fromNumber(1.7014118346e+38) }
|
|
shouldThrow<InternalCompilerException> { Mflpt5.fromNumber(-1.7014118346e+38) }
|
|
shouldThrow<InternalCompilerException> { Mflpt5.fromNumber(1.7014118347e+38) }
|
|
shouldThrow<InternalCompilerException> { Mflpt5.fromNumber(-1.7014118347e+38) }
|
|
}
|
|
|
|
test("testMflpt5ToFloat") {
|
|
val epsilon=0.000000001
|
|
|
|
Mflpt5(0x00u, 0x00u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe 0.0
|
|
Mflpt5(0x82u, 0x49u, 0x0Fu, 0xDAu, 0xA1u).toDouble() shouldBe(3.141592653 plusOrMinus epsilon)
|
|
Mflpt5(0x82u, 0x49u, 0x0Fu, 0xDAu, 0xA2u).toDouble() shouldBe(3.141592653589793 plusOrMinus epsilon)
|
|
Mflpt5(0x90u, 0x00u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe 32768.0
|
|
Mflpt5(0x90u, 0x80u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe -32768.0
|
|
Mflpt5(0x81u, 0x00u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe 1.0
|
|
Mflpt5(0x80u, 0x35u, 0x04u, 0xF3u, 0x34u).toDouble() shouldBe(0.7071067812 plusOrMinus epsilon)
|
|
Mflpt5(0x80u, 0x35u, 0x04u, 0xF3u, 0x33u).toDouble() shouldBe(0.7071067811865476 plusOrMinus epsilon)
|
|
Mflpt5(0x81u, 0x35u, 0x04u, 0xF3u, 0x34u).toDouble() shouldBe(1.4142135624 plusOrMinus epsilon)
|
|
Mflpt5(0x81u, 0x35u, 0x04u, 0xF3u, 0x33u).toDouble() shouldBe(1.4142135623730951 plusOrMinus epsilon)
|
|
Mflpt5(0x80u, 0x80u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe -.5
|
|
Mflpt5(0x80u, 0x31u, 0x72u, 0x17u, 0xF8u).toDouble() shouldBe(0.69314718061 plusOrMinus epsilon)
|
|
Mflpt5(0x80u, 0x31u, 0x72u, 0x17u, 0xF7u).toDouble() shouldBe(0.6931471805599453 plusOrMinus epsilon)
|
|
Mflpt5(0x84u, 0x20u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe 10.0
|
|
Mflpt5(0x9Eu, 0x6Eu, 0x6Bu, 0x28u, 0x00u).toDouble() shouldBe 1000000000.0
|
|
Mflpt5(0x80u, 0x00u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe .5
|
|
Mflpt5(0x81u, 0x38u, 0xAAu, 0x3Bu, 0x29u).toDouble() shouldBe(1.4426950408889634 plusOrMinus epsilon)
|
|
Mflpt5(0x81u, 0x49u, 0x0Fu, 0xDAu, 0xA2u).toDouble() shouldBe(1.5707963267948966 plusOrMinus epsilon)
|
|
Mflpt5(0x83u, 0x49u, 0x0Fu, 0xDAu, 0xA2u).toDouble() shouldBe(6.283185307179586 plusOrMinus epsilon)
|
|
Mflpt5(0x7Fu, 0x00u, 0x00u, 0x00u, 0x00u).toDouble() shouldBe .25
|
|
Mflpt5(0xd1u, 0x02u, 0xb7u, 0x06u, 0xfbu).toDouble() shouldBe(123.45678e22 plusOrMinus 1.0e15)
|
|
Mflpt5(0x3eu, 0xe9u, 0x34u, 0x09u, 0x1bu).toDouble() shouldBe(-123.45678e-22 plusOrMinus epsilon)
|
|
}
|
|
|
|
test("implicit float conversion warning if enabled") {
|
|
val src="""
|
|
%option enable_floats
|
|
main {
|
|
sub start() {
|
|
uword xx = 10
|
|
if xx+99 == 1.23456
|
|
xx++
|
|
if xx+99 == 1234567
|
|
xx++
|
|
}
|
|
}
|
|
"""
|
|
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
|
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldNotBe null
|
|
errors.errors.size shouldBe 0
|
|
errors.warnings.size shouldBe 2
|
|
errors.warnings[0] shouldContain "converted to float"
|
|
errors.warnings[1] shouldContain "converted to float"
|
|
}
|
|
|
|
test("implicit float conversion error if not enabled") {
|
|
val src="""
|
|
main {
|
|
sub start() {
|
|
uword xx = 10
|
|
if xx+99 == 1.23456
|
|
xx++
|
|
if xx+99 == 1234567
|
|
xx++
|
|
}
|
|
}
|
|
"""
|
|
val errors = ErrorReporterForTests()
|
|
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldBe null
|
|
errors.errors.size shouldBe 2
|
|
errors.warnings.size shouldBe 0
|
|
errors.errors[0] shouldContain "converted to float"
|
|
errors.errors[1] shouldContain "converted to float"
|
|
}
|
|
|
|
test("out of range number assignments") {
|
|
val src="""
|
|
main {
|
|
sub start() {
|
|
uword @shared qq = ${'$'}2ff33
|
|
cx16.r0 = ${'$'}1fc0f
|
|
}
|
|
}
|
|
"""
|
|
val errors = ErrorReporterForTests()
|
|
compileText(C64Target(), true, src, writeAssembly = false, errors=errors) shouldBe null
|
|
errors.errors.size shouldBe 2
|
|
errors.warnings.size shouldBe 0
|
|
errors.errors[0] shouldContain "out of range"
|
|
errors.errors[1] shouldContain "out of range"
|
|
}
|
|
|
|
test("big numbers okay in const expressions if result fits") {
|
|
val src="""
|
|
main {
|
|
sub start() {
|
|
uword @shared qq = ${'$'}2ff33 >> 4
|
|
cx16.r0 = ${'$'}1fc0f >> 4
|
|
}
|
|
}
|
|
"""
|
|
compileText(C64Target(), true, src, writeAssembly = false) shouldNotBe null
|
|
}
|
|
|
|
test("signed negative numbers cast to unsigned allowed") {
|
|
val src="""
|
|
main {
|
|
sub start() {
|
|
uword uw1 = -32768
|
|
uword uw = -1
|
|
ubyte ub = -1
|
|
uw = -2 as uword
|
|
ub = -2 as ubyte
|
|
}
|
|
}
|
|
"""
|
|
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
|
val statements = result.compilerAst.entrypoint.statements
|
|
statements.size shouldBe 8
|
|
(statements[1] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 32768.0, Position.DUMMY)
|
|
(statements[3] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 65535.0, Position.DUMMY)
|
|
(statements[5] as Assignment).value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY)
|
|
(statements[6] as Assignment).value shouldBe NumericLiteral(DataType.UWORD, 65534.0, Position.DUMMY)
|
|
(statements[7] as Assignment).value shouldBe NumericLiteral(DataType.UBYTE, 254.0, Position.DUMMY)
|
|
}
|
|
})
|