Skip to content

Commit 802082d

Browse files
committed
Implement the --error-filter-patterns option
1 parent 981094a commit 802082d

File tree

7 files changed

+74
-64
lines changed

7 files changed

+74
-64
lines changed

hephaestus.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ def check_oracle(dirname, oracles):
371371
produce the expected results (and the reason why).
372372
"""
373373
filename = os.path.join(dirname, 'src')
374-
compiler = COMPILERS[cli_args.language](filename)
374+
filter_patterns = utils.path2set(cli_args.error_filter_patterns)
375+
compiler = COMPILERS[cli_args.language](filename, filter_patterns)
375376
command_args = compiler.get_compiler_cmd()
376377
# At this point, we run the compiler
377378
_, err = run_command(command_args)
@@ -382,7 +383,7 @@ def check_oracle(dirname, oracles):
382383

383384
# Analyze the compiler output and check whether there are programs
384385
# that the compiler did not manage to compile.
385-
failed = compiler.analyze_compiler_output(err)
386+
failed, _ = compiler.analyze_compiler_output(err)
386387
if compiler.crash_msg:
387388
# We just found a compiler crash.
388389
shutil.rmtree(dirname)

src/args.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@
161161
action="store_true",
162162
help="Disable parameterized functions"
163163
)
164+
parser.add_argument(
165+
"--error-filter-patterns",
166+
default=None,
167+
type=str,
168+
help=("A file containing regular expressions for filtering compiler error "
169+
"messages")
170+
)
164171

165172

166173
args = parser.parse_args()

src/compilers/base.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
from collections import defaultdict
2+
import re
3+
4+
15
class BaseCompiler():
2-
def __init__(self, input_name):
6+
ERROR_REGEX = None
7+
CRASH_REGEX = None
8+
9+
def __init__(self, input_name, filter_patterns=None):
310
self.input_name = input_name
11+
self.filter_patterns = filter_patterns or []
12+
self.crash_msg = None
413

514
@classmethod
615
def get_compiler_version(cls):
@@ -9,6 +18,25 @@ def get_compiler_version(cls):
918
def get_compiler_cmd(self):
1019
raise NotImplementedError('get_compiler_cmd() must be implemented')
1120

12-
def analyze_compiler_output(cls, output):
13-
raise NotImplementedError(
14-
'analyze_compiler_output() must be implemented')
21+
def get_filename(self, match):
22+
raise NotImplementedError('get_filename() must be implemented')
23+
24+
def get_error_msg(self, match):
25+
raise NotImplementedError('get_error_msg() must be implemented')
26+
27+
def analyze_compiler_output(self, output):
28+
failed = defaultdict(list)
29+
filtered_output = output
30+
for p in self.filter_patterns:
31+
filtered_output = re.sub(p, '', output)
32+
matches = re.findall(self.ERROR_REGEX, filtered_output)
33+
for match in matches:
34+
filename = self.get_filename(match)
35+
error_msg = self.get_error_msg(match)
36+
failed[filename].append(error_msg)
37+
38+
crash_match = re.search(self.CRASH_REGEX, filtered_output)
39+
if crash_match and not matches:
40+
self.crash_msg = output
41+
return None, matches
42+
return failed, matches

src/compilers/groovy.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from collections import defaultdict
21
import re
32
import os
43

@@ -13,10 +12,9 @@ class GroovyCompiler(BaseCompiler):
1312

1413
STACKOVERFLOW_REGEX = re.compile(r'(.*java.lang.StackOverflowError)(.*)')
1514

16-
def __init__(self, input_name):
15+
def __init__(self, input_name, filter_patterns=None):
1716
input_name = os.path.join(input_name, '*', '*.groovy')
18-
super().__init__(input_name)
19-
self.crash_msg = None
17+
super().__init__(input_name, filter_patterns)
2018

2119
@classmethod
2220
def get_compiler_version(cls):
@@ -25,23 +23,17 @@ def get_compiler_version(cls):
2523
def get_compiler_cmd(self):
2624
return ['groovyc', '--compile-static', self.input_name]
2725

28-
def analyze_compiler_output(self, output):
29-
self.crashed = None
30-
failed = defaultdict(list)
31-
matches = re.findall(self.ERROR_REGEX, output)
32-
for match in matches:
33-
filename = match[0]
34-
error_msg = match[1]
35-
failed[filename].append(error_msg)
36-
37-
crash_match = re.search(self.CRASH_REGEX, output)
38-
if crash_match and not matches:
39-
self.crash_msg = output
40-
return None
26+
def get_filename(self, match):
27+
return match[0]
4128

29+
def get_error_msg(self, match):
30+
return match[1]
31+
32+
def analyze_compiler_output(self, output):
33+
failed, matches = super().analyze_compiler_output(output)
4234
stack_overflow = re.search(self.STACKOVERFLOW_REGEX, output)
4335
if stack_overflow and not matches:
4436
self.crash_msg = output
45-
return None
37+
return None, matches
4638

47-
return failed
39+
return failed, matches

src/compilers/java.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from collections import defaultdict
21
import re
32
import os
43

@@ -12,10 +11,9 @@ class JavaCompiler(BaseCompiler):
1211

1312
CRASH_REGEX = re.compile(r'(java\.lang.*)\n(.*)')
1413

15-
def __init__(self, input_name):
14+
def __init__(self, input_name, filter_patterns=None):
1615
input_name = os.path.join(input_name, '*', '*.java')
17-
super().__init__(input_name)
18-
self.crash_msg = None
16+
super().__init__(input_name, filter_patterns)
1917

2018
@classmethod
2119
def get_compiler_version(cls):
@@ -24,17 +22,8 @@ def get_compiler_version(cls):
2422
def get_compiler_cmd(self):
2523
return ['javac', '-nowarn', self.input_name]
2624

27-
def analyze_compiler_output(self, output):
28-
self.crashed = None
29-
failed = defaultdict(list)
30-
matches = re.findall(self.ERROR_REGEX, output)
31-
for match in matches:
32-
filename = match[0]
33-
error_msg = match[1]
34-
failed[filename].append(error_msg)
35-
36-
crash_match = re.search(self.CRASH_REGEX, output)
37-
if crash_match and not matches:
38-
self.crash_msg = output
39-
return None
40-
return failed
25+
def get_filename(self, match):
26+
return match[0]
27+
28+
def get_error_msg(self, match):
29+
return match[1]

src/compilers/kotlin.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from collections import defaultdict
21
import re
32

43
from src.compilers.base import BaseCompiler
@@ -12,9 +11,8 @@ class KotlinCompiler(BaseCompiler):
1211
re.MULTILINE
1312
)
1413

15-
def __init__(self, input_name):
16-
super().__init__(input_name)
17-
self.crash_msg = None
14+
def __init__(self, input_name, filter_patterns=None):
15+
super().__init__(input_name, filter_patterns)
1816

1917
@classmethod
2018
def get_compiler_version(cls):
@@ -24,17 +22,8 @@ def get_compiler_cmd(self):
2422
return ['kotlinc', self.input_name, '-include-runtime', '-d',
2523
'program.jar']
2624

27-
def analyze_compiler_output(self, output):
28-
self.crashed = None
29-
failed = defaultdict(list)
30-
matches = re.findall(self.ERROR_REGEX, output)
31-
for match in matches:
32-
filename = match[0]
33-
error_msg = match[1]
34-
failed[filename].append(error_msg)
35-
36-
match = re.search(self.CRASH_REGEX, output)
37-
if match and not matches:
38-
self.crash_msg = ':'.join(match.groups())
39-
return None
40-
return failed
25+
def get_filename(self, match):
26+
return match[0]
27+
28+
def get_error_msg(self, match):
29+
return match[1]

src/utils.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ def save_text(path, text):
9494
out.write(text)
9595

9696

97-
def get_reserved_words(resource_path, language):
98-
filename = "{}_keywords".format(language)
99-
path = os.path.join(resource_path, filename)
97+
def path2set(path):
10098
if os.path.isfile(path):
10199
with open(path, 'r') as f:
102100
return {
@@ -107,6 +105,12 @@ def get_reserved_words(resource_path, language):
107105
return set()
108106

109107

108+
def get_reserved_words(resource_path, language):
109+
filename = "{}_keywords".format(language)
110+
path = os.path.join(resource_path, filename)
111+
return path2set(path)
112+
113+
110114
class RandomUtils():
111115

112116
resource_path = os.path.join(os.path.split(__file__)[0], "resources")

0 commit comments

Comments
 (0)