From c65297590dd7a2dcc93f644632c7c3383f993038 Mon Sep 17 00:00:00 2001 From: Zhixun Tan Date: Fri, 26 Dec 2025 19:41:17 +0000 Subject: [PATCH] release ir/transforms/generate_tests.py --- maldoca/js/ir/transforms/generate_tests.py | 181 +++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 maldoca/js/ir/transforms/generate_tests.py diff --git a/maldoca/js/ir/transforms/generate_tests.py b/maldoca/js/ir/transforms/generate_tests.py new file mode 100644 index 0000000..cd921bd --- /dev/null +++ b/maldoca/js/ir/transforms/generate_tests.py @@ -0,0 +1,181 @@ +r"""Generates test files for the conversion tests. + +In each directory, only `input.js` is manually written. The other files are +generated by running this tool. + +Usage: + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,ast2hir,constprop,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/constant_propagation/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,extract_prelude,erase_comments,ast2hir,dynconstprop,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/dynamic_constant_propagation/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,erase_comments,ast2hir,movenamedfuncs,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/move_named_functions/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,erase_comments,ast2hir,normalize_member_expressions,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/normalize_member_expressions/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,erase_comments,ast2hir,constprop,normalize_member_expressions,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/normalize_member_expressions/tests/with_constant_propagation + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,ast2hir,normalizeobjprops,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/normalize_object_properties/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,erase_comments,ast2hir,peelparens,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/peel_parentheses/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,ast2hir,split_declaration_statements,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/split_declaration_statements/tests + +python3 maldoca/js/ir/transforms/generate_tests.py \ + --passes source2ast,ast2hir,split_sequence_expressions,hir2ast,ast2source \ + --path maldoca/js/ir/transforms/split_sequence_expressions/tests +""" + +import argparse +import os +import shutil +import subprocess +import sys + + +def run_command(cmd: str) -> bytes: + """Run a shell command and return its output.""" + + print("Running:") + print(" ", cmd) + + try: + return subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE) + except subprocess.CalledProcessError as e: + print("Error running command, output:", e.output) + sys.exit(1) + + +def generate_test_file( + input_path: str, + output_path: str, + passes: str, + prefix: str, +): + """Generates a test file. + + Args: + input_path: Test case name. + output_path: The output file will be /. + passes: Comma-separated list of JSIR passes. + prefix: FileCheck prefix. + """ + input_abs_path: str = os.path.abspath(input_path) + + command: str = ( + "bazel run //maldoca/js/ir:jsir_gen --" + f" --input_file={input_abs_path}" + f" --passes='{passes}'" + ) + + try: + output = run_command(command).decode("utf-8") + except UnicodeDecodeError: + output = run_command(command).decode("latin-1") + + output = output.strip() + + # Prepend prefix + lines = output.split("\n") + out_lines = [] + for i, line in enumerate(lines): + if not line: + line = f"// {prefix}-EMPTY:" + elif i == 0: + line = f"// {prefix}: " + line + else: + line = f"// {prefix}-NEXT: " + line + out_lines.append(line) + + output = "\n".join(out_lines) + "\n" + + with open(output_path, "w") as f: + f.write(output) + + +README_TEMPLATE = r"""To run manually: + +```shell +bazel run //maldoca/js/ir:jsir_gen -- \ + --input_file $(pwd)/{test_path}/input.js \ + --passes "{passes}" +``` +""" + +LIT_TEMPLATE = r"""// RUN: CURRENT_FILE_BASENAME=$(basename %s .lit) && \ +// RUN: jsir_gen --input_file "$(dirname %s)"/input.js \ +// RUN: --passes "{passes}" \ +// RUN: | FileCheck --check-prefix SOURCE "$(dirname %s)"/output.generated.txt +""" + + +def generate_readme_file(test_path: str, passes: str): + with open(os.path.join(test_path, "README.generated.md"), "w") as f: + f.write(README_TEMPLATE.format(test_path=test_path, passes=passes)) + + +def generate_lit_file(test_path: str, passes: str): + with open(os.path.join(test_path, "run.generated.lit"), "w") as f: + f.write(LIT_TEMPLATE.format(test_path=test_path, passes=passes)) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--passes", required=True) + parser.add_argument("--path", required=True) + + args = parser.parse_args() + passes: str = args.passes + root_path: str = args.path + print("Passes:", passes) + print("Path:", root_path) + + for test_path, _, file_names_in_dir in os.walk(root_path): + + if "input.js" not in file_names_in_dir: + continue + + test_name = os.path.basename(test_path) + print("Generating test:", test_name) + + generate_test_file( + input_path=os.path.join(test_path, "input.js"), + output_path=os.path.join(test_path, "output.generated.txt"), + passes=passes, + prefix="SOURCE", + ) + + generate_readme_file( + test_path=test_path, + passes=passes, + ) + + generate_lit_file( + test_path, + passes=passes, + ) + + shutil.copyfile( + os.path.join(root_path, "BUILD.template"), + os.path.join(test_path, "BUILD"), + ) + + +if __name__ == "__main__": + main()