package prog8tests.compiler import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain import prog8.ast.base.ExpressionError import prog8.ast.expressions.ArrayLiteral import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.StringLiteral import prog8.ast.statements.AnonymousScope import prog8.code.core.DataType import prog8.code.core.Encoding import prog8.code.core.Position class TestNumericLiteral: FunSpec({ fun sameValueAndType(lv1: NumericLiteral, lv2: NumericLiteral): Boolean { return lv1.type==lv2.type && lv1==lv2 } val dummyPos = Position("test", 0, 0, 0) test("testIdentity") { val v = NumericLiteral(DataType.UWORD, 12345.0, dummyPos) (v==v) shouldBe true (v != v) shouldBe false (v <= v) shouldBe true (v >= v) shouldBe true (v < v ) shouldBe false (v > v ) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true } test("test truncating") { shouldThrow { NumericLiteral(DataType.BYTE, -2.345, dummyPos) }.message shouldContain "refused truncating" shouldThrow { NumericLiteral(DataType.BYTE, -2.6, dummyPos) }.message shouldContain "refused truncating" shouldThrow { NumericLiteral(DataType.UWORD, 2222.345, dummyPos) }.message shouldContain "refused truncating" NumericLiteral(DataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 NumericLiteral(DataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 NumericLiteral(DataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 NumericLiteral(DataType.FLOAT, 123.456, dummyPos) } test("testEqualsAndNotEquals") { (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.UWORD, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 254.0, dummyPos) == NumericLiteral(DataType.UBYTE, 254.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) == NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) == NumericLiteral(DataType.FLOAT, 12345.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) == NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 22239.0, dummyPos) == NumericLiteral(DataType.UWORD, 22239.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) == NumericLiteral(DataType.FLOAT, 9.99, dummyPos)) shouldBe true sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UWORD, 100.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 254.0, dummyPos), NumericLiteral(DataType.UBYTE, 254.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.FLOAT, 12345.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 22239.0, dummyPos), NumericLiteral(DataType.UWORD, 22239.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.FLOAT, 9.99, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.UWORD, 101.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.FLOAT, 101.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 245.0, dummyPos) != NumericLiteral(DataType.UBYTE, 246.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) != NumericLiteral(DataType.UWORD, 12346.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) != NumericLiteral(DataType.FLOAT, 12346.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.UBYTE, 9.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.UWORD, 9.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.FLOAT, 9.0, dummyPos)) shouldBe true sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UWORD, 101.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.FLOAT, 101.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 245.0, dummyPos), NumericLiteral(DataType.UBYTE, 246.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12346.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.FLOAT, 12346.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.UBYTE, 9.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.UWORD, 9.0, dummyPos)) shouldBe false sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.FLOAT, 9.0, dummyPos)) shouldBe false } test("testEqualsRef") { (StringLiteral.create("hello", Encoding.PETSCII, dummyPos) == StringLiteral.create("hello", Encoding.PETSCII, dummyPos)) shouldBe true (StringLiteral.create("hello", Encoding.PETSCII, dummyPos) != StringLiteral.create("bye", Encoding.PETSCII, dummyPos)) shouldBe true (StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos) == StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos)) shouldBe true (StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos) != StringLiteral.create("bye", Encoding.SCREENCODES, dummyPos)) shouldBe true (StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos) != StringLiteral.create("hello", Encoding.PETSCII, dummyPos)) shouldBe true val lvOne = NumericLiteral(DataType.UBYTE, 1.0, dummyPos) val lvTwo = NumericLiteral(DataType.UBYTE, 2.0, dummyPos) val lvThree = NumericLiteral(DataType.UBYTE, 3.0, dummyPos) val lvOneR = NumericLiteral(DataType.UBYTE, 1.0, dummyPos) val lvTwoR = NumericLiteral(DataType.UBYTE, 2.0, dummyPos) val lvThreeR = NumericLiteral(DataType.UBYTE, 3.0, dummyPos) val lvFour= NumericLiteral(DataType.UBYTE, 4.0, dummyPos) val lv1 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOne, lvTwo, lvThree), dummyPos) val lv2 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos) val lv3 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvFour), dummyPos) lv1 shouldBe lv2 lv1 shouldNotBe lv3 } test("testGreaterThan") { (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) > NumericLiteral(DataType.UBYTE, 99.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 254.0, dummyPos) > NumericLiteral(DataType.UWORD, 253.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) > NumericLiteral(DataType.FLOAT, 99.9, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 254.0, dummyPos) >= NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) > NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UWORD, 254.0, dummyPos) > NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe false (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) > NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UWORD, 254.0, dummyPos) >= NumericLiteral(DataType.UWORD, 255.0, dummyPos)) shouldBe false (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(DataType.FLOAT, 100.1, dummyPos)) shouldBe false } test("testLessThan") { (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) < NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 254.0, dummyPos) < NumericLiteral(DataType.UWORD, 255.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) < NumericLiteral(DataType.FLOAT, 100.1, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UWORD, 254.0, dummyPos) <= NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe true (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) < NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UWORD, 254.0, dummyPos) < NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe false (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) < NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(DataType.UBYTE, 99.0, dummyPos)) shouldBe false (NumericLiteral(DataType.UWORD, 254.0, dummyPos) <= NumericLiteral(DataType.UWORD, 253.0, dummyPos)) shouldBe false (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(DataType.FLOAT, 99.9, dummyPos)) shouldBe false } test("optimalInteger") { NumericLiteral.optimalInteger(10, Position.DUMMY).type shouldBe DataType.UBYTE NumericLiteral.optimalInteger(10, Position.DUMMY).number shouldBe 10.0 NumericLiteral.optimalInteger(-10, Position.DUMMY).type shouldBe DataType.BYTE NumericLiteral.optimalInteger(-10, Position.DUMMY).number shouldBe -10.0 NumericLiteral.optimalInteger(1000, Position.DUMMY).type shouldBe DataType.UWORD NumericLiteral.optimalInteger(-1000, Position.DUMMY).number shouldBe -1000.0 NumericLiteral.optimalInteger(1000u, Position.DUMMY).type shouldBe DataType.UWORD NumericLiteral.optimalInteger(1000u, Position.DUMMY).number shouldBe 1000.0 } test("optimalNumeric") { NumericLiteral.optimalNumeric(10, Position.DUMMY).type shouldBe DataType.UBYTE NumericLiteral.optimalNumeric(10, Position.DUMMY).number shouldBe 10.0 NumericLiteral.optimalNumeric(-10, Position.DUMMY).type shouldBe DataType.BYTE NumericLiteral.optimalNumeric(-10, Position.DUMMY).number shouldBe -10.0 NumericLiteral.optimalNumeric(1000, Position.DUMMY).type shouldBe DataType.UWORD NumericLiteral.optimalNumeric(1000, Position.DUMMY).number shouldBe 1000.0 NumericLiteral.optimalNumeric(-1000, Position.DUMMY).type shouldBe DataType.WORD NumericLiteral.optimalNumeric(-1000, Position.DUMMY).number shouldBe -1000.0 NumericLiteral.optimalNumeric(1.123, Position.DUMMY).type shouldBe DataType.FLOAT NumericLiteral.optimalNumeric(1.123, Position.DUMMY).number shouldBe 1.123 NumericLiteral.optimalNumeric(1.0, Position.DUMMY).type shouldBe DataType.UBYTE NumericLiteral.optimalNumeric(1.0, Position.DUMMY).number shouldBe 1.0 NumericLiteral.optimalNumeric(-1.0, Position.DUMMY).type shouldBe DataType.BYTE NumericLiteral.optimalNumeric(-1.0, Position.DUMMY).number shouldBe -1.0 NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).type shouldBe DataType.UWORD NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).number shouldBe 1234.0 NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe DataType.WORD NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).number shouldBe -1234.0 } test("cast can change value") { fun num(dt: DataType, num: Double): NumericLiteral { val n = NumericLiteral(dt, num, Position.DUMMY) n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY)) return n } val cast1 = num(DataType.UBYTE, 200.0).cast(DataType.BYTE, false) cast1.isValid shouldBe true cast1.valueOrZero().number shouldBe -56.0 val cast2 = num(DataType.BYTE, -50.0).cast(DataType.UBYTE, false) cast2.isValid shouldBe true cast2.valueOrZero().number shouldBe 206.0 val cast3 = num(DataType.UWORD, 55555.0).cast(DataType.WORD, false) cast3.isValid shouldBe true cast3.valueOrZero().number shouldBe -9981.0 val cast4 = num(DataType.WORD, -3333.0).cast(DataType.UWORD, false) cast4.isValid shouldBe true cast4.valueOrZero().number shouldBe 62203.0 } test("convert cannot change value") { fun num(dt: DataType, num: Double): NumericLiteral { val n = NumericLiteral(dt, num, Position.DUMMY) n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY)) return n } num(DataType.UBYTE, 200.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe false num(DataType.BYTE, -50.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe false num(DataType.UWORD, 55555.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe false num(DataType.WORD, -3333.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe false num(DataType.UBYTE, 42.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe true num(DataType.BYTE, 42.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe true num(DataType.UWORD, 12345.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe true num(DataType.WORD, 12345.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe true } })