File indexing completed on 2024-05-05 04:01:50

0001 #!/usr/bin/env python3
0002 # SPDX-FileCopyrightText: 2023 Jonathan Poelen <jonathan.poelen@gmail.com>
0003 # SPDX-License-Identifier: MIT
0004 
0005 from typing import Iterable, Mapping
0006 from xml.etree.ElementTree import ElementTree
0007 
0008 import sys
0009 
0010 if len(sys.argv) < 2:
0011     print(sys.argv[0], 'syntax.xml...', file=sys.stderr)
0012     exit(1)
0013 
0014 
0015 def normalize_bool_or_remove_if_false(d: dict[str, str], key: str) -> None:
0016     value = d.get(key)
0017     if value is not None:
0018         if value == '1' or value.lower() == 'true':
0019             d[key] = '1'
0020         else:
0021             d.pop(key)
0022 
0023 def remove_if_stay(d: dict[str, str], key: str) -> None:
0024     value = d.get(key)
0025     if value is not None and (not value or value == '#stay'):
0026         d.pop(key)
0027 
0028 
0029 for filename in sys.argv[1:]:
0030     tree = ElementTree()
0031     tree.parse(filename)
0032 
0033     identical_contexts = {}
0034 
0035     for context in tree.getroot()[0].find("contexts"):
0036         if len(context) == 0 or (len(context) == 1 and context[0].tag == 'IncludeRules'):
0037             attrib = context.attrib
0038             name = attrib.pop('name')
0039             remove_if_stay(attrib, 'lineEndContext')
0040             remove_if_stay(attrib, 'lineEmptyContext')
0041             remove_if_stay(attrib, 'fallthroughContext')
0042             if len(context):
0043                 attrib.update(context[0].attrib)
0044                 normalize_bool_or_remove_if_false(attrib, 'includeAttrib')
0045 
0046             s = '\n'.join(sorted(f'{k}={v}' for k,v in attrib.items()))
0047             identical_contexts.setdefault(s, []).append(name)
0048         else:
0049             rules = set()
0050             for rule in context:
0051                 attrib = rule.attrib
0052                 remove_if_stay(attrib, 'context')
0053                 normalize_bool_or_remove_if_false(attrib, 'dynamic')
0054                 normalize_bool_or_remove_if_false(attrib, 'minimal')
0055                 normalize_bool_or_remove_if_false(attrib, 'includeAttrib')
0056                 normalize_bool_or_remove_if_false(attrib, 'firstNonSpace')
0057                 normalize_bool_or_remove_if_false(attrib, 'lookAhead')
0058                 s = '\n'.join(f'{k}={v}' for k,v in sorted(attrib.items()))
0059                 rules.add(f'{rule.tag}\n{s}')
0060 
0061             identical_contexts.setdefault('\n'.join(sorted(rules)), []).append(context.attrib['name'])
0062 
0063     for names in identical_contexts.values():
0064         if len(names) > 1:
0065             print(f'{filename}: {names}')