diff --git a/buildroot/share/PlatformIO/scripts/schema.py b/buildroot/share/PlatformIO/scripts/schema.py index 6a669d887e..9621e30c62 100755 --- a/buildroot/share/PlatformIO/scripts/schema.py +++ b/buildroot/share/PlatformIO/scripts/schema.py @@ -61,8 +61,7 @@ def find_grouping(gdict, filekey, sectkey, optkey, pindex): optparts[pindex] = '*' wildkey = '_'.join(optparts) kkey = f'{filekey}|{sectkey}|{wildkey}' - if kkey not in gdict: gdict[kkey] = [] - gdict[kkey].append((subkey, modkey)) + gdict.setdefault(kkey, []).append((subkey, modkey)) # Build a list of potential groups. Only those with multiple items will be grouped. def group_options(schema): @@ -137,7 +136,9 @@ def extract_files(filekey): # Regex for #define NAME [VALUE] [COMMENT] with sanitized line defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$') # Pattern to match a float value - flt = r'[-+]?\s*(\d+\.|\d*\.\d+)([eE][-+]?\d+)?[fF]?' + flt = r'[-+]?\s*(?:\d+\.|\d*\.\d+)(?:[eE][-+]?\d+)?[fF]?' + # Pattern to match an integer expression + int_expr = r'(?:[-+]?\s*\d+(?:\s*[*\/+\-]\s*\d+)*)' # Start with unknown state state = Parse.NORMAL # Serial ID @@ -314,9 +315,11 @@ def extract_files(filekey): # Parenthesize the given expression if needed def atomize(s): - if s == '' \ - or re.match(r'^[A-Za-z0-9_]*(\([^)]+\))?$', s) \ - or re.match(r'^[A-Za-z0-9_]+ == \d+?$', s): + s = s.strip() + if not s or s.isidentifier() or (s.startswith('(') and s.endswith(')')): + return s + if re.match(r'^[A-Za-z0-9_]*(\([^)]+\))$', s) \ + or re.match(r'^[A-Za-z0-9_]+\s*[=!<>]=?\s*.*$', s): return s return f'({s})' @@ -369,27 +372,30 @@ def extract_files(filekey): } # Type is based on the value - value_type = \ - 'switch' if val == '' \ - else 'int' if re.match(r'^[-+]?\s*\d+$', val) \ - else 'ints' if re.match(r'^([-+]?\s*\d+)(\s*,\s*[-+]?\s*\d+)+$', val) \ - else 'floats' if re.match(rf'({flt}(\s*,\s*{flt})+)', val) \ - else 'float' if re.match(f'^({flt})$', val) \ - else 'string' if val[0] == '"' \ - else 'char' if val[0] == "'" \ - else 'bool' if val in ('true', 'false') \ - else 'state' if val in ('HIGH', 'LOW') \ - else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) \ - else 'int[]' if re.match(r'^{\s*[-+]?\s*\d+(\s*,\s*[-+]?\s*\d+)*\s*}$', val) \ - else 'float[]' if re.match(r'^{{\s*{flt}(\s*,\s*{flt})*\s*}}$', val) \ - else 'array' if val[0] == '{' \ - else '' + value_type = ( + 'switch' if val == '' + else 'int' if re.match(r'^[-+]?\s*\d+$', val) + else 'ints' if re.match(r'^[-+]?\s*\d+(?:\s*,\s*[-+]?\s*\d+)+$', val) + else 'floats' if re.match(rf"^{flt}(?:\s*,\s*{flt})+$", val) + else 'float' if re.match(rf"^{flt}$", val) + else 'string' if val.startswith('"') + else 'char' if val.startswith("'") + else 'bool' if val in ('true', 'false') + else 'state' if val in ('HIGH', 'LOW') + else 'int[]' if re.match(rf"^\{{\s*{int_expr}(?:\s*,\s*{int_expr})*\s*\}}$", val) + else 'float[]' if re.match(rf"^\{{\s*{flt}(?:\s*,\s*{flt})*\s*\}}$", val) + else 'array' if val.startswith('{') + else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) + else '' + ) - val = (val == 'true') if value_type == 'bool' \ - else int(val) if value_type == 'int' \ - else val.replace('f','') if value_type == 'floats' \ - else float(val.replace('f','')) if value_type == 'float' \ - else val + val = ( + (val == 'true') if value_type == 'bool' + else int(val) if value_type == 'int' + else val.replace('f','') if value_type == 'floats' + else float(val.replace('f','')) if value_type == 'float' + else val + ) if val != '': define_info['value'] = val if value_type != '': define_info['type'] = value_type @@ -496,9 +502,14 @@ def main(): unk = not inargs(['some','json','jsons','group','yml','yaml', '-h', '--help']) if (unk): print(f"Unknown option: '{args[0]}'") if inargs(['-h', '--help']) or unk: + print("Extract firmware configuration into structured JSON or YAML schema format.") print("Usage: schema.py [-h] [some|json|jsons|group|yml|yaml]") - print(" some = json + yml") - print(" jsons = json + group") + print(" some Generate both JSON and YAML output (schema.json and schema.yml)") + print(" json Generate JSON output (schema.json)") + print(" jsons Generate grouped JSON output with wildcard options (schema.json and schema_grouped.json)") + print(" group Generate grouped JSON output only (schema_grouped.json)") + print(" yml Generate YAML output (schema.yml)") + print(" yaml Same as 'yml'") return # JSON schema