Last active
January 12, 2022 22:21
-
-
Save ytomino/68599bd68d8b0d2691ad3c9de5826004 to your computer and use it in GitHub Desktop.
The reformatter for compiler's error messsages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import fnmatch | |
import os | |
import re | |
import sys | |
msgtype = "gcc" | |
rootdir = os.getcwd() | |
workdir = rootdir | |
linkdict = {} | |
def readlink(source): | |
global linkdict, rootdir, workdir | |
if source in linkdict: | |
return linkdict[source] | |
else: | |
target = source | |
while True: | |
old = target | |
try: | |
target = os.readlink(old) | |
except OSError: | |
break | |
if target[0] != '/': | |
target = os.path.normpath( \ | |
os.path.join( \ | |
os.path.dirname(old), \ | |
target)) | |
#print rootdir, workdir, target | |
if target[0] != '/' and rootdir != workdir: | |
target = os.path.join(workdir, target) | |
if target[0] == '/': | |
target = os.path.relpath(target, rootdir) | |
linkdict[source] = target | |
return target | |
opened_file = None | |
opened_file_line = 0 | |
opened_file_s = "" | |
def fixcol(source, line, col): | |
global msgtype, opened_file, opened_file_line, opened_file_s | |
if msgtype == "ocaml": | |
return col + 1 | |
if opened_file \ | |
and (opened_file.name != source or opened_file_line > line): | |
opened_file.close() | |
opened_file = None | |
if opened_file is None: | |
opened_file = open(source, "r") | |
opened_file_line = 0 | |
while opened_file_line < line: | |
opened_file_s = opened_file.readline() | |
opened_file_line += 1 | |
tabwdith = 8 | |
col1 = 1 | |
col8 = 1 | |
while col8 < col: | |
try: | |
c = opened_file_s[col1 - 1] | |
except IndexError: | |
return None | |
if c == '\t': | |
col8 += tabwdith - (col8 - 1) % tabwdith | |
else: | |
col8 += 1 | |
col1 += 1 | |
if col1 < len(opened_file_s) and opened_file_s[col1 - 1] == '.': | |
col1 += 1 # fix "." included into a next identifier | |
return col1 # for vscode | |
fixcol_filter = [] | |
def have_to_fixcol(source): | |
global fixcol_filter | |
for i in fixcol_filter: | |
if fnmatch.fnmatch(source, i): | |
return True | |
return False | |
def parse_args(): | |
global msgtype, rootdir, workdir, fixcol_filter | |
i = 1 | |
while i < len(sys.argv): | |
if sys.argv[i] == "--ocaml": | |
msgtype = "ocaml" | |
elif sys.argv[i] == "--root": | |
i += 1 | |
rootdir = sys.argv[i] | |
elif sys.argv[i] == "--cd" or sys.argv[i] == '-C': | |
i += 1 | |
workdir = sys.argv[i] | |
elif sys.argv[i] == '--fixcol': | |
i += 1 | |
fixcol_filter.append(sys.argv[i]) | |
elif sys.argv[i][0] == '-': | |
raise Exception | |
i = i + 1 | |
parse_args() | |
if msgtype == "ocaml": | |
errhea_re = None | |
anyhea_re = re.compile(r"^File \"([^:\"]*)\", lines? (\d+)(?:-\d+)?, " \ | |
+ r"characters (\d+)-(?P<endcol>\d+):$") | |
locmsg_re = re.compile(r"^(\d+ \|| +\^)") | |
errmsg_re = re.compile(r"^(?P<level>Error):") | |
anymsg_re = re.compile(r"^(?:(?P<level>Alert \w+:|Warning \d+:)" \ | |
+ "|[A-Z]|$|stdlib-shims library:)") | |
else: | |
errhea_re = re.compile(r"^([^:\"]+):(\d+)(?::(\d+)?):? (?P<level>(?:error:)?)") | |
anyhea_re = re.compile(r"^([^:\"]+):(\d+)(?::(\d+)?):? " \ | |
+ "(?P<level>warning|note):") | |
locmsg_re = re.compile(r"^ ") | |
errmsg_re = None | |
anymsg_re = None | |
makemsg_re = re.compile(r"^Makefile:\d+: recipe for target .* failed$" \ | |
+ r"|^make(?:\[\d+\])?: " \ | |
+ r"|^error: ocamldep.opt ") # ocamlmake | |
def ein(level): | |
if level == 'E': | |
return "\x1b[91m" | |
else: | |
return "\x1b[95m" | |
has_error = False | |
in_error = None | |
for s in sys.stdin: | |
makemsg = makemsg_re.match(s) | |
result = None | |
location_msg = None | |
additional_msg = None | |
if makemsg is None: | |
result = anyhea_re.match(s) | |
if result: | |
in_error = 'L' | |
if result is None and errhea_re: | |
result = errhea_re.match(s) | |
if result: | |
in_error = 'E' | |
if result is None and in_error: | |
if in_error != 'A': | |
location_msg = locmsg_re.match(s) | |
if location_msg is None \ | |
and errmsg_re \ | |
and in_error == 'L': | |
additional_msg = errmsg_re.match(s) | |
if additional_msg: | |
in_error = 'E' | |
if location_msg is None \ | |
and additional_msg is None \ | |
and anymsg_re: | |
additional_msg = anymsg_re.match(s) | |
if additional_msg and in_error == 'L': | |
in_error = 'A' | |
if location_msg is None and additional_msg is None: | |
in_error = None | |
if result: | |
source = result.group(1) # filename | |
target = readlink(source) | |
line = int(result.group(2)) | |
resetted = False | |
# level | |
try: | |
(s5, e5) = result.span('level') | |
except IndexError: | |
(s5, e5) = (-1, -1) | |
if s5 >= 0: | |
s = s[:s5] + ein(in_error) + s[s5:e5] + "\x1b[0m" + s[e5:] | |
resetted = True | |
# endcol | |
try: | |
(s4, e4) = result.span('endcol') | |
except IndexError: | |
(s4, e4) = (-1, -1) | |
if s4 >= 0 and have_to_fixcol(target): | |
endcol = int(result.group(4)) | |
endcol = fixcol(target, line, endcol) | |
if endcol: | |
s = s[:s4] + str(endcol) + s[e4:] | |
else: | |
s = s[:s4 - 1] + s[e4:] | |
# col | |
(s3, e3) = result.span(3) | |
if s3 >= 0: | |
col = int(result.group(3)) | |
if have_to_fixcol(target): | |
col = fixcol(target, line, col) | |
if col: | |
s = s[:s3] + str(col) + s[e3:] | |
else: | |
s = s[:s3 - 1] + s[e3:] | |
if target != source: | |
s = s[:result.start(1)] + target + s[result.end(1):] | |
sys.stdout.write("\x1b[97m") | |
if msgtype == "ocaml": | |
msg = target + ":" + str(line) + ":" + str(col) + ":\n" | |
sys.stdout.write(msg) | |
sys.stdout.write("\x1b[0m") | |
resetted = True | |
sys.stdout.write(s) | |
if not resetted: | |
sys.stdout.write("\x1b[0m") | |
sys.stdout.flush() | |
has_error = True | |
elif location_msg: | |
sys.stdout.write(s) | |
sys.stdout.flush() | |
elif additional_msg: | |
try: | |
(s1, e1) = additional_msg.span('level') | |
except IndexError: | |
(s1, e1) = (-1, -1) | |
if s1 >= 0: | |
sys.stdout.write(ein(in_error)) | |
sys.stdout.write(s[:e1]) | |
sys.stdout.write("\x1b[0m") | |
sys.stdout.write(s[e1:]) | |
else: | |
sys.stdout.write(s) | |
sys.stdout.flush() | |
elif not has_error or not makemsg: | |
sys.stdout.write("\x1b[37m") | |
sys.stdout.write(s) | |
sys.stdout.write("\x1b[0m") | |
sys.stdout.flush() | |
if opened_file: | |
opened_file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment