Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/Advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ for section, section_syms in syms_by_section.items():
if cur_subsegment is not None:
gprint("}")
cur_subsegment = sym.subsegment
gprint(f"subgraph cluster_{cur_subsegment}_{section} " "{")
gprint(f"subgraph cluster_{cur_subsegment}_{section} {{")
y = -i / len(filtered_syms) * 100 + dy - 0.2
gprint(f'"{cur_subsegment} {section}"' " [" f' pos = "{x},{y}!"' f' color="none"' " ]")
gprint(f'"{cur_subsegment} {section}" [ pos = "{x},{y}!" color="none" ]')
dy -= 0.8
assert cur_subsegment is not None
if 0:
Expand Down Expand Up @@ -192,7 +192,7 @@ for section, section_syms in syms_by_section.items():
color = color_by_subsegment[sym_by_name[sym_ref_by].subsegment]
except KeyError:
color = "black"
gprint(f'"{sym_ref_by}" -> "{sym.name}"' f' [ color = "{color}" ]')
gprint(f'"{sym_ref_by}" -> "{sym.name}" [ color = "{color}" ]')

gprint("}")
```
Expand Down
48 changes: 48 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,51 @@ features = ["dev"]

[project.scripts]
splat = "splat.__main__:splat_main"

[tool.ruff.lint]
# Keep alphabetically sorted
extend-select = [
"C401", # https://docs.astral.sh/ruff/rules/unnecessary-generator-set/
"C408", # https://docs.astral.sh/ruff/rules/unnecessary-collection-call/
# "EXE",
"EXE001", # https://docs.astral.sh/ruff/rules/shebang-not-executable/
# "FURB",
"FURB105", # https://docs.astral.sh/ruff/rules/print-empty-string/
"FURB122", # https://docs.astral.sh/ruff/rules/for-loop-writes/
"FURB188", # https://docs.astral.sh/ruff/rules/slice-to-remove-prefix-or-suffix/
# "ISC",
"ISC004", # https://docs.astral.sh/ruff/rules/implicit-string-concatenation-in-collection-literal/
"PERF402", # https://docs.astral.sh/ruff/rules/manual-list-copy/
# "PIE",
"PIE790", # https://docs.astral.sh/ruff/rules/unnecessary-placeholder/
# "PLC",
"PLC0206", # https://docs.astral.sh/ruff/rules/dict-index-missing-items/
"PLR1730", # https://docs.astral.sh/ruff/rules/if-stmt-min-max/
"PLW1510", # https://docs.astral.sh/ruff/rules/subprocess-run-without-check/
# "RUF",
"RUF010", # https://docs.astral.sh/ruff/rules/explicit-f-string-type-conversion/
"RUF015", # https://docs.astral.sh/ruff/rules/unnecessary-iterable-allocation-for-first-element/
"RUF059", # https://docs.astral.sh/ruff/rules/unused-unpacked-variable/
"SIM201", # https://docs.astral.sh/ruff/rules/negate-equal-op/
"TRY002", # https://docs.astral.sh/ruff/rules/raise-vanilla-class/
"TRY004", # https://docs.astral.sh/ruff/rules/type-check-without-type-error/
"UP020", # https://docs.astral.sh/ruff/rules/open-alias/
"UP033", # https://docs.astral.sh/ruff/rules/lru-cache-with-maxsize-none/
]

ignore = [
"B009", # https://docs.astral.sh/ruff/rules/get-attr-with-constant/
"BLE001", # https://docs.astral.sh/ruff/rules/blind-except/ TODO: enable
"FA100", # https://docs.astral.sh/ruff/rules/future-rewritable-type-annotation/
"I001", # https://docs.astral.sh/ruff/rules/unsorted-imports/
"PLR0402", # https://docs.astral.sh/ruff/rules/manual-from-import/
"PLW0211", # https://docs.astral.sh/ruff/rules/bad-staticmethod-argument
"PLW0602", # https://docs.astral.sh/ruff/rules/global-variable-not-assigned/
"SIM102", # https://docs.astral.sh/ruff/rules/collapsible-if/
"SIM103", # https://docs.astral.sh/ruff/rules/needless-bool/
"SIM114", # https://docs.astral.sh/ruff/rules/if-with-same-arms/
"UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation/
"UP035", # https://docs.astral.sh/ruff/rules/deprecated-import/
"UP037", # https://docs.astral.sh/ruff/rules/quoted-annotation/
"UP045", # https://docs.astral.sh/ruff/rules/non-pep604-annotation-optional/
]
Empty file modified src/splat/__main__.py
100644 → 100755
Empty file.
3 changes: 1 addition & 2 deletions src/splat/disassembler/disassembler_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,5 @@ def get_instance() -> Disassembler:
global __instance
global __initialized
if not __initialized:
raise Exception("Disassembler instance not initialized")
return None
raise Exception("Disassembler instance not initialized") # noqa: TRY002
return __instance
4 changes: 2 additions & 2 deletions src/splat/scripts/create_config.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ def find_objcopy() -> str:
]

for name in options:
sub = subprocess.run([name, "--version"], capture_output=True)
sub = subprocess.run([name, "--version"], capture_output=True, check=False)
if sub.returncode == 0:
return name

Expand All @@ -559,7 +559,7 @@ def find_objcopy() -> str:
def run_objcopy(objcopy_name: str, elf_path: str, rom: str) -> list[str]:
cmd = [objcopy_name, "-O", "binary", "--gap-fill=0x00", elf_path, rom]
print("Running:", " ".join(cmd))
sub = subprocess.run(cmd)
sub = subprocess.run(cmd, check=False)
if sub.returncode != 0:
log.error("Failed to run objcopy")
return cmd
Expand Down
4 changes: 2 additions & 2 deletions src/splat/scripts/split.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:

segment_class = Segment.get_class_for_type(seg_type)

this_start, is_auto_segment = Segment.parse_segment_start(seg_yaml)
this_start, _is_auto_segment = Segment.parse_segment_start(seg_yaml)

j = i + 1
while j < len(config_segments):
next_start, next_is_auto_segment = Segment.parse_segment_start(
next_start, _next_is_auto_segment = Segment.parse_segment_start(
config_segments[j]
)
if next_start is not None:
Expand Down
2 changes: 0 additions & 2 deletions src/splat/segtypes/common/bss.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ def configure_disassembler_section(
) -> None:
"Allows to configure the section before running the analysis on it"

pass

def disassemble_data(self, rom_bytes: bytes):
if not options.opts.ld_bss_is_noload:
super().disassemble_data(rom_bytes)
Expand Down
6 changes: 3 additions & 3 deletions src/splat/segtypes/common/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def replacer(match):
def get_funcs_defined_in_c(c_file: Path) -> Set[str]:
text = CommonSegC.strip_c_comments(c_file.read_text(encoding="utf-8"))

return set(m.group(1) for m in C_FUNC_RE.finditer(text))
return {m.group(1) for m in C_FUNC_RE.finditer(text)}

@staticmethod
def find_all_instances(string: str, sub: str):
Expand Down Expand Up @@ -106,15 +106,15 @@ def find_include_rodata(text: str):
def get_global_asm_funcs(c_file: Path) -> Set[str]:
text = CommonSegC.strip_c_comments(c_file.read_text(encoding="utf-8"))
if options.opts.compiler == IDO:
return set(m.group(2) for m in C_GLOBAL_ASM_IDO_RE.finditer(text))
return {m.group(2) for m in C_GLOBAL_ASM_IDO_RE.finditer(text)}
else:
return set(CommonSegC.find_include_asm(text))

@staticmethod
def get_global_asm_rodata_syms(c_file: Path) -> Set[str]:
text = CommonSegC.strip_c_comments(c_file.read_text(encoding="utf-8"))
if options.opts.compiler == IDO:
return set(m.group(2) for m in C_GLOBAL_ASM_IDO_RE.finditer(text))
return {m.group(2) for m in C_GLOBAL_ASM_IDO_RE.finditer(text)}
else:
return set(CommonSegC.find_include_rodata(text))

Expand Down
7 changes: 3 additions & 4 deletions src/splat/segtypes/common/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ def _insert_all_auto_sections(
and link_section not in options.opts.auto_link_sections[: i + 1]
):
last_inserted_index -= 1
if last_inserted_index < 0:
last_inserted_index = 0
last_inserted_index = max(last_inserted_index, 0)
break
last_inserted_index += 1

Expand All @@ -143,7 +142,7 @@ def parse_subsegments(self, segment_yaml) -> List[Segment]:

if "subsegments" not in segment_yaml:
if not self.parent:
raise Exception(
log.error(
f"No subsegments provided in top-level code segment {self.name}"
)
return ret
Expand Down Expand Up @@ -194,7 +193,7 @@ def parse_subsegments(self, segment_yaml) -> List[Segment]:
# Third, try to get the end address from the next segment with a start address
end: Optional[int] = None
if next_subsegment_yaml is not None:
end, end_is_auto_segment = Segment.parse_segment_start(
end, _end_is_auto_segment = Segment.parse_segment_start(
next_subsegment_yaml
)
if start is not None and end is None:
Expand Down
3 changes: 1 addition & 2 deletions src/splat/segtypes/common/codesubsegment.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ def split_as_asmtu_file(self, out_path: Path):
self.print_file_boundaries()

with open(out_path, "w", encoding="utf-8", newline="\n") as f:
for line in self.get_asm_file_header():
f.write(line + "\n")
f.writelines(line + "\n" for line in self.get_asm_file_header())

# self.spim_section would be None if the current section was
# declared `auto` in the yaml.
Expand Down
3 changes: 1 addition & 2 deletions src/splat/segtypes/common/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ def is_data() -> bool:

def asm_out_path(self) -> Path:
typ = self.type
if typ.startswith("."):
typ = typ[1:]
typ = typ.removeprefix(".")

return options.opts.data_path / self.dir / f"{self.name}.{typ}.s"

Expand Down
4 changes: 2 additions & 2 deletions src/splat/segtypes/common/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(
def get_next_seg_start(self, i, subsegment_yamls) -> Optional[int]:
j = i + 1
while j < len(subsegment_yamls):
ret, is_auto_segment = Segment.parse_segment_start(subsegment_yamls[j])
ret, _is_auto_segment = Segment.parse_segment_start(subsegment_yamls[j])
if ret is not None:
return ret
j += 1
Expand Down Expand Up @@ -128,7 +128,7 @@ def parse_subsegments(self, yaml) -> List[Segment]:
# Third, try to get the end address from the next segment with a start address
end: Optional[int] = None
if next_subsegment_yaml is not None:
end, end_is_auto_segment = Segment.parse_segment_start(
end, _end_is_auto_segment = Segment.parse_segment_start(
next_subsegment_yaml
)
if start is not None and end is None:
Expand Down
2 changes: 1 addition & 1 deletion src/splat/segtypes/common/rodata.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def get_possible_text_subsegment_for_symbol(
if len(rodata_sym.contextSym.referenceFunctions) != 1:
return None

func = list(rodata_sym.contextSym.referenceFunctions)[0]
func = next(iter(rodata_sym.contextSym.referenceFunctions))
text_segment = self.parent.get_subsegment_for_ram(func.vram)

if text_segment is None or not text_segment.is_text():
Expand Down
3 changes: 1 addition & 2 deletions src/splat/segtypes/common/textbin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ def out_path(self) -> Optional[Path]:

def bin_path(self) -> Path:
typ = self.type
if typ.startswith("."):
typ = typ[1:]
typ = typ.removeprefix(".")

return options.opts.asset_path / self.dir / f"{self.name}.{typ}.bin"

Expand Down
4 changes: 2 additions & 2 deletions src/splat/segtypes/linker_entry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import re
from functools import lru_cache
from functools import cache
from pathlib import Path
from typing import Dict, List, OrderedDict, Set, Tuple, Union, Optional

Expand All @@ -11,7 +11,7 @@


# clean 'foo/../bar' to 'bar'
@lru_cache(maxsize=None)
@cache
def clean_up_path(path: Path) -> Path:
path_resolved = path.resolve()
base_resolved = options.opts.base_path.resolve()
Expand Down
3 changes: 1 addition & 2 deletions src/splat/segtypes/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ class Segment:
@staticmethod
def get_class_for_type(seg_type) -> Type["Segment"]:
# so .data loads SegData, for example
if seg_type.startswith("."):
seg_type = seg_type[1:]
seg_type = seg_type.removeprefix(".")

if options.opts.allow_segment_overrides:
segment_class = Segment.get_extension_segment_class(seg_type)
Expand Down
2 changes: 1 addition & 1 deletion src/splat/util/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _merge_configs(main_config, additional_config, additional_config_path):
main_config[curkey] = additional_config[curkey]
elif type(main_config[curkey]) is not type(additional_config[curkey]):
raise TypeError(
f"Could not merge {str(additional_config_path)}: type for key '{curkey}' in configs does not match"
f"Could not merge {additional_config_path!s}: type for key '{curkey}' in configs does not match"
)
else:
# keys exist and match, see if a list to append
Expand Down
2 changes: 1 addition & 1 deletion src/splat/util/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def write(*args, status=None, **kwargs):
global newline

if not newline:
print("")
print()
newline = True

print(
Expand Down
2 changes: 1 addition & 1 deletion src/splat/util/n64/rominfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ def main():
print("CIC: " + rom.cic.ntsc_name + " / " + rom.cic.pal_name)
print("RAM entry point: " + hex(rom.entry_point))
print("Header encoding: " + rom.header_encoding)
print("")
print()

get_compiler_info(rom_bytes, rom.entry_point)

Expand Down
2 changes: 1 addition & 1 deletion src/splat/util/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def parse_path_list(self, base_path: Path, opt: str, default: str) -> List[Path]
elif isinstance(paths, list):
return [base_path / path for path in paths]
else:
raise ValueError(f"Expected str or list for '{opt}', got {type(paths)}")
raise TypeError(f"Expected str or list for '{opt}', got {type(paths)}")

def check_no_unread_opts(self) -> None:
opts = [opt for opt in self._yaml if opt not in self._read_opts]
Expand Down
3 changes: 1 addition & 2 deletions src/splat/util/palettes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,8 @@ def process(segments):
)

# Resolve "." palette links
for pal_name in palette_map:
for pal_name, pal in palette_map.items():
if pal_name.startswith(raster.name + "."):
pal = palette_map[pal_name]
raster.palettes.append(pal)
palettes_seen.discard(pal_name)

Expand Down
1 change: 0 additions & 1 deletion src/splat/util/ps2/ps2elfinfo.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ def get_info(elf_path: Path, elf_bytes: bytes) -> Optional[Ps2Elf]:
if typ == Elf32Constants.Elf32SectionHeaderType.PROGBITS:
if previous_type == Elf32Constants.Elf32SectionHeaderType.NOBITS:
do_new_segs = True
pass
elif typ == Elf32Constants.Elf32SectionHeaderType.NOBITS:
pass
elif typ == Elf32Constants.Elf32SectionHeaderType.MIPS_REGINFO:
Expand Down
4 changes: 2 additions & 2 deletions src/splat/util/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ def get_seg_for_rom(rom: int) -> Optional["Segment"]:
return segment
return None

seen_symbols: Dict[str, "Symbol"] = dict()
seen_symbols: Dict[str, "Symbol"] = {}
prog_bar = progress_bar.get_progress_bar(sym_addrs_lines)
prog_bar.set_description(f"Loading symbols ({path.stem})")
line: str
for line_num, line in enumerate(prog_bar):
line = line.strip()
if not line == "" and not line.startswith("//"):
if line != "" and not line.startswith("//"):
comment_loc = line.find("//")
line_main = line
line_ext = ""
Expand Down
12 changes: 4 additions & 8 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import difflib
import filecmp
import io
from pathlib import Path
import spimdisasm
import unittest
Expand All @@ -23,8 +22,8 @@
class Testing(unittest.TestCase):
def compare_files(self, test_path, ref_path):
with (
io.open(test_path, encoding="utf-8") as test_f,
io.open(ref_path, encoding="utf-8") as ref_f,
open(test_path, encoding="utf-8") as test_f,
open(ref_path, encoding="utf-8") as ref_f,
):
self.assertListEqual(list(test_f), list(ref_f))

Expand Down Expand Up @@ -285,9 +284,7 @@ def test_disassemble_data(self):
args=[],
yaml={},
)
rom_data = []
for i in range(0x100):
rom_data.append(i)
rom_data = list(range(0x100))
common_seg_rodata.disassemble_data(bytes(rom_data))
assert common_seg_rodata.spim_section is not None
assert common_seg_rodata.spim_section.get_section().words[0] == 0x0010203
Expand Down Expand Up @@ -466,8 +463,7 @@ def test_boolean_attrs(self):
test_init()

sym_addrs_lines = [
"func_1 = 0x100; // defined:True extract:True force_migration:True force_not_migration:True "
"allow_addend:True dont_allow_addend:True"
"func_1 = 0x100; // defined:True extract:True force_migration:True force_not_migration:True allow_addend:True dont_allow_addend:True",
]

all_segments = [
Expand Down
Empty file modified test_n64_entrypoints.py
100644 → 100755
Empty file.