23
23
import zipfile
24
24
from copy import deepcopy
25
25
from dataclasses import dataclass
26
- from enum import Enum , auto
26
+ from enum import Enum , StrEnum , auto
27
27
from importlib .abc import Traversable
28
28
from typing import Callable , Optional , Union
29
29
@@ -58,6 +58,29 @@ class SpecParsingException(Exception):
58
58
ConformanceCallable = Callable [[uint , list [uint ], list [uint ]], ConformanceDecision ]
59
59
60
60
61
+ class DataTypeEnum (StrEnum ):
62
+ kStruct = 'struct'
63
+ kEnum = 'enum'
64
+ kBitmap = 'bitmap'
65
+
66
+
67
+ @dataclass
68
+ class XmlDataTypeComponent :
69
+ value : uint
70
+ name : str
71
+ # TODO: other fields are available as well - type, constraints etc.
72
+ conformance : ConformanceCallable
73
+
74
+
75
+ @dataclass
76
+ class XmlDataType :
77
+ data_type : DataTypeEnum
78
+ name : str
79
+ components : dict [uint , XmlDataTypeComponent ]
80
+ # if this is None, this is a global struct
81
+ cluster_ids : Optional [list [uint ]]
82
+
83
+
61
84
@dataclass
62
85
class XmlFeature :
63
86
code : str
@@ -120,6 +143,9 @@ class XmlCluster:
120
143
generated_commands : dict [uint , XmlCommand ]
121
144
unknown_commands : list [XmlCommand ]
122
145
events : dict [uint , XmlEvent ]
146
+ structs : dict [str , XmlDataType ]
147
+ enums : dict [str , XmlDataType ]
148
+ bitmaps : dict [str , XmlDataType ]
123
149
pics : str
124
150
is_provisional : bool
125
151
@@ -379,6 +405,56 @@ def str_to_access_type(privilege_str: str) -> Clusters.AccessControl.Enums.Acces
379
405
invoke_access = Clusters .AccessControl .Enums .AccessControlEntryPrivilegeEnum .kUnknownEnumValue
380
406
return (read_access , write_access , invoke_access )
381
407
408
+ def _parse_components (self , struct : ElementTree .Element , component_type : DataTypeEnum ) -> dict [uint , XmlDataTypeComponent ]:
409
+ @dataclass
410
+ class ComponentTag :
411
+ tag : str
412
+ id_attrib : str
413
+ component_tags = {DataTypeEnum .kStruct : ComponentTag ('field' , 'id' ), DataTypeEnum .kEnum : ComponentTag (
414
+ 'item' , 'value' ), DataTypeEnum .kBitmap : ComponentTag ('bitfield' , 'bit' )}
415
+ components = {}
416
+ struct_name = struct .attrib ['name' ]
417
+ location = ClusterPathLocation (0 , self ._cluster_id )
418
+ for xml_field in list (struct ):
419
+ if xml_field .tag != component_tags [component_type ].tag :
420
+ continue
421
+ try :
422
+ name = xml_field .attrib ['name' ]
423
+ id = xml_field .attrib [component_tags [component_type ].id_attrib ]
424
+ except KeyError :
425
+ p = ProblemNotice ("Spec XML Parsing" , location = location ,
426
+ severity = ProblemSeverity .WARNING , problem = f"Struct field in { struct_name } with no id or name" )
427
+ self ._problems .append (p )
428
+ continue
429
+ xml_conformance , problems = get_conformance (xml_field , self ._cluster_id )
430
+ # There are a LOT of struct fields with either arithmetic or desc conformances. We'll just call these as optional if we can't parse
431
+ # These are currently unused, so this is fine for now.
432
+ conformance = None
433
+ if not problems :
434
+ conformance = self .parse_conformance (xml_conformance )
435
+ if not conformance :
436
+ conformance = optional ()
437
+ components [id ] = XmlDataTypeComponent (id , name , conformance )
438
+ return components
439
+
440
+ def _parse_data_type (self , data_type : DataTypeEnum ) -> dict [str , XmlDataType ]:
441
+ ''' Returns XmlStructs, key is the name.'''
442
+ data_types = {}
443
+ container_tags = self ._cluster .iter ('dataTypes' )
444
+ for container in container_tags :
445
+ xmls = container .iter (str (data_type ))
446
+ for element in xmls :
447
+ try :
448
+ name = element .attrib ['name' ]
449
+ except KeyError :
450
+ location = ClusterPathLocation (0 , self ._cluster_id )
451
+ self ._problems .append (ProblemNotice ("Spec XML Parsing" , location = location ,
452
+ severity = ProblemSeverity .WARNING , problem = f"Struct { element } with no id or name" ))
453
+ continue
454
+ data_types [name ] = XmlDataType (data_type = data_type , name = name , components = self ._parse_components (
455
+ element , data_type ), cluster_ids = [self ._cluster_id ])
456
+ return data_types
457
+
382
458
def parse_features (self ) -> dict [uint , XmlFeature ]:
383
459
features = {}
384
460
for element , conformance_xml , _ in self .feature_elements :
@@ -483,7 +559,9 @@ def create_cluster(self) -> XmlCluster:
483
559
accepted_commands = self .parse_commands (CommandType .ACCEPTED ),
484
560
generated_commands = self .parse_commands (CommandType .GENERATED ),
485
561
unknown_commands = self .parse_unknown_commands (),
486
- events = self .parse_events (), pics = self ._pics , is_provisional = self ._is_provisional )
562
+ events = self .parse_events (),
563
+ structs = self ._parse_data_type (DataTypeEnum .kStruct ), enums = self ._parse_data_type (DataTypeEnum .kEnum ),
564
+ bitmaps = self ._parse_data_type (DataTypeEnum .kBitmap ), pics = self ._pics , is_provisional = self ._is_provisional )
487
565
488
566
def get_problems (self ) -> list [ProblemNotice ]:
489
567
return self ._problems
@@ -768,6 +846,12 @@ def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAt
768
846
generated_commands .update (c .generated_commands )
769
847
events = deepcopy (base .events )
770
848
events .update (c .events )
849
+ structs = deepcopy (base .structs )
850
+ structs .update (c .structs )
851
+ enums = deepcopy (base .enums )
852
+ enums .update (c .enums )
853
+ bitmaps = deepcopy (base .bitmaps )
854
+ enums .update (c .bitmaps )
771
855
unknown_commands = deepcopy (base .unknown_commands )
772
856
for cmd in c .unknown_commands :
773
857
if cmd .id in accepted_commands .keys () and cmd .name == accepted_commands [uint (cmd .id )].name :
@@ -781,8 +865,8 @@ def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAt
781
865
new = XmlCluster (revision = c .revision , derived = c .derived , name = c .name ,
782
866
feature_map = feature_map , attribute_map = attribute_map , command_map = command_map ,
783
867
features = features , attributes = attributes , accepted_commands = accepted_commands ,
784
- generated_commands = generated_commands , unknown_commands = unknown_commands , events = events , pics = c . pics ,
785
- is_provisional = provisional )
868
+ generated_commands = generated_commands , unknown_commands = unknown_commands , events = events , structs = structs ,
869
+ enums = enums , bitmaps = bitmaps , pics = c . pics , is_provisional = provisional )
786
870
xml_clusters [id ] = new
787
871
788
872
0 commit comments