typecheck prefix expressions better

This commit is contained in:
Irmen de Jong 2020-08-20 20:34:18 +02:00
parent cffb582568
commit 14f9382cf9
4 changed files with 137 additions and 86 deletions

View File

@ -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)
}

View File

@ -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")
}
}

View File

@ -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")
}

View File

@ -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]
}
}