1#!/usr/bin/env python3
2
3"""Compiles a source file and compares generated .mod files against expected.
4
5Parameters:
6    sys.argv[1]: a source file with contains the input and expected output
7    sys.argv[2]: the Flang frontend driver
8    sys.argv[3:]: Optional arguments to the Flang frontend driver"""
9
10import sys
11import re
12import os
13import tempfile
14import subprocess
15import glob
16import common as cm
17
18from pathlib import Path
19from difflib import unified_diff
20
21cm.check_args_long(sys.argv)
22srcdir = Path(sys.argv[1])
23sources = list(glob.iglob(str(srcdir)))
24sources = sorted(sources)
25diffs = ""
26
27flang_fc1 = cm.set_executable(sys.argv[2])
28flang_fc_args = sys.argv[3:]
29flang_fc1_options = "-fsyntax-only"
30
31with tempfile.TemporaryDirectory() as tmpdir:
32    for src in sources:
33        src = Path(src).resolve()
34        actual = ""
35        expect = ""
36        expected_files = set()
37        actual_files = set()
38
39        if not src.is_file():
40            cm.die(src)
41
42        prev_files = set(os.listdir(tmpdir))
43        cmd = [flang_fc1, *flang_fc_args, flang_fc1_options, str(src)]
44        proc = subprocess.check_output(cmd, stderr=subprocess.PIPE,
45                                       universal_newlines=True, cwd=tmpdir)
46        actual_files = set(os.listdir(tmpdir)).difference(prev_files)
47
48        # The first 3 bytes of the files are an UTF-8 BOM
49        with open(src, 'r', encoding="utf-8", errors="strict") as f:
50            for line in f:
51                m = re.search(r"^!Expect: (.*)", line)
52                if m:
53                    expected_files.add(m.group(1))
54
55        extra_files = actual_files.difference(expected_files)
56        if extra_files:
57            print(f"Unexpected .mod files produced: {extra_files}")
58            sys.exit(1)
59
60        for mod in expected_files:
61            mod = Path(tmpdir).joinpath(mod)
62            if not mod.is_file():
63                print(f"Compilation did not produce expected mod file: {mod}")
64                sys.exit(1)
65            with open(mod, 'r', encoding="utf-8", errors="strict") as f:
66                for line in f:
67                    if "!mod$" in line:
68                        continue
69                    actual += line
70
71            with open(src, 'r', encoding="utf-8", errors="strict") as f:
72                for line in f:
73                    if f"!Expect: {mod.name}" in line:
74                        for line in f:
75                            if re.match(r"^$", line):
76                                break
77                            m = re.sub(r"^!", "", line.lstrip())
78                            expect += m
79
80            diffs = "\n".join(unified_diff(actual.replace(" ", "").split("\n"),
81                                           expect.replace(" ", "").split("\n"),
82                                           fromfile=mod.name, tofile="Expect", n=999999))
83
84            if diffs != "":
85                print(diffs)
86                print()
87                print("FAIL")
88                sys.exit(1)
89
90print()
91print("PASS")
92
93