no operand swap on logical expressions with shortcircuit evaluation (and,or are no longer associative!)

This commit is contained in:
Irmen de Jong 2024-03-20 22:34:39 +01:00
parent 592becc126
commit ad4880997a
5 changed files with 53 additions and 82 deletions

View File

@ -35,9 +35,11 @@ jobs:
name: prog8-compiler-jar-zipped
path: compiler/build/libs/*-all.jar
release:
runs-on: ubuntu-latest
steps:
- name: Calculate hash
uses: MCJack123/ghaction-generate-release-hashes@v4
if: "github.event_name == 'release'"
with:
get-assets: true
hash-type: sha256
@ -45,7 +47,6 @@ jobs:
- name: Upload hashes
uses: actions/upload-artifact@v4
if: "github.event_name == 'release'"
with:
name: Artifact Hashes
path: hashes.txt

View File

@ -1,6 +1,6 @@
package prog8.code.core
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "and", "or", "xor")
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are no longer associative because of Shortcircuit/McCarthy evaluation
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
val BitwiseOperators = setOf("&", "|", "^", "~")

View File

@ -4,7 +4,6 @@ import prog8.ast.*
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.AnonymousScope
import prog8.ast.statements.Assignment
import prog8.ast.statements.IfElse
import prog8.ast.statements.Jump
import prog8.ast.walk.AstWalker
@ -109,12 +108,6 @@ class ExpressionSimplifier(private val program: Program, private val options: Co
if (!leftIDt.isKnown || !rightIDt.isKnown)
throw FatalAstException("can't determine datatype of both expression operands $expr")
// NonBinaryExpression <associativeoperator> BinaryExpression --> BinaryExpression <associativeoperator> NonBinaryExpression
if (expr.operator in AssociativeOperators && expr.left !is BinaryExpression && expr.right is BinaryExpression) {
if(parent !is Assignment || !(expr.left isSameAs parent.target) && maySwapOperandOrder(expr))
return listOf(IAstModification.SwapOperands(expr))
}
// X + (-A) --> X - A
if (expr.operator == "+" && (expr.right as? PrefixExpression)?.operator == "-") {
return listOf(IAstModification.ReplaceNode(

View File

@ -935,4 +935,41 @@ main {
funcarg3.target.nameInSource shouldBe listOf("msb")
funcarg3.args.single() shouldBe instanceOf<BinaryExpression>()
}
test("no operand swap on logical expressions with shortcircuit evaluation") {
val src="""
%import diskio
%zeropage basicsafe
%option no_sysinit
main {
str scanline_buf = "?"* 20
sub start() {
if diskio.f_open("test.prg") and diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") or diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") xor diskio.f_read(scanline_buf, 2)==2
cx16.r0++
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 3
val ifCond1 = (st[0] as IfElse).condition as BinaryExpression
val ifCond2 = (st[1] as IfElse).condition as BinaryExpression
val ifCond3 = (st[2] as IfElse).condition as BinaryExpression
(ifCond1.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
(ifCond2.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
(ifCond3.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
val right1 = ifCond1.right as BinaryExpression
val right2 = ifCond2.right as BinaryExpression
val right3 = ifCond3.right as BinaryExpression
(right1.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
(right2.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
(right3.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
}
})

View File

@ -1,78 +1,18 @@
%import textio
%import string
%import diskio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
str name = "irmen@de@jong"
cx16.r0L = findstr(name, "de-")
if_cs {
txt.print("found1. error. ")
} else {
txt.print("not found1. ok ")
}
txt.print_ub(cx16.r0L)
txt.nl()
txt.nl()
cx16.r0L = findstr(name, "de@")
if_cs {
txt.print("found2 (6?). ")
} else {
txt.print("not found2. error ")
}
txt.print_ub(cx16.r0L)
txt.nl()
txt.nl()
cx16.r0L = findstr(name, "irmen@de@jong")
if_cs {
txt.print("found3 (0?). ")
} else {
txt.print("not found3. error ")
}
txt.print_ub(cx16.r0L)
txt.nl()
txt.nl()
cx16.r0L = findstr(name, "irmen@de@jong1")
if_cs {
txt.print("found4. error. ")
} else {
txt.print("not found4. ok ")
}
txt.print_ub(cx16.r0L)
txt.nl()
txt.nl()
cx16.r0L = findstr(name, "jong")
if_cs {
txt.print("found5 (9?). ")
} else {
txt.print("not found5. error ")
}
txt.print_ub(cx16.r0L)
txt.nl()
txt.nl()
}
str scanline_buf = "?"* 20
sub findstr(str haystack, str needle) -> ubyte {
; searches for needle in haystack.
; returns index in haystack where it first occurs, and Carry set,
; or if needle doesn't occur in haystack it returns Carry clear and 255 (an invalid index.)
txt.print_uwhex(haystack, true)
txt.spc()
txt.print(haystack)
txt.nl()
cx16.r2L = string.length(haystack)
cx16.r3L = string.length(needle)
if cx16.r3L <= cx16.r2L {
cx16.r2L = cx16.r2L-cx16.r3L+1
repeat cx16.r2L {
if string.startswith(haystack, needle) {
sys.set_carry()
return 13 as ubyte
}
haystack++
}
}
sys.clear_carry()
return 255
sub start() {
if diskio.f_open("test.prg") and diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") or diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") xor diskio.f_read(scanline_buf, 2)==2
cx16.r0++
}
}