mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
8b12553d15
Effects the following files: - [x] vehicle-rider - [x] vehicle-control - [x] vehicle-effects - [x] vehicle ~~- [ ] vehicle-util~~ - [x] vehicle-physics - [x] vehicle-states ~~- [ ] vehicle-guard~~ ~~- [ ] traffic-engine~~ ~~- [ ] traffic-manager~~ With the exception of traffic-engine, most of these files are either done or have 1-3 stubborn functions remaining. Draft while I try to resolve as many as possible / cleanup names and such. Co-authored-by: water <awaterford111445@gmail.com>
160 lines
5.2 KiB
Python
160 lines
5.2 KiB
Python
import re
|
|
import argparse
|
|
from utils import get_gsrc_path_from_filename
|
|
from colorama import just_fix_windows_console, Fore, Back, Style
|
|
|
|
just_fix_windows_console()
|
|
|
|
parser = argparse.ArgumentParser("lint-gsrc-file")
|
|
parser.add_argument("--game", help="The name of the game", type=str)
|
|
parser.add_argument("--file", help="The name of the file", type=str)
|
|
args = parser.parse_args()
|
|
|
|
|
|
class LintMatch:
|
|
def __init__(self, src_path, offending_lineno, context):
|
|
self.src_path = src_path
|
|
self.offending_lineno = offending_lineno
|
|
self.context = context
|
|
|
|
def __str__(self):
|
|
output = (
|
|
Style.BRIGHT
|
|
+ Fore.MAGENTA
|
|
+ "@ {}:{}\n".format(self.src_path, self.offending_lineno)
|
|
+ Fore.RESET
|
|
+ Style.RESET_ALL
|
|
)
|
|
for line in self.context:
|
|
# skip lines that are just brackets
|
|
if line.strip() == ")" or line.strip() == "(":
|
|
continue
|
|
output += "\t{}\n".format(line)
|
|
return output
|
|
|
|
|
|
class LinterRule:
|
|
def __init__(self, level, rule_name, regex_pattern, context_size):
|
|
self.level = level
|
|
self.rule_name = rule_name
|
|
self.regex_pattern = regex_pattern
|
|
self.context_size = context_size
|
|
self.matches = []
|
|
|
|
def __str__(self):
|
|
level_color = Fore.LIGHTBLUE_EX
|
|
if self.level == "WARN":
|
|
level_color = Fore.YELLOW
|
|
elif self.level == "ERROR":
|
|
level_color = Fore.RED
|
|
return (
|
|
level_color
|
|
+ "[{}]{} - {} - {}/{}/g".format(
|
|
self.level,
|
|
Fore.RESET,
|
|
level_color + self.rule_name + Fore.RESET,
|
|
Fore.CYAN,
|
|
self.regex_pattern.pattern,
|
|
)
|
|
+ Fore.RESET
|
|
+ ":"
|
|
)
|
|
|
|
|
|
# Construct all rules
|
|
linter_rules = []
|
|
# Infos
|
|
# Warnings
|
|
linter_rules.append(
|
|
LinterRule("WARN", "method_splits", re.compile("method-of-(?:type|object)"), 3)
|
|
)
|
|
linter_rules.append(
|
|
LinterRule("WARN", "func_splits", re.compile("\(t9-\d+(?:\s+[^\s]+\s*)?\)"), 3)
|
|
)
|
|
linter_rules.append(
|
|
LinterRule("WARN", "missing_arg", re.compile("local-vars.*[at].*\s+none\)"), 1)
|
|
)
|
|
# Errors
|
|
linter_rules.append(LinterRule("ERROR", "missing_res_tag", re.compile(".pcpyud"), 1))
|
|
linter_rules.append(LinterRule("ERROR", "decomp_error", re.compile(";; ERROR"), 1))
|
|
linter_rules.append(
|
|
LinterRule(
|
|
"ERROR", "casting_stack_var", re.compile("the-as\s+[^\s]*\s+.*\(new 'stack"), 2
|
|
)
|
|
)
|
|
|
|
src_path = get_gsrc_path_from_filename(args.game, args.file)
|
|
|
|
# Iterate through the file line by line, check against each rule
|
|
# if the rule is violated (it matches) then we append the match with useful details
|
|
|
|
print("Linting GOAL_SRC File...")
|
|
|
|
|
|
def get_context(lines, match_span, idx, amount_inclusive):
|
|
lines_grabbed = []
|
|
# Strip left pad, while maintaining indent
|
|
last_line_indent_width = -1
|
|
last_line_indent = -1
|
|
while len(lines_grabbed) < amount_inclusive and len(lines) > idx + len(
|
|
lines_grabbed
|
|
):
|
|
# TODO - first line, colorize the match
|
|
# if len(lines_grabbed) == 0:
|
|
# line = lines[idx + len(lines_grabbed)]
|
|
# line = line[:match_span[0]] + Back.RED + line[:match_span[1]] + Back.RESET + line[match_span[1]:]
|
|
# line = line.rstrip()
|
|
line = lines[idx + len(lines_grabbed)].rstrip()
|
|
indent_width = len(line) - len(line.lstrip())
|
|
if last_line_indent_width == -1:
|
|
lines_grabbed.append(line.lstrip())
|
|
elif last_line_indent == -1:
|
|
# calculate the difference
|
|
indent_diff = indent_width - last_line_indent_width
|
|
last_line_indent = indent_diff
|
|
stripped_line = line.lstrip()
|
|
lines_grabbed.append(stripped_line.rjust(indent_diff + len(stripped_line)))
|
|
else:
|
|
stripped_line = line.lstrip()
|
|
lines_grabbed.append(
|
|
stripped_line.rjust(last_line_indent + len(stripped_line))
|
|
)
|
|
last_line_indent_width = indent_width
|
|
return lines_grabbed
|
|
|
|
|
|
with open(src_path) as f:
|
|
src_lines = f.readlines()
|
|
for lineno, line in enumerate(src_lines):
|
|
adjusted_lineno = lineno + 1
|
|
for rule in linter_rules:
|
|
match = rule.regex_pattern.search(line)
|
|
if match:
|
|
rule.matches.append(
|
|
LintMatch(
|
|
src_path,
|
|
adjusted_lineno,
|
|
get_context(src_lines, match.span(), lineno, rule.context_size),
|
|
)
|
|
)
|
|
|
|
# Iterate through all our linter rules, printing nicely in groups with the
|
|
# context surrounding the match
|
|
#
|
|
# If we find any violations at warning or above, we will ultimately return exit(1)
|
|
throw_error = False
|
|
for rule in linter_rules:
|
|
# Iterate through violations
|
|
if len(rule.matches) > 0:
|
|
print(rule)
|
|
for match in rule.matches:
|
|
if rule.level == "ERROR" or rule.level == "WARN":
|
|
throw_error = True
|
|
print(match)
|
|
|
|
if throw_error:
|
|
print(Fore.RED + "Found potential problems, exiting with code 1!" + Fore.RESET)
|
|
exit(1)
|
|
else:
|
|
print(Fore.GREEN + "Looks good!" + Fore.RESET)
|