fixed missing non-boolean operand cast in logical expressions

This commit is contained in:
Irmen de Jong 2022-07-12 21:58:33 +02:00
parent f46e131f18
commit 10ddd5b127
5 changed files with 124 additions and 96 deletions

View File

@ -913,7 +913,7 @@ internal class AstChecker(private val program: Program,
if(expr.operator !in ComparisonOperators) { if(expr.operator !in ComparisonOperators) {
if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) { if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) {
// str+str and str*number have already been const evaluated before we get here. // str+str and str*number have already been const evaluated before we get here.
errors.err("no computational expressions with strings or arrays are possible", expr.position) errors.err("no computational or logical expressions with strings or arrays are possible", expr.position)
} }
} }

View File

@ -82,35 +82,40 @@ internal class BoolRemover(val program: Program) : AstWalker() {
"xor" -> "^" "xor" -> "^"
else -> "invalid" else -> "invalid"
} }
return listOf( val mods = mutableListOf<IAstModification>()
IAstModification.ReplaceNodeSafe(expr.left, wrapWithBooleanCastIfNeeded(expr.left), expr), val newLeft = wrapWithBooleanCastIfNeeded(expr.left, program)
IAstModification.ReplaceNodeSafe(expr.right, wrapWithBooleanCastIfNeeded(expr.right), expr),) val newRight = wrapWithBooleanCastIfNeeded(expr.right, program)
if(newLeft!=null)
mods += IAstModification.ReplaceNodeSafe(expr.left, newLeft, expr)
if(newRight!=null)
mods += IAstModification.ReplaceNodeSafe(expr.right, newRight, expr)
return mods
} }
return noModifications return noModifications
} }
}
private fun wrapWithBooleanCastIfNeeded(expr: Expression): Expression {
fun isBoolean(expr: Expression): Boolean { internal fun wrapWithBooleanCastIfNeeded(expr: Expression, program: Program): Expression? {
return if(expr.inferType(program) istype DataType.BOOL) fun isBoolean(expr: Expression): Boolean {
true return if(expr.inferType(program) istype DataType.BOOL)
else if(expr is NumericLiteral && expr.type in IntegerDatatypes && (expr.number==0.0 || expr.number==1.0)) true
true else if(expr is NumericLiteral && expr.type in IntegerDatatypes && (expr.number==0.0 || expr.number==1.0))
else if(expr is BinaryExpression && expr.operator in ComparisonOperators + LogicalOperators) true
true else if(expr is BinaryExpression && expr.operator in ComparisonOperators + LogicalOperators)
else if(expr is PrefixExpression && expr.operator == "not") true
true else if(expr is PrefixExpression && expr.operator == "not")
else if(expr is BinaryExpression && expr.operator in BitwiseOperators) { true
if(isBoolean(expr.left) && isBoolean(expr.right)) else if(expr is BinaryExpression && expr.operator in BitwiseOperators) {
true if(isBoolean(expr.left) && isBoolean(expr.right))
else expr.operator=="&" && expr.right.constValue(program)?.number==1.0 // x & 1 is also a boolean result true
} else expr.operator=="&" && expr.right.constValue(program)?.number==1.0 // x & 1 is also a boolean result
else }
false else
} false
}
return if(isBoolean(expr))
expr return if(isBoolean(expr))
else null
TypecastExpression(expr, DataType.BOOL, true, expr.position) else
} TypecastExpression(expr, DataType.BOOL, true, expr.position)
} }

View File

