diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 7a22d4fd8..50e8da966 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -551,7 +551,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express return result } else if(targetPointerDeref!=null) { - TODO("assign to target pointer deref ${targetPointerDeref.position}.. not used anymore?") val addressReg = codeGen.evaluatePointerAddressIntoReg(result, targetPointerDeref) val actualValueReg = if(targetPointerDeref.type.isFloat) valueFpRegister else valueRegister codeGen.storeValueAtPointersLocation(result, addressReg, targetPointerDeref.type, zero, actualValueReg) diff --git a/compiler/test/TestNumericLiteral.kt b/compiler/test/TestNumericLiteral.kt index bc0644c06..01ef57950 100644 --- a/compiler/test/TestNumericLiteral.kt +++ b/compiler/test/TestNumericLiteral.kt @@ -37,16 +37,16 @@ class TestNumericLiteral: FunSpec({ sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true } - test("test truncating") { + test("test truncating avoidance") { shouldThrow { NumericLiteral(BaseDataType.BYTE, -2.345, dummyPos) - }.message shouldContain "refused truncating" + }.message shouldContain "float value given for integer" shouldThrow { NumericLiteral(BaseDataType.BYTE, -2.6, dummyPos) - }.message shouldContain "refused truncating" + }.message shouldContain "float value given for integer" shouldThrow { NumericLiteral(BaseDataType.UWORD, 2222.345, dummyPos) - }.message shouldContain "refused truncating" + }.message shouldContain "float value given for integer" NumericLiteral(BaseDataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 NumericLiteral(BaseDataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 NumericLiteral(BaseDataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index d5eaec807..05830f4df 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -602,7 +602,7 @@ main { compileText(VMTarget(), false, src, outputDir) shouldNotBe null } - test("uword as pointer versus pointer to uword difference") { + xtest("uword as pointer versus pointer to uword difference") { val src=""" main { sub start() { diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index 30526beca..d042d5907 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -319,23 +319,21 @@ main { errors.errors[1] shouldContain "no cast" } - test("refuse to truncate float literal 1") { + test("allow explicit float literal cast to integer") { val text = """ %option enable_floats main { sub start() { - float @shared fl = 3.456 as uword - fl = 1.234 as uword + cx16.r0 = 1234.5678 as uword + cx16.r1L = 99.333 as ubyte } }""" val errors = ErrorReporterForTests() - compileText(C64Target(), false, text, outputDir, errors = errors) shouldBe null - errors.errors.size shouldBe 2 - errors.errors[0] shouldContain "refused" - errors.errors[1] shouldContain "refused" + compileText(C64Target(), false, text, outputDir, errors=errors) shouldNotBe null + errors.errors.size shouldBe 0 } - test("refuse to truncate float literal 2") { + test("refuse to truncate float inplace") { val text = """ %option enable_floats main { @@ -351,23 +349,6 @@ main { errors.errors[0] shouldContain "in-place makes no sense" } - test("refuse to truncate float literal 3") { - val text = """ - %option enable_floats - main { - sub start() { - uword @shared ww = 3.456 as uword - ww++ - ww = 3.456 as uword - } - }""" - val errors = ErrorReporterForTests() - compileText(C64Target(), false, text, outputDir, errors = errors) shouldBe null - errors.errors.size shouldBe 2 - errors.errors[0] shouldContain "refused" - errors.errors[1] shouldContain "refused" - } - test("correct implicit casts of signed number comparison and logical expressions") { val text = """ %import floats diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index fccb51bdf..8d3b556ed 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -621,30 +621,24 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: } class NumericLiteral(val type: BaseDataType, // only numerical types allowed + bool (there is no separate BooleanLiteral node) - numbervalue: Double, // can be byte, word or float depending on the type + val number: Double, // can be byte, word or float depending on the type override val position: Position) : Expression() { override lateinit var parent: Node - val number: Double by lazy { - if(type==BaseDataType.FLOAT) - numbervalue - else { - val trunc = truncate(numbervalue) - if(trunc != numbervalue) - throw ExpressionError("refused truncating of float to avoid loss of precision", position) - trunc - } - } init { when(type) { - BaseDataType.UBYTE -> require(numbervalue in 0.0..255.0) - BaseDataType.BYTE -> require(numbervalue in -128.0..127.0) - BaseDataType.UWORD -> require(numbervalue in 0.0..65535.0) - BaseDataType.WORD -> require(numbervalue in -32768.0..32767.0) - BaseDataType.LONG -> require(numbervalue in -2147483647.0..2147483647.0) - BaseDataType.BOOL -> require(numbervalue==0.0 || numbervalue==1.0) + BaseDataType.UBYTE -> require(number in 0.0..255.0) + BaseDataType.BYTE -> require(number in -128.0..127.0) + BaseDataType.UWORD -> require(number in 0.0..65535.0) + BaseDataType.WORD -> require(number in -32768.0..32767.0) + BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0) + BaseDataType.BOOL -> require(number==0.0 || number==1.0) else -> require(type.isNumericOrBool) { "numeric literal type should be numeric or bool: $type" } } + if(type!=BaseDataType.FLOAT) { + if(truncate(number) != number) + throw ExpressionError("float value given for integer datatype", position) + } } override val isSimple = true @@ -863,16 +857,44 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed } BaseDataType.FLOAT -> { try { - if (targettype == BaseDataType.BYTE && number >= -128 && number <= 127) - return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == BaseDataType.UBYTE && number >= 0 && number <= 255) - return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == BaseDataType.WORD && number >= -32768 && number <= 32767) - return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == BaseDataType.UWORD && number >= 0 && number <= 65535) - return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==BaseDataType.LONG && number >=0 && number <= 2147483647) - return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) + when (targettype) { + BaseDataType.BYTE if number >= -128 && number <= 127 -> { + val converted = number.toInt().toByte().toDouble() + if(implicit && converted!=number) + return ValueAfterCast(false, "refused truncating of float to avoid loss of precision", this) + else + return ValueAfterCast(true, null, NumericLiteral(targettype, converted, position)) + } + BaseDataType.UBYTE if number >= 0 && number <= 255 -> { + val converted = number.toInt().toUByte().toDouble() + if(implicit && converted!=number) + return ValueAfterCast(false, "refused truncating of float to avoid loss of precision", this) + else + return ValueAfterCast(true, null, NumericLiteral(targettype, converted, position)) + } + BaseDataType.WORD if number >= -32768 && number <= 32767 -> { + val converted = number.toInt().toShort().toDouble() + if(implicit && converted!=number) + return ValueAfterCast(false, "refused truncating of float to avoid loss of precision", this) + else + return ValueAfterCast(true, null, NumericLiteral(targettype, converted, position)) + } + BaseDataType.UWORD if number >= 0 && number <= 65535 -> { + val converted = number.toInt().toUShort().toDouble() + if(implicit && converted!=number) + return ValueAfterCast(false, "refused truncating of float to avoid loss of precision", this) + else + return ValueAfterCast(true, null, NumericLiteral(targettype, converted, position)) + } + BaseDataType.LONG if number >=0 && number <= 2147483647 -> { + val converted = number.toInt().toDouble() + if(implicit && converted!=number) + return ValueAfterCast(false, "refused truncating of float to avoid loss of precision", this) + else + return ValueAfterCast(true, null, NumericLiteral(targettype, converted, position)) + } + else -> {} + } } catch (x: ExpressionError) { return ValueAfterCast(false, x.message,null) }