Skip to content

Commit b26dc09

Browse files
committed
improve sinkhole criteria in script
by also checking for static cells with constraints set to `.` and by checking for missing `CheckType` definitions.
1 parent 7fc5cdd commit b26dc09

2 files changed

Lines changed: 52 additions & 19 deletions

File tree

Controller/RUL0/0000_TuLEPS_CanAM/0460_FlexTurnLanes.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,8 +3115,8 @@ CopyFrom = 0x304B6
31153115
;CellLayout=..^...
31163116

31173117
;CheckType = a - road: 0x02000200
3118-
;###RHD###CheckType = b - road: 0x02000200 onewayroad: 0x00000304, 0xffffffff optional
3119-
;###LHD###CheckType = b - road: 0x02000200 onewayroad: 0x00000104, 0xffffffff optional
3118+
;;###RHD###CheckType = b - road: 0x02000200 onewayroad: 0x00000304, 0xffffffff optional
3119+
;;###LHD###CheckType = b - road: 0x02000200 onewayroad: 0x00000104, 0xffffffff optional
31203120
;CheckType = c - road: 0x02000200 onewayroad: 0x04000003, 0xffffffff optional
31213121
;CheckType = d - road: 0x02000200 onewayroad: 0x00030400, 0xffffffff optional
31223122

src/scripts/syntax-check-rul0.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22
#
3-
# This script checks all the RUL0 files for errors such as sinkhole bugs..
3+
# This script checks all the RUL0 files for errors such as sinkhole bugs.
44
# If any are found, they are printed to stdout and the script exits with a non-zero return code.
55
#
66
# Minimum requirement: Python 3.12+
@@ -9,6 +9,7 @@
99
import sys
1010
import os
1111
import itertools
12+
import re
1213

1314
SRC_DIRS = [
1415
"Controller/RUL0",
@@ -39,14 +40,39 @@ def parse_layout(lines):
3940
return cells
4041

4142

42-
def check_cons_layout(cell_lines, cons_lines):
43+
def parse_checktypes(lines):
44+
definitions = [line[(line.index("=")+1):].strip() for line in drop_comments(l for _, l in lines)]
45+
static_cells = {row[0]: "optional" not in row and "check" not in row
46+
for row in definitions if row}
47+
return static_cells
48+
49+
50+
def _stringify_layout(lines):
51+
return "".join(f" {line_no}: {line}" for line_no, line in lines)
52+
53+
54+
def check_cons_layout(cell_lines, checktype_lines, cons_lines):
4355
cell_layout = parse_layout(cell_lines)
4456
cons_layout = parse_layout(cons_lines)
45-
bad_cells = [xy for xy in cons_layout.keys() if xy not in cell_layout]
57+
static_cells = parse_checktypes(checktype_lines)
58+
undefined_cells = set(c for c in cell_layout.values() if c != '+' and c not in static_cells)
59+
if undefined_cells:
60+
raise Exception(f"Missing CheckType definition for cell {', '.join(undefined_cells)}:\n{_stringify_layout(cell_lines)}")
61+
bad_cells = [xy for xy in cons_layout.keys() if xy not in cell_layout] # constraint != '.' but cell == '.'
62+
if not bad_cells:
63+
bad_cells = [xy for xy, c in cell_layout.items()
64+
if static_cells.get(c) and
65+
(xy not in cons_layout or cons_layout[xy] == '.')] # cell != '.' but constraint == '.'
4666
if bad_cells:
47-
cell_layout_str = "".join(f" {line_no}: {line}" for line_no, line in cell_lines)
48-
cons_layout_str = "".join(f" {line_no}: {line}" for line_no, line in cons_lines)
49-
raise Exception(f"Potential sinkhole bug in ConsLayout at cells {' '.join(map(str, bad_cells))}:\n{cell_layout_str} ---\n{cons_layout_str}")
67+
raise Exception(f"Potential sinkhole bug in ConsLayout at cells {' '.join(map(str, bad_cells))}:\n{_stringify_layout(cell_lines)} ---\n{_stringify_layout(cons_lines)}")
68+
69+
70+
_relevant_line_starts = (
71+
re.compile(r"^CellLayout", re.IGNORECASE),
72+
re.compile(r"^CheckType", re.IGNORECASE),
73+
re.compile(r"^ConsLayout", re.IGNORECASE),
74+
re.compile(r"^\[HighwayIntersectionInfo"),
75+
)
5076

5177

5278
def scan_rul0_file(lines):
@@ -55,18 +81,25 @@ def relevant_lines():
5581
line = line.lstrip()
5682
if line.startswith(";###RHD###"): # TODO for simplicity, we ignore LHD for now
5783
line = line[10:]
58-
if line.startswith("CellLayout") or line.startswith("ConsLayout"):
59-
yield line_no, line
60-
61-
grouped = list((b, list(it)) for b, it in itertools.groupby(relevant_lines(), key=lambda tup: tup[1].startswith("ConsLayout")))
62-
if grouped and grouped[0][0]:
63-
yield "Found no matching CellLayout for first ConsLayout in file"
64-
elif grouped and not grouped[-1][0]:
65-
yield "Found no matching ConsLayout for last CellLayout in file"
66-
else:
67-
for ((_, cell_lines), (_, cons_lines)) in itertools.batched(grouped, 2):
84+
for re_idx, pattern in enumerate(_relevant_line_starts):
85+
if pattern.match(line):
86+
yield line_no, line, re_idx
87+
break
88+
89+
grouped = [list(it) for heading, it in
90+
itertools.groupby(relevant_lines(), key=lambda tup: tup[2] == 3)
91+
if not heading]
92+
for grouped_lines in grouped:
93+
cell_lines = [(line_no, line) for line_no, line, re_idx in grouped_lines if re_idx == 0]
94+
checktype_lines = [(line_no, line) for line_no, line, re_idx in grouped_lines if re_idx == 1]
95+
cons_lines = [(line_no, line) for line_no, line, re_idx in grouped_lines if re_idx == 2]
96+
if not cell_lines and not cons_lines: # checktype_lines might be non-empty in `CopyFrom` case
97+
continue
98+
elif not cell_lines or not checktype_lines or not cons_lines:
99+
yield f"Found no matching CellLayout, ConsLayout or CheckType definitions starting at line {grouped_lines[0][0]}"
100+
else:
68101
try:
69-
check_cons_layout(cell_lines, cons_lines)
102+
check_cons_layout(cell_lines, checktype_lines, cons_lines)
70103
except Exception as err:
71104
yield str(err)
72105

0 commit comments

Comments
 (0)