diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index e1ce880b0..b86b41b74 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -873,20 +873,20 @@ internal class AssignmentAsmGen(private val program: Program, throw AssemblyError("containment check of floats not supported") } DataType.ARRAY_B, DataType.ARRAY_UB -> { - val arrayVal = variable.value as ArrayLiteral + val numElements = variable.arraysize!!.constIndex()!! assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) - asmgen.out(" ldy #${arrayVal.value.size}") + asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") return } DataType.ARRAY_W, DataType.ARRAY_UW -> { - val arrayVal = variable.value as ArrayLiteral + val numElements = variable.arraysize!!.constIndex()!! assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) - asmgen.out(" ldy #${arrayVal.value.size}") + asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_wordarray") return } @@ -1005,7 +1005,7 @@ internal class AssignmentAsmGen(private val program: Program, } } - if(valueDt==DataType.UBYTE) { + if(valueDt==DataType.UBYTE || valueDt==DataType.BOOL) { when(target.register) { RegisterOrPair.A, RegisterOrPair.X, @@ -1069,8 +1069,10 @@ internal class AssignmentAsmGen(private val program: Program, } } - if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt.isAssignableTo(targetDt)) { - require(targetDt in WordDatatypes && valueDt in ByteDatatypes) { "should be byte to word assignment ${origTypeCastExpression.position}"} + if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt!=targetDt && valueDt.isAssignableTo(targetDt)) { + require(targetDt in WordDatatypes && valueDt in ByteDatatypes) { + "should be byte to word assignment ${origTypeCastExpression.position}" + } when(target.kind) { // TargetStorageKind.VARIABLE -> { // This has been handled already earlier on line 961. @@ -1136,13 +1138,12 @@ internal class AssignmentAsmGen(private val program: Program, asmgen.out(" jsr floats.MOVEF") } return - } else { - // No more special optmized cases yet. Do the rest via more complex evaluation - // note: cannot use assignTypeCastedValue because that is ourselves :P - // NOTE: THIS MAY TURN INTO A STACK OVERFLOW ERROR IF IT CAN'T SIMPLIFY THE TYPECAST..... :-/ - asmgen.assignExpressionTo(origTypeCastExpression, target) - return } + + // No more special optmized cases yet. Do the rest via more complex evaluation + // note: cannot use assignTypeCastedValue because that is ourselves :P + // NOTE: THIS MAY TURN INTO A STACK OVERFLOW ERROR IF IT CAN'T SIMPLIFY THE TYPECAST..... :-/ + asmgen.assignExpressionTo(origTypeCastExpression, target) } private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) { diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 7559716c5..8c6d20915 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -7,6 +7,7 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor import prog8.code.core.* +import prog8.code.target.VMTarget import prog8.compiler.BuiltinFunctions import prog8.compiler.InplaceModifyingBuiltinFunctions import prog8.compiler.builtinFunctionReturnType @@ -1259,8 +1260,14 @@ internal class AstChecker(private val program: Program, val elementDt = containment.element.inferType(program) val iterableDt = containment.iterable.inferType(program) - if(containment.parent is BinaryExpression) - errors.err("containment check is currently not supported inside complex expressions", containment.position) + if(compilerOptions.compTarget.name!=VMTarget.NAME) { + val parentBinexpr = containment.parent as? BinaryExpression + if(parentBinexpr!=null) { + // only supported if compared to 1 or 0, more complex expressions aren't supported in the 6502 code-gen. + if(parentBinexpr.operator!="==" || parentBinexpr.right.constValue(program)?.number !in listOf(0.0, 1.0)) + errors.err("containment check is currently not supported inside complex expressions", containment.position) + } + } if(iterableDt.isIterable && containment.iterable !is RangeExpression) { val iterableEltDt = ArrayToElementTypes.getValue(iterableDt.getOr(DataType.UNDEFINED)) diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 90b47f150..86cea5abb 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -6,10 +6,7 @@ import prog8.ast.Node import prog8.ast.Program import prog8.ast.base.FatalAstException import prog8.ast.expressions.* -import prog8.ast.statements.AnonymousScope -import prog8.ast.statements.Assignment -import prog8.ast.statements.ConditionalBranch -import prog8.ast.statements.IfElse +import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* @@ -175,6 +172,19 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, return noModifications } + fun checkArray(variable: VarDecl): Iterable { + return if(variable.value==null) { + val arraySpec = variable.arraysize!! + val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size") + return if(size==0) + replaceWithFalse() + else + noModifications + } + else + checkArray((variable.value as ArrayLiteral).value) + } + fun checkString(stringVal: StringLiteral): Iterable { if(stringVal.value.isEmpty()) return replaceWithFalse() @@ -198,8 +208,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, return checkString(stringVal) } in ArrayDatatypes -> { - val array = (variable.value as ArrayLiteral).value - return checkArray(array) + return checkArray(variable) } else -> {} } diff --git a/compiler/test/codegeneration/TestVarious.kt b/compiler/test/codegeneration/TestVarious.kt new file mode 100644 index 000000000..785d2f066 --- /dev/null +++ b/compiler/test/codegeneration/TestVarious.kt @@ -0,0 +1,22 @@ +package prog8tests.codegeneration + +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldNotBe +import prog8.code.target.C64Target +import prog8tests.helpers.compileText + +class TestVarious: FunSpec({ + test("bool to byte cast in expression is correct") { + val text=""" +main { + sub start() { + ubyte[3] values + func(33 + (22 in values)) + } + sub func(ubyte arg) { + arg++ + } +}""" + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + } +}) \ No newline at end of file diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index 09e5f98ed..06007a04a 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -327,4 +327,19 @@ main { instructions.size shouldBe 18 instructions.last().opcode shouldBe Opcode.RETURN } + + test("compile virtual: various expressions") { + val text=""" +main { + sub start() { + ubyte[3] values = [1,2,3] + func(33 + (22 in values)) ; bool cast to byte + func(values[cx16.r0L] + (22 in values)) ; containment in complex expression + } + sub func(ubyte arg) { + arg++ + } +}""" + compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null + } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 83e447960..c40079012 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,12 +3,12 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- bool bb = not bb -> larger code than bool bb ^= 1 -- bool xx = ~xx -> larger code than xx ^= 1 -- ubyte xx = not xx -> much larger code than xx ^= 1 -- try to support "not (xx in array)" or maybe even "xx not in array" -- astchecker: "containment check is currently not supported inside complex expressions" fix this? - or at least disable this check for virtual target? +- allow "xx not in array" and rewrite it into "not xx in array" +- make sure bool value is always 0 or 1 (all casts should convert), then: + - rewrite bool=bool^1 into bool=not bool + - should solve: bool bb = not bb -> larger code than bool bb ^= 1 + - should solve: bool xx = ~xx -> larger code than xx ^= 1 + ...