more nonstrictbool conversions

This commit is contained in:
Irmen de Jong 2024-03-03 18:37:08 +01:00
parent 84afb374e6
commit e55cde2a81
8 changed files with 117 additions and 19 deletions

View File

@ -233,7 +233,7 @@ class AsmGen6502Internal (
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
private val anyExprGen = AnyExprAsmGen(this)
private val assignmentAsmGen = AssignmentAsmGen(program, this, anyExprGen, allocator)
private val assignmentAsmGen = AssignmentAsmGen(program, this, options, anyExprGen, allocator)
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
private val ifElseAsmgen = IfElseAsmGen(program, symbolTable, this, allocator, assignmentAsmGen, errors)

View File

@ -11,6 +11,7 @@ import prog8.codegen.cpu6502.returnsWhatWhere
internal class AssignmentAsmGen(private val program: PtProgram,
private val asmgen: AsmGen6502Internal,
private val options: CompilationOptions,
private val anyExprGen: AnyExprAsmGen,
private val allocator: VariableAllocator) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
@ -59,7 +60,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val variable = assign.source.asmVarname
when (assign.target.datatype) {
DataType.BOOL -> {
if (assign.source.datatype == DataType.BOOL) assignVariableByte(assign.target, variable)
if (assign.source.datatype == DataType.BOOL || !options.strictBool) assignVariableByte(assign.target, variable)
else throw AssemblyError("assigning non-bool variable to boolean, should have been typecasted")
}
DataType.UBYTE, DataType.BYTE -> assignVariableByte(assign.target, variable)

View File

@ -158,7 +158,7 @@ sub setchr (ubyte col, ubyte row, ubyte char) {
sub petscii2scr(ubyte petscii_char) -> ubyte {
; -- convert petscii character to screencode
byte[8] offsets = [128, 0, 64, 32, 64, 192, 128, 128]
ubyte[8] offsets = [128, 0, 64, 32, 64, 192, 128, 128]
return petscii_char ^ offsets[petscii_char>>5]
}

View File

@ -7,9 +7,9 @@ const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler"
const val VERSION = "10.2-BOOLEANS"
const val GIT_REVISION = 4530
const val GIT_SHA = "c7843b4ed8919870983fdf9d27413caf690d948a"
const val GIT_DATE = "2024-03-03T13:01:46Z"
const val GIT_SHA = "26102becb7ed4f9875d83fbd3e1c0b59420f81d1"
const val GIT_DATE = "2024-03-03T17:58:39Z"
const val GIT_BRANCH = "booleans-nostrictbool"
const val BUILD_DATE = "2024-03-03T13:12:36Z"
const val BUILD_UNIX_TIME = 1709471556477L
const val BUILD_DATE = "2024-03-03T18:28:38Z"
const val BUILD_UNIX_TIME = 1709490518135L
const val DIRTY = 1

View File

@ -967,8 +967,10 @@ internal class AstChecker(private val program: Program,
errors.err("bitwise invert is for integer types, use 'not' on booleans", expr.position)
}
else if(expr.operator == "not") {
if(dt!=DataType.BOOL)
errors.err("logical not is for booleans", expr.position)
if(dt!=DataType.BOOL) {
if(compilerOptions.strictBool || dt !in ByteDatatypes)
errors.err("logical not is for booleans", expr.position)
}
}
super.visit(expr)
}
@ -1085,8 +1087,10 @@ internal class AstChecker(private val program: Program,
if(expr.operator in LogicalOperators) {
if (leftDt != DataType.BOOL || rightDt != DataType.BOOL)
errors.err("logical operator requires boolean operands", expr.right.position)
if (leftDt != DataType.BOOL || rightDt != DataType.BOOL) {
if(compilerOptions.strictBool || leftDt !in ByteDatatypes || rightDt !in ByteDatatypes)
errors.err("logical operator requires boolean operands", expr.right.position)
}
}
else {
if (leftDt == DataType.BOOL || rightDt == DataType.BOOL) {

View File

@ -147,6 +147,26 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
if(leftDt!=rightDt) {
if(!options.strictBool) {
if (expr.operator in LogicalOperators) {
if (leftDt.isBool) {
val cast = TypecastExpression(expr.right, DataType.BOOL, false, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
} else {
val cast = TypecastExpression(expr.left, DataType.BOOL, false, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
}
} else {
if(leftDt.isBool && rightDt.isBytes) {
val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), false, expr.left.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
} else if(rightDt.isBool && leftDt.isBytes) {
val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), false, expr.right.position)
return listOf(IAstModification.ReplaceNode(expr.right, cast, 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) {
@ -254,13 +274,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
// more complex comparisons if the type is different, but the constant value is compatible
if(!options.strictBool) {
if (targettype == DataType.BOOL && valuetype in ByteDatatypes) {
return castLiteral(cvalue)
val cast = NumericLiteral.fromBoolean(number!=0.0, cvalue.position)
return listOf(IAstModification.ReplaceNode(assignment.value, cast, assignment))
}
if (targettype == DataType.UBYTE && valuetype == DataType.BOOL) {
return castLiteral(cvalue)
}
if (targettype == DataType.BYTE && valuetype == DataType.BOOL) {
return castLiteral(cvalue)
if (targettype in ByteDatatypes && valuetype == DataType.BOOL) {
val cast = NumericLiteral(targettype, if(cvalue.asBooleanValue) 1.0 else 0.0, cvalue.position)
return listOf(IAstModification.ReplaceNode(assignment.value, cast, assignment))
}
}
if (valuetype == DataType.BYTE && targettype == DataType.UBYTE) {
@ -276,6 +295,17 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(number<0x8000)
return castLiteral(cvalue)
}
} else {
if(!options.strictBool) {
if (targettype == DataType.BOOL && valuetype in ByteDatatypes) {
val cast = TypecastExpression(assignment.value, targettype, false, assignment.value.position)
return listOf(IAstModification.ReplaceNode(assignment.value, cast, assignment))
}
if (targettype in ByteDatatypes && valuetype == DataType.BOOL) {
val cast = TypecastExpression(assignment.value, targettype, false, assignment.value.position)
return listOf(IAstModification.ReplaceNode(assignment.value, cast, assignment))
}
}
}
}
}
@ -328,7 +358,8 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
} else if(argDt isAssignableTo targetDt) {
if(argDt!=DataType.STR || targetDt!=DataType.UWORD)
addTypecastOrCastedValueModification(modifications, it.second, targetDt, call as Node)
}
} else if(!options.strictBool && targetDt in ByteDatatypes && argDt==DataType.BOOL)
addTypecastOrCastedValueModification(modifications, it.second, targetDt, call as Node)
}
} else {
val identifier = it.second as? IdentifierReference
@ -394,6 +425,18 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(subroutine.returntypes.size==1) {
val subReturnType = subroutine.returntypes.first()
val returnDt = returnValue.inferType(program)
if(!options.strictBool) {
if(subReturnType==DataType.BOOL && returnDt.isBytes) {
val cast = TypecastExpression(returnValue, DataType.BOOL, false, returnValue.position)
return listOf(IAstModification.ReplaceNode(returnValue, cast, returnStmt))
}
if(subReturnType in ByteDatatypes && returnDt.isBool) {
val cast = TypecastExpression(returnValue, subReturnType, false, returnValue.position)
return listOf(IAstModification.ReplaceNode(returnValue, cast, returnStmt))
}
}
if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType))
return noModifications
if (returnValue is NumericLiteral) {
@ -436,6 +479,14 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return modifications
}
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
if(!options.strictBool && ifElse.condition.inferType(program).isBytes) {
val cast = TypecastExpression(ifElse.condition, DataType.BOOL, false, ifElse.condition.position)
return listOf(IAstModification.ReplaceNode(ifElse.condition, cast, ifElse))
}
return noModifications
}
private fun addTypecastOrCastedValueModification(
modifications: MutableList<IAstModification>,
@ -446,8 +497,21 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val sourceDt = expressionToCast.inferType(program).getOr(DataType.UNDEFINED)
if(sourceDt == requiredType)
return
if(requiredType==DataType.BOOL)
if(!options.strictBool) {
if(requiredType==DataType.BOOL && sourceDt in ByteDatatypes) {
val cast = TypecastExpression(expressionToCast, DataType.BOOL, false, expressionToCast.position)
modifications.add(IAstModification.ReplaceNode(expressionToCast, cast, parent))
return
}
if(requiredType in ByteDatatypes && sourceDt==DataType.BOOL) {
val cast = TypecastExpression(expressionToCast, requiredType, false, expressionToCast.position)
modifications.add(IAstModification.ReplaceNode(expressionToCast, cast, parent))
return
}
}
if(requiredType==DataType.BOOL) {
return
}
if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats
val castedValue = expressionToCast.cast(requiredType, true)
if (castedValue.isValid) {

View File

@ -155,6 +155,10 @@ One or more .p8 module files
Don't perform any code optimizations.
Useful for debugging or faster compilation cycles.
``-nostrictbool``
Relax the strict boolean type checks: bytes and booleans can be interchanged again without explicit type casts.
*This option will likely disappear in a future prog8 version, so you may want to prepare for that in your code!*
``-optfloatx``
Also optimize float expressions if optimizations are enabled.
Warning: can increase program size significantly if a lot of floating point expressions are used.

View File

@ -14,10 +14,15 @@ main {
bool @shared bb1, bb2
bb1 = 0
bb2 = 44
bb1 = cx16.r0L
bb2 = bb1 and cx16.r0L
cx16.r0L = bb1 ^ cx16.r0L
; bool[3] barr1 = 42
byte[3] @shared sbarr1 = true
ubyte[3] @shared ubarr1 = true
ubyte[3] @shared ubarr2 = bb2
bool[] @shared boolarray = [1,0]
bool[] @shared boolarray2 = [42,0,false]
@ -26,6 +31,9 @@ main {
ubyte[] @shared uba = [true, false]
ubyte[] @shared uba2 = [true, false, 42]
if cx16.r0L >= 44 and not cx16.r0L
cx16.r0L++
txt.print_ubhex(bb1, 1)
txt.print_ubhex(bb2, 42)
txt.print_ubhex(bb2, cx16.r0L)
@ -33,6 +41,23 @@ main {
if cx16.r0L {
cx16.r0L++
}
if cx16.r0 {
cx16.r0L++
}
kapoof()
kapoof2()
}
sub kapoof() -> bool {
cx16.r0L++
return cx16.r0L
}
sub kapoof2() -> ubyte {
cx16.r0L++
return cx16.r0L==0
}
}