7from pathlib
import Path
21def parse_opcode_declarations(header_path: Path) -> list[tuple[str, str]]:
22 entries: list[tuple[str, str]] = []
24 r"^\s*int\s+(op_[A-Za-z0-9_]+)\s*\([^;]*\)\s*;\s*//\s*(0x[0-9A-Fa-f]+)\s*$"
27 for line
in header_path.read_text(encoding=
"utf-8").splitlines():
28 match = pattern.match(line)
30 entries.append((match.group(1), match.group(2).upper()))
35def collect_dummy_symbols(source_dir: Path) -> set[str]:
36 pattern = re.compile(
r"DUMMY\(\s*(op_[A-Za-z0-9_]+)\s*\)")
37 dummies: set[str] = set()
39 for cpp_file
in sorted(source_dir.glob(
"*.cpp")):
40 content = cpp_file.read_text(encoding=
"utf-8")
41 for symbol
in pattern.findall(content):
47def use_color(args: argparse.Namespace) -> bool:
52 if os.environ.get(
"NO_COLOR")
is not None:
54 return sys.stdout.isatty()
57def color_text(text: str, color: str, enabled: bool) -> str:
58 if not enabled
or not text:
60 return f
"{color}{text}{RESET}"
64 done: int, total: int, width: int, unicode_bar: bool, colored: bool, fill_color: str
67 empty_char = EMPTY_BLOCK
if unicode_bar
else "-"
68 return "[" + (empty_char * width) +
"]"
70 filled = int((done * width) / total)
71 filled = max(0, min(width, filled))
72 empty = width - filled
74 full_char = FULL_BLOCK
if unicode_bar
else "#"
75 empty_char = EMPTY_BLOCK
if unicode_bar
else "-"
77 fill_text = full_char * filled
78 empty_text = empty_char * empty
81 fill_text = color_text(fill_text, fill_color,
True)
82 empty_text = color_text(empty_text, DIM,
True)
84 return f
"[{fill_text}{empty_text}]"
97 pct = 0.0
if total == 0
else (done / total) * 100.0
98 bar = progress_bar(done, total, width, unicode_bar, colored, fill_color)
99 spacer =
" " * (label_width - len(label) + 1)
100 pct_text = f
"{pct:.1f}%"
102 pct_text = color_text(pct_text, BOLD,
True)
103 print(f
"- {label}:{spacer}{bar} {pct_text} ({done}/{total})")
107 parser = argparse.ArgumentParser(
108 description=
"Show opcode implementation progress based on DUMMY placeholders"
114 help=
"Progress bar width (default: 20)",
119 help=
"Print missing opcode symbols",
124 help=
"Use ASCII bars (# and -) instead of block bars",
129 help=
"Disable ANSI colors",
134 help=
"Force ANSI colors even when not in a TTY",
136 args = parser.parse_args()
138 project_root = Path(__file__).resolve().parent.parent
140 base_header = project_root /
"include" /
"opcodes.hpp"
141 cb_header = project_root /
"include" /
"cb_opcodes.hpp"
142 base_src = project_root /
"src" /
"core" /
"cpu" /
"instructions" /
"opcodes"
143 cb_src = project_root /
"src" /
"core" /
"cpu" /
"instructions" /
"cb_opcodes"
145 base_entries = parse_opcode_declarations(base_header)
146 cb_entries = parse_opcode_declarations(cb_header)
148 base_dummies = collect_dummy_symbols(base_src)
149 cb_dummies = collect_dummy_symbols(cb_src)
152 (name, opcode)
for name, opcode
in base_entries
if name
in base_dummies
154 cb_missing = [(name, opcode)
for name, opcode
in cb_entries
if name
in cb_dummies]
156 base_total = len(base_entries)
157 cb_total = len(cb_entries)
158 base_done = base_total - len(base_missing)
159 cb_done = cb_total - len(cb_missing)
161 total_all = base_total + cb_total
162 done_all = base_done + cb_done
164 colored = use_color(args)
165 unicode_bar =
not args.ascii
166 label_width = len(
"Base Opcodes")
199 if args.show_missing:
201 print(
"\nMissing Base Opcodes")
202 for name, opcode
in base_missing:
203 print(f
"- {opcode}: {name}")
205 print(
"\nMissing CB Opcodes")
206 for name, opcode
in cb_missing:
207 print(f
"- {opcode}: {name}")
208 if not base_missing
and not cb_missing:
209 print(
"\nNo missing opcode implementations detected.")
214if __name__ ==
"__main__":
215 raise SystemExit(main())