Skip to content

Commit 866dc50

Browse files
committed
add script to check RUL0 files for sinkhole issues
1 parent 33534a8 commit 866dc50

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

.github/workflows/scala.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,7 @@ jobs:
4141
- uses: actions/checkout@v4
4242
with:
4343
persist-credentials: false
44+
- name: Check RUL0 syntax
45+
run: python src/scripts/syntax-check-rul0.py
4446
- name: Check RUL2 syntax
4547
run: sh src/scripts/syntax-check-rul2.sh

src/scripts/syntax-check-rul0.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python3
2+
#
3+
# This script checks all the RUL0 files for errors such as sinkhole bugs..
4+
# If any are found, they are printed to stdout and the script exits with a non-zero return code.
5+
6+
import sys
7+
import os
8+
import itertools
9+
10+
SRC_DIRS = [
11+
"Controller/RUL0",
12+
"Lite Controller/RUL0",
13+
]
14+
15+
16+
def drop_comments(lines):
17+
for line in lines:
18+
idx = line.find(";")
19+
yield line if idx == -1 else line[:idx]
20+
21+
22+
# create mapping of (x,y)-cell to char
23+
def parse_layout(lines):
24+
layout = [line[(line.index("=")+1):].strip() for line in drop_comments(lines)]
25+
origin_x = ([l.index("^") for l in layout if "^" in l] or [0])[0]
26+
origin_y = ([i for i, l in enumerate(layout) if "<" in l] or [0])[0]
27+
cells = {(j-origin_x, i-origin_y): char
28+
for i, row in enumerate(layout)
29+
for j, char in enumerate(row)
30+
if char not in ".^<"
31+
}
32+
return cells
33+
34+
35+
def check_cons_layout(cell_lines, cons_lines):
36+
cell_layout = parse_layout(l for _, l in cell_lines)
37+
cons_layout = parse_layout(l for _, l in cons_lines)
38+
bad_cells = [xy for xy in cons_layout.keys() if xy not in cell_layout]
39+
if bad_cells:
40+
cell_layout_str = "".join(f" {line_no}: {line}" for line_no, line in cell_lines)
41+
cons_layout_str = "".join(f" {line_no}: {line}" for line_no, line in cons_lines)
42+
raise Exception(f"Potential sinkhole bug in ConsLayout at cells {" ".join(map(str, bad_cells))}:\n{cell_layout_str} ---\n{cons_layout_str}")
43+
44+
45+
def scan_rul0_file(lines):
46+
def relevant_lines():
47+
for line_no, line in enumerate(lines, 1):
48+
line = line.lstrip()
49+
if line.startswith(";###RHD###"): # TODO for simplicity, we ignore LHD for now
50+
line = line[10:]
51+
if line.startswith("CellLayout") or line.startswith("ConsLayout"):
52+
yield line_no, line
53+
54+
grouped = list((b, list(it)) for b, it in itertools.groupby(relevant_lines(), key=lambda tup: tup[1].startswith("ConsLayout")))
55+
if grouped and grouped[0][0]:
56+
yield "Found no matching CellLayout for first ConsLayout in file"
57+
elif grouped and not grouped[-1][0]:
58+
yield "Found no matching ConsLayout for last CellLayout in file"
59+
else:
60+
for ((_, cell_lines), (_, cons_lines)) in itertools.batched(grouped, 2):
61+
try:
62+
check_cons_layout(cell_lines, cons_lines)
63+
except Exception as err:
64+
yield str(err)
65+
66+
67+
def main() -> int:
68+
validated = 0
69+
errors = 0
70+
for src_dir in SRC_DIRS:
71+
for (parent, dirs, files) in os.walk(src_dir):
72+
for fname in files:
73+
if not fname.endswith(".rul") and not fname.endswith(".txt"):
74+
continue
75+
msgs = []
76+
p = os.path.join(parent, fname)
77+
with open(p, encoding='utf-8') as f:
78+
validated += 1
79+
msgs.extend(scan_rul0_file(f))
80+
if msgs:
81+
errors += len(msgs)
82+
print(f"===> {p}")
83+
for msg in msgs:
84+
print(msg)
85+
if errors > 0:
86+
print(f"Finished with {errors} errors in RUL0 files.")
87+
return 1
88+
else:
89+
print(f"Successfully validated {validated} RUL0 files.")
90+
return 0
91+
92+
93+
if __name__ == '__main__':
94+
sys.exit(main())

0 commit comments

Comments
 (0)