-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror_parser.py
More file actions
126 lines (104 loc) · 4.01 KB
/
Copy patherror_parser.py
File metadata and controls
126 lines (104 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import re
import sys
from pathlib import Path
from typing import Dict, List, NamedTuple
def format_error(message):
return f"ERROR: {message}"
def format_warning(message):
return f"WARNING: {message}"
class BuildError(NamedTuple):
file: str
line: int
col: int
type: str
message: str
symbol: str = ""
first_defined: str = ""
class ErrorParser:
def __init__(self):
self.errors: List[BuildError] = []
self.multiple_defs: Dict[str, List[str]] = {}
# Compile regex patterns
self.linker_pattern = re.compile(
r"(?P<file>.+?):(?P<line>\d+):(?P<col>\d+):\s*(?P<type>warning|error):\s*(?P<message>.+)"
)
self.multiple_def_pattern = re.compile(
r'(?P<file>.+?):\(.+?\):\s*multiple definition of\s*[\'"](?P<symbol>.+?)[\'"];\s*(?P<first_def>.+?):\s*first defined here'
)
def parse_line(self, line: str) -> None:
# Check for multiple definition errors
multiple_def_match = self.multiple_def_pattern.match(line)
if multiple_def_match:
groups = multiple_def_match.groupdict()
symbol = groups["symbol"]
if symbol not in self.multiple_defs:
self.multiple_defs[symbol] = []
self.multiple_defs[symbol].append(groups["file"])
self.errors.append(
BuildError(
file=groups["file"],
line=0,
col=0,
type="error",
message=f"Multiple definition of '{symbol}', first defined in {groups['first_def']}",
symbol=symbol,
first_defined=groups["first_def"],
)
)
return
# Check for regular compiler/linker errors
linker_match = self.linker_pattern.match(line)
if linker_match:
groups = linker_match.groupdict()
self.errors.append(
BuildError(
file=groups["file"],
line=int(groups["line"]),
col=int(groups["col"]),
type=groups["type"],
message=groups["message"],
)
)
def print_summary(self) -> None:
if not self.errors:
print(colored("✓ Build successful - no errors found", "green"))
return
print("\n=== Build Error Summary ===\n")
# Group errors by file
errors_by_file: Dict[str, List[BuildError]] = {}
for error in self.errors:
if error.file not in errors_by_file:
errors_by_file[error.file] = []
errors_by_file[error.file].append(error)
# Print errors grouped by file
for file, errors in errors_by_file.items():
print(colored(f"\nFile: {file}", "cyan"))
for error in errors:
color = "red" if error.type == "error" else "yellow"
if error.symbol: # Multiple definition error
print(
colored(f" ↳ Multiple definition of '{error.symbol}'", color)
)
print(f" First defined in: {error.first_defined}")
else: # Regular error
print(
colored(
f" ↳ {error.type.upper()} at line {error.line}:", color
)
)
print(f" {error.message}")
# Print statistics
total_errors = len([e for e in self.errors if e.type == "error"])
total_warnings = len([e for e in self.errors if e.type == "warning"])
print(
f"\nTotal: {colored(f'{total_errors} errors', 'red')}, "
f"{colored(f'{total_warnings} warnings', 'yellow')}"
)
def main():
parser = ErrorParser()
# Read from stdin if no file provided
for line in sys.stdin:
parser.parse_line(line.strip())
parser.print_summary()
if __name__ == "__main__":
main()