Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ytomino
Last active January 12, 2022 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ytomino/68599bd68d8b0d2691ad3c9de5826004 to your computer and use it in GitHub Desktop.
Save ytomino/68599bd68d8b0d2691ad3c9de5826004 to your computer and use it in GitHub Desktop.
The reformatter for compiler's error messsages
#!/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