removed the -nostrictbool compiler option

boolean types and bytes are no longer implicitly interchangeable using this option
This commit is contained in:
Irmen de Jong 2024-09-01 20:49:42 +02:00
parent 6516d7cb15
commit bdeac74cfc
19 changed files with 53 additions and 250 deletions

View File

@ -27,7 +27,6 @@ class CompilationOptions(val output: OutputType,
var slabsHighBank: Int? = null, var slabsHighBank: Int? = null,
var slabsGolden: Boolean = false, var slabsGolden: Boolean = false,
var splitWordArrays: Boolean = false, var splitWordArrays: Boolean = false,
var strictBool: Boolean = true,
var breakpointCpuInstruction: String? = null, var breakpointCpuInstruction: String? = null,
var outputDir: Path = Path(""), var outputDir: Path = Path(""),
var symbolDefs: Map<String, String> = emptyMap() var symbolDefs: Map<String, String> = emptyMap()

View File

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

View File

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

View File

@ -490,7 +490,6 @@ internal class ConstantIdentifierReplacer(
if(numericLv!=null) { if(numericLv!=null) {
// arraysize initializer is a single value, and we know the array size. // arraysize initializer is a single value, and we know the array size.
if(numericLv.type!=DataType.BOOL) { if(numericLv.type!=DataType.BOOL) {
if(options.strictBool || numericLv.type !in ByteDatatypes)
errors.err("initializer value is not a boolean", numericLv.position) errors.err("initializer value is not a boolean", numericLv.position)
return null return null
} }

View File

@ -11,9 +11,9 @@ import prog8.ast.walk.IAstModification
import prog8.code.core.* import prog8.code.core.*
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.log2 import kotlin.math.log2
import kotlin.math.pow
class ExpressionSimplifier(private val program: Program, private val options: CompilationOptions, private val errors: IErrorReporter) : AstWalker() {
class ExpressionSimplifier(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> { override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
val mods = mutableListOf<IAstModification>() val mods = mutableListOf<IAstModification>()
@ -246,23 +246,18 @@ class ExpressionSimplifier(private val program: Program, private val options: Co
} }
} }
if (rightVal?.number == 1.0) { if (rightVal?.number == 1.0) {
if (options.strictBool) {
if (rightDt != leftDt) { if (rightDt != leftDt) {
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
} }
} else
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
} }
else if (rightVal?.number == 0.0) { else if (rightVal?.number == 0.0) {
if (options.strictBool) {
if (rightDt != leftDt) { if (rightDt != leftDt) {
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
} }
} }
} }
}
if (expr.operator=="!=") { if (expr.operator=="!=") {
if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) { if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) {
val rightConstBool = rightVal?.asBooleanValue val rightConstBool = rightVal?.asBooleanValue
@ -274,21 +269,16 @@ class ExpressionSimplifier(private val program: Program, private val options: Co
} }
} }
if (rightVal?.number == 1.0) { if (rightVal?.number == 1.0) {
if(options.strictBool) {
if(rightDt!=leftDt) { if(rightDt!=leftDt) {
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
} }
} }
}
else if (rightVal?.number == 0.0) { else if (rightVal?.number == 0.0) {
if(options.strictBool) {
if(rightDt!=leftDt) { if(rightDt!=leftDt) {
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
} }
} else
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
} }
} }

View File

@ -59,8 +59,8 @@ fun Program.inlineSubroutines(options: CompilationOptions): Int {
return inliner.applyModifications() return inliner.applyModifications()
} }
fun Program.simplifyExpressions(errors: IErrorReporter, options: CompilationOptions) : Int { fun Program.simplifyExpressions(errors: IErrorReporter) : Int {
val opti = ExpressionSimplifier(this, options, errors) val opti = ExpressionSimplifier(this, errors)
opti.visit(this) opti.visit(this)
return opti.applyModifications() return opti.applyModifications()
} }

View File