@ -46,71 +46,85 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val leftCv = expr.left.constValue(program) val leftCv = expr.left.constValue(program)
val rightCv = expr.right.constValue(program) val rightCv = expr.right.constValue(program)
if(leftDt.isKnown && rightDt.isKnown && leftDt!=rightDt) { if(leftDt.isKnown && rightDt.isKnown) {
if(expr.operator in LogicalOperators && leftDt.isInteger && rightDt.isInteger) {
// convert bool type to byte if needed // see if any of the operands needs conversion to bool
if(leftDt istype DataType.BOOL && rightDt.isBytes && !rightDt.istype(DataType.BOOL)) {
if(rightCv==null || (rightCv.number!=1.0 && rightCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.left,
TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED),true, expr.left.position), expr))
} else if(leftDt.isBytes && !leftDt.istype(DataType.BOOL) && rightDt istype DataType.BOOL) {
if(leftCv==null || (leftCv.number!=1.0 && leftCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.right,
TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED),true, expr.right.position), expr))
}
// convert a negative operand for bitwise operator to the 2's complement positive number instead
if(expr.operator in BitwiseOperators && leftDt.isInteger && rightDt.isInteger) {
if(leftCv!=null && leftCv.number<0) {
val value = if(rightDt.isBytes) 256+leftCv.number else 65536+leftCv.number
return listOf(IAstModification.ReplaceNode(
expr.left,
NumericLiteral(rightDt.getOr(DataType.UNDEFINED), value, expr.left.position),
expr))
}
if(rightCv!=null && rightCv.number<0) {
val value = if(leftDt.isBytes) 256+rightCv.number else 65536+rightCv.number
return listOf(IAstModification.ReplaceNode(
expr.right,
NumericLiteral(leftDt.getOr(DataType.UNDEFINED), value, expr.right.position),
expr))
}
if(leftDt istype DataType.BYTE && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast left to unsigned
val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), true, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
}
if(leftDt istype DataType.WORD && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast left to unsigned
val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), true, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
}
if(rightDt istype DataType.BYTE && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast right to unsigned
val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), true, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
}
if(rightDt istype DataType.WORD && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast right to unsigned
val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), true, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
}
}
// determine common datatype and add typecast as required to make left and right equal types
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right)
if(toFix!=null) {
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
when { val newLeft = wrapWithBooleanCastIfNeeded(expr.left, program)
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt, expr) val newRight = wrapWithBooleanCastIfNeeded(expr.right, program)
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt, expr) if(newLeft!=null)
else -> throw FatalAstException("confused binary expression side") modifications += IAstModification.ReplaceNode(expr.left, newLeft, expr)
if(newRight!=null)
modifications += IAstModification.ReplaceNode(expr.right, newRight, expr)
if(modifications.isNotEmpty())
return modifications
}
if(leftDt!=rightDt) {
// convert bool type to byte if needed
if(leftDt istype DataType.BOOL && rightDt.isBytes && !rightDt.istype(DataType.BOOL)) {
if(rightCv==null || (rightCv.number!=1.0 && rightCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.left,
TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED),true, expr.left.position), expr))
} else if(leftDt.isBytes && !leftDt.istype(DataType.BOOL) && rightDt istype DataType.BOOL) {
if(leftCv==null || (leftCv.number!=1.0 && leftCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.right,
TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED),true, expr.right.position), expr))
}
// convert a negative operand for bitwise operator to the 2's complement positive number instead
if(expr.operator in BitwiseOperators && leftDt.isInteger && rightDt.isInteger) {
if(leftCv!=null && leftCv.number<0) {
val value = if(rightDt.isBytes) 256+leftCv.number else 65536+leftCv.number
return listOf(IAstModification.ReplaceNode(
expr.left,
NumericLiteral(rightDt.getOr(DataType.UNDEFINED), value, expr.left.position),
expr))
}
if(rightCv!=null && rightCv.number<0) {
val value = if(leftDt.isBytes) 256+rightCv.number else 65536+rightCv.number
return listOf(IAstModification.ReplaceNode(
expr.right,
NumericLiteral(leftDt.getOr(DataType.UNDEFINED), value, expr.right.position),
expr))
}
if(leftDt istype DataType.BYTE && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast left to unsigned
val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), true, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
}
if(leftDt istype DataType.WORD && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast left to unsigned
val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), true, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
}
if(rightDt istype DataType.BYTE && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast right to unsigned
val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), true, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
}
if(rightDt istype DataType.WORD && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) {
// cast right to unsigned
val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), true, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
}
}
// determine common datatype and add typecast as required to make left and right equal types
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right)
if(toFix!=null) {
val modifications = mutableListOf<IAstModification>()
when {
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt, expr)
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt, expr)
else -> throw FatalAstException("confused binary expression side")
}
return modifications
} }
return modifications
} }
} }
return noModifications return noModifications
} }

View File

@ -3,9 +3,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- fix compiler bug: tehtriz: blocks fall through the bottom
- fix compiler bug: maze: maze runner goes all wacky (both c64 and cx6)
... ...

View File

@ -3,8 +3,20 @@
main { main {
sub start() { sub start() {
bool bb2=true ubyte value1 = %1110
bool @shared bb = bb2 and true ubyte value2 = %1111
txt.print_ub(bb)
bool[2] @shared barr = [true, false]
; if value1 and value2 ; TODO value1 isn't converted to bool in 6502 preprocess
; txt.print("ok")
; else
; txt.print("fail!")
; txt.nl()
if value1 and value2!=255 ; TODO value1 isn't converted to bool in 6502 preprocess
txt.print("ok")
else
txt.print("fail!")
} }
} }