# 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)