update compile error checker
git@afc91852902ef57d16fbdc7a91760e45b849469c
https://github.com/srz-zumix/iutest/commit/afc91852902ef57d16fbdc7a91760e45b849469c
support --command option
git@c1aa8bce246ec76eda8f3ed8e811a446c9fb9882
update .gitignore
git@bac1b721c097170f95d067239af1b2e3b288b694
update compiler error checker
git@33ced2b97503156ecd307015de9d7006fe073fa0
@@ -2,4 +2,4 @@ | ||
2 | 2 | *.png |
3 | 3 | *.css |
4 | 4 | benchmark/benchmark_n*.cpp |
5 | - | |
5 | +cpplint/cpplint.py |
@@ -79,5 +79,5 @@ | ||
79 | 79 | |
80 | 80 | $(COMPILEERROR_TARGETS) : $(SRCS) $(IUTEST_HEADERS) Makefile |
81 | 81 | # -$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) /Fe$@ $@.cpp $(LDFLAGS) |
82 | - $(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) /Fe$@ $@.cpp $(LDFLAGS) | python ../tools/python/iutest_compile_error_test.py -c $(CXX) | |
82 | + $(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) /Fe$@ $@.cpp $(LDFLAGS) | python ../tools/python/iutest_compile_error_test.py -c $(CXX) --verbose | |
83 | 83 |
@@ -1,415 +1,433 @@ | ||
1 | -#!/usr/bin/env python | |
2 | -# -*- coding: utf-8 -*- | |
3 | -# | |
4 | -# iutest_compiler_error_test.py | |
5 | -# | |
6 | -# Copyright (C) 2015-2016, Takazumi Shirayanagi | |
7 | -# This software is released under the new BSD License, | |
8 | -# see LICENSE | |
9 | -# | |
10 | - | |
11 | -import os | |
12 | -import sys | |
13 | -import argparse | |
14 | -import re | |
15 | - | |
16 | -from argparse import ArgumentParser | |
17 | - | |
18 | - | |
19 | -class ErrorMessage: | |
20 | - file = "" | |
21 | - line = 0 | |
22 | - type = "" | |
23 | - message = "" | |
24 | - parent = None | |
25 | - child = None | |
26 | - checked = False | |
27 | - | |
28 | - def set_type(self, str): | |
29 | - s = str.strip() | |
30 | - if s in {"error", u"エラー"}: | |
31 | - self.type = "error" | |
32 | - elif s in {"note", u"備考"}: | |
33 | - self.type = "note" | |
34 | - elif s in {"warning", u"警告"}: | |
35 | - self.type = "warning" | |
36 | - if s in {"error", "エラー"}: | |
37 | - self.type = "error" | |
38 | - elif s in {"note", "備考"}: | |
39 | - self.type = "note" | |
40 | - elif s in {"warning", "警告"}: | |
41 | - self.type = "warning" | |
42 | - else: | |
43 | - self.type = s | |
44 | - | |
45 | - def is_error(self): | |
46 | - if self.type == "error": | |
47 | - return True | |
48 | - return False | |
49 | - | |
50 | - def is_note(self): | |
51 | - if self.type == "note": | |
52 | - return True | |
53 | - return False | |
54 | - | |
55 | - def is_type_none(self): | |
56 | - if not self.type: | |
57 | - return True | |
58 | - return False | |
59 | - | |
60 | - def is_warning(self): | |
61 | - if self.type == "warning": | |
62 | - return True | |
63 | - return False | |
64 | - | |
65 | - def has_error(self): | |
66 | - if self.type == "error": | |
67 | - return True | |
68 | - elif self.parent and self.parent.has_error_parent(): | |
69 | - return True | |
70 | - elif self.child and self.child.has_error_child(): | |
71 | - return True | |
72 | - return False | |
73 | - | |
74 | - def has_error_parent(self): | |
75 | - if self.type == "error": | |
76 | - return True | |
77 | - elif self.parent: | |
78 | - return self.parent.has_error_parent() | |
79 | - return False | |
80 | - | |
81 | - def has_error_child(self): | |
82 | - if self.type == "error": | |
83 | - return True | |
84 | - elif self.child: | |
85 | - return self.child.has_error_child() | |
86 | - return False | |
87 | - | |
88 | - def is_checked(self): | |
89 | - if self.checked: | |
90 | - return True | |
91 | - elif self.parent: | |
92 | - return self.parent.is_checked() | |
93 | - return False | |
94 | - | |
95 | - def is_tail(self): | |
96 | - if self.child: | |
97 | - return False | |
98 | - return True | |
99 | - | |
100 | - def get_error(self): | |
101 | - if self.type == "error": | |
102 | - return self | |
103 | - if self.parent: | |
104 | - e = self.parent.get_error_parent() | |
105 | - if e: | |
106 | - return e | |
107 | - if self.child: | |
108 | - e = self.child.get_error_child() | |
109 | - if e: | |
110 | - return e | |
111 | - return None | |
112 | - | |
113 | - def get_error_parent(self): | |
114 | - if self.type == "error": | |
115 | - return self | |
116 | - elif self.parent: | |
117 | - return self.parent.get_error_parent() | |
118 | - return None | |
119 | - | |
120 | - def get_error_child(self): | |
121 | - if self.type == "error": | |
122 | - return self | |
123 | - elif self.child: | |
124 | - return self.child.get_error_child() | |
125 | - return None | |
126 | - | |
127 | -format_gcc = True | |
128 | -color_prompt = False | |
129 | - | |
130 | - | |
131 | -# command line option | |
132 | -def parse_command_line(): | |
133 | - parser = ArgumentParser() | |
134 | - parser.add_argument( | |
135 | - '-v', | |
136 | - '--version', | |
137 | - action='version', | |
138 | - version=u'%(prog)s version 0.3' | |
139 | - ) | |
140 | - parser.add_argument( | |
141 | - '-c', | |
142 | - '--compiler', | |
143 | - help='set compiler.', | |
144 | - default='gcc' | |
145 | - ) | |
146 | - parser.add_argument( | |
147 | - '--verbose', | |
148 | - action='store_true', | |
149 | - help='print input message.' | |
150 | - ) | |
151 | - parser.add_argument( | |
152 | - '--debug', | |
153 | - action='store_true', | |
154 | - help='debug.' | |
155 | - ) | |
156 | - if sys.version_info[0] >= 3: | |
157 | - parser.add_argument( | |
158 | - '-i', | |
159 | - '--infile', | |
160 | - type=argparse.FileType('r', encoding='UTF-8'), | |
161 | - help='compiler stdout.', | |
162 | - default=sys.stdin | |
163 | - ) | |
164 | - else: | |
165 | - parser.add_argument( | |
166 | - '-i', | |
167 | - '--infile', | |
168 | - type=argparse.FileType('r'), | |
169 | - help='compiler stdout.', | |
170 | - default=sys.stdin | |
171 | - ) | |
172 | - | |
173 | - options = parser.parse_args() | |
174 | - return options | |
175 | - | |
176 | - | |
177 | -def parse_gcc_clang(options, f, r_expansion, note_is_child): | |
178 | - re_fatal = re.compile(r'(\S+)\s*:\s*fatal\s*error\s*.*') | |
179 | - re_file = re.compile(r'(\S+):(\d+):(\d+)\s*:(.*)') | |
180 | - re_infile = re.compile(r'In file included from (\S+):(\d+):(\d+)(.*)') | |
181 | - re_message = re.compile(r'.*:\d+:\d+: (\S*): (.*)') | |
182 | - re_expansion = re.compile(r_expansion) | |
183 | - re_declaration = re.compile(r'.*declaration of\s*(.*)') | |
184 | - msg_list = [] | |
185 | - msg = None | |
186 | - prev = None | |
187 | - for line in f: | |
188 | - if options.verbose: | |
189 | - print(line) | |
190 | - if re_fatal.match(line): | |
191 | - raise Exception(line) | |
192 | - | |
193 | - m = re_file.match(line) | |
194 | - if not m: | |
195 | - m = re_infile.match(line) | |
196 | - | |
197 | - if m: | |
198 | - if msg: | |
199 | - msg_list.append(msg) | |
200 | - prev = msg | |
201 | - msg = ErrorMessage() | |
202 | - msg.file = m.group(1) | |
203 | - msg.line = int(m.group(2)) | |
204 | - msg.type = "" | |
205 | - n = re_message.match(line) | |
206 | - if n: | |
207 | - msg.set_type(n.group(1)) | |
208 | - msg.message += n.group(2) | |
209 | - else: | |
210 | - msg.set_type('') | |
211 | - msg.message += m.group(4) | |
212 | - | |
213 | - is_child = note_is_child and msg.is_note() | |
214 | - is_type_none = prev and prev.is_type_none() | |
215 | - is_declaration = False | |
216 | - n = re_declaration.match(line) | |
217 | - if n and prev and prev.message.find(n.group(1)) != -1: | |
218 | - is_declaration = True | |
219 | - | |
220 | - if prev: | |
221 | - if is_child or is_type_none or is_declaration or re_expansion.search(msg.message): | |
222 | - prev.child = msg | |
223 | - msg.parent = prev | |
224 | - else: | |
225 | - if msg: | |
226 | - msg.message += '\n' | |
227 | - msg.message += line | |
228 | - msg_list.append(msg) | |
229 | - return msg_list | |
230 | - | |
231 | - | |
232 | -def parse_gcc(options, f): | |
233 | - return parse_gcc_clang(options, f, r'in expansion of macro', False) | |
234 | - | |
235 | - | |
236 | -def parse_clang(options, f): | |
237 | - return parse_gcc_clang(options, f, r'expanded from ', True) | |
238 | - | |
239 | - | |
240 | -def parse_vc(options, f): | |
241 | - re_fatal = re.compile(r'(\S+)\s*:\s*fatal\s*error\s*.*') | |
242 | - re_file = re.compile(r'(\s*)(\S+)\((\d+)\)\s*:\s*(.*)') | |
243 | - re_message = re.compile(r'.*\(\d+\)\s*: (\S*) (\S*: .*)') | |
244 | - msg_list = [] | |
245 | - msg = None | |
246 | - prev = None | |
247 | - for line in f: | |
248 | - if options.verbose: | |
249 | - print(line) | |
250 | - if re_fatal.match(line): | |
251 | - raise Exception(line) | |
252 | - | |
253 | - m = re_file.match(line) | |
254 | - if m: | |
255 | - if msg: | |
256 | - msg_list.append(msg) | |
257 | - prev = msg | |
258 | - msg = ErrorMessage() | |
259 | - msg.file = m.group(2) | |
260 | - msg.line = int(m.group(3)) | |
261 | - msg.type = "" | |
262 | - n = re_message.match(line) | |
263 | - if n: | |
264 | - msg.set_type(n.group(1)) | |
265 | - msg.message += n.group(2) | |
266 | - else: | |
267 | - msg.set_type('') | |
268 | - msg.message += m.group(4) | |
269 | - | |
270 | - if m.group(1) and prev: | |
271 | - prev.child = msg | |
272 | - msg.parent = prev | |
273 | - else: | |
274 | - if msg: | |
275 | - msg.message += '\n' | |
276 | - msg.message += line | |
277 | - msg_list.append(msg) | |
278 | - return msg_list | |
279 | - | |
280 | - | |
281 | -def dump_msg(m): | |
282 | - if format_gcc: | |
283 | - if m.is_type_none(): | |
284 | - print("%s:%d: %s" % (m.file, m.line, m.message)) | |
285 | - else: | |
286 | - print("%s:%d: %s: %s" % (m.file, m.line, m.type, m.message)) | |
287 | - else: | |
288 | - if m.parent: | |
289 | - print("\t%s(%d): %s %s" % (m.file, m.line, m.type, m.message)) | |
290 | - else: | |
291 | - print("%s(%d): %s %s" % (m.file, m.line, m.type, m.message)) | |
292 | - | |
293 | - | |
294 | -def dump_msgs(m): | |
295 | - if m.parent: | |
296 | - dump_msgs(m.parent) | |
297 | - dump_msg(m) | |
298 | - | |
299 | - | |
300 | -def dump_list(l): | |
301 | - for m in l: | |
302 | - if not m.parent: | |
303 | - print('------------------------------') | |
304 | - dump_msg(m) | |
305 | - if not m.child: | |
306 | - print('------------------------------') | |
307 | - | |
308 | - return True | |
309 | - | |
310 | - | |
311 | -def test_result(result, msg, e): | |
312 | - OKGREEN = '\033[32m' | |
313 | -# WARNING = '\033[33m' | |
314 | - FAIL = '\033[31m' | |
315 | - ENDC = '\033[0m' | |
316 | - | |
317 | - if e: | |
318 | - msg += ': ' + e.file + ': ' + str(e.line) | |
319 | - | |
320 | - if result: | |
321 | - if color_prompt: | |
322 | - print(OKGREEN + '[OK] ' + ENDC + msg) | |
323 | - else: | |
324 | - print('[OK] ' + msg) | |
325 | - else: | |
326 | - if color_prompt: | |
327 | - print(FAIL + '[NG] ' + ENDC + msg) | |
328 | - else: | |
329 | - print('[NG] ' + msg) | |
330 | - | |
331 | - | |
332 | -def iutest(l): | |
333 | - result = True | |
334 | - re_iutest = re.compile(r'IUTEST_TEST_COMPILEERROR\( (.*) \)') | |
335 | - re_m = None | |
336 | - check = None | |
337 | - for msg in l: | |
338 | - if not msg: | |
339 | - continue | |
340 | - | |
341 | - mm = re_iutest.search(msg.message) | |
342 | - if mm: | |
343 | - if msg.parent: | |
344 | - continue | |
345 | - if check and not check.checked: | |
346 | - dump_msg(check) | |
347 | - dump_msg(msg) | |
348 | - test_result(False, re_m.group(0), check) | |
349 | - check = None | |
350 | - result = False | |
351 | - else: | |
352 | - check = msg | |
353 | - re_m = mm | |
354 | - elif msg.has_error(): | |
355 | - #print('%s - %d' % (msg.file, msg.line)) | |
356 | - if check and msg.file in check.file and msg.line == check.line + 1: | |
357 | - actual = msg.get_error() | |
358 | - expect = re_m.group(1).strip('"') | |
359 | - #print(actual.message) | |
360 | - if not expect or actual.message.find(expect) != -1: | |
361 | - check.checked = True | |
362 | - msg.checked = True | |
363 | - test_result(True, re_m.group(0), check) | |
364 | - elif msg.is_tail() and not msg.is_checked(): | |
365 | - dump_msgs(msg) | |
366 | - result = False | |
367 | - elif msg.is_warning(): | |
368 | - dump_msg(msg) | |
369 | - | |
370 | - if check and not check.checked: | |
371 | - test_result(False, re_m.group(0), check) | |
372 | - result = False | |
373 | - return result | |
374 | - | |
375 | - | |
376 | -def parse_output(options): | |
377 | - global format_gcc | |
378 | - l = None | |
379 | - if not options.infile: | |
380 | - raise Exception("infile null") | |
381 | - #print(options.infile.encoding) | |
382 | - f = options.infile | |
383 | - #f = codecs.getreader('utf-8')(options.infile) | |
384 | - | |
385 | - if any(options.compiler.find(s) != -1 for s in ('clang', 'clang++')): | |
386 | - l = parse_clang(options, f) | |
387 | - elif any(options.compiler.find(s) != -1 for s in ('gcc', 'g++')): | |
388 | - l = parse_gcc(options, f) | |
389 | - elif options.compiler == 'cl': | |
390 | - format_gcc = False | |
391 | - l = parse_vc(options, f) | |
392 | - else: | |
393 | - raise Exception("sorry, %s compiler is not supported", (options.compiler)) | |
394 | - | |
395 | - if options.debug: | |
396 | - dump_list(l) | |
397 | - return iutest(l) | |
398 | - | |
399 | - | |
400 | -def setup(): | |
401 | - global color_prompt | |
402 | - term = os.environ.get('TERM') | |
403 | - if term: | |
404 | - if any(term.find(s) for s in ('xterm', 'screen', 'rxvt', 'linux', 'cygwin')): | |
405 | - color_prompt = True | |
406 | - | |
407 | - | |
408 | -def main(): | |
409 | - options = parse_command_line() | |
410 | - setup() | |
411 | - if not parse_output(options): | |
412 | - sys.exit(1) | |
413 | - | |
414 | -if __name__ == '__main__': | |
415 | - main() | |
1 | +#!/usr/bin/env python | |
2 | +# -*- coding: utf-8 -*- | |
3 | +# | |
4 | +# iutest_compiler_error_test.py | |
5 | +# | |
6 | +# Copyright (C) 2015-2016, Takazumi Shirayanagi | |
7 | +# This software is released under the new BSD License, | |
8 | +# see LICENSE | |
9 | +# | |
10 | + | |
11 | +import os | |
12 | +import sys | |
13 | +import argparse | |
14 | +import re | |
15 | + | |
16 | +from argparse import ArgumentParser | |
17 | +from subprocess import Popen, PIPE, STDOUT | |
18 | + | |
19 | + | |
20 | +class ErrorMessage: | |
21 | + file = "" | |
22 | + line = 0 | |
23 | + type = "" | |
24 | + message = "" | |
25 | + parent = None | |
26 | + child = None | |
27 | + checked = False | |
28 | + | |
29 | + def set_type(self, str): | |
30 | + s = str.strip() | |
31 | + if s in {"error", u"エラー"}: | |
32 | + self.type = "error" | |
33 | + elif s in {"note", u"備考"}: | |
34 | + self.type = "note" | |
35 | + elif s in {"warning", u"警告"}: | |
36 | + self.type = "warning" | |
37 | + if s in {"error", "エラー"}: | |
38 | + self.type = "error" | |
39 | + elif s in {"note", "備考"}: | |
40 | + self.type = "note" | |
41 | + elif s in {"warning", "警告"}: | |
42 | + self.type = "warning" | |
43 | + else: | |
44 | + self.type = s | |
45 | + | |
46 | + def is_error(self): | |
47 | + if self.type == "error": | |
48 | + return True | |
49 | + return False | |
50 | + | |
51 | + def is_note(self): | |
52 | + if self.type == "note": | |
53 | + return True | |
54 | + return False | |
55 | + | |
56 | + def is_iutest(self): | |
57 | + if self.is_note() and self.message.find("IUTEST_TEST_COMPILEERROR") != -1: | |
58 | + return True | |
59 | + return False | |
60 | + | |
61 | + def is_type_none(self): | |
62 | + if not self.type: | |
63 | + return True | |
64 | + return False | |
65 | + | |
66 | + def is_warning(self): | |
67 | + if self.type == "warning": | |
68 | + return True | |
69 | + return False | |
70 | + | |
71 | + def has_error(self): | |
72 | + if self.type == "error": | |
73 | + return True | |
74 | + elif self.parent and self.parent.has_error_parent(): | |
75 | + return True | |
76 | + elif self.child and self.child.has_error_child(): | |
77 | + return True | |
78 | + return False | |
79 | + | |
80 | + def has_error_parent(self): | |
81 | + if self.type == "error": | |
82 | + return True | |
83 | + elif self.parent: | |
84 | + return self.parent.has_error_parent() | |
85 | + return False | |
86 | + | |
87 | + def has_error_child(self): | |
88 | + if self.type == "error": | |
89 | + return True | |
90 | + elif self.child: | |
91 | + return self.child.has_error_child() | |
92 | + return False | |
93 | + | |
94 | + def is_checked(self): | |
95 | + if self.checked: | |
96 | + return True | |
97 | + elif self.parent: | |
98 | + return self.parent.is_checked() | |
99 | + return False | |
100 | + | |
101 | + def is_tail(self): | |
102 | + if self.child: | |
103 | + return False | |
104 | + return True | |
105 | + | |
106 | + def get_error(self): | |
107 | + if self.type == "error": | |
108 | + return self | |
109 | + if self.parent: | |
110 | + e = self.parent.get_error_parent() | |
111 | + if e: | |
112 | + return e | |
113 | + if self.child: | |
114 | + e = self.child.get_error_child() | |
115 | + if e: | |
116 | + return e | |
117 | + return None | |
118 | + | |
119 | + def get_error_parent(self): | |
120 | + if self.type == "error": | |
121 | + return self | |
122 | + elif self.parent: | |
123 | + return self.parent.get_error_parent() | |
124 | + return None | |
125 | + | |
126 | + def get_error_child(self): | |
127 | + if self.type == "error": | |
128 | + return self | |
129 | + elif self.child: | |
130 | + return self.child.get_error_child() | |
131 | + return None | |
132 | + | |
133 | +format_gcc = True | |
134 | +color_prompt = False | |
135 | + | |
136 | + | |
137 | +# command line option | |
138 | +def parse_command_line(): | |
139 | + parser = ArgumentParser() | |
140 | + parser.add_argument( | |
141 | + '-v', | |
142 | + '--version', | |
143 | + action='version', | |
144 | + version=u'%(prog)s version 0.3' | |
145 | + ) | |
146 | + parser.add_argument( | |
147 | + '-c', | |
148 | + '--compiler', | |
149 | + help='set compiler.', | |
150 | + default='gcc' | |
151 | + ) | |
152 | + parser.add_argument( | |
153 | + '--verbose', | |
154 | + action='store_true', | |
155 | + help='print input message.' | |
156 | + ) | |
157 | + parser.add_argument( | |
158 | + '--debug', | |
159 | + action='store_true', | |
160 | + help='debug.' | |
161 | + ) | |
162 | + parser.add_argument( | |
163 | + '--command', | |
164 | + help='execute command.', | |
165 | + default=None | |
166 | + ) | |
167 | + if sys.version_info[0] >= 3: | |
168 | + parser.add_argument( | |
169 | + '-i', | |
170 | + '--infile', | |
171 | + type=argparse.FileType('r', encoding='UTF-8'), | |
172 | + help='compiler stdout.', | |
173 | + default=sys.stdin | |
174 | + ) | |
175 | + else: | |
176 | + parser.add_argument( | |
177 | + '-i', | |
178 | + '--infile', | |
179 | + type=argparse.FileType('r'), | |
180 | + help='compiler stdout.', | |
181 | + default=sys.stdin | |
182 | + ) | |
183 | + | |
184 | + options = parser.parse_args() | |
185 | + return options | |
186 | + | |
187 | + | |
188 | +def parse_gcc_clang(options, f, r_expansion, note_is_child): | |
189 | + re_fatal = re.compile(r'(\S+)\s*:\s*fatal\s*error\s*.*') | |
190 | + re_file = re.compile(r'(\S+):(\d+):(\d+)\s*:(.*)') | |
191 | + re_infile = re.compile(r'In file included from (\S+):(\d+):(\d+)(.*)') | |
192 | + re_message = re.compile(r'.*:\d+:\d+: (\S*): (.*)') | |
193 | + re_expansion = re.compile(r_expansion) | |
194 | + re_declaration = re.compile(r'.*declaration of\s*(.*)') | |
195 | + msg_list = [] | |
196 | + msg = None | |
197 | + prev = None | |
198 | + for line in f: | |
199 | + if options.verbose: | |
200 | + print(line) | |
201 | + if re_fatal.match(line): | |
202 | + raise Exception(line) | |
203 | + | |
204 | + m = re_file.match(line) | |
205 | + if not m: | |
206 | + m = re_infile.match(line) | |
207 | + | |
208 | + if m: | |
209 | + if msg: | |
210 | + msg_list.append(msg) | |
211 | + prev = msg | |
212 | + msg = ErrorMessage() | |
213 | + msg.file = m.group(1) | |
214 | + msg.line = int(m.group(2)) | |
215 | + msg.type = "" | |
216 | + n = re_message.match(line) | |
217 | + if n: | |
218 | + msg.set_type(n.group(1)) | |
219 | + msg.message += n.group(2) | |
220 | + else: | |
221 | + msg.set_type('') | |
222 | + msg.message += m.group(4) | |
223 | + | |
224 | + is_child = note_is_child and msg.is_note() | |
225 | + is_type_none = prev and prev.is_type_none() | |
226 | + is_declaration = False | |
227 | + n = re_declaration.match(line) | |
228 | + if n and prev and prev.message.find(n.group(1)) != -1: | |
229 | + is_declaration = True | |
230 | + | |
231 | + if prev: | |
232 | + if is_child or is_type_none or is_declaration or re_expansion.search(msg.message): | |
233 | + prev.child = msg | |
234 | + msg.parent = prev | |
235 | + else: | |
236 | + if msg: | |
237 | + msg.message += '\n' | |
238 | + msg.message += line | |
239 | + msg_list.append(msg) | |
240 | + return msg_list | |
241 | + | |
242 | + | |
243 | +def parse_gcc(options, f): | |
244 | + return parse_gcc_clang(options, f, r'in expansion of macro', False) | |
245 | + | |
246 | + | |
247 | +def parse_clang(options, f): | |
248 | + return parse_gcc_clang(options, f, r'expanded from ', True) | |
249 | + | |
250 | + | |
251 | +def parse_vc(options, f): | |
252 | + re_fatal = re.compile(r'(\S+)\s*:\s*fatal\s*error\s*.*') | |
253 | + re_file = re.compile(r'(\s*)(\S+)\((\d+)\)\s*:\s*(.*)') | |
254 | + re_message = re.compile(r'.*\(\d+\)\s*: (\S*)\s*(\S*: .*)') | |
255 | + msg_list = [] | |
256 | + msg = None | |
257 | + prev = None | |
258 | + for line in f: | |
259 | + if options.verbose: | |
260 | + print(line) | |
261 | + if re_fatal.match(line): | |
262 | + raise Exception(line) | |
263 | + | |
264 | + m = re_file.match(line) | |
265 | + if m: | |
266 | + if msg: | |
267 | + msg_list.append(msg) | |
268 | + prev = msg | |
269 | + msg = ErrorMessage() | |
270 | + msg.file = m.group(2) | |
271 | + msg.line = int(m.group(3)) | |
272 | + msg.type = "" | |
273 | + n = re_message.match(line) | |
274 | + if n: | |
275 | + msg.set_type(n.group(1)) | |
276 | + msg.message += n.group(2) | |
277 | + else: | |
278 | + msg.set_type('') | |
279 | + msg.message += m.group(4) | |
280 | + | |
281 | + child_note = m.group(1) or (msg.is_note() and not msg.is_iutest()) | |
282 | + if (m.group(1) or child_note) and prev: | |
283 | + prev.child = msg | |
284 | + msg.parent = prev | |
285 | + else: | |
286 | + if msg: | |
287 | + msg.message += '\n' | |
288 | + msg.message += line | |
289 | + msg_list.append(msg) | |
290 | + return msg_list | |
291 | + | |
292 | + | |
293 | +def dump_msg(m): | |
294 | + if format_gcc: | |
295 | + if m.is_type_none(): | |
296 | + print("%s:%d: %s" % (m.file, m.line, m.message)) | |
297 | + else: | |
298 | + print("%s:%d: %s: %s" % (m.file, m.line, m.type, m.message)) | |
299 | + else: | |
300 | + if m.parent: | |
301 | + print("\t%s(%d): %s %s" % (m.file, m.line, m.type, m.message)) | |
302 | + else: | |
303 | + print("%s(%d): %s %s" % (m.file, m.line, m.type, m.message)) | |
304 | + | |
305 | + | |
306 | +def dump_msgs(m): | |
307 | + if m.parent: | |
308 | + dump_msgs(m.parent) | |
309 | + dump_msg(m) | |
310 | + | |
311 | + | |
312 | +def dump_list(l): | |
313 | + for m in l: | |
314 | + if not m.parent: | |
315 | + print('------------------------------') | |
316 | + dump_msg(m) | |
317 | + if not m.child: | |
318 | + print('------------------------------') | |
319 | + | |
320 | + return True | |
321 | + | |
322 | + | |
323 | +def test_result(result, msg, e): | |
324 | + OKGREEN = '\033[32m' | |
325 | +# WARNING = '\033[33m' | |
326 | + FAIL = '\033[31m' | |
327 | + ENDC = '\033[0m' | |
328 | + | |
329 | + if e: | |
330 | + msg += ': ' + e.file + ': ' + str(e.line) | |
331 | + | |
332 | + if result: | |
333 | + if color_prompt: | |
334 | + print(OKGREEN + '[OK] ' + ENDC + msg) | |
335 | + else: | |
336 | + print('[OK] ' + msg) | |
337 | + else: | |
338 | + if color_prompt: | |
339 | + print(FAIL + '[NG] ' + ENDC + msg) | |
340 | + else: | |
341 | + print('[NG] ' + msg) | |
342 | + | |
343 | + | |
344 | +def iutest(l): | |
345 | + result = True | |
346 | + re_iutest = re.compile(r'IUTEST_TEST_COMPILEERROR\( (.*) \)') | |
347 | + re_m = None | |
348 | + check = None | |
349 | + for msg in l: | |
350 | + if not msg: | |
351 | + continue | |
352 | + | |
353 | + mm = re_iutest.search(msg.message) | |
354 | + if mm: | |
355 | + if msg.parent: | |
356 | + continue | |
357 | + if check and not check.checked: | |
358 | + dump_msg(check) | |
359 | + dump_msg(msg) | |
360 | + test_result(False, re_m.group(0), check) | |
361 | + result = False | |
362 | + check = msg | |
363 | + re_m = mm | |
364 | + elif msg.has_error(): | |
365 | + #print('%s - %d' % (msg.file, msg.line)) | |
366 | + if check and msg.file in check.file and msg.line == check.line + 1: | |
367 | + actual = msg.get_error() | |
368 | + expect = re_m.group(1).strip('"') | |
369 | + #print(actual.message) | |
370 | + if not expect or actual.message.find(expect) != -1: | |
371 | + check.checked = True | |
372 | + msg.checked = True | |
373 | + test_result(True, re_m.group(0), check) | |
374 | + elif msg.is_tail() and not msg.is_checked(): | |
375 | + dump_msgs(msg) | |
376 | + result = False | |
377 | + elif msg.is_warning(): | |
378 | + dump_msg(msg) | |
379 | + | |
380 | + if check and not check.checked: | |
381 | + test_result(False, re_m.group(0), check) | |
382 | + result = False | |
383 | + return result | |
384 | + | |
385 | + | |
386 | +def parse_output(options): | |
387 | + global format_gcc | |
388 | + l = None | |
389 | + if options.command: | |
390 | + args = re.split('\s+', options.command) | |
391 | + for i in range(len(args)): | |
392 | + args[i] = os.path.expandvars(args[i]) | |
393 | + p = Popen(args, stdout=PIPE, stderr=STDOUT) | |
394 | + p.wait() | |
395 | + out, err = p.communicate() | |
396 | + f = out.splitlines() | |
397 | + else: | |
398 | + if not options.infile: | |
399 | + raise Exception("infile null") | |
400 | + #print(options.infile.encoding) | |
401 | + f = options.infile | |
402 | + #f = codecs.getreader('utf-8')(options.infile) | |
403 | + | |
404 | + if any(options.compiler.find(s) != -1 for s in ('clang', 'clang++')): | |
405 | + l = parse_clang(options, f) | |
406 | + elif any(options.compiler.find(s) != -1 for s in ('gcc', 'g++')): | |
407 | + l = parse_gcc(options, f) | |
408 | + elif options.compiler == 'cl': | |
409 | + format_gcc = False | |
410 | + l = parse_vc(options, f) | |
411 | + else: | |
412 | + raise Exception("sorry, %s compiler is not supported", (options.compiler)) | |
413 | + | |
414 | + if options.debug: | |
415 | + dump_list(l) | |
416 | + return iutest(l) | |
417 | + | |
418 | + | |
419 | +def setup(): | |
420 | + global color_prompt | |
421 | + term = os.environ.get('TERM') | |
422 | + if term: | |
423 | + if any(term.find(s) for s in ('xterm', 'screen', 'rxvt', 'linux', 'cygwin')): | |
424 | + color_prompt = True | |
425 | + | |
426 | +def main(): | |
427 | + options = parse_command_line() | |
428 | + setup() | |
429 | + if not parse_output(options): | |
430 | + sys.exit(1) | |
431 | + | |
432 | +if __name__ == '__main__': | |
433 | + main() |