From 1509de390edea13ce0fbb6400d401d6bf44f8aba Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 2 Dec 2023 12:36:49 +0100 Subject: [PATCH] various fixes print_f() no longer prints a leading space. Better error message if using float in for loop. Fix crash when using non-const as when choice value. VM print_f() more closely resembles the CBM version. --- .../optimizer/ConstantFoldingOptimizer.kt | 3 +- compiler/res/prog8lib/floats_functions.p8 | 9 +++-- .../compiler/astprocessing/AstChecker.kt | 14 +++---- .../astprocessing/StatementReorderer.kt | 5 --- .../compiler/astprocessing/TypecastsAdder.kt | 33 ++++------------ docs/source/todo.rst | 1 - examples/test.p8 | 39 ++++++++++++++----- virtualmachine/src/prog8/vm/SysCalls.kt | 4 +- 8 files changed, 53 insertions(+), 55 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index b7ea87847..b1b4581fb 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -2,7 +2,6 @@ package prog8.optimizer import prog8.ast.Node import prog8.ast.Program -import prog8.ast.base.FatalAstException import prog8.ast.expressions.* import prog8.ast.maySwapOperandOrder import prog8.ast.statements.ForLoop @@ -389,7 +388,7 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) } } - else -> throw FatalAstException("invalid loopvar datatype $loopvar") + else -> { /* nothing for floats, these are not allowed in for loops and will give an error elsewhere */ } } return noModifications diff --git a/compiler/res/prog8lib/floats_functions.p8 b/compiler/res/prog8lib/floats_functions.p8 index 7ba347d00..4f8a221da 100644 --- a/compiler/res/prog8lib/floats_functions.p8 +++ b/compiler/res/prog8lib/floats_functions.p8 @@ -3,7 +3,7 @@ floats { %option merge, no_symbol_prefixing sub print_f(float value) { - ; ---- prints the floating point value (without a newline). + ; ---- prints the floating point value (without a newline). No leading space (unlike BASIC)! %asm {{ lda #value @@ -12,10 +12,13 @@ sub print_f(float value) { sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 ldy #0 -- lda (P8ZP_SCRATCH_W1),y + lda (P8ZP_SCRATCH_W1),y + cmp #' ' beq + +- lda (P8ZP_SCRATCH_W1),y + beq ++ jsr cbm.CHROUT - iny ++ iny bne - + rts }} diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 26d25f51b..17ea474b3 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -1348,7 +1348,7 @@ internal class AstChecker(private val program: Program, if(choices!=null) { for (c in choices) { if(c in tally) - errors.err("choice value already occurs earlier", choiceNode.position) + errors.err("choice value already occurs elsewhere", choiceNode.position) else tally.add(c) } @@ -1368,18 +1368,18 @@ internal class AstChecker(private val program: Program, val whenStmt = whenChoice.parent as When if(whenChoice.values!=null) { val conditionType = whenStmt.condition.inferType(program) - val constvalues = whenChoice.values!!.map { it.constValue(program) } - for(constvalue in constvalues) { + val constvalues = whenChoice.values!!.map { it.constValue(program) to it.position } + for((constvalue, pos) in constvalues) { when { - constvalue == null -> errors.err("choice value must be a constant", whenChoice.position) - constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", whenChoice.position) + constvalue == null -> errors.err("choice value must be a constant", pos) + constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", pos) conditionType isnot constvalue.type -> { if(conditionType.isKnown) { if(conditionType.istype(DataType.BOOL)) { if(constvalue.number!=0.0 && constvalue.number!=1.0) - errors.err("choice value datatype differs from condition value", whenChoice.position) + errors.err("choice value datatype differs from condition value", pos) } else { - errors.err("choice value datatype differs from condition value", whenChoice.position) + errors.err("choice value datatype differs from condition value", pos) } } } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 888671a33..2fb9b3035 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -191,11 +191,6 @@ internal class StatementReorderer( errors.err("else choice must be the last one", whenStmt.choices[elseChoice].position) } - val choices = whenStmt.choiceValues(program).sortedBy { - it.first?.first() ?: Int.MAX_VALUE - } - whenStmt.choices.clear() - choices.mapTo(whenStmt.choices) { it.second } return noModifications } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 8a399b915..352bf963e 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -364,34 +364,17 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val override fun after(whenChoice: WhenChoice, parent: Node): Iterable { val conditionDt = (whenChoice.parent as When).condition.inferType(program) - if((parent as When).condition.inferType(program).isWords) { - val values = whenChoice.values - values?.toTypedArray()?.withIndex()?.forEach { (index, value) -> - val valueDt = value.inferType(program) - if(valueDt!=conditionDt) { - val castedValue = (value as NumericLiteral).cast(conditionDt.getOr(DataType.UNDEFINED)) - if(castedValue.isValid) { - values[index] = castedValue.valueOrZero() - } else { - errors.err("choice value datatype differs from condition value", value.position) - } - } - } - } else { - val values = whenChoice.values - values?.toTypedArray()?.withIndex()?.forEach { (index, value) -> - val valueDt = value.inferType(program) - if(valueDt!=conditionDt) { - val castedValue = (value as NumericLiteral).cast(conditionDt.getOr(DataType.UNDEFINED)) - if(castedValue.isValid) { - values[index] = castedValue.valueOrZero() - } else { - errors.err("choice value datatype differs from condition value", value.position) - } + val values = whenChoice.values + values?.toTypedArray()?.withIndex()?.forEach { (index, value) -> + val valueDt = value.inferType(program) + if(valueDt!=conditionDt) { + val castedValue = value.typecastTo(conditionDt.getOr(DataType.UNDEFINED), valueDt.getOr(DataType.UNDEFINED), true) + if(castedValue.first) { + castedValue.second.linkParents(whenChoice) + values[index] = castedValue.second } } } - return noModifications } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 654a6fde6..f3af7cef9 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,6 @@ TODO ==== -- don't print the leading space in print_f() - uword scanline_buf = memory("scanline", 320, 0) different result when inside a sub or outside a sub??! (imageviewer iff module) - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - once VAL_1 is merged into the kernal properly, remove all the workarounds in cx16 floats.parse_f() diff --git a/examples/test.p8 b/examples/test.p8 index 71bfa6fc1..4dd64a7ba 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,21 +1,40 @@ -%import textio -%import floats %zeropage basicsafe +%import floats +%import textio %option no_sysinit main { sub start() { - ubyte uw = 97 - txt.print_ub( 10 * (uw/10) ) ; 90 + floats.print_f(0.0) txt.nl() - txt.print_ub( (uw/10) * 10 ) ; 90 + floats.print_f(1.0) + txt.nl() + floats.print_f(11111.0) + txt.nl() + floats.print_f(1e10) + txt.nl() + floats.print_f(1.234) + txt.nl() + floats.print_f(111.234) + txt.nl() + floats.print_f(-111.234) + txt.nl() + floats.print_f(-111.234) txt.nl() - float fl = 999.876 - floats.print_f( 10 * (fl/10) ) ; 999.876 - txt.nl() - floats.print_f( (fl/10) * 10 ) ; 999.876 - txt.nl() + uword zz + const ubyte check = 99 + when zz { + 1,2,check -> { + cx16.r0++ + } + 9999 -> { + cx16.r0++ + } + else -> { + cx16.r0++ + } + } } } diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 8dfc7a7ff..ca1d8dd11 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -348,8 +348,8 @@ object SysCalls { } Syscall.PRINT_F -> { val value = getArgValues(callspec.arguments, vm).single() as Double - if(value==0.0) - print("0") + if(value.toInt().toDouble()==value) + print(value.toInt()) else print(value) }