mirror of
https://github.com/irmen/prog8.git
synced 2024-10-17 10:24:55 +00:00
fixed missing non-boolean operand cast in logical expressions
This commit is contained in:
parent
f46e131f18
commit
10ddd5b127
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -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!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user