@ -45,7 +45,6 @@ private fun compileMain(args: Array<String>): Boolean {
val dumpVariables by cli.option(ArgType.Boolean, fullName = "dumpvars", description = "print a dump of the variables in the program") val dumpVariables by cli.option(ArgType.Boolean, fullName = "dumpvars", description = "print a dump of the variables in the program")
val dumpSymbols by cli.option(ArgType.Boolean, fullName = "dumpsymbols", description = "print a dump of the variable declarations and subroutine signatures") val dumpSymbols by cli.option(ArgType.Boolean, fullName = "dumpsymbols", description = "print a dump of the variable declarations and subroutine signatures")
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code") val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
val noStrictBool by cli.option(ArgType.Boolean, fullName = "nostrictbool", description = "allow implicit conversions between bool and bytes")
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform code optimizations") val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform code optimizations")
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
@ -178,7 +177,6 @@ private fun compileMain(args: Array<String>): Boolean {
breakpointCpuInstruction, breakpointCpuInstruction,
printAst1 == true, printAst1 == true,
printAst2 == true, printAst2 == true,
noStrictBool != true,
processedSymbols, processedSymbols,
srcdirs, srcdirs,
outputPath outputPath
@ -259,7 +257,6 @@ private fun compileMain(args: Array<String>): Boolean {
breakpointCpuInstruction, breakpointCpuInstruction,
printAst1 == true, printAst1 == true,
printAst2 == true, printAst2 == true,
noStrictBool != true,
processedSymbols, processedSymbols,
srcdirs, srcdirs,
outputPath outputPath

View File

@ -54,7 +54,6 @@ class CompilerArguments(val filepath: Path,
val breakpointCpuInstruction: String?, val breakpointCpuInstruction: String?,
val printAst1: Boolean, val printAst1: Boolean,
val printAst2: Boolean, val printAst2: Boolean,
val strictBool: Boolean,
val symbolDefs: Map<String, String>, val symbolDefs: Map<String, String>,
val sourceDirs: List<String> = emptyList(), val sourceDirs: List<String> = emptyList(),
val outputDir: Path = Path(""), val outputDir: Path = Path(""),
@ -91,7 +90,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
splitWordArrays = args.splitWordArrays splitWordArrays = args.splitWordArrays
outputDir = args.outputDir.normalize() outputDir = args.outputDir.normalize()
symbolDefs = args.symbolDefs symbolDefs = args.symbolDefs
strictBool = args.strictBool
} }
resultingProgram = program resultingProgram = program
importedFiles = imported importedFiles = imported
@ -412,7 +410,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
errors.report() errors.report()
program.reorderStatements(errors) program.reorderStatements(errors)
errors.report() errors.report()
program.desugaring(errors, compilerOptions) program.desugaring(errors)
errors.report() errors.report()
program.changeNotExpressionAndIfComparisonExpr(errors, compilerOptions.compTarget) program.changeNotExpressionAndIfComparisonExpr(errors, compilerOptions.compTarget)
errors.report() errors.report()
@ -438,7 +436,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
removeUnusedCode(program, errors,compilerOptions) removeUnusedCode(program, errors,compilerOptions)
while (true) { while (true) {
// keep optimizing expressions and statements until no more steps remain // keep optimizing expressions and statements until no more steps remain
val optsDone1 = program.simplifyExpressions(errors, compilerOptions) val optsDone1 = program.simplifyExpressions(errors)
val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions) val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions)
val optsDone3 = program.inlineSubroutines(compilerOptions) val optsDone3 = program.inlineSubroutines(compilerOptions)
program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away
@ -452,7 +450,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
removeUnusedCode(program, errors, compilerOptions) removeUnusedCode(program, errors, compilerOptions)
if(errors.noErrors()) { if(errors.noErrors()) {
// last round of optimizations because constFold may have enabled more... // last round of optimizations because constFold may have enabled more...
program.simplifyExpressions(errors, compilerOptions) program.simplifyExpressions(errors)
program.optimizeStatements(errors, functions, compilerOptions) program.optimizeStatements(errors, functions, compilerOptions)
program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away program.constantFold(errors, compilerOptions) // because simplified statements and expressions can result in more constants that can be folded away
} }
@ -461,7 +459,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
} }
private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) {
program.desugaring(errors, compilerOptions) program.desugaring(errors)
program.addTypecasts(errors, compilerOptions) program.addTypecasts(errors, compilerOptions)
errors.report() errors.report()
program.variousCleanups(errors, compilerOptions) program.variousCleanups(errors, compilerOptions)

View File

@ -163,8 +163,6 @@ internal class AstChecker(private val program: Program,
override fun visit(ifElse: IfElse) { override fun visit(ifElse: IfElse) {
if(!ifElse.condition.inferType(program).isBool) { if(!ifElse.condition.inferType(program).isBool) {
val ctype = ifElse.condition.inferType(program).getOr(DataType.UNDEFINED)
if(compilerOptions.strictBool || ctype !in ByteDatatypes)
errors.err("condition should be a boolean", ifElse.condition.position) errors.err("condition should be a boolean", ifElse.condition.position)
} }
@ -506,8 +504,6 @@ internal class AstChecker(private val program: Program,
override fun visit(untilLoop: UntilLoop) { override fun visit(untilLoop: UntilLoop) {
if(!untilLoop.condition.inferType(program).isBool) { if(!untilLoop.condition.inferType(program).isBool) {
val ctype = untilLoop.condition.inferType(program).getOr(DataType.UNDEFINED)
if(compilerOptions.strictBool || ctype !in ByteDatatypes)
errors.err("condition should be a boolean", untilLoop.condition.position) errors.err("condition should be a boolean", untilLoop.condition.position)
} }
@ -516,8 +512,6 @@ internal class AstChecker(private val program: Program,
override fun visit(whileLoop: WhileLoop) { override fun visit(whileLoop: WhileLoop) {
if(!whileLoop.condition.inferType(program).isBool) { if(!whileLoop.condition.inferType(program).isBool) {
val ctype = whileLoop.condition.inferType(program).getOr(DataType.UNDEFINED)
if(compilerOptions.strictBool || ctype !in ByteDatatypes)
errors.err("condition should be a boolean", whileLoop.condition.position) errors.err("condition should be a boolean", whileLoop.condition.position)
} }
@ -780,12 +774,8 @@ internal class AstChecker(private val program: Program,
if (iDt isnot decl.datatype) { if (iDt isnot decl.datatype) {
if(decl.isArray) { if(decl.isArray) {
val eltDt = ArrayToElementTypes.getValue(decl.datatype) val eltDt = ArrayToElementTypes.getValue(decl.datatype)
if(iDt isnot eltDt) { if(iDt isnot eltDt)
if(compilerOptions.strictBool)
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
else if(!(iDt.isBool && eltDt==DataType.UBYTE || iDt.istype(DataType.UBYTE) && eltDt==DataType.BOOL))
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
}
} else { } else {
if(!(iDt.isBool && decl.datatype==DataType.UBYTE || iDt.istype(DataType.UBYTE) && decl.datatype==DataType.BOOL)) if(!(iDt.isBool && decl.datatype==DataType.UBYTE || iDt.istype(DataType.UBYTE) && decl.datatype==DataType.BOOL))
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
@ -1048,7 +1038,6 @@ internal class AstChecker(private val program: Program,
} }
else if(expr.operator == "not") { else if(expr.operator == "not") {
if(dt!=DataType.BOOL) { if(dt!=DataType.BOOL) {
if(compilerOptions.strictBool || dt !in ByteDatatypes)
errors.err("logical not is for booleans", expr.position) errors.err("logical not is for booleans", expr.position)
} }
} }
@ -1168,7 +1157,6 @@ internal class AstChecker(private val program: Program,
if(expr.operator in LogicalOperators) { if(expr.operator in LogicalOperators) {
if (leftDt != DataType.BOOL || rightDt != DataType.BOOL) { 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) errors.err("logical operator requires boolean operands", expr.right.position)
} }
} }
@ -1248,7 +1236,7 @@ internal class AstChecker(private val program: Program,
errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCallExpr.args.first().position) errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCallExpr.args.first().position)
} }
val error = VerifyFunctionArgTypes.checkTypes(functionCallExpr, program, compilerOptions) val error = VerifyFunctionArgTypes.checkTypes(functionCallExpr, program)
if(error!=null) if(error!=null)
errors.err(error.first, error.second) errors.err(error.first, error.second)
@ -1339,7 +1327,7 @@ internal class AstChecker(private val program: Program,
} }
val error = VerifyFunctionArgTypes.checkTypes(functionCallStatement, program, compilerOptions) val error = VerifyFunctionArgTypes.checkTypes(functionCallStatement, program)
if(error!=null) if(error!=null)
errors.err(error.first, error.second) errors.err(error.first, error.second)
@ -1727,7 +1715,6 @@ internal class AstChecker(private val program: Program,
} }
DataType.BOOL -> { DataType.BOOL -> {
if (value.type!=DataType.BOOL) { if (value.type!=DataType.BOOL) {
if (compilerOptions.strictBool || value.type !in ByteDatatypes)
err("type of value ${value.type} doesn't match target $targetDt") err("type of value ${value.type} doesn't match target $targetDt")
} }
} }
@ -1829,11 +1816,9 @@ internal class AstChecker(private val program: Program,
// this is allowed: a pass-by-reference datatype into a uword (pointer value). // this is allowed: a pass-by-reference datatype into a uword (pointer value).
} }
else if(sourceDatatype==DataType.BOOL && targetDatatype!=DataType.BOOL) { else if(sourceDatatype==DataType.BOOL && targetDatatype!=DataType.BOOL) {
if(compilerOptions.strictBool || targetDatatype !in ByteDatatypes)
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
} }
else if(targetDatatype==DataType.BOOL && sourceDatatype!=DataType.BOOL) { else if(targetDatatype==DataType.BOOL && sourceDatatype!=DataType.BOOL) {
if(compilerOptions.strictBool || sourceDatatype !in ByteDatatypes)
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
} }
else { else {

View File

@ -92,8 +92,8 @@ internal fun Program.addTypecasts(errors: IErrorReporter, options: CompilationOp
caster.applyModifications() caster.applyModifications()
} }
fun Program.desugaring(errors: IErrorReporter, options: CompilationOptions) { fun Program.desugaring(errors: IErrorReporter) {
val desugar = CodeDesugarer(this, options, errors) val desugar = CodeDesugarer(this, errors)
desugar.visit(this) desugar.visit(this)
while(errors.noErrors() && desugar.applyModifications()>0) while(errors.noErrors() && desugar.applyModifications()>0)
desugar.visit(this) desugar.visit(this)

View File

@ -8,7 +8,7 @@ import prog8.ast.walk.IAstModification
import prog8.code.core.* import prog8.code.core.*
internal class CodeDesugarer(val program: Program, private val options: CompilationOptions, private val errors: IErrorReporter) : AstWalker() { internal class CodeDesugarer(val program: Program, private val errors: IErrorReporter) : AstWalker() {
// Some more code shuffling to simplify the Ast that the codegenerator has to process. // Some more code shuffling to simplify the Ast that the codegenerator has to process.
// Several changes have already been done by the StatementReorderer ! // Several changes have already been done by the StatementReorderer !
@ -123,8 +123,6 @@ if not CONDITION
override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> { override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> {
if(!whileLoop.condition.inferType(program).isBool) { if(!whileLoop.condition.inferType(program).isBool) {
val ctype = whileLoop.condition.inferType(program).getOr(DataType.UNDEFINED)
if(options.strictBool || ctype !in ByteDatatypes)
errors.err("condition should be a boolean", whileLoop.condition.position) errors.err("condition should be a boolean", whileLoop.condition.position)
} }

View File

@ -24,11 +24,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val valueDt = declValue.inferType(program) val valueDt = declValue.inferType(program)
if(valueDt isnot decl.datatype) { if(valueDt isnot decl.datatype) {
if(decl.isArray && !options.strictBool) {
if(tryConvertBooleanArrays(decl, declValue, parent))
return noModifications
}
if(valueDt.isInteger && decl.isArray) { if(valueDt.isInteger && decl.isArray) {
if(decl.datatype == DataType.ARRAY_BOOL) { if(decl.datatype == DataType.ARRAY_BOOL) {
val integer = declValue.constValue(program)?.number val integer = declValue.constValue(program)?.number
@ -54,69 +49,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return noModifications return noModifications
} }
private fun tryConvertBooleanArrays(decl: VarDecl, declValue: Expression, parent: Node): Boolean {
val valueNumber = declValue.constValue(program)
val valueArray = declValue as? ArrayLiteral
when (decl.datatype) {
DataType.ARRAY_BOOL -> {
if(valueNumber!=null) {
decl.value = NumericLiteral.fromBoolean(valueNumber.number!=0.0, declValue.position)
decl.linkParents(parent)
return true
} else if(valueArray!=null) {
val newArray = valueArray.value.map {
if(it.inferType(program).isBytes) {
TypecastExpression(it, DataType.BOOL, false, it.position)
} else {
it
}
}
decl.value = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_BOOL), newArray.toTypedArray(), valueArray.position)
decl.linkParents(parent)
return true
}
}
DataType.ARRAY_B -> {
if(valueNumber!=null) {
decl.value = NumericLiteral(DataType.BYTE, if(valueNumber.asBooleanValue) 1.0 else 0.0, declValue.position)
decl.linkParents(parent)
return true
} else if(valueArray!=null) {
val newArray = valueArray.value.map {
if(it.inferType(program).isBool) {
TypecastExpression(it, DataType.BYTE, false, it.position)
} else {
it
}
}
decl.value = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_B), newArray.toTypedArray(), valueArray.position)
decl.linkParents(parent)
return true
}
}
DataType.ARRAY_UB -> {
if(valueNumber!=null) {
decl.value = NumericLiteral(DataType.UBYTE, if(valueNumber.asBooleanValue) 1.0 else 0.0, declValue.position)
decl.linkParents(parent)
return true
} else if(valueArray!=null) {
val newArray = valueArray.value.map {
if(it.inferType(program).isBool) {
TypecastExpression(it, DataType.UBYTE, false, it.position)
} else {
it
}
}
decl.value = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), newArray.toTypedArray(), valueArray.position)
decl.linkParents(parent)
return true
}
}
else -> { /* no casting possible */ }
}
return false
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> { override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val leftDt = expr.left.inferType(program) val leftDt = expr.left.inferType(program)
val rightDt = expr.right.inferType(program) val rightDt = expr.right.inferType(program)
@ -155,26 +87,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
} }
if(leftDt!=rightDt) { 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 // 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(expr.operator in BitwiseOperators && leftDt.isInteger && rightDt.isInteger) {
if(leftCv!=null && leftCv.number<0) { if(leftCv!=null && leftCv.number<0) {
@ -280,16 +192,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(cvalue!=null) { if(cvalue!=null) {
val number = cvalue.number val number = cvalue.number
// more complex comparisons if the type is different, but the constant value is compatible // more complex comparisons if the type is different, but the constant value is compatible
if(!options.strictBool) {
if (targettype == DataType.BOOL && valuetype in ByteDatatypes) {
val cast = NumericLiteral.fromBoolean(number!=0.0, cvalue.position)
return listOf(IAstModification.ReplaceNode(assignment.value, cast, assignment))
}
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) { if (valuetype == DataType.BYTE && targettype == DataType.UBYTE) {
if(number>0) if(number>0)
return castLiteral(cvalue) return castLiteral(cvalue)
@ -303,17 +205,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(number<0x8000) if(number<0x8000)
return castLiteral(cvalue) 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))
}
}
} }
} }
} }
@ -365,8 +256,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
} else if(argDt isAssignableTo targetDt) { } else if(argDt isAssignableTo targetDt) {
if(argDt!=DataType.STR || targetDt!=DataType.UWORD) if(argDt!=DataType.STR || targetDt!=DataType.UWORD)
addTypecastOrCastedValueModification(modifications, it.second, targetDt, call as Node) 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 { } else {
val identifier = it.second as? IdentifierReference val identifier = it.second as? IdentifierReference
@ -432,18 +322,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(subroutine.returntypes.size==1) { if(subroutine.returntypes.size==1) {
val subReturnType = subroutine.returntypes.first() val subReturnType = subroutine.returntypes.first()
val returnDt = returnValue.inferType(program) 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)) if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType))
return noModifications return noModifications
if (returnValue is NumericLiteral) { if (returnValue is NumericLiteral) {
@ -488,14 +366,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return modifications 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( private fun addTypecastOrCastedValueModification(
modifications: MutableList<IAstModification>, modifications: MutableList<IAstModification>,
expressionToCast: Expression, expressionToCast: Expression,
@ -505,18 +375,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val sourceDt = expressionToCast.inferType(program).getOr(DataType.UNDEFINED) val sourceDt = expressionToCast.inferType(program).getOr(DataType.UNDEFINED)
if(sourceDt == requiredType) if(sourceDt == requiredType)
return return
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) { if(requiredType==DataType.BOOL) {
return return
} }

View File

@ -97,16 +97,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent)) return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
} }
if(!options.strictBool && expr.operator=="not") {
if(expr.expression.inferType(program).isBytes) {
// not bytevalue --> bytevalue==0
val cmp = BinaryExpression(expr.expression, "==",
NumericLiteral(expr.expression.inferType(program).getOr(DataType.UNDEFINED), 0.0, expr.expression.position),
expr.expression.position)
return listOf(IAstModification.ReplaceNode(expr, cmp, parent))
}
}
return noModifications return noModifications
} }

View File

@ -41,7 +41,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
private val memorySlabs = mutableListOf<Slab>() private val memorySlabs = mutableListOf<Slab>()
override fun visit(functionCallExpr: FunctionCallExpression) { override fun visit(functionCallExpr: FunctionCallExpression) {
val error = checkTypes(functionCallExpr as IFunctionCall, program, options) val error = checkTypes(functionCallExpr as IFunctionCall, program)
if(error!=null) if(error!=null)
errors.err(error.first, error.second) errors.err(error.first, error.second)
else { else {
@ -62,7 +62,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
} }
override fun visit(functionCallStatement: FunctionCallStatement) { override fun visit(functionCallStatement: FunctionCallStatement) {
val error = checkTypes(functionCallStatement as IFunctionCall, program, options) val error = checkTypes(functionCallStatement as IFunctionCall, program)
if(error!=null) if(error!=null)
errors.err(error.first, error.second) errors.err(error.first, error.second)
@ -85,7 +85,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
return false return false
} }
fun checkTypes(call: IFunctionCall, program: Program, options: CompilationOptions): Pair<String, Position>? { fun checkTypes(call: IFunctionCall, program: Program): Pair<String, Position>? {
val argITypes = call.args.map { it.inferType(program) } val argITypes = call.args.map { it.inferType(program) }
val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown } val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown }
if(firstUnknownDt>=0) { if(firstUnknownDt>=0) {
@ -105,12 +105,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
if(mismatch>=0) { if(mismatch>=0) {
val actual = argtypes[mismatch] val actual = argtypes[mismatch]
val expected = consideredParamTypes[mismatch] val expected = consideredParamTypes[mismatch]
return if(expected==DataType.BOOL && !options.strictBool && actual in ByteDatatypes) return Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position)
null
else if(expected in ByteDatatypes && !options.strictBool && actual==DataType.BOOL)
null
else
Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position)
} }
if(target.isAsmSubroutine) { if(target.isAsmSubroutine) {
if(target.asmReturnvaluesRegisters.size>1) { if(target.asmReturnvaluesRegisters.size>1) {

View File

@ -43,7 +43,6 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,
strictBool = true,
symbolDefs = emptyMap(), symbolDefs = emptyMap(),
outputDir = outputDir outputDir = outputDir
) )

View File

@ -41,7 +41,6 @@ class TestCompilerOptionSourcedirs: FunSpec({
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,
strictBool = true,
symbolDefs = emptyMap(), symbolDefs = emptyMap(),
sourceDirs, sourceDirs,
outputDir outputDir

View File

@ -43,7 +43,6 @@ internal fun compileFile(
breakpointCpuInstruction = null, breakpointCpuInstruction = null,
printAst1 = false, printAst1 = false,
printAst2 = false, printAst2 = false,
strictBool = true
) )
return compileProgram(args) return compileProgram(args)
} }

View File

@ -155,10 +155,6 @@ One or more .p8 module files
Don't perform any code optimizations. Don't perform any code optimizations.
Useful for debugging or faster compilation cycles. 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`` ``-optfloatx``
Also optimize float expressions if optimizations are enabled. Also optimize float expressions if optimizations are enabled.
Warning: can increase program size significantly if a lot of floating point expressions are used. Warning: can increase program size significantly if a lot of floating point expressions are used.

View File

@ -5,4 +5,4 @@ org.gradle.daemon=true
kotlin.code.style=official kotlin.code.style=official
javaVersion=11 javaVersion=11
kotlinVersion=2.0.20 kotlinVersion=2.0.20
version=10.4 version=10.5-SNAPSHOT