prog8/compiler/test/comparisons/make_cmp_tests.py
2024-03-02 23:19:39 +01:00

377 lines
11 KiB
Python

# generates various Prog8 files with a large amount of number comparison tests,
# using various forms of the if statement (because these forms have their own code gen paths)
import sys
fail_index = 0
class C:
def __init__(self, short, long, operator, compare):
self.short=short
self.long=long
self.operator=operator
self.compare=compare
def header(dt, comparison: C):
print(f"""
%import textio
%import floats
%import test_stack
%zeropage dontuse
%option no_sysinit
main {{
ubyte success = 0
str datatype = "{dt}"
uword @shared comparison
sub start() {{
txt.print("\\n{comparison.long} tests for: ")
txt.print(datatype)
txt.nl()
test_stack.test()
txt.print("\\n{comparison.operator}number: ")
test_cmp_number()
txt.print("\\n{comparison.operator}var: ")
test_cmp_var()
txt.print("\\n{comparison.operator}array[]: ")
test_cmp_array()
txt.print("\\n{comparison.operator}expr: ")
test_cmp_expr()
test_stack.test()
}}
sub verify_success(ubyte expected) {{
if success==expected {{
txt.print("ok")
}} else {{
txt.print(" **failed** ")
txt.print_ub(success)
txt.print(" success, expected ")
txt.print_ub(expected)
}}
}}
sub fail_byte(uword idx) {{
txt.print(" **fail#")
txt.print_uw(idx)
txt.print(" **")
}}
sub fail_ubyte(uword idx) {{
txt.print(" **fail#")
txt.print_uw(idx)
txt.print(" **")
}}
sub fail_word(uword idx) {{
txt.print(" **fail#")
txt.print_uw(idx)
txt.print(" **")
}}
sub fail_uword(uword idx) {{
txt.print(" **fail#")
txt.print_uw(idx)
txt.print(" **")
}}
sub fail_float(uword idx) {{
txt.print(" **fail#")
txt.print_uw(idx)
txt.print(" **")
}}
""")
def tc(value):
if value < 0x8000:
return value
else:
return -(65536 - value)
testnumbers = {
"byte": [-1, 0, 1],
"ubyte": [0, 1, 255],
"word": [tc(0xaabb), -1, 0, 1, 0x00aa, 0x7700, 0x7fff],
"uword": [0, 1, 0x7700, 0xffff],
"float": [0.0, 1234.56]
}
def make_test_number(datatype, comparison: C):
numbers = testnumbers[datatype]
print(" sub test_cmp_number() {")
print(f""" {datatype} @shared x
success = 0""")
expected = 0
test_index = 0
global fail_index
for x in numbers:
print(f" x={x}")
for value in numbers:
result = comparison.compare(x, value)
comp = comparison.operator
test_index += 1
if result:
expected += 4 # there are 4 test types for every successful combo
true_action1 = "success++"
true_action2 = "success++"
true_action3 = "success++"
true_action4 = "success++"
fail_action4 = "cx16.r0L++"
else:
fail_index += 1
true_action1 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action2 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action3 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action4 = f"fail_{datatype}({fail_index})"
fail_action4 = "success++"
expected += 1
print(f""" ; direct jump
if x{comp}{value}
goto lbl{test_index}a
goto skip{test_index}a
lbl{test_index}a: {true_action1}
skip{test_index}a:
; indirect jump
cx16.r3 = &lbl{test_index}b
if x{comp}{value}
goto cx16.r3
goto skip{test_index}b
lbl{test_index}b: {true_action2}
skip{test_index}b:
; no else
if x{comp}{value}
{true_action3}
; with else
if x{comp}{value}
{true_action4}
else
{fail_action4}
""")
print(f" verify_success({expected})\n}}")
def make_test_var(datatype, comparison: C):
numbers = testnumbers[datatype]
print(" sub test_cmp_var() {")
print(f""" {datatype} @shared x, value
success = 0""")
expected = 0
test_index = 0
global fail_index
for x in numbers:
print(f" x={x}")
for value in numbers:
print(f" value={value}")
result = comparison.compare(x, value)
comp = comparison.operator
test_index += 1
if result:
expected += 4 # there are 4 test types for every successful combo
true_action1 = "success++"
true_action2 = "success++"
true_action3 = "success++"
true_action4 = "success++"
fail_action4 = "cx16.r0L++"
else:
fail_index += 1
true_action1 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action2 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action3 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action4 = f"fail_{datatype}({fail_index})"
fail_action4 = "success++"
expected += 1
print(f""" ; direct jump
if x{comp}value
goto lbl{test_index}a
goto skip{test_index}a
lbl{test_index}a: {true_action1}
skip{test_index}a:
; indirect jump
cx16.r3 = &lbl{test_index}b
if x{comp}value
goto cx16.r3
goto skip{test_index}b
lbl{test_index}b: {true_action2}
skip{test_index}b:
; no else
if x{comp}value
{true_action3}
; with else
if x{comp}value
{true_action4}
else
{fail_action4}
""")
print(f" verify_success({expected})\n}}")
def make_test_array(datatype, comparison: C):
numbers = testnumbers[datatype]
print(" sub test_cmp_array() {")
print(f""" {datatype} @shared x
{datatype}[] values = [0, 0]
success = 0""")
expected = 0
test_index = 0
global fail_index
for x in numbers:
print(f" x={x}")
for value in numbers:
print(f" values[1]={value}")
result = comparison.compare(x, value)
comp = comparison.operator
test_index += 1
if result:
expected += 4 # there are 4 test types for every successful combo
true_action1 = "success++"
true_action2 = "success++"
true_action3 = "success++"
true_action4 = "success++"
fail_action4 = "cx16.r0L++"
else:
fail_index += 1
true_action1 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action2 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action3 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action4 = f"fail_{datatype}({fail_index})"
fail_action4 = "success++"
expected += 1
print(f""" ; direct jump
if x{comp}values[1]
goto lbl{test_index}a
goto skip{test_index}a
lbl{test_index}a: {true_action1}
skip{test_index}a:
; indirect jump
cx16.r3 = &lbl{test_index}b
if x{comp}values[1]
goto cx16.r3
goto skip{test_index}b
lbl{test_index}b: {true_action2}
skip{test_index}b:
; no else
if x{comp}values[1]
{true_action3}
; with else
if x{comp}values[1]
{true_action4}
else
{fail_action4}
""")
print(f" verify_success({expected})\n}}")
def make_test_expr(datatype, comparison: C):
numbers = testnumbers[datatype]
print(" sub test_cmp_expr() {")
print(f""" {datatype} @shared x
cx16.r4 = 1
cx16.r5 = 1
float @shared f4 = 1.0
float @shared f5 = 1.0
success = 0""")
expected = 0
test_index = 0
global fail_index
for x in numbers:
print(f" x={x}")
for value in numbers:
if datatype=="byte":
expr = f"cx16.r4sL+{value}-cx16.r5sL"
elif datatype=="ubyte":
expr = f"cx16.r4L+{value}-cx16.r5L"
elif datatype=="word":
expr = f"cx16.r4s+{value}-cx16.r5s"
elif datatype=="uword":
expr = f"cx16.r4+{value}-cx16.r5"
elif datatype=="float":
expr = f"f4+{value}-f5"
result = comparison.compare(x, value)
comp = comparison.operator
test_index += 1
if result:
expected += 4 # there are 4 test types for every successful combo
true_action1 = "success++"
true_action2 = "success++"
true_action3 = "success++"
true_action4 = "success++"
fail_action4 = "cx16.r0L++"
else:
fail_index += 1
true_action1 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action2 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action3 = f"fail_{datatype}({fail_index})"
fail_index += 1
true_action4 = f"fail_{datatype}({fail_index})"
fail_action4 = "success++"
expected += 1
print(f""" ; direct jump
if x{comp}{expr}
goto lbl{test_index}a
goto skip{test_index}a
lbl{test_index}a: {true_action1}
skip{test_index}a:
; indirect jump
cx16.r3 = &lbl{test_index}b
if x{comp}{expr}
goto cx16.r3
goto skip{test_index}b
lbl{test_index}b: {true_action2}
skip{test_index}b:
; no else
if x{comp}{expr}
{true_action3}
; with else
if x{comp}{expr}
{true_action4}
else
{fail_action4}
""")
print(f" verify_success({expected})\n}}")
def generate(datatype, comparison: C):
global fail_index
fail_index = 0
header(datatype, comparison)
make_test_number(datatype, comparison)
make_test_var(datatype, comparison)
make_test_array(datatype, comparison)
make_test_expr(datatype, comparison)
print("\n}\n")
if __name__ == '__main__':
comparisons = [
C("lt", "less-than", "<", lambda x,y: x < y),
C("lte", "less-equal", "<=", lambda x,y: x <= y),
C("gt", "greater-than", ">", lambda x,y: x > y),
C("gte", "greater-equal", ">=", lambda x,y: x >= y),
]
for comparison in comparisons:
for dt in ["ubyte", "uword", "byte", "word", "float"]:
sys.stdout = open(f"test_{dt}_{comparison.short}.p8", "wt")
generate(dt, comparison)