From 14f9382cf9f76b9b7080cccb0f5412bc5d586af4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 20 Aug 2020 20:34:18 +0200 Subject: [PATCH] typecheck prefix expressions better --- .../src/prog8/ast/processing/AstChecker.kt | 18 ++- .../target/c64/codegen/AssignmentAsmGen.kt | 9 +- .../codegen/AugmentableAssignmentAsmGen.kt | 113 ++++++++++++------ examples/test.p8 | 83 ++++++------- 4 files changed, 137 insertions(+), 86 deletions(-) diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 70578be21..5800f01be 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -360,9 +360,15 @@ internal class AstChecker(private val program: Program, } } - if(assignment.value.inferType(program) != assignment.target.inferType(program, assignment)) + val targetDt = assignment.target.inferType(program, assignment) + if(assignment.value.inferType(program) != targetDt) errors.err("assignment value is of different type as the target", assignment.value.position) + if(assignment.value is TypecastExpression) { + if(assignment.isAugmentable && targetDt.istype(DataType.FLOAT)) + errors.err("typecasting a float value in-place makes no sense", assignment.value.position) + } + super.visit(assignment) } @@ -708,12 +714,20 @@ internal class AstChecker(private val program: Program, } override fun visit(expr: PrefixExpression) { + val dt = expr.inferType(program).typeOrElse(DataType.STRUCT) if(expr.operator=="-") { - val dt = expr.inferType(program).typeOrElse(DataType.STRUCT) if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) { errors.err("can only take negative of a signed number type", expr.position) } } + else if(expr.operator == "not") { + if(dt !in IntegerDatatypes) + errors.err("can only use boolean not on integer types", expr.position) + } + else if(expr.operator == "~") { + if(dt !in IntegerDatatypes) + errors.err("can only use bitwise invert on integer types", expr.position) + } super.visit(expr) } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt index 80e08b09a..7b6c53d71 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt @@ -113,10 +113,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen is TypecastExpression -> { val cast = assign.value as TypecastExpression val sourceType = cast.expression.inferType(program) - val targetType = assign.target.inferType(program, assign) - if (sourceType.isKnown && targetType.isKnown && - (sourceType.typeOrElse(DataType.STRUCT) in ByteDatatypes && targetType.typeOrElse(DataType.STRUCT) in ByteDatatypes) || - (sourceType.typeOrElse(DataType.STRUCT) in WordDatatypes && targetType.typeOrElse(DataType.STRUCT) in WordDatatypes)) { + if (sourceType.isKnown && + (sourceType.typeOrElse(DataType.STRUCT) in ByteDatatypes && cast.type in ByteDatatypes) || + (sourceType.typeOrElse(DataType.STRUCT) in WordDatatypes && cast.type in WordDatatypes)) { // no need for a type cast assign.value = cast.expression translate(assign) @@ -131,7 +130,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}") - else -> throw AssemblyError("assignment value type should have been handled elsewhere") + else -> throw AssemblyError("assignment value type ${assign.value} should have been handled elsewhere") } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AugmentableAssignmentAsmGen.kt index d605d8486..7df7b3142 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AugmentableAssignmentAsmGen.kt @@ -2,12 +2,14 @@ package prog8.compiler.target.c64.codegen import prog8.ast.Program import prog8.ast.base.DataType +import prog8.ast.base.IterableDatatypes import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.PrefixExpression import prog8.ast.expressions.TypecastExpression import prog8.ast.statements.AssignTarget import prog8.ast.statements.Assignment import prog8.compiler.AssemblyError +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage internal class AugmentableAssignmentAsmGen(private val program: Program, private val assignmentAsmGen: AssignmentAsmGen, @@ -28,17 +30,53 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else -> throw AssemblyError("invalid prefix operator") } } - is TypecastExpression -> { - println("TODO optimize typecast assignment ${assign.position}") - assignmentAsmGen.translateOtherAssignment(assign) // TODO get rid of this fallback - } - is BinaryExpression -> { - println("TODO optimize binexpr assignment ${assign.position}") - assignmentAsmGen.translateOtherAssignment(assign) // TODO get rid of this fallback - } - else -> { - throw AssemblyError("invalid aug assign value type") + is TypecastExpression -> inplaceCast(assign.target, assign.value as TypecastExpression, assign) + is BinaryExpression -> inplaceBinary(assign.target, assign.value as BinaryExpression, assign) + else -> throw AssemblyError("invalid aug assign value type") + } + } + + private fun inplaceBinary(target: AssignTarget, binaryExpression: BinaryExpression, assign: Assignment) { + println("TODO optimize binexpr assignment ${binaryExpression.position}") + assignmentAsmGen.translateOtherAssignment(assign) // TODO get rid of this fallback + } + + private fun inplaceCast(target: AssignTarget, cast: TypecastExpression, assign: Assignment) { + val targetDt = target.inferType(program, assign).typeOrElse(DataType.STRUCT) + val outerCastDt = cast.type + val innerCastDt = (cast.expression as? TypecastExpression)?.type + + if(innerCastDt==null) { + // simple typecast where the value is the target + when(targetDt) { + DataType.UBYTE, DataType.BYTE -> { /* byte target can't be casted to anything else at all */ } + DataType.UWORD, DataType.WORD -> { + when(outerCastDt) { + DataType.UBYTE, DataType.BYTE -> { + if(target.identifier!=null) { + val name = asmgen.asmIdentifierName(target.identifier!!) + asmgen.out(" lda #0 | sta $name+1") + } else + throw AssemblyError("weird value") + } + DataType.UWORD, DataType.WORD, in IterableDatatypes -> {} + DataType.FLOAT -> throw AssemblyError("incompatible cast type") + else -> throw AssemblyError("weird cast type") + } + } + DataType.FLOAT -> { + if(outerCastDt!=DataType.FLOAT) + throw AssemblyError("in-place cast of a float makes no sense") + } + else -> throw AssemblyError("invalid cast target type") } + } else { + // typecast with nested typecast, that has the target as a value + // calculate singular cast that is required + val castDt = if(outerCastDt largerThan innerCastDt) innerCastDt else outerCastDt + val value = (cast.expression as TypecastExpression).expression + val resultingCast = TypecastExpression(value, castDt, false, assign.position) + inplaceCast(target, resultingCast, assign) } } @@ -60,10 +98,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sta $name""") } memory!=null -> { - TODO() + TODO("in-place not of ubyte memory") } arrayIdx!=null -> { - TODO() + TODO("in-place not of ubyte array") } } } @@ -81,12 +119,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, lsr a sta $name+1""") } - memory!=null -> { - TODO() - } - arrayIdx!=null -> { - TODO() - } + arrayIdx!=null -> TODO("in-place not of uword array") + memory!=null -> throw AssemblyError("no asm gen for uword-memory not") } } else -> throw AssemblyError("boolean-not of invalid type") @@ -109,10 +143,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sta $name""") } memory!=null -> { - TODO() + TODO("in-place invert ubyte memory") } arrayIdx!=null -> { - TODO() + TODO("in-place invert ubyte array") } } } @@ -128,12 +162,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, eor #255 sta $name+1""") } - memory!=null -> { - TODO() - } - arrayIdx!=null -> { - TODO() - } + arrayIdx!=null -> TODO("in-place invert uword array") + memory!=null -> throw AssemblyError("no asm gen for uword-memory invert") } } else -> throw AssemblyError("invert of invalid type") @@ -157,10 +187,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sta $name""") } memory!=null -> { - TODO() + TODO("in-place negate byte memory") } arrayIdx!=null -> { - TODO() + TODO("in-place negate byte array") } } } @@ -177,16 +207,29 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sbc $name+1 sta $name+1""") } - memory!=null -> { - TODO() - } - arrayIdx!=null -> { - TODO() - } + arrayIdx!=null -> TODO("in-place negate word array") + memory!=null -> throw AssemblyError("no asm gen for word memory negate") } } DataType.FLOAT -> { - TODO() + when { + identifier!=null -> { + val name = asmgen.asmIdentifierName(identifier) + asmgen.out(""" + stx ${C64Zeropage.SCRATCH_REG_X} + lda #<$name + ldy #>$name + jsr c64flt.MOVFM + jsr c64flt.NEGOP + ldx #<$name + ldy #>$name + jsr c64flt.MOVMF + ldx ${C64Zeropage.SCRATCH_REG_X} + """) + } + arrayIdx!=null -> TODO("in-place negate float array") + memory!=null -> throw AssemblyError("no asm gen for float memory negate") + } } else -> throw AssemblyError("negate of invalid type") } diff --git a/examples/test.p8 b/examples/test.p8 index 8e1d53301..3b1924e06 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,55 +7,50 @@ main { sub start() { - byte A = 99 - ubyte U = $18 - word B = 9999 - uword W = $18f0 - - c64scr.print_b(A) - c64.CHROUT('\n') - A = -A - c64scr.print_b(A) - c64.CHROUT('\n') - - U = ~U - c64scr.print_ubhex(U, true) - c64.CHROUT('\n') - U = not U - c64scr.print_ubhex(U, true) - c64.CHROUT('\n') - U = not U - c64scr.print_ubhex(U, true) - c64.CHROUT('\n') - - c64scr.print_w(B) - c64.CHROUT('\n') - B = -B - c64scr.print_w(B) - c64.CHROUT('\n') - - W = ~W - c64scr.print_uwhex(W, true) - c64.CHROUT('\n') - W = not W - c64scr.print_uwhex(W, true) - c64.CHROUT('\n') - W = not W - c64scr.print_uwhex(W, true) - c64.CHROUT('\n') - +; byte A = 99 +; ubyte U = $18 +; word B = 9999 +; uword W = $18f0 ; -; byte B = +A -; byte C = -A -; uword W = 43210 +; c64scr.print_b(A) +; c64.CHROUT('\n') ; A = -A -; -; c64scr.print_uw(W) +; c64scr.print_b(A) ; c64.CHROUT('\n') ; -; W = W as ubyte ; TODO cast(W as ubyte) as uword -> W and 255 -; c64scr.print_uw(W) +; U = ~U +; c64scr.print_ubhex(U, true) +; c64.CHROUT('\n') +; U = not U +; c64scr.print_ubhex(U, true) +; c64.CHROUT('\n') +; U = not U +; c64scr.print_ubhex(U, true) +; c64.CHROUT('\n') +; +; c64scr.print_w(B) +; c64.CHROUT('\n') +; B = -B +; c64scr.print_w(B) +; c64.CHROUT('\n') +; +; W = ~W +; c64scr.print_uwhex(W, true) +; c64.CHROUT('\n') +; W = not W +; c64scr.print_uwhex(W, true) +; c64.CHROUT('\n') +; W = not W +; c64scr.print_uwhex(W, true) ; c64.CHROUT('\n') + uword W = 43210 + W = W as ubyte + c64scr.print_uw(W) + c64.CHROUT('\n') + + ubyte[] array = [1,2,3] + array[1] = array[1] as ubyte + W = array[0] } }