From a23e23099c06160874cd1748441bb649e5ee4a99 Mon Sep 17 00:00:00 2001 From: Benign X <1341398182@qq.com> Date: Fri, 6 Mar 2026 17:51:48 +0800 Subject: [PATCH] chore(gdb): refactor generators into shared enum_parser and unified generate_all entry --- scripts/gdb/.gitignore | 6 + .../gdb/lvglgdb/lvgl/core/lv_indev_consts.py | 4 +- .../lvglgdb/lvgl/core/lv_observer_consts.py | 4 +- .../gdb/lvglgdb/lvgl/draw/lv_draw_consts.py | 4 +- .../gdb/lvglgdb/lvgl/misc/lv_event_consts.py | 4 +- .../gdb/lvglgdb/lvgl/misc/lv_style_consts.py | 4 +- scripts/gdb/scripts/enum_parser.py | 105 +++++++++++++ scripts/gdb/scripts/gen_draw_consts.py | 141 ------------------ scripts/gdb/scripts/gen_event_consts.py | 95 ------------ scripts/gdb/scripts/gen_indev_consts.py | 89 ----------- scripts/gdb/scripts/gen_subject_consts.py | 53 ------- scripts/gdb/scripts/generate_all.py | 44 ++++++ scripts/gdb/scripts/generators/__init__.py | 1 + .../gdb/scripts/generators/gen_draw_consts.py | 59 ++++++++ .../scripts/generators/gen_event_consts.py | 32 ++++ .../scripts/generators/gen_indev_consts.py | 29 ++++ .../{ => generators}/gen_style_consts.py | 100 +++---------- .../scripts/generators/gen_subject_consts.py | 29 ++++ 18 files changed, 339 insertions(+), 464 deletions(-) create mode 100644 scripts/gdb/.gitignore create mode 100644 scripts/gdb/scripts/enum_parser.py delete mode 100644 scripts/gdb/scripts/gen_draw_consts.py delete mode 100644 scripts/gdb/scripts/gen_event_consts.py delete mode 100644 scripts/gdb/scripts/gen_indev_consts.py delete mode 100644 scripts/gdb/scripts/gen_subject_consts.py create mode 100644 scripts/gdb/scripts/generate_all.py create mode 100644 scripts/gdb/scripts/generators/__init__.py create mode 100644 scripts/gdb/scripts/generators/gen_draw_consts.py create mode 100644 scripts/gdb/scripts/generators/gen_event_consts.py create mode 100644 scripts/gdb/scripts/generators/gen_indev_consts.py rename scripts/gdb/scripts/{ => generators}/gen_style_consts.py (72%) create mode 100644 scripts/gdb/scripts/generators/gen_subject_consts.py diff --git a/scripts/gdb/.gitignore b/scripts/gdb/.gitignore new file mode 100644 index 0000000000..1286997d97 --- /dev/null +++ b/scripts/gdb/.gitignore @@ -0,0 +1,6 @@ +*.egg-info/ +dist/ +build/ +__pycache__/ +.idea/ +.DS_Store diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py b/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py index 0501354dea..1f41e25085 100644 --- a/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py @@ -1,8 +1,8 @@ """ Auto-generated indev constants from LVGL headers. -Do not edit manually. Regenerate with: - python3 scripts/gen_indev_consts.py +Do not edit manually. Regenerate from the GDB script root with: + python3 scripts/generate_all.py """ INDEV_TYPE_NAMES = { diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_observer_consts.py b/scripts/gdb/lvglgdb/lvgl/core/lv_observer_consts.py index 9aed3ac13b..98f66ddc54 100644 --- a/scripts/gdb/lvglgdb/lvgl/core/lv_observer_consts.py +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_observer_consts.py @@ -1,8 +1,8 @@ """ Auto-generated observer constants from LVGL headers. -Do not edit manually. Regenerate with: - python3 scripts/gen_subject_consts.py +Do not edit manually. Regenerate from the GDB script root with: + python3 scripts/generate_all.py """ SUBJECT_TYPE_NAMES = { diff --git a/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_consts.py b/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_consts.py index a25b2da489..db6ccff5c7 100644 --- a/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_consts.py +++ b/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_consts.py @@ -1,8 +1,8 @@ """ Auto-generated draw constants from LVGL headers. -Do not edit manually. Regenerate with: - python3 scripts/gen_draw_consts.py +Do not edit manually. Regenerate from the GDB script root with: + python3 scripts/generate_all.py """ DRAW_TASK_TYPE_NAMES = { diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_event_consts.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_event_consts.py index b1f3f6a9fc..0c37ac93e4 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_event_consts.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_event_consts.py @@ -1,8 +1,8 @@ """ Auto-generated event constants from LVGL headers. -Do not edit manually. Regenerate with: - python3 scripts/gen_event_consts.py +Do not edit manually. Regenerate from the GDB script root with: + python3 scripts/generate_all.py """ EVENT_CODE_NAMES = { diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py index 79b986d888..95fd6e3e7f 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py @@ -1,8 +1,8 @@ """ Auto-generated style constants from LVGL headers. -Do not edit manually. Regenerate with: - python3 scripts/gen_style_consts.py +Do not edit manually. Regenerate from the GDB script root with: + python3 scripts/generate_all.py """ STYLE_PROP_NAMES = { diff --git a/scripts/gdb/scripts/enum_parser.py b/scripts/gdb/scripts/enum_parser.py new file mode 100644 index 0000000000..d70543c55d --- /dev/null +++ b/scripts/gdb/scripts/enum_parser.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +""" +Shared utilities for LVGL constant generators. + +Provides: + - parse_enum(): Parse a C typedef enum from a header file. + - generate_dict_module(): Generate a Python module with dict constants. +""" + +import re +from pathlib import Path + + +def parse_enum(path: Path, enum_type: str, prefix: str, + skip: set[str] | None = None) -> dict[int, str]: + """Parse a C typedef enum from a header file. + + Args: + path: Path to the C header file. + enum_type: The typedef name (e.g. "lv_indev_type_t"). + prefix: Enum member prefix to strip (e.g. "LV_INDEV_TYPE_"). + skip: Optional set of full enum member names to skip. + + Returns: + Dict mapping int value -> short name string. + """ + text = path.read_text() + skip = skip or set() + + pattern = rf"\}}\s*{re.escape(enum_type)}\s*;" + m = re.search(rf"typedef\s+enum\s*\{{(.*?){pattern}", text, re.DOTALL) + if not m: + raise RuntimeError(f"Cannot find {enum_type} enum in {path}") + + entries = {} + current_val = 0 + for line in m.group(1).splitlines(): + line = line.strip().rstrip(",") + if ( + not line + or line.startswith("/*") + or line.startswith("//") + or line.startswith("*") + or line.startswith("#") + ): + continue + + match = re.match( + rf"({re.escape(prefix)}\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line + ) + if match: + name = match.group(1) + current_val = int(match.group(2), 0) + else: + match = re.match(rf"({re.escape(prefix)}\w+)", line) + if not match: + continue + name = match.group(1) + + if name in skip: + current_val += 1 + continue + + short = name.removeprefix(prefix) + entries[current_val] = short + current_val += 1 + + return entries + + +def generate_dict_module( + description: str, + dicts: dict[str, dict], +) -> str: + """Generate a Python module containing one or more dict constants. + + Args: + description: Short description for the module docstring. + dicts: Mapping of variable_name -> dict to emit. + + Returns: + Python source code string. + """ + lines = [ + '"""', + f"Auto-generated {description}.", + "", + "Do not edit manually. Regenerate from the GDB script root with:", + " python3 scripts/generate_all.py", + '"""', + "", + ] + + for var_name, data in dicts.items(): + lines.append(f"{var_name} = {{") + for k in sorted(data): + v = data[k] + if isinstance(k, int): + lines.append(f' {k}: "{v}",') + else: + lines.append(f' "{k}": "{v}",') + lines.append("}") + lines.append("") + + return "\n".join(lines) diff --git a/scripts/gdb/scripts/gen_draw_consts.py b/scripts/gdb/scripts/gen_draw_consts.py deleted file mode 100644 index dfe0682ce1..0000000000 --- a/scripts/gdb/scripts/gen_draw_consts.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate draw constant tables from LVGL header and source files. - -Parses lv_draw.h for task type/state enums, and scans draw unit source -files for name-to-struct-type mappings. - -Usage: - python3 scripts/gen_draw_consts.py -""" - -import re -import sys -from pathlib import Path - -SCRIPT_DIR = Path(__file__).parent -GDB_ROOT = SCRIPT_DIR.parent -LVGL_SRC = GDB_ROOT.parent.parent / "src" -OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "draw" / "lv_draw_consts.py" - -DRAW_H = LVGL_SRC / "draw" / "lv_draw.h" -DRAW_DIR = LVGL_SRC / "draw" - -sys.path.insert(0, str(SCRIPT_DIR)) - - -def parse_enum(path: Path, enum_type: str, prefix: str) -> dict[int, str]: - """Parse a C enum from a header file.""" - text = path.read_text() - - pattern = rf"\}}\s*{re.escape(enum_type)}\s*;" - m = re.search(rf"typedef\s+enum\s*\{{(.*?){pattern}", text, re.DOTALL) - if not m: - raise RuntimeError(f"Cannot find {enum_type} enum in {path}") - - entries = {} - current_val = 0 - for line in m.group(1).splitlines(): - line = line.strip().rstrip(",") - if ( - not line - or line.startswith("/*") - or line.startswith("//") - or line.startswith("*") - or line.startswith("#") - ): - continue - - match = re.match(rf"({re.escape(prefix)}\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) - if match: - name = match.group(1) - current_val = int(match.group(2), 0) - else: - match = re.match(rf"({re.escape(prefix)}\w+)", line) - if not match: - continue - name = match.group(1) - - short = name.removeprefix(prefix) - entries[current_val] = short - current_val += 1 - - return entries - - -def parse_draw_unit_types(draw_dir: Path) -> dict[str, str]: - """Scan draw unit .c files for name-to-struct-type mappings. - - Looks for patterns like: unit->base_unit.name = "SW"; - Then finds the corresponding struct type from the variable declaration. - """ - mappings = {} - - for c_file in draw_dir.rglob("*.c"): - text = c_file.read_text() - - for m in re.finditer(r'(\w+)->base_unit\.name\s*=\s*"(\w+)"', text): - var_name = m.group(1) - unit_name = m.group(2) - - decl = re.search( - rf"(lv_draw_\w+_unit_t)\s*\*\s*{re.escape(var_name)}\b", text - ) - if decl: - mappings[unit_name] = decl.group(1) - - return mappings - - -def generate( - task_types: dict[int, str], - task_states: dict[int, str], - unit_types: dict[str, str], -) -> str: - """Generate Python source for the draw constants module.""" - lines = [ - '"""', - "Auto-generated draw constants from LVGL headers.", - "", - "Do not edit manually. Regenerate with:", - " python3 scripts/gen_draw_consts.py", - '"""', - "", - ] - - lines.append("DRAW_TASK_TYPE_NAMES = {") - for k in sorted(task_types): - lines.append(f' {k}: "{task_types[k]}",') - lines.append("}") - lines.append("") - - lines.append("DRAW_TASK_STATE_NAMES = {") - for k in sorted(task_states): - lines.append(f' {k}: "{task_states[k]}",') - lines.append("}") - lines.append("") - - lines.append("DRAW_UNIT_TYPE_NAMES = {") - for name in sorted(unit_types): - lines.append(f' "{name}": "{unit_types[name]}",') - lines.append("}") - lines.append("") - - return "\n".join(lines) - - -def main(): - task_types = parse_enum(DRAW_H, "lv_draw_task_type_t", "LV_DRAW_TASK_TYPE_") - task_states = parse_enum(DRAW_H, "lv_draw_task_state_t", "LV_DRAW_TASK_STATE_") - unit_types = parse_draw_unit_types(DRAW_DIR) - - src = generate(task_types, task_states, unit_types) - OUTPUT.write_text(src) - print( - f"Generated {OUTPUT} ({len(task_types)} task types, " - f"{len(task_states)} task states, {len(unit_types)} unit types)" - ) - - -if __name__ == "__main__": - main() diff --git a/scripts/gdb/scripts/gen_event_consts.py b/scripts/gdb/scripts/gen_event_consts.py deleted file mode 100644 index 0f7b6d14cd..0000000000 --- a/scripts/gdb/scripts/gen_event_consts.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate event constant tables from LVGL header files. - -Parses lv_event.h for the lv_event_code_t enum. - -Usage: - python3 scripts/gen_event_consts.py -""" - -import re -from pathlib import Path - -SCRIPT_DIR = Path(__file__).parent -GDB_ROOT = SCRIPT_DIR.parent -LVGL_SRC = GDB_ROOT.parent.parent / "src" -OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "misc" / "lv_event_consts.py" - -EVENT_H = LVGL_SRC / "misc" / "lv_event.h" - - -def parse_event_codes(path: Path) -> dict[int, str]: - """Parse lv_event_code_t enum from lv_event.h.""" - text = path.read_text() - - m = re.search(r"typedef\s+enum\s*\{(.*?)\}\s*lv_event_code_t", text, re.DOTALL) - if not m: - raise RuntimeError("Cannot find lv_event_code_t enum") - - codes = {} - current_val = 0 - for line in m.group(1).splitlines(): - line = line.strip().rstrip(",") - if ( - not line - or line.startswith("/*") - or line.startswith("//") - or line.startswith("*") - or line.startswith("#") - ): - continue - - # Match: LV_EVENT_XXX = value - match = re.match(r"(LV_EVENT_\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) - if match: - name = match.group(1) - current_val = int(match.group(2), 0) - else: - match = re.match(r"(LV_EVENT_\w+)", line) - if not match: - continue - name = match.group(1) - - # Skip meta entries - if name in ("LV_EVENT_LAST", "LV_EVENT_PREPROCESS", "LV_EVENT_MARKED_DELETING"): - current_val += 1 - continue - - short = name.removeprefix("LV_EVENT_") - codes[current_val] = short - current_val += 1 - - return codes - - -def generate(codes: dict[int, str]) -> str: - """Generate Python source for the event constants module.""" - lines = [ - '"""', - "Auto-generated event constants from LVGL headers.", - "", - "Do not edit manually. Regenerate with:", - " python3 scripts/gen_event_consts.py", - '"""', - "", - ] - - lines.append("EVENT_CODE_NAMES = {") - for k in sorted(codes): - lines.append(f' {k}: "{codes[k]}",') - lines.append("}") - lines.append("") - - return "\n".join(lines) - - -def main(): - codes = parse_event_codes(EVENT_H) - src = generate(codes) - OUTPUT.write_text(src) - print(f"Generated {OUTPUT} ({len(codes)} event codes)") - - -if __name__ == "__main__": - main() diff --git a/scripts/gdb/scripts/gen_indev_consts.py b/scripts/gdb/scripts/gen_indev_consts.py deleted file mode 100644 index f33f7dc0c4..0000000000 --- a/scripts/gdb/scripts/gen_indev_consts.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate indev constant tables from LVGL header files. - -Parses lv_indev.h for indev type enum. - -Usage: - python3 scripts/gen_indev_consts.py -""" - -import re -from pathlib import Path - -SCRIPT_DIR = Path(__file__).parent -GDB_ROOT = SCRIPT_DIR.parent -LVGL_SRC = GDB_ROOT.parent.parent / "src" -OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "core" / "lv_indev_consts.py" - -INDEV_H = LVGL_SRC / "indev" / "lv_indev.h" - - -def parse_enum(path: Path, enum_type: str, prefix: str) -> dict[int, str]: - """Parse a C enum from a header file.""" - text = path.read_text() - - pattern = rf"\}}\s*{re.escape(enum_type)}\s*;" - m = re.search(rf"typedef\s+enum\s*\{{(.*?){pattern}", text, re.DOTALL) - if not m: - raise RuntimeError(f"Cannot find {enum_type} enum in {path}") - - entries = {} - current_val = 0 - for line in m.group(1).splitlines(): - line = line.strip().rstrip(",") - if ( - not line - or line.startswith("/*") - or line.startswith("//") - or line.startswith("*") - or line.startswith("#") - ): - continue - - match = re.match(rf"({re.escape(prefix)}\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) - if match: - name = match.group(1) - current_val = int(match.group(2), 0) - else: - match = re.match(rf"({re.escape(prefix)}\w+)", line) - if not match: - continue - name = match.group(1) - - short = name.removeprefix(prefix) - entries[current_val] = short - current_val += 1 - - return entries - - -def generate(indev_types: dict[int, str]) -> str: - """Generate Python source for the indev constants module.""" - lines = [ - '"""', - "Auto-generated indev constants from LVGL headers.", - "", - "Do not edit manually. Regenerate with:", - " python3 scripts/gen_indev_consts.py", - '"""', - "", - "INDEV_TYPE_NAMES = {", - ] - for k in sorted(indev_types): - lines.append(f' {k}: "{indev_types[k]}",') - lines.append("}") - lines.append("") - - return "\n".join(lines) - - -def main(): - indev_types = parse_enum(INDEV_H, "lv_indev_type_t", "LV_INDEV_TYPE_") - src = generate(indev_types) - OUTPUT.write_text(src) - print(f"Generated {OUTPUT} ({len(indev_types)} indev types)") - - -if __name__ == "__main__": - main() diff --git a/scripts/gdb/scripts/gen_subject_consts.py b/scripts/gdb/scripts/gen_subject_consts.py deleted file mode 100644 index f8379b3af3..0000000000 --- a/scripts/gdb/scripts/gen_subject_consts.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate subject type constant table from LVGL header files. - -Parses lv_observer.h for subject type enum. - -Usage: - python3 scripts/gen_subject_consts.py -""" - -import sys -from pathlib import Path - -SCRIPT_DIR = Path(__file__).parent -GDB_ROOT = SCRIPT_DIR.parent -LVGL_SRC = GDB_ROOT.parent.parent / "src" -OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "core" / "lv_observer_consts.py" - -OBSERVER_H = LVGL_SRC / "core" / "lv_observer.h" - -sys.path.insert(0, str(SCRIPT_DIR)) -from gen_indev_consts import parse_enum - - -def generate(subject_types: dict[int, str]) -> str: - """Generate Python source for the observer constants module.""" - lines = [ - '"""', - "Auto-generated observer constants from LVGL headers.", - "", - "Do not edit manually. Regenerate with:", - " python3 scripts/gen_subject_consts.py", - '"""', - "", - "SUBJECT_TYPE_NAMES = {", - ] - for k in sorted(subject_types): - lines.append(f' {k}: "{subject_types[k]}",') - lines.append("}") - lines.append("") - - return "\n".join(lines) - - -def main(): - subject_types = parse_enum(OBSERVER_H, "lv_subject_type_t", "LV_SUBJECT_TYPE_") - src = generate(subject_types) - OUTPUT.write_text(src) - print(f"Generated {OUTPUT} ({len(subject_types)} subject types)") - - -if __name__ == "__main__": - main() diff --git a/scripts/gdb/scripts/generate_all.py b/scripts/gdb/scripts/generate_all.py new file mode 100644 index 0000000000..d4a970ac80 --- /dev/null +++ b/scripts/gdb/scripts/generate_all.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +""" +Unified entry point for all LVGL GDB constant generators. + +Scans the generators/ subdirectory for gen_*.py modules and calls +each module's main() function. + +Usage (from the GDB script root): + python3 scripts/generate_all.py +""" + +import importlib +import sys +from pathlib import Path + +SCRIPT_DIR = Path(__file__).parent +GENERATORS_DIR = SCRIPT_DIR / "generators" + +# Make enum_parser importable from generators +sys.path.insert(0, str(SCRIPT_DIR)) + + +def main(): + gen_files = sorted(GENERATORS_DIR.glob("gen_*.py")) + if not gen_files: + print("No generators found.") + return + + print(f"Running {len(gen_files)} generator(s)...\n") + + for gen_file in gen_files: + module_name = gen_file.stem + print(f" [{module_name}]") + spec = importlib.util.spec_from_file_location(module_name, gen_file) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + mod.main() + print() + + print("All generators completed.") + + +if __name__ == "__main__": + main() diff --git a/scripts/gdb/scripts/generators/__init__.py b/scripts/gdb/scripts/generators/__init__.py new file mode 100644 index 0000000000..3054cd7152 --- /dev/null +++ b/scripts/gdb/scripts/generators/__init__.py @@ -0,0 +1 @@ +# generators package diff --git a/scripts/gdb/scripts/generators/gen_draw_consts.py b/scripts/gdb/scripts/generators/gen_draw_consts.py new file mode 100644 index 0000000000..e823c56e4f --- /dev/null +++ b/scripts/gdb/scripts/generators/gen_draw_consts.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""Generate draw constant tables from LVGL headers and source files.""" + +import re +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from enum_parser import parse_enum, generate_dict_module + +LVGL_SRC = Path(__file__).parent.parent.parent.parent.parent / "src" +OUTPUT = Path(__file__).parent.parent.parent / "lvglgdb" / "lvgl" / "draw" / "lv_draw_consts.py" + +DRAW_H = LVGL_SRC / "draw" / "lv_draw.h" +DRAW_DIR = LVGL_SRC / "draw" + + +def parse_draw_unit_types(draw_dir: Path) -> dict[str, str]: + """Scan draw unit .c files for name-to-struct-type mappings. + + Looks for patterns like: unit->base_unit.name = "SW"; + Then finds the corresponding struct type from the variable declaration. + """ + mappings = {} + for c_file in draw_dir.rglob("*.c"): + text = c_file.read_text() + for m in re.finditer(r'(\w+)->base_unit\.name\s*=\s*"(\w+)"', text): + var_name = m.group(1) + unit_name = m.group(2) + decl = re.search( + rf"(lv_draw_\w+_unit_t)\s*\*\s*{re.escape(var_name)}\b", text + ) + if decl: + mappings[unit_name] = decl.group(1) + return mappings + + +def main(): + task_types = parse_enum(DRAW_H, "lv_draw_task_type_t", "LV_DRAW_TASK_TYPE_") + task_states = parse_enum(DRAW_H, "lv_draw_task_state_t", "LV_DRAW_TASK_STATE_") + unit_types = parse_draw_unit_types(DRAW_DIR) + + src = generate_dict_module( + "draw constants from LVGL headers", + { + "DRAW_TASK_TYPE_NAMES": task_types, + "DRAW_TASK_STATE_NAMES": task_states, + "DRAW_UNIT_TYPE_NAMES": unit_types, + }, + ) + OUTPUT.write_text(src) + print( + f"Generated {OUTPUT.name} ({len(task_types)} task types, " + f"{len(task_states)} task states, {len(unit_types)} unit types)" + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/gdb/scripts/generators/gen_event_consts.py b/scripts/gdb/scripts/generators/gen_event_consts.py new file mode 100644 index 0000000000..46fa030901 --- /dev/null +++ b/scripts/gdb/scripts/generators/gen_event_consts.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +"""Generate event constant tables from LVGL headers.""" + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from enum_parser import parse_enum, generate_dict_module + +LVGL_SRC = Path(__file__).parent.parent.parent.parent.parent / "src" +OUTPUT = Path(__file__).parent.parent.parent / "lvglgdb" / "lvgl" / "misc" / "lv_event_consts.py" + +SKIP_EVENTS = {"LV_EVENT_LAST", "LV_EVENT_PREPROCESS", "LV_EVENT_MARKED_DELETING"} + + +def main(): + event_codes = parse_enum( + LVGL_SRC / "misc" / "lv_event.h", + "lv_event_code_t", + "LV_EVENT_", + skip=SKIP_EVENTS, + ) + src = generate_dict_module( + "event constants from LVGL headers", + {"EVENT_CODE_NAMES": event_codes}, + ) + OUTPUT.write_text(src) + print(f"Generated {OUTPUT.name} ({len(event_codes)} event codes)") + + +if __name__ == "__main__": + main() diff --git a/scripts/gdb/scripts/generators/gen_indev_consts.py b/scripts/gdb/scripts/generators/gen_indev_consts.py new file mode 100644 index 0000000000..e918323cde --- /dev/null +++ b/scripts/gdb/scripts/generators/gen_indev_consts.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Generate indev constant tables from LVGL headers.""" + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from enum_parser import parse_enum, generate_dict_module + +LVGL_SRC = Path(__file__).parent.parent.parent.parent.parent / "src" +OUTPUT = Path(__file__).parent.parent.parent / "lvglgdb" / "lvgl" / "core" / "lv_indev_consts.py" + + +def main(): + indev_types = parse_enum( + LVGL_SRC / "indev" / "lv_indev.h", + "lv_indev_type_t", + "LV_INDEV_TYPE_", + ) + src = generate_dict_module( + "indev constants from LVGL headers", + {"INDEV_TYPE_NAMES": indev_types}, + ) + OUTPUT.write_text(src) + print(f"Generated {OUTPUT.name} ({len(indev_types)} indev types)") + + +if __name__ == "__main__": + main() diff --git a/scripts/gdb/scripts/gen_style_consts.py b/scripts/gdb/scripts/generators/gen_style_consts.py similarity index 72% rename from scripts/gdb/scripts/gen_style_consts.py rename to scripts/gdb/scripts/generators/gen_style_consts.py index 5422162697..ea3cd2c766 100644 --- a/scripts/gdb/scripts/gen_style_consts.py +++ b/scripts/gdb/scripts/generators/gen_style_consts.py @@ -1,32 +1,29 @@ #!/usr/bin/env python3 -""" -Generate style constant tables from LVGL header files. - -Parses lv_style.h, lv_obj_style.h, and lv_style_gen.h to produce -lv_style_consts.py used by the lvglgdb GDB plugin. - -Usage: - python3 scripts/gen_style_consts.py -""" +"""Generate style constant tables from LVGL headers.""" import re from pathlib import Path -SCRIPT_DIR = Path(__file__).parent -GDB_ROOT = SCRIPT_DIR.parent -LVGL_SRC = GDB_ROOT.parent.parent / "src" +LVGL_SRC = Path(__file__).parent.parent.parent.parent.parent / "src" +GDB_ROOT = Path(__file__).parent.parent.parent OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "misc" / "lv_style_consts.py" STYLE_H = LVGL_SRC / "misc" / "lv_style.h" OBJ_STYLE_H = LVGL_SRC / "core" / "lv_obj_style.h" STYLE_GEN_H = LVGL_SRC / "misc" / "lv_style_gen.h" +SKIP_PROPS = { + "LV_STYLE_PROP_INV", + "LV_STYLE_PROP_ANY", + "LV_STYLE_PROP_CONST", + "LV_STYLE_LAST_BUILT_IN_PROP", + "LV_STYLE_NUM_BUILT_IN_PROPS", +} + def parse_style_props(path: Path) -> dict[int, str]: """Parse _lv_style_id_t enum from lv_style.h.""" text = path.read_text() - - # Extract enum block m = re.search(r"enum\s+_lv_style_id_t\s*\{(.*?)\}", text, re.DOTALL) if not m: raise RuntimeError("Cannot find _lv_style_id_t enum") @@ -35,41 +32,21 @@ def parse_style_props(path: Path) -> dict[int, str]: current_val = 0 for line in m.group(1).splitlines(): line = line.strip().rstrip(",") - if ( - not line - or line.startswith("/*") - or line.startswith("//") - or line.startswith("*") - ): + if not line or line.startswith(("/*", "//", "*")): continue - - # Match: LV_STYLE_XXX = value or LV_STYLE_XXX (auto-increment) match = re.match(r"(LV_STYLE_\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) if match: - name = match.group(1) - val_str = match.group(2) - current_val = int(val_str, 0) + name, current_val = match.group(1), int(match.group(2), 0) else: match = re.match(r"(LV_STYLE_\w+)", line) if not match: continue name = match.group(1) - - # Skip meta entries - if name in ( - "LV_STYLE_PROP_INV", - "LV_STYLE_PROP_ANY", - "LV_STYLE_PROP_CONST", - "LV_STYLE_LAST_BUILT_IN_PROP", - "LV_STYLE_NUM_BUILT_IN_PROPS", - ): + if name in SKIP_PROPS: current_val += 1 continue - - short = name.removeprefix("LV_STYLE_") - props[current_val] = short + props[current_val] = name.removeprefix("LV_STYLE_") current_val += 1 - return props @@ -79,18 +56,13 @@ def parse_parts(path: Path) -> dict[int, str]: m = re.search(r"typedef\s+enum\s*\{(.*?)\}\s*lv_part_t", text, re.DOTALL) if not m: raise RuntimeError("Cannot find lv_part_t enum") - parts = {} for line in m.group(1).splitlines(): match = re.match(r"\s*(LV_PART_\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) if not match: continue - name = match.group(1) val = int(match.group(2), 0) - short = name.removeprefix("LV_PART_") - # Selector uses bits [23:16], shift down to get the key - parts[val >> 16] = short - + parts[val >> 16] = match.group(1).removeprefix("LV_PART_") return parts @@ -112,25 +84,17 @@ def parse_states(path: Path) -> dict[int, str]: m = re.search(r"typedef\s+enum\s*\{(.*?)\}\s*lv_state_t", text, re.DOTALL) if not m: raise RuntimeError("Cannot find lv_state_t enum") - states = {} for line in m.group(1).splitlines(): match = re.match(r"\s*(LV_STATE_\w+)\s*=\s*(.+?)(?:,|/)", line) if not match: continue name = match.group(1) - expr = match.group(2).strip() - - # Skip DEFAULT (0) and ANY (0xFFFF) if name in ("LV_STATE_DEFAULT", "LV_STATE_ANY"): continue - - val = _parse_int_expr(expr) - if val is None: - continue - short = name.removeprefix("LV_STATE_") - states[val] = short - + val = _parse_int_expr(match.group(2)) + if val is not None: + states[val] = name.removeprefix("LV_STATE_") return states @@ -138,7 +102,6 @@ def parse_color_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int]: """Identify color properties from lv_style_gen.h setter signatures.""" text = style_gen_h.read_text() name_to_id = {v: k for k, v in prop_map.items()} - color_ids = set() for match in re.finditer( r"void\s+lv_style_set_(\w+)\s*\([^,]+,\s*lv_color_t", text @@ -146,7 +109,6 @@ def parse_color_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int]: prop_name = match.group(1).upper() if prop_name in name_to_id: color_ids.add(name_to_id[prop_name]) - return color_ids @@ -154,7 +116,6 @@ def parse_pointer_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int] """Identify pointer properties from lv_style_gen.h setter signatures.""" text = style_gen_h.read_text() name_to_id = {v: k for k, v in prop_map.items()} - ptr_ids = set() for match in re.finditer( r"void\s+lv_style_set_(\w+)\s*\([^,]+,\s*(?:const\s+)?(?:void|lv_\w+)\s*\*", @@ -163,50 +124,38 @@ def parse_pointer_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int] prop_name = match.group(1).upper() if prop_name in name_to_id: ptr_ids.add(name_to_id[prop_name]) - return ptr_ids -def generate( - props: dict[int, str], - parts: dict[int, str], - states: dict[int, str], - color_ids: set[int], - pointer_ids: set[int], -) -> str: - """Generate Python source for the constants module.""" +def generate(props, parts, states, color_ids, pointer_ids) -> str: + """Generate Python source for the style constants module.""" lines = [ '"""', "Auto-generated style constants from LVGL headers.", "", - "Do not edit manually. Regenerate with:", - " python3 scripts/gen_style_consts.py", + "Do not edit manually. Regenerate from the GDB script root with:", + " python3 scripts/generate_all.py", '"""', "", ] - - # STYLE_PROP_NAMES lines.append("STYLE_PROP_NAMES = {") for k in sorted(props): lines.append(f' {k}: "{props[k]}",') lines.append("}") lines.append("") - # PART_NAMES lines.append("PART_NAMES = {") for k in sorted(parts): lines.append(f' 0x{k:02X}: "{parts[k]}",') lines.append("}") lines.append("") - # STATE_FLAGS lines.append("STATE_FLAGS = {") for k in sorted(states): lines.append(f' 0x{k:04X}: "{states[k]}",') lines.append("}") lines.append("") - # COLOR_PROPS if color_ids: lines.append("COLOR_PROPS = {") for v in sorted(color_ids): @@ -216,7 +165,6 @@ def generate( lines.append("COLOR_PROPS = set()") lines.append("") - # POINTER_PROPS if pointer_ids: lines.append("POINTER_PROPS = {") for v in sorted(pointer_ids): @@ -239,7 +187,7 @@ def main(): src = generate(props, parts, states, color_ids, pointer_ids) OUTPUT.write_text(src) print( - f"Generated {OUTPUT} ({len(props)} props, {len(parts)} parts, " + f"Generated {OUTPUT.name} ({len(props)} props, {len(parts)} parts, " f"{len(states)} states, {len(color_ids)} color, {len(pointer_ids)} pointer)" ) diff --git a/scripts/gdb/scripts/generators/gen_subject_consts.py b/scripts/gdb/scripts/generators/gen_subject_consts.py new file mode 100644 index 0000000000..6a08c75644 --- /dev/null +++ b/scripts/gdb/scripts/generators/gen_subject_consts.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Generate subject type constant table from LVGL headers.""" + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from enum_parser import parse_enum, generate_dict_module + +LVGL_SRC = Path(__file__).parent.parent.parent.parent.parent / "src" +OUTPUT = Path(__file__).parent.parent.parent / "lvglgdb" / "lvgl" / "core" / "lv_observer_consts.py" + + +def main(): + subject_types = parse_enum( + LVGL_SRC / "core" / "lv_observer.h", + "lv_subject_type_t", + "LV_SUBJECT_TYPE_", + ) + src = generate_dict_module( + "observer constants from LVGL headers", + {"SUBJECT_TYPE_NAMES": subject_types}, + ) + OUTPUT.write_text(src) + print(f"Generated {OUTPUT.name} ({len(subject_types)} subject types)") + + +if __name__ == "__main__": + main()