mirror of
https://github.com/irmen/prog8.git
synced 2025-01-23 00:31:14 +00:00
fix: boolean values of terms in logical expressions are now properly evaluated
This commit is contained in:
parent
a6d0ea347c
commit
bb1cda0916
@ -702,10 +702,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
when (val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)) {
|
||||
in ByteDatatypes -> {
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.A, dt==DataType.BYTE)
|
||||
asmgen.out(" beq + | lda #1")
|
||||
asmgen.out("+")
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY, dt==DataType.WORD)
|
||||
asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1")
|
||||
asmgen.out(" beq + | lda #1")
|
||||
asmgen.out("+")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.FAC1, true)
|
||||
|
@ -368,12 +368,20 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
VmDataType.WORD -> {
|
||||
val msbReg = codeGen.vmRegisters.nextFree()
|
||||
val skipLabel = codeGen.createLabelName()
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = msbReg, reg2=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=resultRegister, labelSymbol = skipLabel)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value = 1)
|
||||
code += VmCodeLabel(skipLabel)
|
||||
}
|
||||
else -> {
|
||||
val skipLabel = codeGen.createLabelName()
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=resultRegister, labelSymbol = skipLabel)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value = 1)
|
||||
code += VmCodeLabel(skipLabel)
|
||||
}
|
||||
}
|
||||
return code
|
||||
|
@ -249,7 +249,7 @@ internal class StatementReorderer(val program: Program,
|
||||
}
|
||||
else if(expr.operator in LogicalOperators) {
|
||||
fun wrapped(expr: Expression): Expression {
|
||||
return if(expr.inferType(program).isBytes)
|
||||
return if(expr is IFunctionCall && expr.target.nameInSource==listOf("boolean"))
|
||||
expr
|
||||
else
|
||||
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
|
||||
@ -320,6 +320,17 @@ internal class StatementReorderer(val program: Program,
|
||||
// rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand
|
||||
val binExpr = assignment.value as? BinaryExpression
|
||||
if(binExpr!=null) {
|
||||
// if (binExpr.operator == "and") {
|
||||
// val leftBinExpr = binExpr.left as? BinaryExpression
|
||||
// if (leftBinExpr?.operator == "and")
|
||||
// return mcCarthyAndAssignment(binExpr, assignment, parent)
|
||||
// }
|
||||
// if (binExpr.operator == "or") {
|
||||
// val leftBinExpr = binExpr.left as? BinaryExpression
|
||||
// if (leftBinExpr?.operator == "or")
|
||||
// return mcCarthyOrAssignment(binExpr, assignment, parent)
|
||||
// }
|
||||
|
||||
if(binExpr.left isSameAs assignment.target) {
|
||||
// A = A <operator> 5, unchanged
|
||||
return noModifications
|
||||
@ -425,6 +436,56 @@ internal class StatementReorderer(val program: Program,
|
||||
checkUnusedReturnValues(functionCallStatement, function, errors)
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||
}
|
||||
|
||||
private fun mcCarthyAndAssignment(andExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||
val andTerms = findTerms(andExpr, "and")
|
||||
if(andTerms.any { it.constValue(program)?.asBooleanValue == false }) {
|
||||
errors.warn("expression is always false", andExpr.position)
|
||||
return listOf(IAstModification.ReplaceNode(andExpr, NumericLiteral.fromBoolean(false, andExpr.position), assignment))
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// repeat for all terms:
|
||||
// assign term to target
|
||||
// add if: if target==0: goto done
|
||||
// done:.
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun mcCarthyOrAssignment(orExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||
val andTerms = findTerms(orExpr, "or")
|
||||
if(andTerms.any { it.constValue(program)?.asBooleanValue == true }) {
|
||||
errors.warn("expression is always true", orExpr.position)
|
||||
return listOf(IAstModification.ReplaceNode(orExpr, NumericLiteral.fromBoolean(true, orExpr.position), assignment))
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// repeat for all terms:
|
||||
// assign term to target
|
||||
// add if: if target!=0: goto done
|
||||
// done:.
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun findTerms(expr: BinaryExpression, operator: String, terms: List<Expression> = emptyList()): List<Expression> {
|
||||
if(expr.operator!=operator)
|
||||
return listOf(expr) + terms
|
||||
val leftBinExpr = expr.left as? BinaryExpression ?: return listOf(expr.left, expr.right) + terms
|
||||
return findTerms(leftBinExpr, operator, listOf(expr.right)+terms)
|
||||
}
|
||||
|
||||
private fun mcCarthyAndExpression(e1: Expression, e2: Expression, e3: Expression, origAndExpression: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
// TODO
|
||||
println("AND EXPRESSION:")
|
||||
println(" $e1")
|
||||
println(" $e2")
|
||||
println(" $e3")
|
||||
println(" (orig) $origAndExpression")
|
||||
val replacement = NumericLiteral.fromBoolean(false, origAndExpression.position)
|
||||
return listOf(IAstModification.ReplaceNode(origAndExpression, replacement, parent))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,14 +233,5 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||
}
|
||||
|
||||
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(functionCallExpr.target.nameInSource==listOf("boolean")) {
|
||||
if(functionCallExpr.args[0].inferType(program).isBytes) {
|
||||
return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,17 +255,10 @@ private fun builtinBoolean(args: List<Expression>, position: Position, program:
|
||||
if (args.size != 1)
|
||||
throw SyntaxError("boolean requires one argument", position)
|
||||
val constvalue = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||
return if(constvalue.number==0.0)
|
||||
NumericLiteral(DataType.UBYTE, 0.0, args[0].position)
|
||||
else if(constvalue.type==DataType.UBYTE)
|
||||
constvalue
|
||||
else if(constvalue.type==DataType.FLOAT)
|
||||
return if(constvalue.type==DataType.FLOAT)
|
||||
NumericLiteral(DataType.UBYTE, constvalue.number.sign, args[0].position)
|
||||
else {
|
||||
val value = constvalue.number.toInt()
|
||||
val byteValue = ((value ushr 8) or value) and 255
|
||||
NumericLiteral(DataType.UBYTE, byteValue.toDouble(), args[0].position)
|
||||
}
|
||||
else
|
||||
NumericLiteral.fromBoolean(constvalue.number!=0.0, args[0].position)
|
||||
}
|
||||
|
||||
private fun builtinSgn(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
|
@ -777,7 +777,7 @@ Miscellaneous
|
||||
|
||||
boolean(x)
|
||||
Returns a byte value representing the boolean (truthy) value of x, where x can be any numeric type.
|
||||
This means it returns 0 (false) when x equals 0, and a value other than 0 otherwise.
|
||||
This means it returns 0 (false) when x equals 0, and 1 otherwise.
|
||||
|
||||
cmp(x,y)
|
||||
Compare the integer value x to integer value y. Doesn't return a value or boolean result, only sets the processor's status bits!
|
||||
|
@ -4,6 +4,7 @@ TODO
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
|
||||
StatementReorder.after(assignment).
|
||||
- add some more optimizations in vmPeepholeOptimizer
|
||||
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
||||
this info is needed for more advanced optimizations and later code generation steps.
|
||||
|
@ -48,10 +48,24 @@ main {
|
||||
sub start() {
|
||||
ubyte value
|
||||
uword wvalue
|
||||
byte svalue = -99
|
||||
|
||||
wvalue = 3*abs(svalue) +abs(svalue)+abs(svalue)+abs(svalue)
|
||||
txt.print_uw(wvalue)
|
||||
ubyte ub1 = 11
|
||||
ubyte ub2 = 22
|
||||
ubyte ub3 = 33
|
||||
ubyte ub4 = 44
|
||||
ubyte ub5 = 55
|
||||
|
||||
ub4 = 42
|
||||
txt.print("and with bytes: ")
|
||||
ub5 = ub1 and ub2 and ub3 and ub4 and ub5 ; TODO FIX !! should be True (!=0)
|
||||
txt.print_ub(ub5)
|
||||
txt.nl()
|
||||
|
||||
ub4 = 42
|
||||
txt.print("or with bytes: ")
|
||||
ub5 = ub1 or ub2 or ub3 or ub4 or ub5 ; TODO FIX!! should be False (0)
|
||||
txt.print_ub(ub5)
|
||||
txt.nl()
|
||||
|
||||
txt.print("short and with false (word): ")
|
||||
wvalue = funcw() and funcFalseWord() and funcw() and funcw()
|
||||
@ -72,7 +86,7 @@ main {
|
||||
txt.nl()
|
||||
|
||||
txt.print("and with false: ")
|
||||
value = func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
|
||||
value = func1(25) and func2(25) and funcFalse() and false and func3(25) and func4(25)
|
||||
txt.print_ub(value)
|
||||
txt.nl()
|
||||
txt.print("and with true: ")
|
||||
@ -80,7 +94,7 @@ main {
|
||||
txt.print_ub(value)
|
||||
txt.nl()
|
||||
txt.print("or with false: ")
|
||||
value = func1(25) or func2(25) or funcFalse() or func3(25) or func4(25)
|
||||
value = func1(25) or func2(25) or funcFalse() or true or func3(25) or func4(25)
|
||||
txt.print_ub(value)
|
||||
txt.nl()
|
||||
txt.print("or with true: ")
|
||||
|
Loading…
x
Reference in New Issue
Block a user