#!/usr/bin/env python3 """Compiles a source file and checks errors against those listed in the file. Parameters: sys.argv[1]: a source file with contains the input and expected output sys.argv[2]: the Flang frontend driver sys.argv[3:]: Optional arguments to the Flang frontend driver""" import sys import re import tempfile import subprocess import common as cm from difflib import unified_diff cm.check_args(sys.argv) srcdir = cm.set_source(sys.argv[1]) with open(srcdir, "r") as f: src = f.readlines() actual = "" expect = "" diffs = "" log = "" flang_fc1 = cm.set_executable(sys.argv[2]) flang_fc1_args = sys.argv[3:] flang_fc1_options = "-fsyntax-only" # Compiles, and reads in the output from the compilation process cmd = [flang_fc1, *flang_fc1_args, flang_fc1_options, str(srcdir)] with tempfile.TemporaryDirectory() as tmpdir: try: proc = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, universal_newlines=True, cwd=tmpdir, ) except subprocess.CalledProcessError as e: log = e.stderr if e.returncode >= 128: print(f"{log}") sys.exit(1) # Cleans up the output from the compilation process to be easier to process for line in log.split("\n"): m = re.search(r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line) if m: if re.search(r"warning: .*fold.*host", line): continue # ignore host-dependent folding warnings actual += m.expand(r"\1\2\n") # Gets the expected errors and their line numbers errors = [] for i, line in enumerate(src, 1): m = re.search(r"(?:^\s*!\s*(?:ERROR|WARNING|PORTABILITY|BECAUSE): )(.*)", line) if m: errors.append(m.group(1)) continue if errors: for x in errors: expect += f"{i}: {x}\n" errors = [] # Compares the expected errors with the compiler errors for line in unified_diff(actual.split("\n"), expect.split("\n"), n=0): line = re.sub(r"(^\-)(\d+:)", r"\nactual at \g<2>", line) line = re.sub(r"(^\+)(\d+:)", r"\nexpect at \g<2>", line) diffs += line if diffs != "": print(diffs) print() print("FAIL") sys.exit(1) else: print() print("PASS")