1e5c31af7Sopenharmony_ci#!/usr/bin/python3 -i
2e5c31af7Sopenharmony_ci#
3e5c31af7Sopenharmony_ci# Copyright 2013-2024 The Khronos Group Inc.
4e5c31af7Sopenharmony_ci#
5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
6e5c31af7Sopenharmony_ci
7e5c31af7Sopenharmony_ci"""Types and classes for manipulating an API registry."""
8e5c31af7Sopenharmony_ci
9e5c31af7Sopenharmony_ciimport copy
10e5c31af7Sopenharmony_ciimport re
11e5c31af7Sopenharmony_ciimport sys
12e5c31af7Sopenharmony_ciimport xml.etree.ElementTree as etree
13e5c31af7Sopenharmony_cifrom collections import defaultdict, deque, namedtuple
14e5c31af7Sopenharmony_ci
15e5c31af7Sopenharmony_cifrom generator import GeneratorOptions, OutputGenerator, noneStr, write
16e5c31af7Sopenharmony_cifrom apiconventions import APIConventions
17e5c31af7Sopenharmony_ci
18e5c31af7Sopenharmony_cidef apiNameMatch(str, supported):
19e5c31af7Sopenharmony_ci    """Return whether a required api name matches a pattern specified for an
20e5c31af7Sopenharmony_ci    XML <feature> 'api' attribute or <extension> 'supported' attribute.
21e5c31af7Sopenharmony_ci
22e5c31af7Sopenharmony_ci    - str - API name such as 'vulkan' or 'openxr'. May be None, in which
23e5c31af7Sopenharmony_ci        case it never matches (this should not happen).
24e5c31af7Sopenharmony_ci    - supported - comma-separated list of XML API names. May be None, in
25e5c31af7Sopenharmony_ci        which case str always matches (this is the usual case)."""
26e5c31af7Sopenharmony_ci
27e5c31af7Sopenharmony_ci    if str is not None:
28e5c31af7Sopenharmony_ci        return supported is None or str in supported.split(',')
29e5c31af7Sopenharmony_ci
30e5c31af7Sopenharmony_ci    # Fallthrough case - either str is None or the test failed
31e5c31af7Sopenharmony_ci    return False
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_cidef matchAPIProfile(api, profile, elem):
34e5c31af7Sopenharmony_ci    """Return whether an API and profile
35e5c31af7Sopenharmony_ci    being generated matches an element's profile
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_ci    - api - string naming the API to match
38e5c31af7Sopenharmony_ci    - profile - string naming the profile to match
39e5c31af7Sopenharmony_ci    - elem - Element which (may) have 'api' and 'profile'
40e5c31af7Sopenharmony_ci      attributes to match to.
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_ci    If a tag is not present in the Element, the corresponding API
43e5c31af7Sopenharmony_ci      or profile always matches.
44e5c31af7Sopenharmony_ci
45e5c31af7Sopenharmony_ci    Otherwise, the tag must exactly match the API or profile.
46e5c31af7Sopenharmony_ci
47e5c31af7Sopenharmony_ci    Thus, if 'profile' = core:
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci    - `<remove>`  with no attribute will match
50e5c31af7Sopenharmony_ci    - `<remove profile="core">` will match
51e5c31af7Sopenharmony_ci    - `<remove profile="compatibility">` will not match
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ci    Possible match conditions:
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_ci    ```
56e5c31af7Sopenharmony_ci      Requested   Element
57e5c31af7Sopenharmony_ci      Profile     Profile
58e5c31af7Sopenharmony_ci      ---------   --------
59e5c31af7Sopenharmony_ci      None        None        Always matches
60e5c31af7Sopenharmony_ci      'string'    None        Always matches
61e5c31af7Sopenharmony_ci      None        'string'    Does not match. Cannot generate multiple APIs
62e5c31af7Sopenharmony_ci                              or profiles, so if an API/profile constraint
63e5c31af7Sopenharmony_ci                              is present, it must be asked for explicitly.
64e5c31af7Sopenharmony_ci      'string'    'string'    Strings must match
65e5c31af7Sopenharmony_ci    ```
66e5c31af7Sopenharmony_ci
67e5c31af7Sopenharmony_ci    ** In the future, we will allow regexes for the attributes,
68e5c31af7Sopenharmony_ci    not just strings, so that `api="^(gl|gles2)"` will match. Even
69e5c31af7Sopenharmony_ci    this is not really quite enough, we might prefer something
70e5c31af7Sopenharmony_ci    like `"gl(core)|gles1(common-lite)"`."""
71e5c31af7Sopenharmony_ci    # Match 'api', if present
72e5c31af7Sopenharmony_ci    elem_api = elem.get('api')
73e5c31af7Sopenharmony_ci    if elem_api:
74e5c31af7Sopenharmony_ci        if api is None:
75e5c31af7Sopenharmony_ci            raise UserWarning("No API requested, but 'api' attribute is present with value '"
76e5c31af7Sopenharmony_ci                              + elem_api + "'")
77e5c31af7Sopenharmony_ci        elif api != elem_api:
78e5c31af7Sopenharmony_ci            # Requested API does not match attribute
79e5c31af7Sopenharmony_ci            return False
80e5c31af7Sopenharmony_ci    elem_profile = elem.get('profile')
81e5c31af7Sopenharmony_ci    if elem_profile:
82e5c31af7Sopenharmony_ci        if profile is None:
83e5c31af7Sopenharmony_ci            raise UserWarning("No profile requested, but 'profile' attribute is present with value '"
84e5c31af7Sopenharmony_ci                              + elem_profile + "'")
85e5c31af7Sopenharmony_ci        elif profile != elem_profile:
86e5c31af7Sopenharmony_ci            # Requested profile does not match attribute
87e5c31af7Sopenharmony_ci            return False
88e5c31af7Sopenharmony_ci    return True
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_cidef mergeAPIs(tree, fromApiNames, toApiName):
92e5c31af7Sopenharmony_ci    """Merge multiple APIs using the precedence order specified in apiNames.
93e5c31af7Sopenharmony_ci    Also deletes <remove> elements.
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci        tree - Element at the root of the hierarchy to merge.
96e5c31af7Sopenharmony_ci        apiNames - list of strings of API names."""
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci    stack = deque()
99e5c31af7Sopenharmony_ci    stack.append(tree)
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci    while len(stack) > 0:
102e5c31af7Sopenharmony_ci        parent = stack.pop()
103e5c31af7Sopenharmony_ci
104e5c31af7Sopenharmony_ci        for child in parent.findall('*'):
105e5c31af7Sopenharmony_ci            if child.tag == 'remove':
106e5c31af7Sopenharmony_ci                # Remove <remove> elements
107e5c31af7Sopenharmony_ci                parent.remove(child)
108e5c31af7Sopenharmony_ci            else:
109e5c31af7Sopenharmony_ci                stack.append(child)
110e5c31af7Sopenharmony_ci
111e5c31af7Sopenharmony_ci            supportedList = child.get('supported')
112e5c31af7Sopenharmony_ci            if supportedList:
113e5c31af7Sopenharmony_ci                supportedList = supportedList.split(',')
114e5c31af7Sopenharmony_ci                for apiName in [toApiName] + fromApiNames:
115e5c31af7Sopenharmony_ci                    if apiName in supportedList:
116e5c31af7Sopenharmony_ci                        child.set('supported', toApiName)
117e5c31af7Sopenharmony_ci
118e5c31af7Sopenharmony_ci            if child.get('api'):
119e5c31af7Sopenharmony_ci                definitionName = None
120e5c31af7Sopenharmony_ci                definitionVariants = []
121e5c31af7Sopenharmony_ci
122e5c31af7Sopenharmony_ci                # Keep only one definition with the same name if there are multiple definitions
123e5c31af7Sopenharmony_ci                if child.tag in ['type']:
124e5c31af7Sopenharmony_ci                    if child.get('name') is not None:
125e5c31af7Sopenharmony_ci                        definitionName = child.get('name')
126e5c31af7Sopenharmony_ci                        definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']")
127e5c31af7Sopenharmony_ci                    else:
128e5c31af7Sopenharmony_ci                        definitionName = child.find('name').text
129e5c31af7Sopenharmony_ci                        definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..")
130e5c31af7Sopenharmony_ci                elif child.tag in ['member', 'param']:
131e5c31af7Sopenharmony_ci                    definitionName = child.find('name').text
132e5c31af7Sopenharmony_ci                    definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..")
133e5c31af7Sopenharmony_ci                elif child.tag in ['enum', 'feature']:
134e5c31af7Sopenharmony_ci                    definitionName = child.get('name')
135e5c31af7Sopenharmony_ci                    definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']")
136e5c31af7Sopenharmony_ci                elif child.tag in ['require']:
137e5c31af7Sopenharmony_ci                    definitionName = child.get('feature')
138e5c31af7Sopenharmony_ci                    definitionVariants = parent.findall(f"{child.tag}[@feature='{definitionName}']")
139e5c31af7Sopenharmony_ci                elif child.tag in ['command']:
140e5c31af7Sopenharmony_ci                    definitionName = child.find('proto/name').text
141e5c31af7Sopenharmony_ci                    definitionVariants = parent.findall(f"{child.tag}/proto/name[.='{definitionName}']/../..")
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci                if definitionName:
144e5c31af7Sopenharmony_ci                    bestMatchApi = None
145e5c31af7Sopenharmony_ci                    requires = None
146e5c31af7Sopenharmony_ci                    for apiName in [toApiName] + fromApiNames:
147e5c31af7Sopenharmony_ci                        for variant in definitionVariants:
148e5c31af7Sopenharmony_ci                            # Keep any requires attributes from the target API
149e5c31af7Sopenharmony_ci                            if variant.get('requires') and variant.get('api') == apiName:
150e5c31af7Sopenharmony_ci                                requires = variant.get('requires')
151e5c31af7Sopenharmony_ci                            # Find the best matching definition
152e5c31af7Sopenharmony_ci                            if apiName in variant.get('api').split(',') and bestMatchApi is None:
153e5c31af7Sopenharmony_ci                                bestMatchApi = variant.get('api')
154e5c31af7Sopenharmony_ci
155e5c31af7Sopenharmony_ci                    if bestMatchApi:
156e5c31af7Sopenharmony_ci                        for variant in definitionVariants:
157e5c31af7Sopenharmony_ci                            if variant.get('api') != bestMatchApi:
158e5c31af7Sopenharmony_ci                                # Only keep best matching definition
159e5c31af7Sopenharmony_ci                                parent.remove(variant)
160e5c31af7Sopenharmony_ci                            else:
161e5c31af7Sopenharmony_ci                                # Add requires attribute from the target API if it is not overridden
162e5c31af7Sopenharmony_ci                                if requires is not None and variant.get('requires') is None:
163e5c31af7Sopenharmony_ci                                    variant.set('requires', requires)
164e5c31af7Sopenharmony_ci                                variant.set('api', toApiName)
165e5c31af7Sopenharmony_ci
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_cidef stripNonmatchingAPIs(tree, apiName, actuallyDelete = True):
168e5c31af7Sopenharmony_ci    """Remove tree Elements with 'api' attributes matching apiName.
169e5c31af7Sopenharmony_ci
170e5c31af7Sopenharmony_ci        tree - Element at the root of the hierarchy to strip. Only its
171e5c31af7Sopenharmony_ci            children can actually be removed, not the tree itself.
172e5c31af7Sopenharmony_ci        apiName - string which much match a command-separated component of
173e5c31af7Sopenharmony_ci            the 'api' attribute.
174e5c31af7Sopenharmony_ci        actuallyDelete - only delete matching elements if True."""
175e5c31af7Sopenharmony_ci
176e5c31af7Sopenharmony_ci    stack = deque()
177e5c31af7Sopenharmony_ci    stack.append(tree)
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_ci    while len(stack) > 0:
180e5c31af7Sopenharmony_ci        parent = stack.pop()
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci        for child in parent.findall('*'):
183e5c31af7Sopenharmony_ci            api = child.get('api')
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_ci            if apiNameMatch(apiName, api):
186e5c31af7Sopenharmony_ci                # Add child to the queue
187e5c31af7Sopenharmony_ci                stack.append(child)
188e5c31af7Sopenharmony_ci            elif not apiNameMatch(apiName, api):
189e5c31af7Sopenharmony_ci                # Child does not match requested api. Remove it.
190e5c31af7Sopenharmony_ci                if actuallyDelete:
191e5c31af7Sopenharmony_ci                    parent.remove(child)
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_ci
194e5c31af7Sopenharmony_ciclass BaseInfo:
195e5c31af7Sopenharmony_ci    """Base class for information about a registry feature
196e5c31af7Sopenharmony_ci    (type/group/enum/command/API/extension).
197e5c31af7Sopenharmony_ci
198e5c31af7Sopenharmony_ci    Represents the state of a registry feature, used during API generation.
199e5c31af7Sopenharmony_ci    """
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_ci    def __init__(self, elem):
202e5c31af7Sopenharmony_ci        self.required = False
203e5c31af7Sopenharmony_ci        """should this feature be defined during header generation
204e5c31af7Sopenharmony_ci        (has it been removed by a profile or version)?"""
205e5c31af7Sopenharmony_ci
206e5c31af7Sopenharmony_ci        self.declared = False
207e5c31af7Sopenharmony_ci        "has this feature been defined already?"
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_ci        self.elem = elem
210e5c31af7Sopenharmony_ci        "etree Element for this feature"
211e5c31af7Sopenharmony_ci
212e5c31af7Sopenharmony_ci    def resetState(self):
213e5c31af7Sopenharmony_ci        """Reset required/declared to initial values. Used
214e5c31af7Sopenharmony_ci        prior to generating a new API interface."""
215e5c31af7Sopenharmony_ci        self.required = False
216e5c31af7Sopenharmony_ci        self.declared = False
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci    def compareKeys(self, info, key, required = False):
219e5c31af7Sopenharmony_ci        """Return True if self.elem and info.elem have the same attribute
220e5c31af7Sopenharmony_ci           value for key.
221e5c31af7Sopenharmony_ci           If 'required' is not True, also returns True if neither element
222e5c31af7Sopenharmony_ci           has an attribute value for key."""
223e5c31af7Sopenharmony_ci
224e5c31af7Sopenharmony_ci        if required and key not in self.elem.keys():
225e5c31af7Sopenharmony_ci            return False
226e5c31af7Sopenharmony_ci        return self.elem.get(key) == info.elem.get(key)
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci    def compareElem(self, info, infoName):
229e5c31af7Sopenharmony_ci        """Return True if self.elem and info.elem have the same definition.
230e5c31af7Sopenharmony_ci        info - the other object
231e5c31af7Sopenharmony_ci        infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' /
232e5c31af7Sopenharmony_ci                   'extension'"""
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ci        if infoName == 'enum':
235e5c31af7Sopenharmony_ci            if self.compareKeys(info, 'extends'):
236e5c31af7Sopenharmony_ci                # Either both extend the same type, or no type
237e5c31af7Sopenharmony_ci                if (self.compareKeys(info, 'value', required = True) or
238e5c31af7Sopenharmony_ci                    self.compareKeys(info, 'bitpos', required = True)):
239e5c31af7Sopenharmony_ci                    # If both specify the same value or bit position,
240e5c31af7Sopenharmony_ci                    # they are equal
241e5c31af7Sopenharmony_ci                    return True
242e5c31af7Sopenharmony_ci                elif (self.compareKeys(info, 'extnumber') and
243e5c31af7Sopenharmony_ci                      self.compareKeys(info, 'offset') and
244e5c31af7Sopenharmony_ci                      self.compareKeys(info, 'dir')):
245e5c31af7Sopenharmony_ci                    # If both specify the same relative offset, they are equal
246e5c31af7Sopenharmony_ci                    return True
247e5c31af7Sopenharmony_ci                elif (self.compareKeys(info, 'alias')):
248e5c31af7Sopenharmony_ci                    # If both are aliases of the same value
249e5c31af7Sopenharmony_ci                    return True
250e5c31af7Sopenharmony_ci                else:
251e5c31af7Sopenharmony_ci                    return False
252e5c31af7Sopenharmony_ci            else:
253e5c31af7Sopenharmony_ci                # The same enum cannot extend two different types
254e5c31af7Sopenharmony_ci                return False
255e5c31af7Sopenharmony_ci        else:
256e5c31af7Sopenharmony_ci            # Non-<enum>s should never be redefined
257e5c31af7Sopenharmony_ci            return False
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci
260e5c31af7Sopenharmony_ciclass TypeInfo(BaseInfo):
261e5c31af7Sopenharmony_ci    """Registry information about a type. No additional state
262e5c31af7Sopenharmony_ci      beyond BaseInfo is required."""
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci    def __init__(self, elem):
265e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
266e5c31af7Sopenharmony_ci        self.additionalValidity = []
267e5c31af7Sopenharmony_ci        self.removedValidity = []
268e5c31af7Sopenharmony_ci
269e5c31af7Sopenharmony_ci    def getMembers(self):
270e5c31af7Sopenharmony_ci        """Get a collection of all member elements for this type, if any."""
271e5c31af7Sopenharmony_ci        return self.elem.findall('member')
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_ci    def resetState(self):
274e5c31af7Sopenharmony_ci        BaseInfo.resetState(self)
275e5c31af7Sopenharmony_ci        self.additionalValidity = []
276e5c31af7Sopenharmony_ci        self.removedValidity = []
277e5c31af7Sopenharmony_ci
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ciclass GroupInfo(BaseInfo):
280e5c31af7Sopenharmony_ci    """Registry information about a group of related enums
281e5c31af7Sopenharmony_ci    in an <enums> block, generally corresponding to a C "enum" type."""
282e5c31af7Sopenharmony_ci
283e5c31af7Sopenharmony_ci    def __init__(self, elem):
284e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
285e5c31af7Sopenharmony_ci
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ciclass EnumInfo(BaseInfo):
288e5c31af7Sopenharmony_ci    """Registry information about an enum"""
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci    def __init__(self, elem):
291e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
292e5c31af7Sopenharmony_ci        self.type = elem.get('type')
293e5c31af7Sopenharmony_ci        """numeric type of the value of the <enum> tag
294e5c31af7Sopenharmony_ci        ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )"""
295e5c31af7Sopenharmony_ci        if self.type is None:
296e5c31af7Sopenharmony_ci            self.type = ''
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ciclass CmdInfo(BaseInfo):
300e5c31af7Sopenharmony_ci    """Registry information about a command"""
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci    def __init__(self, elem):
303e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
304e5c31af7Sopenharmony_ci        self.additionalValidity = []
305e5c31af7Sopenharmony_ci        self.removedValidity = []
306e5c31af7Sopenharmony_ci
307e5c31af7Sopenharmony_ci    def getParams(self):
308e5c31af7Sopenharmony_ci        """Get a collection of all param elements for this command, if any."""
309e5c31af7Sopenharmony_ci        return self.elem.findall('param')
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci    def resetState(self):
312e5c31af7Sopenharmony_ci        BaseInfo.resetState(self)
313e5c31af7Sopenharmony_ci        self.additionalValidity = []
314e5c31af7Sopenharmony_ci        self.removedValidity = []
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_ciclass FeatureInfo(BaseInfo):
318e5c31af7Sopenharmony_ci    """Registry information about an API <feature>
319e5c31af7Sopenharmony_ci    or <extension>."""
320e5c31af7Sopenharmony_ci
321e5c31af7Sopenharmony_ci    def __init__(self, elem):
322e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
323e5c31af7Sopenharmony_ci        self.name = elem.get('name')
324e5c31af7Sopenharmony_ci        "feature name string (e.g. 'VK_KHR_surface')"
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci        self.emit = False
327e5c31af7Sopenharmony_ci        "has this feature been defined already?"
328e5c31af7Sopenharmony_ci
329e5c31af7Sopenharmony_ci        self.sortorder = int(elem.get('sortorder', 0))
330e5c31af7Sopenharmony_ci        """explicit numeric sort key within feature and extension groups.
331e5c31af7Sopenharmony_ci        Defaults to 0."""
332e5c31af7Sopenharmony_ci
333e5c31af7Sopenharmony_ci        # Determine element category (vendor). Only works
334e5c31af7Sopenharmony_ci        # for <extension> elements.
335e5c31af7Sopenharmony_ci        if elem.tag == 'feature':
336e5c31af7Sopenharmony_ci            # Element category (vendor) is meaningless for <feature>
337e5c31af7Sopenharmony_ci            self.category = 'VERSION'
338e5c31af7Sopenharmony_ci            """category, e.g. VERSION or khr/vendor tag"""
339e5c31af7Sopenharmony_ci
340e5c31af7Sopenharmony_ci            self.version = elem.get('name')
341e5c31af7Sopenharmony_ci            """feature name string"""
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci            self.versionNumber = elem.get('number')
344e5c31af7Sopenharmony_ci            """versionNumber - API version number, taken from the 'number'
345e5c31af7Sopenharmony_ci               attribute of <feature>. Extensions do not have API version
346e5c31af7Sopenharmony_ci               numbers and are assigned number 0."""
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_ci            self.number = 0
349e5c31af7Sopenharmony_ci            self.supported = None
350e5c31af7Sopenharmony_ci        else:
351e5c31af7Sopenharmony_ci            # Extract vendor portion of <APIprefix>_<vendor>_<name>
352e5c31af7Sopenharmony_ci            self.category = self.name.split('_', 2)[1]
353e5c31af7Sopenharmony_ci            self.version = "0"
354e5c31af7Sopenharmony_ci            self.versionNumber = "0"
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci            self.number = int(elem.get('number','0'))
357e5c31af7Sopenharmony_ci            """extension number, used for ordering and for assigning
358e5c31af7Sopenharmony_ci            enumerant offsets. <feature> features do not have extension
359e5c31af7Sopenharmony_ci            numbers and are assigned number 0, as are extensions without
360e5c31af7Sopenharmony_ci            numbers, so sorting works."""
361e5c31af7Sopenharmony_ci
362e5c31af7Sopenharmony_ci            self.supported = elem.get('supported', 'disabled')
363e5c31af7Sopenharmony_ci
364e5c31af7Sopenharmony_ciclass SpirvInfo(BaseInfo):
365e5c31af7Sopenharmony_ci    """Registry information about an API <spirvextensions>
366e5c31af7Sopenharmony_ci    or <spirvcapability>."""
367e5c31af7Sopenharmony_ci
368e5c31af7Sopenharmony_ci    def __init__(self, elem):
369e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ciclass FormatInfo(BaseInfo):
372e5c31af7Sopenharmony_ci    """Registry information about an API <format>."""
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci    def __init__(self, elem, condition):
375e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
376e5c31af7Sopenharmony_ci        # Need to save the condition here when it is known
377e5c31af7Sopenharmony_ci        self.condition = condition
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ciclass SyncStageInfo(BaseInfo):
380e5c31af7Sopenharmony_ci    """Registry information about <syncstage>."""
381e5c31af7Sopenharmony_ci
382e5c31af7Sopenharmony_ci    def __init__(self, elem, condition):
383e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
384e5c31af7Sopenharmony_ci        # Need to save the condition here when it is known
385e5c31af7Sopenharmony_ci        self.condition = condition
386e5c31af7Sopenharmony_ci
387e5c31af7Sopenharmony_ciclass SyncAccessInfo(BaseInfo):
388e5c31af7Sopenharmony_ci    """Registry information about <syncaccess>."""
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci    def __init__(self, elem, condition):
391e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
392e5c31af7Sopenharmony_ci        # Need to save the condition here when it is known
393e5c31af7Sopenharmony_ci        self.condition = condition
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_ciclass SyncPipelineInfo(BaseInfo):
396e5c31af7Sopenharmony_ci    """Registry information about <syncpipeline>."""
397e5c31af7Sopenharmony_ci
398e5c31af7Sopenharmony_ci    def __init__(self, elem):
399e5c31af7Sopenharmony_ci        BaseInfo.__init__(self, elem)
400e5c31af7Sopenharmony_ci
401e5c31af7Sopenharmony_ciclass Registry:
402e5c31af7Sopenharmony_ci    """Object representing an API registry, loaded from an XML file."""
403e5c31af7Sopenharmony_ci
404e5c31af7Sopenharmony_ci    def __init__(self, gen=None, genOpts=None):
405e5c31af7Sopenharmony_ci        if gen is None:
406e5c31af7Sopenharmony_ci            # If not specified, give a default object so messaging will work
407e5c31af7Sopenharmony_ci            self.gen = OutputGenerator()
408e5c31af7Sopenharmony_ci        else:
409e5c31af7Sopenharmony_ci            self.gen = gen
410e5c31af7Sopenharmony_ci        "Output generator used to write headers / messages"
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_ci        if genOpts is None:
413e5c31af7Sopenharmony_ci            # If no generator is provided, we may still need the XML API name
414e5c31af7Sopenharmony_ci            # (for example, in genRef.py).
415e5c31af7Sopenharmony_ci            self.genOpts = GeneratorOptions(apiname = APIConventions().xml_api_name)
416e5c31af7Sopenharmony_ci        else:
417e5c31af7Sopenharmony_ci            self.genOpts = genOpts
418e5c31af7Sopenharmony_ci        "Options controlling features to write and how to format them"
419e5c31af7Sopenharmony_ci
420e5c31af7Sopenharmony_ci        self.gen.registry = self
421e5c31af7Sopenharmony_ci        self.gen.genOpts = self.genOpts
422e5c31af7Sopenharmony_ci        self.gen.genOpts.registry = self
423e5c31af7Sopenharmony_ci
424e5c31af7Sopenharmony_ci        self.tree = None
425e5c31af7Sopenharmony_ci        "ElementTree containing the root `<registry>`"
426e5c31af7Sopenharmony_ci
427e5c31af7Sopenharmony_ci        self.typedict = {}
428e5c31af7Sopenharmony_ci        "dictionary of TypeInfo objects keyed by type name"
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci        self.groupdict = {}
431e5c31af7Sopenharmony_ci        "dictionary of GroupInfo objects keyed by group name"
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci        self.enumdict = {}
434e5c31af7Sopenharmony_ci        "dictionary of EnumInfo objects keyed by enum name"
435e5c31af7Sopenharmony_ci
436e5c31af7Sopenharmony_ci        self.cmddict = {}
437e5c31af7Sopenharmony_ci        "dictionary of CmdInfo objects keyed by command name"
438e5c31af7Sopenharmony_ci
439e5c31af7Sopenharmony_ci        self.apidict = {}
440e5c31af7Sopenharmony_ci        "dictionary of FeatureInfo objects for `<feature>` elements keyed by API name"
441e5c31af7Sopenharmony_ci
442e5c31af7Sopenharmony_ci        self.extensions = []
443e5c31af7Sopenharmony_ci        "list of `<extension>` Elements"
444e5c31af7Sopenharmony_ci
445e5c31af7Sopenharmony_ci        self.extdict = {}
446e5c31af7Sopenharmony_ci        "dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name"
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ci        self.spirvextdict = {}
449e5c31af7Sopenharmony_ci        "dictionary of FeatureInfo objects for `<spirvextension>` elements keyed by spirv extension name"
450e5c31af7Sopenharmony_ci
451e5c31af7Sopenharmony_ci        self.spirvcapdict = {}
452e5c31af7Sopenharmony_ci        "dictionary of FeatureInfo objects for `<spirvcapability>` elements keyed by spirv capability name"
453e5c31af7Sopenharmony_ci
454e5c31af7Sopenharmony_ci        self.formatsdict = {}
455e5c31af7Sopenharmony_ci        "dictionary of FeatureInfo objects for `<format>` elements keyed by VkFormat name"
456e5c31af7Sopenharmony_ci
457e5c31af7Sopenharmony_ci        self.syncstagedict = {}
458e5c31af7Sopenharmony_ci        "dictionary of Sync*Info objects for `<syncstage>` elements keyed by VkPipelineStageFlagBits2 name"
459e5c31af7Sopenharmony_ci
460e5c31af7Sopenharmony_ci        self.syncaccessdict = {}
461e5c31af7Sopenharmony_ci        "dictionary of Sync*Info objects for `<syncaccess>` elements keyed by VkAccessFlagBits2 name"
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci        self.syncpipelinedict = {}
464e5c31af7Sopenharmony_ci        "dictionary of Sync*Info objects for `<syncpipeline>` elements keyed by pipeline type name"
465e5c31af7Sopenharmony_ci
466e5c31af7Sopenharmony_ci        self.emitFeatures = False
467e5c31af7Sopenharmony_ci        """True to actually emit features for a version / extension,
468e5c31af7Sopenharmony_ci        or False to just treat them as emitted"""
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci        self.breakPat = None
471e5c31af7Sopenharmony_ci        "regexp pattern to break on when generating names"
472e5c31af7Sopenharmony_ci        # self.breakPat     = re.compile('VkFenceImportFlagBits.*')
473e5c31af7Sopenharmony_ci
474e5c31af7Sopenharmony_ci        self.requiredextensions = []  # Hack - can remove it after validity generator goes away
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci        # ** Global types for automatic source generation **
477e5c31af7Sopenharmony_ci        # Length Member data
478e5c31af7Sopenharmony_ci        self.commandextensiontuple = namedtuple('commandextensiontuple',
479e5c31af7Sopenharmony_ci                                                ['command',        # The name of the command being modified
480e5c31af7Sopenharmony_ci                                                 'value',          # The value to append to the command
481e5c31af7Sopenharmony_ci                                                 'extension'])     # The name of the extension that added it
482e5c31af7Sopenharmony_ci        self.validextensionstructs = defaultdict(list)
483e5c31af7Sopenharmony_ci        self.commandextensionsuccesses = []
484e5c31af7Sopenharmony_ci        self.commandextensionerrors = []
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci        self.filename     = None
487e5c31af7Sopenharmony_ci
488e5c31af7Sopenharmony_ci    def loadElementTree(self, tree):
489e5c31af7Sopenharmony_ci        """Load ElementTree into a Registry object and parse it."""
490e5c31af7Sopenharmony_ci        self.tree = tree
491e5c31af7Sopenharmony_ci        self.parseTree()
492e5c31af7Sopenharmony_ci
493e5c31af7Sopenharmony_ci    def loadFile(self, file):
494e5c31af7Sopenharmony_ci        """Load an API registry XML file into a Registry object and parse it"""
495e5c31af7Sopenharmony_ci        self.filename = file
496e5c31af7Sopenharmony_ci        self.tree = etree.parse(file)
497e5c31af7Sopenharmony_ci        self.parseTree()
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci    def setGenerator(self, gen):
500e5c31af7Sopenharmony_ci        """Specify output generator object.
501e5c31af7Sopenharmony_ci
502e5c31af7Sopenharmony_ci        `None` restores the default generator."""
503e5c31af7Sopenharmony_ci        self.gen = gen
504e5c31af7Sopenharmony_ci        self.gen.setRegistry(self)
505e5c31af7Sopenharmony_ci
506e5c31af7Sopenharmony_ci    def addElementInfo(self, elem, info, infoName, dictionary):
507e5c31af7Sopenharmony_ci        """Add information about an element to the corresponding dictionary.
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_ci        Intended for internal use only.
510e5c31af7Sopenharmony_ci
511e5c31af7Sopenharmony_ci        - elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>`/`<spirvextension>`/`<spirvcapability>`/`<format>`/`<syncstage>`/`<syncaccess>`/`<syncpipeline>` Element
512e5c31af7Sopenharmony_ci        - info - corresponding {Type|Group|Enum|Cmd|Feature|Spirv|Format|SyncStage|SyncAccess|SyncPipeline}Info object
513e5c31af7Sopenharmony_ci        - infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' / 'spirvextension' / 'spirvcapability' / 'format' / 'syncstage' / 'syncaccess' / 'syncpipeline'
514e5c31af7Sopenharmony_ci        - dictionary - self.{type|group|enum|cmd|api|ext|format|spirvext|spirvcap|sync}dict
515e5c31af7Sopenharmony_ci
516e5c31af7Sopenharmony_ci        The dictionary key is the element 'name' attribute."""
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci        # self.gen.logMsg('diag', 'Adding ElementInfo.required =',
519e5c31af7Sopenharmony_ci        #     info.required, 'name =', elem.get('name'))
520e5c31af7Sopenharmony_ci        key = elem.get('name')
521e5c31af7Sopenharmony_ci        if key in dictionary:
522e5c31af7Sopenharmony_ci            if not dictionary[key].compareElem(info, infoName):
523e5c31af7Sopenharmony_ci                self.gen.logMsg('warn', 'Attempt to redefine', key,
524e5c31af7Sopenharmony_ci                                '(this should not happen)')
525e5c31af7Sopenharmony_ci        else:
526e5c31af7Sopenharmony_ci            dictionary[key] = info
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_ci    def lookupElementInfo(self, fname, dictionary):
529e5c31af7Sopenharmony_ci        """Find a {Type|Enum|Cmd}Info object by name.
530e5c31af7Sopenharmony_ci
531e5c31af7Sopenharmony_ci        Intended for internal use only.
532e5c31af7Sopenharmony_ci
533e5c31af7Sopenharmony_ci        If an object qualified by API name exists, use that.
534e5c31af7Sopenharmony_ci
535e5c31af7Sopenharmony_ci        - fname - name of type / enum / command
536e5c31af7Sopenharmony_ci        - dictionary - self.{type|enum|cmd}dict"""
537e5c31af7Sopenharmony_ci        key = (fname, self.genOpts.apiname)
538e5c31af7Sopenharmony_ci        if key in dictionary:
539e5c31af7Sopenharmony_ci            # self.gen.logMsg('diag', 'Found API-specific element for feature', fname)
540e5c31af7Sopenharmony_ci            return dictionary[key]
541e5c31af7Sopenharmony_ci        if fname in dictionary:
542e5c31af7Sopenharmony_ci            # self.gen.logMsg('diag', 'Found generic element for feature', fname)
543e5c31af7Sopenharmony_ci            return dictionary[fname]
544e5c31af7Sopenharmony_ci
545e5c31af7Sopenharmony_ci        return None
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci    def breakOnName(self, regexp):
548e5c31af7Sopenharmony_ci        """Specify a feature name regexp to break on when generating features."""
549e5c31af7Sopenharmony_ci        self.breakPat = re.compile(regexp)
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci    def parseTree(self):
552e5c31af7Sopenharmony_ci        """Parse the registry Element, once created"""
553e5c31af7Sopenharmony_ci        # This must be the Element for the root <registry>
554e5c31af7Sopenharmony_ci        if self.tree is None:
555e5c31af7Sopenharmony_ci            raise RuntimeError("Tree not initialized!")
556e5c31af7Sopenharmony_ci        self.reg = self.tree.getroot()
557e5c31af7Sopenharmony_ci
558e5c31af7Sopenharmony_ci        # Preprocess the tree in one of the following ways:
559e5c31af7Sopenharmony_ci        # - either merge a set of APIs to another API based on their 'api' attributes
560e5c31af7Sopenharmony_ci        # - or remove all elements with non-matching 'api' attributes
561e5c31af7Sopenharmony_ci        # The preprocessing happens through a breath-first tree traversal.
562e5c31af7Sopenharmony_ci        # This is a blunt hammer, but eliminates the need to track and test
563e5c31af7Sopenharmony_ci        # the apis deeper in processing to select the correct elements and
564e5c31af7Sopenharmony_ci        # avoid duplicates.
565e5c31af7Sopenharmony_ci        # Schema validation should prevent duplicate elements with
566e5c31af7Sopenharmony_ci        # overlapping api attributes, or where one element has an api
567e5c31af7Sopenharmony_ci        # attribute and the other does not.
568e5c31af7Sopenharmony_ci
569e5c31af7Sopenharmony_ci        if self.genOpts.mergeApiNames:
570e5c31af7Sopenharmony_ci            mergeAPIs(self.reg, self.genOpts.mergeApiNames.split(','), self.genOpts.apiname)
571e5c31af7Sopenharmony_ci        else:
572e5c31af7Sopenharmony_ci            stripNonmatchingAPIs(self.reg, self.genOpts.apiname, actuallyDelete = True)
573e5c31af7Sopenharmony_ci
574e5c31af7Sopenharmony_ci        # Create dictionary of registry types from toplevel <types> tags
575e5c31af7Sopenharmony_ci        # and add 'name' attribute to each <type> tag (where missing)
576e5c31af7Sopenharmony_ci        # based on its <name> element.
577e5c31af7Sopenharmony_ci        #
578e5c31af7Sopenharmony_ci        # There is usually one <types> block; more are OK
579e5c31af7Sopenharmony_ci        # Required <type> attributes: 'name' or nested <name> tag contents
580e5c31af7Sopenharmony_ci        self.typedict = {}
581e5c31af7Sopenharmony_ci        for type_elem in self.reg.findall('types/type'):
582e5c31af7Sopenharmony_ci            # If the <type> does not already have a 'name' attribute, set
583e5c31af7Sopenharmony_ci            # it from contents of its <name> tag.
584e5c31af7Sopenharmony_ci            if type_elem.get('name') is None:
585e5c31af7Sopenharmony_ci                name_elem = type_elem.find('name')
586e5c31af7Sopenharmony_ci                if name_elem is None or not name_elem.text:
587e5c31af7Sopenharmony_ci                    raise RuntimeError("Type without a name!")
588e5c31af7Sopenharmony_ci                type_elem.set('name', name_elem.text)
589e5c31af7Sopenharmony_ci            self.addElementInfo(type_elem, TypeInfo(type_elem), 'type', self.typedict)
590e5c31af7Sopenharmony_ci
591e5c31af7Sopenharmony_ci        # Create dictionary of registry enum groups from <enums> tags.
592e5c31af7Sopenharmony_ci        #
593e5c31af7Sopenharmony_ci        # Required <enums> attributes: 'name'. If no name is given, one is
594e5c31af7Sopenharmony_ci        # generated, but that group cannot be identified and turned into an
595e5c31af7Sopenharmony_ci        # enum type definition - it is just a container for <enum> tags.
596e5c31af7Sopenharmony_ci        self.groupdict = {}
597e5c31af7Sopenharmony_ci        for group in self.reg.findall('enums'):
598e5c31af7Sopenharmony_ci            self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict)
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci        # Create dictionary of registry enums from <enum> tags
601e5c31af7Sopenharmony_ci        #
602e5c31af7Sopenharmony_ci        # <enums> tags usually define different namespaces for the values
603e5c31af7Sopenharmony_ci        #   defined in those tags, but the actual names all share the
604e5c31af7Sopenharmony_ci        #   same dictionary.
605e5c31af7Sopenharmony_ci        # Required <enum> attributes: 'name', 'value'
606e5c31af7Sopenharmony_ci        # For containing <enums> which have type="enum" or type="bitmask",
607e5c31af7Sopenharmony_ci        # tag all contained <enum>s are required. This is a stopgap until
608e5c31af7Sopenharmony_ci        # a better scheme for tagging core and extension enums is created.
609e5c31af7Sopenharmony_ci        self.enumdict = {}
610e5c31af7Sopenharmony_ci        for enums in self.reg.findall('enums'):
611e5c31af7Sopenharmony_ci            required = (enums.get('type') is not None)
612e5c31af7Sopenharmony_ci            for enum in enums.findall('enum'):
613e5c31af7Sopenharmony_ci                enumInfo = EnumInfo(enum)
614e5c31af7Sopenharmony_ci                enumInfo.required = required
615e5c31af7Sopenharmony_ci                self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci        # Create dictionary of registry commands from <command> tags
618e5c31af7Sopenharmony_ci        # and add 'name' attribute to each <command> tag (where missing)
619e5c31af7Sopenharmony_ci        # based on its <proto><name> element.
620e5c31af7Sopenharmony_ci        #
621e5c31af7Sopenharmony_ci        # There is usually only one <commands> block; more are OK.
622e5c31af7Sopenharmony_ci        # Required <command> attributes: 'name' or <proto><name> tag contents
623e5c31af7Sopenharmony_ci        self.cmddict = {}
624e5c31af7Sopenharmony_ci        # List of commands which alias others. Contains
625e5c31af7Sopenharmony_ci        #   [ aliasName, element ]
626e5c31af7Sopenharmony_ci        # for each alias
627e5c31af7Sopenharmony_ci        cmdAlias = []
628e5c31af7Sopenharmony_ci        for cmd in self.reg.findall('commands/command'):
629e5c31af7Sopenharmony_ci            # If the <command> does not already have a 'name' attribute, set
630e5c31af7Sopenharmony_ci            # it from contents of its <proto><name> tag.
631e5c31af7Sopenharmony_ci            name = cmd.get('name')
632e5c31af7Sopenharmony_ci            if name is None:
633e5c31af7Sopenharmony_ci                name_elem = cmd.find('proto/name')
634e5c31af7Sopenharmony_ci                if name_elem is None or not name_elem.text:
635e5c31af7Sopenharmony_ci                    raise RuntimeError("Command without a name!")
636e5c31af7Sopenharmony_ci                name = cmd.set('name', name_elem.text)
637e5c31af7Sopenharmony_ci            ci = CmdInfo(cmd)
638e5c31af7Sopenharmony_ci            self.addElementInfo(cmd, ci, 'command', self.cmddict)
639e5c31af7Sopenharmony_ci            alias = cmd.get('alias')
640e5c31af7Sopenharmony_ci            if alias:
641e5c31af7Sopenharmony_ci                cmdAlias.append([name, alias, cmd])
642e5c31af7Sopenharmony_ci
643e5c31af7Sopenharmony_ci        # Now loop over aliases, injecting a copy of the aliased command's
644e5c31af7Sopenharmony_ci        # Element with the aliased prototype name replaced with the command
645e5c31af7Sopenharmony_ci        # name - if it exists.
646e5c31af7Sopenharmony_ci        for (name, alias, cmd) in cmdAlias:
647e5c31af7Sopenharmony_ci            if alias in self.cmddict:
648e5c31af7Sopenharmony_ci                aliasInfo = self.cmddict[alias]
649e5c31af7Sopenharmony_ci                cmdElem = copy.deepcopy(aliasInfo.elem)
650e5c31af7Sopenharmony_ci                cmdElem.find('proto/name').text = name
651e5c31af7Sopenharmony_ci                cmdElem.set('name', name)
652e5c31af7Sopenharmony_ci                cmdElem.set('alias', alias)
653e5c31af7Sopenharmony_ci                ci = CmdInfo(cmdElem)
654e5c31af7Sopenharmony_ci                # Replace the dictionary entry for the CmdInfo element
655e5c31af7Sopenharmony_ci                self.cmddict[name] = ci
656e5c31af7Sopenharmony_ci
657e5c31af7Sopenharmony_ci                # @  newString = etree.tostring(base, encoding="unicode").replace(aliasValue, aliasName)
658e5c31af7Sopenharmony_ci                # @elem.append(etree.fromstring(replacement))
659e5c31af7Sopenharmony_ci            else:
660e5c31af7Sopenharmony_ci                self.gen.logMsg('warn', 'No matching <command> found for command',
661e5c31af7Sopenharmony_ci                                cmd.get('name'), 'alias', alias)
662e5c31af7Sopenharmony_ci
663e5c31af7Sopenharmony_ci        # Create dictionaries of API and extension interfaces
664e5c31af7Sopenharmony_ci        #   from toplevel <api> and <extension> tags.
665e5c31af7Sopenharmony_ci        self.apidict = {}
666e5c31af7Sopenharmony_ci        format_condition = dict()
667e5c31af7Sopenharmony_ci        for feature in self.reg.findall('feature'):
668e5c31af7Sopenharmony_ci            featureInfo = FeatureInfo(feature)
669e5c31af7Sopenharmony_ci            self.addElementInfo(feature, featureInfo, 'feature', self.apidict)
670e5c31af7Sopenharmony_ci
671e5c31af7Sopenharmony_ci            # Add additional enums defined only in <feature> tags
672e5c31af7Sopenharmony_ci            # to the corresponding enumerated type.
673e5c31af7Sopenharmony_ci            # When seen here, the <enum> element, processed to contain the
674e5c31af7Sopenharmony_ci            # numeric enum value, is added to the corresponding <enums>
675e5c31af7Sopenharmony_ci            # element, as well as adding to the enum dictionary. It is no
676e5c31af7Sopenharmony_ci            # longer removed from the <require> element it is introduced in.
677e5c31af7Sopenharmony_ci            # Instead, generateRequiredInterface ignores <enum> elements
678e5c31af7Sopenharmony_ci            # that extend enumerated types.
679e5c31af7Sopenharmony_ci            #
680e5c31af7Sopenharmony_ci            # For <enum> tags which are actually just constants, if there is
681e5c31af7Sopenharmony_ci            # no 'extends' tag but there is a 'value' or 'bitpos' tag, just
682e5c31af7Sopenharmony_ci            # add an EnumInfo record to the dictionary. That works because
683e5c31af7Sopenharmony_ci            # output generation of constants is purely dependency-based, and
684e5c31af7Sopenharmony_ci            # does not need to iterate through the XML tags.
685e5c31af7Sopenharmony_ci            for elem in feature.findall('require'):
686e5c31af7Sopenharmony_ci                for enum in elem.findall('enum'):
687e5c31af7Sopenharmony_ci                    addEnumInfo = False
688e5c31af7Sopenharmony_ci                    groupName = enum.get('extends')
689e5c31af7Sopenharmony_ci                    if groupName is not None:
690e5c31af7Sopenharmony_ci                        # self.gen.logMsg('diag', 'Found extension enum',
691e5c31af7Sopenharmony_ci                        #     enum.get('name'))
692e5c31af7Sopenharmony_ci                        # Add version number attribute to the <enum> element
693e5c31af7Sopenharmony_ci                        enum.set('version', featureInfo.version)
694e5c31af7Sopenharmony_ci                        # Look up the GroupInfo with matching groupName
695e5c31af7Sopenharmony_ci                        if groupName in self.groupdict:
696e5c31af7Sopenharmony_ci                            # self.gen.logMsg('diag', 'Matching group',
697e5c31af7Sopenharmony_ci                            #     groupName, 'found, adding element...')
698e5c31af7Sopenharmony_ci                            gi = self.groupdict[groupName]
699e5c31af7Sopenharmony_ci                            gi.elem.append(copy.deepcopy(enum))
700e5c31af7Sopenharmony_ci                        else:
701e5c31af7Sopenharmony_ci                            self.gen.logMsg('warn', 'NO matching group',
702e5c31af7Sopenharmony_ci                                            groupName, 'for enum', enum.get('name'), 'found.')
703e5c31af7Sopenharmony_ci                        if groupName == "VkFormat":
704e5c31af7Sopenharmony_ci                            format_name = enum.get('name')
705e5c31af7Sopenharmony_ci                            if enum.get('alias'):
706e5c31af7Sopenharmony_ci                                format_name = enum.get('alias')
707e5c31af7Sopenharmony_ci                            format_condition[format_name] = featureInfo.name
708e5c31af7Sopenharmony_ci                        addEnumInfo = True
709e5c31af7Sopenharmony_ci                    elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
710e5c31af7Sopenharmony_ci                        # self.gen.logMsg('diag', 'Adding extension constant "enum"',
711e5c31af7Sopenharmony_ci                        #     enum.get('name'))
712e5c31af7Sopenharmony_ci                        addEnumInfo = True
713e5c31af7Sopenharmony_ci                    if addEnumInfo:
714e5c31af7Sopenharmony_ci                        enumInfo = EnumInfo(enum)
715e5c31af7Sopenharmony_ci                        self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
716e5c31af7Sopenharmony_ci
717e5c31af7Sopenharmony_ci        sync_pipeline_stage_condition = dict()
718e5c31af7Sopenharmony_ci        sync_access_condition = dict()
719e5c31af7Sopenharmony_ci
720e5c31af7Sopenharmony_ci        self.extensions = self.reg.findall('extensions/extension')
721e5c31af7Sopenharmony_ci        self.extdict = {}
722e5c31af7Sopenharmony_ci        for feature in self.extensions:
723e5c31af7Sopenharmony_ci            featureInfo = FeatureInfo(feature)
724e5c31af7Sopenharmony_ci            self.addElementInfo(feature, featureInfo, 'extension', self.extdict)
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci            # Add additional enums defined only in <extension> tags
727e5c31af7Sopenharmony_ci            # to the corresponding core type.
728e5c31af7Sopenharmony_ci            # Algorithm matches that of enums in a "feature" tag as above.
729e5c31af7Sopenharmony_ci            #
730e5c31af7Sopenharmony_ci            # This code also adds a 'extnumber' attribute containing the
731e5c31af7Sopenharmony_ci            # extension number, used for enumerant value calculation.
732e5c31af7Sopenharmony_ci            for elem in feature.findall('require'):
733e5c31af7Sopenharmony_ci                for enum in elem.findall('enum'):
734e5c31af7Sopenharmony_ci                    addEnumInfo = False
735e5c31af7Sopenharmony_ci                    groupName = enum.get('extends')
736e5c31af7Sopenharmony_ci                    if groupName is not None:
737e5c31af7Sopenharmony_ci                        # self.gen.logMsg('diag', 'Found extension enum',
738e5c31af7Sopenharmony_ci                        #     enum.get('name'))
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci                        # Add <extension> block's extension number attribute to
741e5c31af7Sopenharmony_ci                        # the <enum> element unless specified explicitly, such
742e5c31af7Sopenharmony_ci                        # as when redefining an enum in another extension.
743e5c31af7Sopenharmony_ci                        extnumber = enum.get('extnumber')
744e5c31af7Sopenharmony_ci                        if not extnumber:
745e5c31af7Sopenharmony_ci                            enum.set('extnumber', str(featureInfo.number))
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ci                        enum.set('extname', featureInfo.name)
748e5c31af7Sopenharmony_ci                        enum.set('supported', noneStr(featureInfo.supported))
749e5c31af7Sopenharmony_ci                        # Look up the GroupInfo with matching groupName
750e5c31af7Sopenharmony_ci                        if groupName in self.groupdict:
751e5c31af7Sopenharmony_ci                            # self.gen.logMsg('diag', 'Matching group',
752e5c31af7Sopenharmony_ci                            #     groupName, 'found, adding element...')
753e5c31af7Sopenharmony_ci                            gi = self.groupdict[groupName]
754e5c31af7Sopenharmony_ci                            gi.elem.append(copy.deepcopy(enum))
755e5c31af7Sopenharmony_ci                        else:
756e5c31af7Sopenharmony_ci                            self.gen.logMsg('warn', 'NO matching group',
757e5c31af7Sopenharmony_ci                                            groupName, 'for enum', enum.get('name'), 'found.')
758e5c31af7Sopenharmony_ci                        # This is Vulkan-specific
759e5c31af7Sopenharmony_ci                        if groupName == "VkFormat":
760e5c31af7Sopenharmony_ci                            format_name = enum.get('name')
761e5c31af7Sopenharmony_ci                            if enum.get('alias'):
762e5c31af7Sopenharmony_ci                                format_name = enum.get('alias')
763e5c31af7Sopenharmony_ci                            if format_name in format_condition:
764e5c31af7Sopenharmony_ci                                format_condition[format_name] += "," + featureInfo.name
765e5c31af7Sopenharmony_ci                            else:
766e5c31af7Sopenharmony_ci                                format_condition[format_name] = featureInfo.name
767e5c31af7Sopenharmony_ci                        elif groupName == "VkPipelineStageFlagBits2":
768e5c31af7Sopenharmony_ci                            stage_flag = enum.get('name')
769e5c31af7Sopenharmony_ci                            if enum.get('alias'):
770e5c31af7Sopenharmony_ci                                stage_flag = enum.get('alias')
771e5c31af7Sopenharmony_ci                            featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name
772e5c31af7Sopenharmony_ci                            if stage_flag in sync_pipeline_stage_condition:
773e5c31af7Sopenharmony_ci                                sync_pipeline_stage_condition[stage_flag] += "," + featureName
774e5c31af7Sopenharmony_ci                            else:
775e5c31af7Sopenharmony_ci                                sync_pipeline_stage_condition[stage_flag] = featureName
776e5c31af7Sopenharmony_ci                        elif groupName == "VkAccessFlagBits2":
777e5c31af7Sopenharmony_ci                            access_flag = enum.get('name')
778e5c31af7Sopenharmony_ci                            if enum.get('alias'):
779e5c31af7Sopenharmony_ci                                access_flag = enum.get('alias')
780e5c31af7Sopenharmony_ci                            featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name
781e5c31af7Sopenharmony_ci                            if access_flag in sync_access_condition:
782e5c31af7Sopenharmony_ci                                sync_access_condition[access_flag] += "," + featureName
783e5c31af7Sopenharmony_ci                            else:
784e5c31af7Sopenharmony_ci                                sync_access_condition[access_flag] = featureName
785e5c31af7Sopenharmony_ci
786e5c31af7Sopenharmony_ci                        addEnumInfo = True
787e5c31af7Sopenharmony_ci                    elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
788e5c31af7Sopenharmony_ci                        # self.gen.logMsg('diag', 'Adding extension constant "enum"',
789e5c31af7Sopenharmony_ci                        #     enum.get('name'))
790e5c31af7Sopenharmony_ci                        addEnumInfo = True
791e5c31af7Sopenharmony_ci                    if addEnumInfo:
792e5c31af7Sopenharmony_ci                        enumInfo = EnumInfo(enum)
793e5c31af7Sopenharmony_ci                        self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci        # Parse out all spirv tags in dictionaries
796e5c31af7Sopenharmony_ci        # Use addElementInfo to catch duplicates
797e5c31af7Sopenharmony_ci        for spirv in self.reg.findall('spirvextensions/spirvextension'):
798e5c31af7Sopenharmony_ci            spirvInfo = SpirvInfo(spirv)
799e5c31af7Sopenharmony_ci            self.addElementInfo(spirv, spirvInfo, 'spirvextension', self.spirvextdict)
800e5c31af7Sopenharmony_ci        for spirv in self.reg.findall('spirvcapabilities/spirvcapability'):
801e5c31af7Sopenharmony_ci            spirvInfo = SpirvInfo(spirv)
802e5c31af7Sopenharmony_ci            self.addElementInfo(spirv, spirvInfo, 'spirvcapability', self.spirvcapdict)
803e5c31af7Sopenharmony_ci
804e5c31af7Sopenharmony_ci        for format in self.reg.findall('formats/format'):
805e5c31af7Sopenharmony_ci            condition = None
806e5c31af7Sopenharmony_ci            format_name = format.get('name')
807e5c31af7Sopenharmony_ci            if format_name in format_condition:
808e5c31af7Sopenharmony_ci                condition = format_condition[format_name]
809e5c31af7Sopenharmony_ci            formatInfo = FormatInfo(format, condition)
810e5c31af7Sopenharmony_ci            self.addElementInfo(format, formatInfo, 'format', self.formatsdict)
811e5c31af7Sopenharmony_ci
812e5c31af7Sopenharmony_ci        for stage in self.reg.findall('sync/syncstage'):
813e5c31af7Sopenharmony_ci            condition = None
814e5c31af7Sopenharmony_ci            stage_flag = stage.get('name')
815e5c31af7Sopenharmony_ci            if stage_flag in sync_pipeline_stage_condition:
816e5c31af7Sopenharmony_ci                condition = sync_pipeline_stage_condition[stage_flag]
817e5c31af7Sopenharmony_ci            syncInfo = SyncStageInfo(stage, condition)
818e5c31af7Sopenharmony_ci            self.addElementInfo(stage, syncInfo, 'syncstage', self.syncstagedict)
819e5c31af7Sopenharmony_ci
820e5c31af7Sopenharmony_ci        for access in self.reg.findall('sync/syncaccess'):
821e5c31af7Sopenharmony_ci            condition = None
822e5c31af7Sopenharmony_ci            access_flag = access.get('name')
823e5c31af7Sopenharmony_ci            if access_flag in sync_access_condition:
824e5c31af7Sopenharmony_ci                condition = sync_access_condition[access_flag]
825e5c31af7Sopenharmony_ci            syncInfo = SyncAccessInfo(access, condition)
826e5c31af7Sopenharmony_ci            self.addElementInfo(access, syncInfo, 'syncaccess', self.syncaccessdict)
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_ci        for pipeline in self.reg.findall('sync/syncpipeline'):
829e5c31af7Sopenharmony_ci            syncInfo = SyncPipelineInfo(pipeline)
830e5c31af7Sopenharmony_ci            self.addElementInfo(pipeline, syncInfo, 'syncpipeline', self.syncpipelinedict)
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_ci    def dumpReg(self, maxlen=120, filehandle=sys.stdout):
833e5c31af7Sopenharmony_ci        """Dump all the dictionaries constructed from the Registry object.
834e5c31af7Sopenharmony_ci
835e5c31af7Sopenharmony_ci        Diagnostic to dump the dictionaries to specified file handle (default stdout).
836e5c31af7Sopenharmony_ci        Truncates type / enum / command elements to maxlen characters (default 120)"""
837e5c31af7Sopenharmony_ci        write('***************************************', file=filehandle)
838e5c31af7Sopenharmony_ci        write('    ** Dumping Registry contents **',     file=filehandle)
839e5c31af7Sopenharmony_ci        write('***************************************', file=filehandle)
840e5c31af7Sopenharmony_ci        write('// Types', file=filehandle)
841e5c31af7Sopenharmony_ci        for name in self.typedict:
842e5c31af7Sopenharmony_ci            tobj = self.typedict[name]
843e5c31af7Sopenharmony_ci            write('    Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle)
844e5c31af7Sopenharmony_ci        write('// Groups', file=filehandle)
845e5c31af7Sopenharmony_ci        for name in self.groupdict:
846e5c31af7Sopenharmony_ci            gobj = self.groupdict[name]
847e5c31af7Sopenharmony_ci            write('    Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle)
848e5c31af7Sopenharmony_ci        write('// Enums', file=filehandle)
849e5c31af7Sopenharmony_ci        for name in self.enumdict:
850e5c31af7Sopenharmony_ci            eobj = self.enumdict[name]
851e5c31af7Sopenharmony_ci            write('    Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle)
852e5c31af7Sopenharmony_ci        write('// Commands', file=filehandle)
853e5c31af7Sopenharmony_ci        for name in self.cmddict:
854e5c31af7Sopenharmony_ci            cobj = self.cmddict[name]
855e5c31af7Sopenharmony_ci            write('    Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle)
856e5c31af7Sopenharmony_ci        write('// APIs', file=filehandle)
857e5c31af7Sopenharmony_ci        for key in self.apidict:
858e5c31af7Sopenharmony_ci            write('    API Version ', key, '->',
859e5c31af7Sopenharmony_ci                  etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle)
860e5c31af7Sopenharmony_ci        write('// Extensions', file=filehandle)
861e5c31af7Sopenharmony_ci        for key in self.extdict:
862e5c31af7Sopenharmony_ci            write('    Extension', key, '->',
863e5c31af7Sopenharmony_ci                  etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle)
864e5c31af7Sopenharmony_ci        write('// SPIR-V', file=filehandle)
865e5c31af7Sopenharmony_ci        for key in self.spirvextdict:
866e5c31af7Sopenharmony_ci            write('    SPIR-V Extension', key, '->',
867e5c31af7Sopenharmony_ci                  etree.tostring(self.spirvextdict[key].elem)[0:maxlen], file=filehandle)
868e5c31af7Sopenharmony_ci        for key in self.spirvcapdict:
869e5c31af7Sopenharmony_ci            write('    SPIR-V Capability', key, '->',
870e5c31af7Sopenharmony_ci                  etree.tostring(self.spirvcapdict[key].elem)[0:maxlen], file=filehandle)
871e5c31af7Sopenharmony_ci        write('// VkFormat', file=filehandle)
872e5c31af7Sopenharmony_ci        for key in self.formatsdict:
873e5c31af7Sopenharmony_ci            write('    VkFormat', key, '->',
874e5c31af7Sopenharmony_ci                  etree.tostring(self.formatsdict[key].elem)[0:maxlen], file=filehandle)
875e5c31af7Sopenharmony_ci
876e5c31af7Sopenharmony_ci    def markTypeRequired(self, typename, required):
877e5c31af7Sopenharmony_ci        """Require (along with its dependencies) or remove (but not its dependencies) a type.
878e5c31af7Sopenharmony_ci
879e5c31af7Sopenharmony_ci        - typename - name of type
880e5c31af7Sopenharmony_ci        - required - boolean (to tag features as required or not)
881e5c31af7Sopenharmony_ci        """
882e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'tagging type:', typename, '-> required =', required)
883e5c31af7Sopenharmony_ci
884e5c31af7Sopenharmony_ci        # Get TypeInfo object for <type> tag corresponding to typename
885e5c31af7Sopenharmony_ci        typeinfo = self.lookupElementInfo(typename, self.typedict)
886e5c31af7Sopenharmony_ci        if typeinfo is not None:
887e5c31af7Sopenharmony_ci            if required:
888e5c31af7Sopenharmony_ci                # Tag type dependencies in 'alias' and 'required' attributes as
889e5c31af7Sopenharmony_ci                # required. This does not un-tag dependencies in a <remove>
890e5c31af7Sopenharmony_ci                # tag. See comments in markRequired() below for the reason.
891e5c31af7Sopenharmony_ci                for attrib_name in ['requires', 'alias']:
892e5c31af7Sopenharmony_ci                    depname = typeinfo.elem.get(attrib_name)
893e5c31af7Sopenharmony_ci                    if depname:
894e5c31af7Sopenharmony_ci                        self.gen.logMsg('diag', 'Generating dependent type',
895e5c31af7Sopenharmony_ci                                        depname, 'for', attrib_name, 'type', typename)
896e5c31af7Sopenharmony_ci                        # Do not recurse on self-referential structures.
897e5c31af7Sopenharmony_ci                        if typename != depname:
898e5c31af7Sopenharmony_ci                            self.markTypeRequired(depname, required)
899e5c31af7Sopenharmony_ci                        else:
900e5c31af7Sopenharmony_ci                            self.gen.logMsg('diag', 'type', typename, 'is self-referential')
901e5c31af7Sopenharmony_ci                # Tag types used in defining this type (e.g. in nested
902e5c31af7Sopenharmony_ci                # <type> tags)
903e5c31af7Sopenharmony_ci                # Look for <type> in entire <command> tree,
904e5c31af7Sopenharmony_ci                # not just immediate children
905e5c31af7Sopenharmony_ci                for subtype in typeinfo.elem.findall('.//type'):
906e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'markRequired: type requires dependent <type>', subtype.text)
907e5c31af7Sopenharmony_ci                    if typename != subtype.text:
908e5c31af7Sopenharmony_ci                        self.markTypeRequired(subtype.text, required)
909e5c31af7Sopenharmony_ci                    else:
910e5c31af7Sopenharmony_ci                        self.gen.logMsg('diag', 'type', typename, 'is self-referential')
911e5c31af7Sopenharmony_ci                # Tag enums used in defining this type, for example in
912e5c31af7Sopenharmony_ci                #   <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
913e5c31af7Sopenharmony_ci                for subenum in typeinfo.elem.findall('.//enum'):
914e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'markRequired: type requires dependent <enum>', subenum.text)
915e5c31af7Sopenharmony_ci                    self.markEnumRequired(subenum.text, required)
916e5c31af7Sopenharmony_ci                # Tag type dependency in 'bitvalues' attributes as
917e5c31af7Sopenharmony_ci                # required. This ensures that the bit values for a flag
918e5c31af7Sopenharmony_ci                # are emitted
919e5c31af7Sopenharmony_ci                depType = typeinfo.elem.get('bitvalues')
920e5c31af7Sopenharmony_ci                if depType:
921e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'Generating bitflag type',
922e5c31af7Sopenharmony_ci                                    depType, 'for type', typename)
923e5c31af7Sopenharmony_ci                    self.markTypeRequired(depType, required)
924e5c31af7Sopenharmony_ci                    group = self.lookupElementInfo(depType, self.groupdict)
925e5c31af7Sopenharmony_ci                    if group is not None:
926e5c31af7Sopenharmony_ci                        group.flagType = typeinfo
927e5c31af7Sopenharmony_ci
928e5c31af7Sopenharmony_ci            typeinfo.required = required
929e5c31af7Sopenharmony_ci        elif '.h' not in typename:
930e5c31af7Sopenharmony_ci            self.gen.logMsg('warn', 'type:', typename, 'IS NOT DEFINED')
931e5c31af7Sopenharmony_ci
932e5c31af7Sopenharmony_ci    def markEnumRequired(self, enumname, required):
933e5c31af7Sopenharmony_ci        """Mark an enum as required or not.
934e5c31af7Sopenharmony_ci
935e5c31af7Sopenharmony_ci        - enumname - name of enum
936e5c31af7Sopenharmony_ci        - required - boolean (to tag features as required or not)"""
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'markEnumRequired: tagging enum:', enumname, '-> required =', required)
939e5c31af7Sopenharmony_ci        enum = self.lookupElementInfo(enumname, self.enumdict)
940e5c31af7Sopenharmony_ci        if enum is not None:
941e5c31af7Sopenharmony_ci            # If the enum is part of a group, and is being removed, then
942e5c31af7Sopenharmony_ci            # look it up in that <enums> tag and remove the Element there,
943e5c31af7Sopenharmony_ci            # so that it is not visible to generators (which traverse the
944e5c31af7Sopenharmony_ci            # <enums> tag elements rather than using the dictionaries).
945e5c31af7Sopenharmony_ci            if not required:
946e5c31af7Sopenharmony_ci                groupName = enum.elem.get('extends')
947e5c31af7Sopenharmony_ci                if groupName is not None:
948e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', f'markEnumRequired: Removing extending enum {enum.elem.get("name")}')
949e5c31af7Sopenharmony_ci
950e5c31af7Sopenharmony_ci                    # Look up the Info with matching groupName
951e5c31af7Sopenharmony_ci                    if groupName in self.groupdict:
952e5c31af7Sopenharmony_ci                        gi = self.groupdict[groupName]
953e5c31af7Sopenharmony_ci                        gienum = gi.elem.find("enum[@name='" + enumname + "']")
954e5c31af7Sopenharmony_ci                        if gienum is not None:
955e5c31af7Sopenharmony_ci                            # Remove copy of this enum from the group
956e5c31af7Sopenharmony_ci                            gi.elem.remove(gienum)
957e5c31af7Sopenharmony_ci                        else:
958e5c31af7Sopenharmony_ci                            self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum',
959e5c31af7Sopenharmony_ci                                            enumname, 'not found in group',
960e5c31af7Sopenharmony_ci                                            groupName)
961e5c31af7Sopenharmony_ci                    else:
962e5c31af7Sopenharmony_ci                        self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum',
963e5c31af7Sopenharmony_ci                                        enumname, 'from nonexistent group',
964e5c31af7Sopenharmony_ci                                        groupName)
965e5c31af7Sopenharmony_ci                else:
966e5c31af7Sopenharmony_ci                    # This enum is not an extending enum.
967e5c31af7Sopenharmony_ci                    # The XML tree must be searched for all <enums> that
968e5c31af7Sopenharmony_ci                    # might have it, so we know the parent to delete from.
969e5c31af7Sopenharmony_ci
970e5c31af7Sopenharmony_ci                    enumName = enum.elem.get('name')
971e5c31af7Sopenharmony_ci
972e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', f'markEnumRequired: Removing non-extending enum {enumName}')
973e5c31af7Sopenharmony_ci
974e5c31af7Sopenharmony_ci                    count = 0
975e5c31af7Sopenharmony_ci                    for enums in self.reg.findall('enums'):
976e5c31af7Sopenharmony_ci                        for thisEnum in enums.findall('enum'):
977e5c31af7Sopenharmony_ci                            if thisEnum.get('name') == enumName:
978e5c31af7Sopenharmony_ci                                # Actually remove it
979e5c31af7Sopenharmony_ci                                count = count + 1
980e5c31af7Sopenharmony_ci                                enums.remove(thisEnum)
981e5c31af7Sopenharmony_ci
982e5c31af7Sopenharmony_ci                    if count == 0:
983e5c31af7Sopenharmony_ci                        self.gen.logMsg('warn', f'markEnumRequired: {enumName}) not found in any <enums> tag')
984e5c31af7Sopenharmony_ci
985e5c31af7Sopenharmony_ci            enum.required = required
986e5c31af7Sopenharmony_ci            # Tag enum dependencies in 'alias' attribute as required
987e5c31af7Sopenharmony_ci            depname = enum.elem.get('alias')
988e5c31af7Sopenharmony_ci            if depname:
989e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'markEnumRequired: Generating dependent enum',
990e5c31af7Sopenharmony_ci                                depname, 'for alias', enumname, 'required =', enum.required)
991e5c31af7Sopenharmony_ci                self.markEnumRequired(depname, required)
992e5c31af7Sopenharmony_ci        else:
993e5c31af7Sopenharmony_ci            self.gen.logMsg('warn', f'markEnumRequired: {enumname} IS NOT DEFINED')
994e5c31af7Sopenharmony_ci
995e5c31af7Sopenharmony_ci    def markCmdRequired(self, cmdname, required):
996e5c31af7Sopenharmony_ci        """Mark a command as required or not.
997e5c31af7Sopenharmony_ci
998e5c31af7Sopenharmony_ci        - cmdname - name of command
999e5c31af7Sopenharmony_ci        - required - boolean (to tag features as required or not)"""
1000e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'tagging command:', cmdname, '-> required =', required)
1001e5c31af7Sopenharmony_ci        cmd = self.lookupElementInfo(cmdname, self.cmddict)
1002e5c31af7Sopenharmony_ci        if cmd is not None:
1003e5c31af7Sopenharmony_ci            cmd.required = required
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci            # Tag command dependencies in 'alias' attribute as required
1006e5c31af7Sopenharmony_ci            #
1007e5c31af7Sopenharmony_ci            # This is usually not done, because command 'aliases' are not
1008e5c31af7Sopenharmony_ci            # actual C language aliases like type and enum aliases. Instead
1009e5c31af7Sopenharmony_ci            # they are just duplicates of the function signature of the
1010e5c31af7Sopenharmony_ci            # alias. This means that there is no dependency of a command
1011e5c31af7Sopenharmony_ci            # alias on what it aliases. One exception is validity includes,
1012e5c31af7Sopenharmony_ci            # where the spec markup needs the promoted-to validity include
1013e5c31af7Sopenharmony_ci            # even if only the promoted-from command is being built.
1014e5c31af7Sopenharmony_ci            if self.genOpts.requireCommandAliases:
1015e5c31af7Sopenharmony_ci                depname = cmd.elem.get('alias')
1016e5c31af7Sopenharmony_ci                if depname:
1017e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'Generating dependent command',
1018e5c31af7Sopenharmony_ci                                    depname, 'for alias', cmdname)
1019e5c31af7Sopenharmony_ci                    self.markCmdRequired(depname, required)
1020e5c31af7Sopenharmony_ci
1021e5c31af7Sopenharmony_ci            # Tag all parameter types of this command as required.
1022e5c31af7Sopenharmony_ci            # This does not remove types of commands in a <remove>
1023e5c31af7Sopenharmony_ci            # tag, because many other commands may use the same type.
1024e5c31af7Sopenharmony_ci            # We could be more clever and reference count types,
1025e5c31af7Sopenharmony_ci            # instead of using a boolean.
1026e5c31af7Sopenharmony_ci            if required:
1027e5c31af7Sopenharmony_ci                # Look for <type> in entire <command> tree,
1028e5c31af7Sopenharmony_ci                # not just immediate children
1029e5c31af7Sopenharmony_ci                for type_elem in cmd.elem.findall('.//type'):
1030e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'markRequired: command implicitly requires dependent type', type_elem.text)
1031e5c31af7Sopenharmony_ci                    self.markTypeRequired(type_elem.text, required)
1032e5c31af7Sopenharmony_ci        else:
1033e5c31af7Sopenharmony_ci            self.gen.logMsg('warn', 'command:', cmdname, 'IS NOT DEFINED')
1034e5c31af7Sopenharmony_ci
1035e5c31af7Sopenharmony_ci    def markRequired(self, featurename, feature, required):
1036e5c31af7Sopenharmony_ci        """Require or remove features specified in the Element.
1037e5c31af7Sopenharmony_ci
1038e5c31af7Sopenharmony_ci        - featurename - name of the feature
1039e5c31af7Sopenharmony_ci        - feature - Element for `<require>` or `<remove>` tag
1040e5c31af7Sopenharmony_ci        - required - boolean (to tag features as required or not)"""
1041e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'markRequired (feature = <too long to print>, required =', required, ')')
1042e5c31af7Sopenharmony_ci
1043e5c31af7Sopenharmony_ci        # Loop over types, enums, and commands in the tag
1044e5c31af7Sopenharmony_ci        # @@ It would be possible to respect 'api' and 'profile' attributes
1045e5c31af7Sopenharmony_ci        #  in individual features, but that is not done yet.
1046e5c31af7Sopenharmony_ci        for typeElem in feature.findall('type'):
1047e5c31af7Sopenharmony_ci            self.markTypeRequired(typeElem.get('name'), required)
1048e5c31af7Sopenharmony_ci        for enumElem in feature.findall('enum'):
1049e5c31af7Sopenharmony_ci            self.markEnumRequired(enumElem.get('name'), required)
1050e5c31af7Sopenharmony_ci
1051e5c31af7Sopenharmony_ci        for cmdElem in feature.findall('command'):
1052e5c31af7Sopenharmony_ci            self.markCmdRequired(cmdElem.get('name'), required)
1053e5c31af7Sopenharmony_ci
1054e5c31af7Sopenharmony_ci        # Extensions may need to extend existing commands or other items in the future.
1055e5c31af7Sopenharmony_ci        # So, look for extend tags.
1056e5c31af7Sopenharmony_ci        for extendElem in feature.findall('extend'):
1057e5c31af7Sopenharmony_ci            extendType = extendElem.get('type')
1058e5c31af7Sopenharmony_ci            if extendType == 'command':
1059e5c31af7Sopenharmony_ci                commandName = extendElem.get('name')
1060e5c31af7Sopenharmony_ci                successExtends = extendElem.get('successcodes')
1061e5c31af7Sopenharmony_ci                if successExtends is not None:
1062e5c31af7Sopenharmony_ci                    for success in successExtends.split(','):
1063e5c31af7Sopenharmony_ci                        self.commandextensionsuccesses.append(self.commandextensiontuple(command=commandName,
1064e5c31af7Sopenharmony_ci                                                                                         value=success,
1065e5c31af7Sopenharmony_ci                                                                                         extension=featurename))
1066e5c31af7Sopenharmony_ci                errorExtends = extendElem.get('errorcodes')
1067e5c31af7Sopenharmony_ci                if errorExtends is not None:
1068e5c31af7Sopenharmony_ci                    for error in errorExtends.split(','):
1069e5c31af7Sopenharmony_ci                        self.commandextensionerrors.append(self.commandextensiontuple(command=commandName,
1070e5c31af7Sopenharmony_ci                                                                                      value=error,
1071e5c31af7Sopenharmony_ci                                                                                      extension=featurename))
1072e5c31af7Sopenharmony_ci            else:
1073e5c31af7Sopenharmony_ci                self.gen.logMsg('warn', 'extend type:', extendType, 'IS NOT SUPPORTED')
1074e5c31af7Sopenharmony_ci
1075e5c31af7Sopenharmony_ci    def getAlias(self, elem, dict):
1076e5c31af7Sopenharmony_ci        """Check for an alias in the same require block.
1077e5c31af7Sopenharmony_ci
1078e5c31af7Sopenharmony_ci        - elem - Element to check for an alias"""
1079e5c31af7Sopenharmony_ci
1080e5c31af7Sopenharmony_ci        # Try to find an alias
1081e5c31af7Sopenharmony_ci        alias = elem.get('alias')
1082e5c31af7Sopenharmony_ci        if alias is None:
1083e5c31af7Sopenharmony_ci            name = elem.get('name')
1084e5c31af7Sopenharmony_ci            typeinfo = self.lookupElementInfo(name, dict)
1085e5c31af7Sopenharmony_ci            if not typeinfo:
1086e5c31af7Sopenharmony_ci                self.gen.logMsg('error', name, 'is not a known name')
1087e5c31af7Sopenharmony_ci            alias = typeinfo.elem.get('alias')
1088e5c31af7Sopenharmony_ci
1089e5c31af7Sopenharmony_ci        return alias
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci    def checkForCorrectionAliases(self, alias, require, tag):
1092e5c31af7Sopenharmony_ci        """Check for an alias in the same require block.
1093e5c31af7Sopenharmony_ci
1094e5c31af7Sopenharmony_ci        - alias - String name of the alias
1095e5c31af7Sopenharmony_ci        - require -  `<require>` block from the registry
1096e5c31af7Sopenharmony_ci        - tag - tag to look for in the require block"""
1097e5c31af7Sopenharmony_ci
1098e5c31af7Sopenharmony_ci        # For the time being, the code below is bypassed. It has the effect
1099e5c31af7Sopenharmony_ci        # of excluding "spelling aliases" created to comply with the style
1100e5c31af7Sopenharmony_ci        # guide, but this leaves references out of the specification and
1101e5c31af7Sopenharmony_ci        # causes broken internal links.
1102e5c31af7Sopenharmony_ci        #
1103e5c31af7Sopenharmony_ci        # if alias and require.findall(tag + "[@name='" + alias + "']"):
1104e5c31af7Sopenharmony_ci        #     return True
1105e5c31af7Sopenharmony_ci
1106e5c31af7Sopenharmony_ci        return False
1107e5c31af7Sopenharmony_ci
1108e5c31af7Sopenharmony_ci    def fillFeatureDictionary(self, interface, featurename, api, profile):
1109e5c31af7Sopenharmony_ci        """Capture added interfaces for a `<version>` or `<extension>`.
1110e5c31af7Sopenharmony_ci
1111e5c31af7Sopenharmony_ci        - interface - Element for `<version>` or `<extension>`, containing
1112e5c31af7Sopenharmony_ci          `<require>` and `<remove>` tags
1113e5c31af7Sopenharmony_ci        - featurename - name of the feature
1114e5c31af7Sopenharmony_ci        - api - string specifying API name being generated
1115e5c31af7Sopenharmony_ci        - profile - string specifying API profile being generated"""
1116e5c31af7Sopenharmony_ci
1117e5c31af7Sopenharmony_ci        # Explicitly initialize known types - errors for unhandled categories
1118e5c31af7Sopenharmony_ci        self.gen.featureDictionary[featurename] = {
1119e5c31af7Sopenharmony_ci            "enumconstant": {},
1120e5c31af7Sopenharmony_ci            "command": {},
1121e5c31af7Sopenharmony_ci            "enum": {},
1122e5c31af7Sopenharmony_ci            "struct": {},
1123e5c31af7Sopenharmony_ci            "handle": {},
1124e5c31af7Sopenharmony_ci            "basetype": {},
1125e5c31af7Sopenharmony_ci            "include": {},
1126e5c31af7Sopenharmony_ci            "define": {},
1127e5c31af7Sopenharmony_ci            "bitmask": {},
1128e5c31af7Sopenharmony_ci            "union": {},
1129e5c31af7Sopenharmony_ci            "funcpointer": {},
1130e5c31af7Sopenharmony_ci        }
1131e5c31af7Sopenharmony_ci
1132e5c31af7Sopenharmony_ci        # <require> marks things that are required by this version/profile
1133e5c31af7Sopenharmony_ci        for require in interface.findall('require'):
1134e5c31af7Sopenharmony_ci            if matchAPIProfile(api, profile, require):
1135e5c31af7Sopenharmony_ci
1136e5c31af7Sopenharmony_ci                # Determine the required extension or version needed for a require block
1137e5c31af7Sopenharmony_ci                # Assumes that only one of these is specified
1138e5c31af7Sopenharmony_ci                # 'extension', and therefore 'required_key', may be a boolean
1139e5c31af7Sopenharmony_ci                # expression of extension names.
1140e5c31af7Sopenharmony_ci                # 'required_key' is used only as a dictionary key at
1141e5c31af7Sopenharmony_ci                # present, and passed through to the script generators, so
1142e5c31af7Sopenharmony_ci                # they must be prepared to parse that boolean expression.
1143e5c31af7Sopenharmony_ci                required_key = require.get('depends')
1144e5c31af7Sopenharmony_ci
1145e5c31af7Sopenharmony_ci                # Loop over types, enums, and commands in the tag
1146e5c31af7Sopenharmony_ci                for typeElem in require.findall('type'):
1147e5c31af7Sopenharmony_ci                    typename = typeElem.get('name')
1148e5c31af7Sopenharmony_ci                    typeinfo = self.lookupElementInfo(typename, self.typedict)
1149e5c31af7Sopenharmony_ci
1150e5c31af7Sopenharmony_ci                    if typeinfo:
1151e5c31af7Sopenharmony_ci                        # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
1152e5c31af7Sopenharmony_ci                        alias = self.getAlias(typeElem, self.typedict)
1153e5c31af7Sopenharmony_ci                        if not self.checkForCorrectionAliases(alias, require, 'type'):
1154e5c31af7Sopenharmony_ci                            # Resolve the type info to the actual type, so we get an accurate read for 'structextends'
1155e5c31af7Sopenharmony_ci                            while alias:
1156e5c31af7Sopenharmony_ci                                typeinfo = self.lookupElementInfo(alias, self.typedict)
1157e5c31af7Sopenharmony_ci                                alias = typeinfo.elem.get('alias')
1158e5c31af7Sopenharmony_ci
1159e5c31af7Sopenharmony_ci                            typecat = typeinfo.elem.get('category')
1160e5c31af7Sopenharmony_ci                            typeextends = typeinfo.elem.get('structextends')
1161e5c31af7Sopenharmony_ci                            if not required_key in self.gen.featureDictionary[featurename][typecat]:
1162e5c31af7Sopenharmony_ci                                self.gen.featureDictionary[featurename][typecat][required_key] = {}
1163e5c31af7Sopenharmony_ci                            if not typeextends in self.gen.featureDictionary[featurename][typecat][required_key]:
1164e5c31af7Sopenharmony_ci                                self.gen.featureDictionary[featurename][typecat][required_key][typeextends] = []
1165e5c31af7Sopenharmony_ci                            self.gen.featureDictionary[featurename][typecat][required_key][typeextends].append(typename)
1166e5c31af7Sopenharmony_ci                        else:
1167e5c31af7Sopenharmony_ci                            self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
1168e5c31af7Sopenharmony_ci
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci                for enumElem in require.findall('enum'):
1171e5c31af7Sopenharmony_ci                    enumname = enumElem.get('name')
1172e5c31af7Sopenharmony_ci                    typeinfo = self.lookupElementInfo(enumname, self.enumdict)
1173e5c31af7Sopenharmony_ci
1174e5c31af7Sopenharmony_ci                    # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
1175e5c31af7Sopenharmony_ci                    alias = self.getAlias(enumElem, self.enumdict)
1176e5c31af7Sopenharmony_ci                    if not self.checkForCorrectionAliases(alias, require, 'enum'):
1177e5c31af7Sopenharmony_ci                        enumextends = enumElem.get('extends')
1178e5c31af7Sopenharmony_ci                        if not required_key in self.gen.featureDictionary[featurename]['enumconstant']:
1179e5c31af7Sopenharmony_ci                            self.gen.featureDictionary[featurename]['enumconstant'][required_key] = {}
1180e5c31af7Sopenharmony_ci                        if not enumextends in self.gen.featureDictionary[featurename]['enumconstant'][required_key]:
1181e5c31af7Sopenharmony_ci                            self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends] = []
1182e5c31af7Sopenharmony_ci                        self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends].append(enumname)
1183e5c31af7Sopenharmony_ci                    else:
1184e5c31af7Sopenharmony_ci                        self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
1185e5c31af7Sopenharmony_ci
1186e5c31af7Sopenharmony_ci                for cmdElem in require.findall('command'):
1187e5c31af7Sopenharmony_ci                    # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
1188e5c31af7Sopenharmony_ci                    alias = self.getAlias(cmdElem, self.cmddict)
1189e5c31af7Sopenharmony_ci                    if not self.checkForCorrectionAliases(alias, require, 'command'):
1190e5c31af7Sopenharmony_ci                        if not required_key in self.gen.featureDictionary[featurename]['command']:
1191e5c31af7Sopenharmony_ci                            self.gen.featureDictionary[featurename]['command'][required_key] = []
1192e5c31af7Sopenharmony_ci                        self.gen.featureDictionary[featurename]['command'][required_key].append(cmdElem.get('name'))
1193e5c31af7Sopenharmony_ci                    else:
1194e5c31af7Sopenharmony_ci                        self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
1195e5c31af7Sopenharmony_ci
1196e5c31af7Sopenharmony_ci    def requireFeatures(self, interface, featurename, api, profile):
1197e5c31af7Sopenharmony_ci        """Process `<require>` tags for a `<version>` or `<extension>`.
1198e5c31af7Sopenharmony_ci
1199e5c31af7Sopenharmony_ci        - interface - Element for `<version>` or `<extension>`, containing
1200e5c31af7Sopenharmony_ci          `<require>` tags
1201e5c31af7Sopenharmony_ci        - featurename - name of the feature
1202e5c31af7Sopenharmony_ci        - api - string specifying API name being generated
1203e5c31af7Sopenharmony_ci        - profile - string specifying API profile being generated"""
1204e5c31af7Sopenharmony_ci
1205e5c31af7Sopenharmony_ci        # <require> marks things that are required by this version/profile
1206e5c31af7Sopenharmony_ci        for feature in interface.findall('require'):
1207e5c31af7Sopenharmony_ci            if matchAPIProfile(api, profile, feature):
1208e5c31af7Sopenharmony_ci                self.markRequired(featurename, feature, True)
1209e5c31af7Sopenharmony_ci
1210e5c31af7Sopenharmony_ci    def removeFeatures(self, interface, featurename, api, profile):
1211e5c31af7Sopenharmony_ci        """Process `<remove>` tags for a `<version>` or `<extension>`.
1212e5c31af7Sopenharmony_ci
1213e5c31af7Sopenharmony_ci        - interface - Element for `<version>` or `<extension>`, containing
1214e5c31af7Sopenharmony_ci          `<remove>` tags
1215e5c31af7Sopenharmony_ci        - featurename - name of the feature
1216e5c31af7Sopenharmony_ci        - api - string specifying API name being generated
1217e5c31af7Sopenharmony_ci        - profile - string specifying API profile being generated"""
1218e5c31af7Sopenharmony_ci
1219e5c31af7Sopenharmony_ci        # <remove> marks things that are removed by this version/profile
1220e5c31af7Sopenharmony_ci        for feature in interface.findall('remove'):
1221e5c31af7Sopenharmony_ci            if matchAPIProfile(api, profile, feature):
1222e5c31af7Sopenharmony_ci                self.markRequired(featurename, feature, False)
1223e5c31af7Sopenharmony_ci
1224e5c31af7Sopenharmony_ci    def assignAdditionalValidity(self, interface, api, profile):
1225e5c31af7Sopenharmony_ci        # Loop over all usage inside all <require> tags.
1226e5c31af7Sopenharmony_ci        for feature in interface.findall('require'):
1227e5c31af7Sopenharmony_ci            if matchAPIProfile(api, profile, feature):
1228e5c31af7Sopenharmony_ci                for v in feature.findall('usage'):
1229e5c31af7Sopenharmony_ci                    if v.get('command'):
1230e5c31af7Sopenharmony_ci                        self.cmddict[v.get('command')].additionalValidity.append(copy.deepcopy(v))
1231e5c31af7Sopenharmony_ci                    if v.get('struct'):
1232e5c31af7Sopenharmony_ci                        self.typedict[v.get('struct')].additionalValidity.append(copy.deepcopy(v))
1233e5c31af7Sopenharmony_ci
1234e5c31af7Sopenharmony_ci    def removeAdditionalValidity(self, interface, api, profile):
1235e5c31af7Sopenharmony_ci        # Loop over all usage inside all <remove> tags.
1236e5c31af7Sopenharmony_ci        for feature in interface.findall('remove'):
1237e5c31af7Sopenharmony_ci            if matchAPIProfile(api, profile, feature):
1238e5c31af7Sopenharmony_ci                for v in feature.findall('usage'):
1239e5c31af7Sopenharmony_ci                    if v.get('command'):
1240e5c31af7Sopenharmony_ci                        self.cmddict[v.get('command')].removedValidity.append(copy.deepcopy(v))
1241e5c31af7Sopenharmony_ci                    if v.get('struct'):
1242e5c31af7Sopenharmony_ci                        self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v))
1243e5c31af7Sopenharmony_ci
1244e5c31af7Sopenharmony_ci    def generateFeature(self, fname, ftype, dictionary, explicit=False):
1245e5c31af7Sopenharmony_ci        """Generate a single type / enum group / enum / command,
1246e5c31af7Sopenharmony_ci        and all its dependencies as needed.
1247e5c31af7Sopenharmony_ci
1248e5c31af7Sopenharmony_ci        - fname - name of feature (`<type>`/`<enum>`/`<command>`)
1249e5c31af7Sopenharmony_ci        - ftype - type of feature, 'type' | 'enum' | 'command'
1250e5c31af7Sopenharmony_ci        - dictionary - of *Info objects - self.{type|enum|cmd}dict
1251e5c31af7Sopenharmony_ci        - explicit - True if this is explicitly required by the top-level
1252e5c31af7Sopenharmony_ci          XML <require> tag, False if it is a dependency of an explicit
1253e5c31af7Sopenharmony_ci          requirement."""
1254e5c31af7Sopenharmony_ci
1255e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname)
1256e5c31af7Sopenharmony_ci
1257e5c31af7Sopenharmony_ci        if not (explicit or self.genOpts.requireDepends):
1258e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'generateFeature: NOT generating', ftype, fname, 'because generator does not require dependencies')
1259e5c31af7Sopenharmony_ci            return
1260e5c31af7Sopenharmony_ci
1261e5c31af7Sopenharmony_ci        f = self.lookupElementInfo(fname, dictionary)
1262e5c31af7Sopenharmony_ci        if f is None:
1263e5c31af7Sopenharmony_ci            # No such feature. This is an error, but reported earlier
1264e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'No entry found for feature', fname,
1265e5c31af7Sopenharmony_ci                            'returning!')
1266e5c31af7Sopenharmony_ci            return
1267e5c31af7Sopenharmony_ci
1268e5c31af7Sopenharmony_ci        # If feature is not required, or has already been declared, return
1269e5c31af7Sopenharmony_ci        if not f.required:
1270e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)')
1271e5c31af7Sopenharmony_ci            return
1272e5c31af7Sopenharmony_ci        if f.declared:
1273e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'Skipping', ftype, fname, '(already declared)')
1274e5c31af7Sopenharmony_ci            return
1275e5c31af7Sopenharmony_ci        # Always mark feature declared, as though actually emitted
1276e5c31af7Sopenharmony_ci        f.declared = True
1277e5c31af7Sopenharmony_ci
1278e5c31af7Sopenharmony_ci        # Determine if this is an alias, and of what, if so
1279e5c31af7Sopenharmony_ci        alias = f.elem.get('alias')
1280e5c31af7Sopenharmony_ci        if alias:
1281e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', fname, 'is an alias of', alias)
1282e5c31af7Sopenharmony_ci
1283e5c31af7Sopenharmony_ci        # Pull in dependent declaration(s) of the feature.
1284e5c31af7Sopenharmony_ci        # For types, there may be one type in the 'requires' attribute of
1285e5c31af7Sopenharmony_ci        #   the element, one in the 'alias' attribute, and many in
1286e5c31af7Sopenharmony_ci        #   embedded <type> and <enum> tags within the element.
1287e5c31af7Sopenharmony_ci        # For commands, there may be many in <type> tags within the element.
1288e5c31af7Sopenharmony_ci        # For enums, no dependencies are allowed (though perhaps if you
1289e5c31af7Sopenharmony_ci        #   have a uint64 enum, it should require that type).
1290e5c31af7Sopenharmony_ci        genProc = None
1291e5c31af7Sopenharmony_ci        followupFeature = None
1292e5c31af7Sopenharmony_ci        if ftype == 'type':
1293e5c31af7Sopenharmony_ci            genProc = self.gen.genType
1294e5c31af7Sopenharmony_ci
1295e5c31af7Sopenharmony_ci            # Generate type dependencies in 'alias' and 'requires' attributes
1296e5c31af7Sopenharmony_ci            if alias:
1297e5c31af7Sopenharmony_ci                self.generateFeature(alias, 'type', self.typedict)
1298e5c31af7Sopenharmony_ci            requires = f.elem.get('requires')
1299e5c31af7Sopenharmony_ci            if requires:
1300e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Generating required dependent type',
1301e5c31af7Sopenharmony_ci                                requires)
1302e5c31af7Sopenharmony_ci                self.generateFeature(requires, 'type', self.typedict)
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci            # Generate types used in defining this type (e.g. in nested
1305e5c31af7Sopenharmony_ci            # <type> tags)
1306e5c31af7Sopenharmony_ci            # Look for <type> in entire <command> tree,
1307e5c31af7Sopenharmony_ci            # not just immediate children
1308e5c31af7Sopenharmony_ci            for subtype in f.elem.findall('.//type'):
1309e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Generating required dependent <type>',
1310e5c31af7Sopenharmony_ci                                subtype.text)
1311e5c31af7Sopenharmony_ci                self.generateFeature(subtype.text, 'type', self.typedict)
1312e5c31af7Sopenharmony_ci
1313e5c31af7Sopenharmony_ci            # Generate enums used in defining this type, for example in
1314e5c31af7Sopenharmony_ci            #   <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
1315e5c31af7Sopenharmony_ci            for subtype in f.elem.findall('.//enum'):
1316e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Generating required dependent <enum>',
1317e5c31af7Sopenharmony_ci                                subtype.text)
1318e5c31af7Sopenharmony_ci                self.generateFeature(subtype.text, 'enum', self.enumdict)
1319e5c31af7Sopenharmony_ci
1320e5c31af7Sopenharmony_ci            # If the type is an enum group, look up the corresponding
1321e5c31af7Sopenharmony_ci            # group in the group dictionary and generate that instead.
1322e5c31af7Sopenharmony_ci            if f.elem.get('category') == 'enum':
1323e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Type', fname, 'is an enum group, so generate that instead')
1324e5c31af7Sopenharmony_ci                group = self.lookupElementInfo(fname, self.groupdict)
1325e5c31af7Sopenharmony_ci                if alias is not None:
1326e5c31af7Sopenharmony_ci                    # An alias of another group name.
1327e5c31af7Sopenharmony_ci                    # Pass to genGroup with 'alias' parameter = aliased name
1328e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'Generating alias', fname,
1329e5c31af7Sopenharmony_ci                                    'for enumerated type', alias)
1330e5c31af7Sopenharmony_ci                    # Now, pass the *aliased* GroupInfo to the genGroup, but
1331e5c31af7Sopenharmony_ci                    # with an additional parameter which is the alias name.
1332e5c31af7Sopenharmony_ci                    genProc = self.gen.genGroup
1333e5c31af7Sopenharmony_ci                    f = self.lookupElementInfo(alias, self.groupdict)
1334e5c31af7Sopenharmony_ci                elif group is None:
1335e5c31af7Sopenharmony_ci                    self.gen.logMsg('warn', 'Skipping enum type', fname,
1336e5c31af7Sopenharmony_ci                                    ': No matching enumerant group')
1337e5c31af7Sopenharmony_ci                    return
1338e5c31af7Sopenharmony_ci                else:
1339e5c31af7Sopenharmony_ci                    genProc = self.gen.genGroup
1340e5c31af7Sopenharmony_ci                    f = group
1341e5c31af7Sopenharmony_ci
1342e5c31af7Sopenharmony_ci                    # @ The enum group is not ready for generation. At this
1343e5c31af7Sopenharmony_ci                    # @   point, it contains all <enum> tags injected by
1344e5c31af7Sopenharmony_ci                    # @   <extension> tags without any verification of whether
1345e5c31af7Sopenharmony_ci                    # @   they are required or not. It may also contain
1346e5c31af7Sopenharmony_ci                    # @   duplicates injected by multiple consistent
1347e5c31af7Sopenharmony_ci                    # @   definitions of an <enum>.
1348e5c31af7Sopenharmony_ci
1349e5c31af7Sopenharmony_ci                    # @ Pass over each enum, marking its enumdict[] entry as
1350e5c31af7Sopenharmony_ci                    # @ required or not. Mark aliases of enums as required,
1351e5c31af7Sopenharmony_ci                    # @ too.
1352e5c31af7Sopenharmony_ci
1353e5c31af7Sopenharmony_ci                    enums = group.elem.findall('enum')
1354e5c31af7Sopenharmony_ci
1355e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'generateFeature: checking enums for group', fname)
1356e5c31af7Sopenharmony_ci
1357e5c31af7Sopenharmony_ci                    # Check for required enums, including aliases
1358e5c31af7Sopenharmony_ci                    # LATER - Check for, report, and remove duplicates?
1359e5c31af7Sopenharmony_ci                    enumAliases = []
1360e5c31af7Sopenharmony_ci                    for elem in enums:
1361e5c31af7Sopenharmony_ci                        name = elem.get('name')
1362e5c31af7Sopenharmony_ci
1363e5c31af7Sopenharmony_ci                        required = False
1364e5c31af7Sopenharmony_ci
1365e5c31af7Sopenharmony_ci                        extname = elem.get('extname')
1366e5c31af7Sopenharmony_ci                        version = elem.get('version')
1367e5c31af7Sopenharmony_ci                        if extname is not None:
1368e5c31af7Sopenharmony_ci                            # 'supported' attribute was injected when the <enum> element was
1369e5c31af7Sopenharmony_ci                            # moved into the <enums> group in Registry.parseTree()
1370e5c31af7Sopenharmony_ci                            supported_list = elem.get('supported').split(",")
1371e5c31af7Sopenharmony_ci                            if self.genOpts.defaultExtensions in supported_list:
1372e5c31af7Sopenharmony_ci                                required = True
1373e5c31af7Sopenharmony_ci                            elif re.match(self.genOpts.addExtensions, extname) is not None:
1374e5c31af7Sopenharmony_ci                                required = True
1375e5c31af7Sopenharmony_ci                        elif version is not None:
1376e5c31af7Sopenharmony_ci                            required = re.match(self.genOpts.emitversions, version) is not None
1377e5c31af7Sopenharmony_ci                        else:
1378e5c31af7Sopenharmony_ci                            required = True
1379e5c31af7Sopenharmony_ci
1380e5c31af7Sopenharmony_ci                        self.gen.logMsg('diag', '* required =', required, 'for', name)
1381e5c31af7Sopenharmony_ci                        if required:
1382e5c31af7Sopenharmony_ci                            # Mark this element as required (in the element, not the EnumInfo)
1383e5c31af7Sopenharmony_ci                            elem.set('required', 'true')
1384e5c31af7Sopenharmony_ci                            # If it is an alias, track that for later use
1385e5c31af7Sopenharmony_ci                            enumAlias = elem.get('alias')
1386e5c31af7Sopenharmony_ci                            if enumAlias:
1387e5c31af7Sopenharmony_ci                                enumAliases.append(enumAlias)
1388e5c31af7Sopenharmony_ci                    for elem in enums:
1389e5c31af7Sopenharmony_ci                        name = elem.get('name')
1390e5c31af7Sopenharmony_ci                        if name in enumAliases:
1391e5c31af7Sopenharmony_ci                            elem.set('required', 'true')
1392e5c31af7Sopenharmony_ci                            self.gen.logMsg('diag', '* also need to require alias', name)
1393e5c31af7Sopenharmony_ci            if f is None:
1394e5c31af7Sopenharmony_ci                raise RuntimeError("Should not get here")
1395e5c31af7Sopenharmony_ci            if f.elem.get('category') == 'bitmask':
1396e5c31af7Sopenharmony_ci                followupFeature = f.elem.get('bitvalues')
1397e5c31af7Sopenharmony_ci        elif ftype == 'command':
1398e5c31af7Sopenharmony_ci            # Generate command dependencies in 'alias' attribute
1399e5c31af7Sopenharmony_ci            if alias:
1400e5c31af7Sopenharmony_ci                self.generateFeature(alias, 'command', self.cmddict)
1401e5c31af7Sopenharmony_ci
1402e5c31af7Sopenharmony_ci            genProc = self.gen.genCmd
1403e5c31af7Sopenharmony_ci            for type_elem in f.elem.findall('.//type'):
1404e5c31af7Sopenharmony_ci                depname = type_elem.text
1405e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Generating required parameter type',
1406e5c31af7Sopenharmony_ci                                depname)
1407e5c31af7Sopenharmony_ci                self.generateFeature(depname, 'type', self.typedict)
1408e5c31af7Sopenharmony_ci        elif ftype == 'enum':
1409e5c31af7Sopenharmony_ci            # Generate enum dependencies in 'alias' attribute
1410e5c31af7Sopenharmony_ci            if alias:
1411e5c31af7Sopenharmony_ci                self.generateFeature(alias, 'enum', self.enumdict)
1412e5c31af7Sopenharmony_ci            genProc = self.gen.genEnum
1413e5c31af7Sopenharmony_ci
1414e5c31af7Sopenharmony_ci        # Actually generate the type only if emitting declarations
1415e5c31af7Sopenharmony_ci        if self.emitFeatures:
1416e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'Emitting', ftype, 'decl for', fname)
1417e5c31af7Sopenharmony_ci            if genProc is None:
1418e5c31af7Sopenharmony_ci                raise RuntimeError("genProc is None when we should be emitting")
1419e5c31af7Sopenharmony_ci            genProc(f, fname, alias)
1420e5c31af7Sopenharmony_ci        else:
1421e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'Skipping', ftype, fname,
1422e5c31af7Sopenharmony_ci                            '(should not be emitted)')
1423e5c31af7Sopenharmony_ci
1424e5c31af7Sopenharmony_ci        if followupFeature:
1425e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'Generating required bitvalues <enum>',
1426e5c31af7Sopenharmony_ci                            followupFeature)
1427e5c31af7Sopenharmony_ci            self.generateFeature(followupFeature, "type", self.typedict)
1428e5c31af7Sopenharmony_ci
1429e5c31af7Sopenharmony_ci    def generateRequiredInterface(self, interface):
1430e5c31af7Sopenharmony_ci        """Generate all interfaces required by an API version or extension.
1431e5c31af7Sopenharmony_ci
1432e5c31af7Sopenharmony_ci        - interface - Element for `<version>` or `<extension>`"""
1433e5c31af7Sopenharmony_ci
1434e5c31af7Sopenharmony_ci        # Loop over all features inside all <require> tags.
1435e5c31af7Sopenharmony_ci        for features in interface.findall('require'):
1436e5c31af7Sopenharmony_ci            for t in features.findall('type'):
1437e5c31af7Sopenharmony_ci                self.generateFeature(t.get('name'), 'type', self.typedict, explicit=True)
1438e5c31af7Sopenharmony_ci            for e in features.findall('enum'):
1439e5c31af7Sopenharmony_ci                # If this is an enum extending an enumerated type, do not
1440e5c31af7Sopenharmony_ci                # generate it - this has already been done in reg.parseTree,
1441e5c31af7Sopenharmony_ci                # by copying this element into the enumerated type.
1442e5c31af7Sopenharmony_ci                enumextends = e.get('extends')
1443e5c31af7Sopenharmony_ci                if not enumextends:
1444e5c31af7Sopenharmony_ci                    self.generateFeature(e.get('name'), 'enum', self.enumdict, explicit=True)
1445e5c31af7Sopenharmony_ci            for c in features.findall('command'):
1446e5c31af7Sopenharmony_ci                self.generateFeature(c.get('name'), 'command', self.cmddict, explicit=True)
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci    def generateSpirv(self, spirv, dictionary):
1449e5c31af7Sopenharmony_ci        if spirv is None:
1450e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'No entry found for element', name,
1451e5c31af7Sopenharmony_ci                            'returning!')
1452e5c31af7Sopenharmony_ci            return
1453e5c31af7Sopenharmony_ci
1454e5c31af7Sopenharmony_ci        name = spirv.elem.get('name')
1455e5c31af7Sopenharmony_ci        # No known alias for spirv elements
1456e5c31af7Sopenharmony_ci        alias = None
1457e5c31af7Sopenharmony_ci        if spirv.emit:
1458e5c31af7Sopenharmony_ci            genProc = self.gen.genSpirv
1459e5c31af7Sopenharmony_ci            genProc(spirv, name, alias)
1460e5c31af7Sopenharmony_ci
1461e5c31af7Sopenharmony_ci    def stripUnsupportedAPIs(self, dictionary, attribute, supportedDictionary):
1462e5c31af7Sopenharmony_ci        """Strip unsupported APIs from attributes of APIs.
1463e5c31af7Sopenharmony_ci           dictionary - *Info dictionary of APIs to be updated
1464e5c31af7Sopenharmony_ci           attribute - attribute name to look for in each API
1465e5c31af7Sopenharmony_ci           supportedDictionary - dictionary in which to look for supported
1466e5c31af7Sopenharmony_ci            API elements in the attribute"""
1467e5c31af7Sopenharmony_ci
1468e5c31af7Sopenharmony_ci        for key in dictionary:
1469e5c31af7Sopenharmony_ci            eleminfo = dictionary[key]
1470e5c31af7Sopenharmony_ci            attribstring = eleminfo.elem.get(attribute)
1471e5c31af7Sopenharmony_ci            if attribstring is not None:
1472e5c31af7Sopenharmony_ci                apis = []
1473e5c31af7Sopenharmony_ci                stripped = False
1474e5c31af7Sopenharmony_ci                for api in attribstring.split(','):
1475e5c31af7Sopenharmony_ci                    ##print('Checking API {} referenced by {}'.format(api, key))
1476e5c31af7Sopenharmony_ci                    if api in supportedDictionary and supportedDictionary[api].required:
1477e5c31af7Sopenharmony_ci                        apis.append(api)
1478e5c31af7Sopenharmony_ci                    else:
1479e5c31af7Sopenharmony_ci                        stripped = True
1480e5c31af7Sopenharmony_ci                        ##print('\t**STRIPPING API {} from {}'.format(api, key))
1481e5c31af7Sopenharmony_ci
1482e5c31af7Sopenharmony_ci                # Update the attribute after stripping stuff.
1483e5c31af7Sopenharmony_ci                # Could sort apis before joining, but it is not a clear win
1484e5c31af7Sopenharmony_ci                if stripped:
1485e5c31af7Sopenharmony_ci                    eleminfo.elem.set(attribute, ','.join(apis))
1486e5c31af7Sopenharmony_ci
1487e5c31af7Sopenharmony_ci    def stripUnsupportedAPIsFromList(self, dictionary, supportedDictionary):
1488e5c31af7Sopenharmony_ci        """Strip unsupported APIs from attributes of APIs.
1489e5c31af7Sopenharmony_ci           dictionary - dictionary of list of structure name strings
1490e5c31af7Sopenharmony_ci           supportedDictionary - dictionary in which to look for supported
1491e5c31af7Sopenharmony_ci            API elements in the attribute"""
1492e5c31af7Sopenharmony_ci
1493e5c31af7Sopenharmony_ci        for key in dictionary:
1494e5c31af7Sopenharmony_ci            attribstring = dictionary[key]
1495e5c31af7Sopenharmony_ci            if attribstring is not None:
1496e5c31af7Sopenharmony_ci                apis = []
1497e5c31af7Sopenharmony_ci                stripped = False
1498e5c31af7Sopenharmony_ci                for api in attribstring:
1499e5c31af7Sopenharmony_ci                    ##print('Checking API {} referenced by {}'.format(api, key))
1500e5c31af7Sopenharmony_ci                    if supportedDictionary[api].required:
1501e5c31af7Sopenharmony_ci                        apis.append(api)
1502e5c31af7Sopenharmony_ci                    else:
1503e5c31af7Sopenharmony_ci                        stripped = True
1504e5c31af7Sopenharmony_ci                        ##print('\t**STRIPPING API {} from {}'.format(api, key))
1505e5c31af7Sopenharmony_ci
1506e5c31af7Sopenharmony_ci                # Update the attribute after stripping stuff.
1507e5c31af7Sopenharmony_ci                # Could sort apis before joining, but it is not a clear win
1508e5c31af7Sopenharmony_ci                if stripped:
1509e5c31af7Sopenharmony_ci                    dictionary[key] = apis
1510e5c31af7Sopenharmony_ci
1511e5c31af7Sopenharmony_ci    def generateFormat(self, format, dictionary):
1512e5c31af7Sopenharmony_ci        if format is None:
1513e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'No entry found for format element',
1514e5c31af7Sopenharmony_ci                            'returning!')
1515e5c31af7Sopenharmony_ci            return
1516e5c31af7Sopenharmony_ci
1517e5c31af7Sopenharmony_ci        name = format.elem.get('name')
1518e5c31af7Sopenharmony_ci        # No known alias for VkFormat elements
1519e5c31af7Sopenharmony_ci        alias = None
1520e5c31af7Sopenharmony_ci        if format.emit:
1521e5c31af7Sopenharmony_ci            genProc = self.gen.genFormat
1522e5c31af7Sopenharmony_ci            genProc(format, name, alias)
1523e5c31af7Sopenharmony_ci
1524e5c31af7Sopenharmony_ci    def generateSyncStage(self, sync):
1525e5c31af7Sopenharmony_ci        genProc = self.gen.genSyncStage
1526e5c31af7Sopenharmony_ci        genProc(sync)
1527e5c31af7Sopenharmony_ci
1528e5c31af7Sopenharmony_ci    def generateSyncAccess(self, sync):
1529e5c31af7Sopenharmony_ci        genProc = self.gen.genSyncAccess
1530e5c31af7Sopenharmony_ci        genProc(sync)
1531e5c31af7Sopenharmony_ci
1532e5c31af7Sopenharmony_ci    def generateSyncPipeline(self, sync):
1533e5c31af7Sopenharmony_ci        genProc = self.gen.genSyncPipeline
1534e5c31af7Sopenharmony_ci        genProc(sync)
1535e5c31af7Sopenharmony_ci
1536e5c31af7Sopenharmony_ci    def tagValidExtensionStructs(self):
1537e5c31af7Sopenharmony_ci        """Construct a "validextensionstructs" list for parent structures
1538e5c31af7Sopenharmony_ci           based on "structextends" tags in child structures.
1539e5c31af7Sopenharmony_ci           Only do this for structures tagged as required."""
1540e5c31af7Sopenharmony_ci
1541e5c31af7Sopenharmony_ci        for typeinfo in self.typedict.values():
1542e5c31af7Sopenharmony_ci            type_elem = typeinfo.elem
1543e5c31af7Sopenharmony_ci            if typeinfo.required and type_elem.get('category') == 'struct':
1544e5c31af7Sopenharmony_ci                struct_extends = type_elem.get('structextends')
1545e5c31af7Sopenharmony_ci                if struct_extends is not None:
1546e5c31af7Sopenharmony_ci                    for parent in struct_extends.split(','):
1547e5c31af7Sopenharmony_ci                        # self.gen.logMsg('diag', type_elem.get('name'), 'extends', parent)
1548e5c31af7Sopenharmony_ci                        self.validextensionstructs[parent].append(type_elem.get('name'))
1549e5c31af7Sopenharmony_ci
1550e5c31af7Sopenharmony_ci        # Sort the lists so they do not depend on the XML order
1551e5c31af7Sopenharmony_ci        for parent in self.validextensionstructs:
1552e5c31af7Sopenharmony_ci            self.validextensionstructs[parent].sort()
1553e5c31af7Sopenharmony_ci
1554e5c31af7Sopenharmony_ci    def apiGen(self):
1555e5c31af7Sopenharmony_ci        """Generate interface for specified versions using the current
1556e5c31af7Sopenharmony_ci        generator and generator options"""
1557e5c31af7Sopenharmony_ci
1558e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', '*******************************************')
1559e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', '  Registry.apiGen file:', self.genOpts.filename,
1560e5c31af7Sopenharmony_ci                        'api:', self.genOpts.apiname,
1561e5c31af7Sopenharmony_ci                        'profile:', self.genOpts.profile)
1562e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', '*******************************************')
1563e5c31af7Sopenharmony_ci
1564e5c31af7Sopenharmony_ci        # Could reset required/declared flags for all features here.
1565e5c31af7Sopenharmony_ci        # This has been removed as never used. The initial motivation was
1566e5c31af7Sopenharmony_ci        # the idea of calling apiGen() repeatedly for different targets, but
1567e5c31af7Sopenharmony_ci        # this has never been done. The 20% or so build-time speedup that
1568e5c31af7Sopenharmony_ci        # might result is not worth the effort to make it actually work.
1569e5c31af7Sopenharmony_ci        #
1570e5c31af7Sopenharmony_ci        # self.apiReset()
1571e5c31af7Sopenharmony_ci
1572e5c31af7Sopenharmony_ci        # Compile regexps used to select versions & extensions
1573e5c31af7Sopenharmony_ci        regVersions = re.compile(self.genOpts.versions)
1574e5c31af7Sopenharmony_ci        regEmitVersions = re.compile(self.genOpts.emitversions)
1575e5c31af7Sopenharmony_ci        regAddExtensions = re.compile(self.genOpts.addExtensions)
1576e5c31af7Sopenharmony_ci        regRemoveExtensions = re.compile(self.genOpts.removeExtensions)
1577e5c31af7Sopenharmony_ci        regEmitExtensions = re.compile(self.genOpts.emitExtensions)
1578e5c31af7Sopenharmony_ci        regEmitSpirv = re.compile(self.genOpts.emitSpirv)
1579e5c31af7Sopenharmony_ci        regEmitFormats = re.compile(self.genOpts.emitFormats)
1580e5c31af7Sopenharmony_ci
1581e5c31af7Sopenharmony_ci        # Get all matching API feature names & add to list of FeatureInfo
1582e5c31af7Sopenharmony_ci        # Note we used to select on feature version attributes, not names.
1583e5c31af7Sopenharmony_ci        features = []
1584e5c31af7Sopenharmony_ci        apiMatch = False
1585e5c31af7Sopenharmony_ci        for key in self.apidict:
1586e5c31af7Sopenharmony_ci            fi = self.apidict[key]
1587e5c31af7Sopenharmony_ci            api = fi.elem.get('api')
1588e5c31af7Sopenharmony_ci            if apiNameMatch(self.genOpts.apiname, api):
1589e5c31af7Sopenharmony_ci                apiMatch = True
1590e5c31af7Sopenharmony_ci                if regVersions.match(fi.name):
1591e5c31af7Sopenharmony_ci                    # Matches API & version #s being generated. Mark for
1592e5c31af7Sopenharmony_ci                    # emission and add to the features[] list .
1593e5c31af7Sopenharmony_ci                    # @@ Could use 'declared' instead of 'emit'?
1594e5c31af7Sopenharmony_ci                    fi.emit = (regEmitVersions.match(fi.name) is not None)
1595e5c31af7Sopenharmony_ci                    features.append(fi)
1596e5c31af7Sopenharmony_ci                    if not fi.emit:
1597e5c31af7Sopenharmony_ci                        self.gen.logMsg('diag', 'NOT tagging feature api =', api,
1598e5c31af7Sopenharmony_ci                                        'name =', fi.name, 'version =', fi.version,
1599e5c31af7Sopenharmony_ci                                        'for emission (does not match emitversions pattern)')
1600e5c31af7Sopenharmony_ci                    else:
1601e5c31af7Sopenharmony_ci                        self.gen.logMsg('diag', 'Including feature api =', api,
1602e5c31af7Sopenharmony_ci                                        'name =', fi.name, 'version =', fi.version,
1603e5c31af7Sopenharmony_ci                                        'for emission (matches emitversions pattern)')
1604e5c31af7Sopenharmony_ci                else:
1605e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'NOT including feature api =', api,
1606e5c31af7Sopenharmony_ci                                    'name =', fi.name, 'version =', fi.version,
1607e5c31af7Sopenharmony_ci                                    '(does not match requested versions)')
1608e5c31af7Sopenharmony_ci            else:
1609e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'NOT including feature api =', api,
1610e5c31af7Sopenharmony_ci                                'name =', fi.name,
1611e5c31af7Sopenharmony_ci                                '(does not match requested API)')
1612e5c31af7Sopenharmony_ci        if not apiMatch:
1613e5c31af7Sopenharmony_ci            self.gen.logMsg('warn', 'No matching API versions found!')
1614e5c31af7Sopenharmony_ci
1615e5c31af7Sopenharmony_ci        # Get all matching extensions, in order by their extension number,
1616e5c31af7Sopenharmony_ci        # and add to the list of features.
1617e5c31af7Sopenharmony_ci        # Start with extensions whose 'supported' attributes match the API
1618e5c31af7Sopenharmony_ci        # being generated. Add extensions matching the pattern specified in
1619e5c31af7Sopenharmony_ci        # regExtensions, then remove extensions matching the pattern
1620e5c31af7Sopenharmony_ci        # specified in regRemoveExtensions
1621e5c31af7Sopenharmony_ci        for (extName, ei) in sorted(self.extdict.items(), key=lambda x: x[1].number if x[1].number is not None else '0'):
1622e5c31af7Sopenharmony_ci            extName = ei.name
1623e5c31af7Sopenharmony_ci            include = False
1624e5c31af7Sopenharmony_ci
1625e5c31af7Sopenharmony_ci            # Include extension if defaultExtensions is not None and is
1626e5c31af7Sopenharmony_ci            # exactly matched by the 'supported' attribute.
1627e5c31af7Sopenharmony_ci            if apiNameMatch(self.genOpts.defaultExtensions,
1628e5c31af7Sopenharmony_ci                            ei.elem.get('supported')):
1629e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Including extension',
1630e5c31af7Sopenharmony_ci                                extName, "(defaultExtensions matches the 'supported' attribute)")
1631e5c31af7Sopenharmony_ci                include = True
1632e5c31af7Sopenharmony_ci
1633e5c31af7Sopenharmony_ci            # Include additional extensions if the extension name matches
1634e5c31af7Sopenharmony_ci            # the regexp specified in the generator options. This allows
1635e5c31af7Sopenharmony_ci            # forcing extensions into an interface even if they are not
1636e5c31af7Sopenharmony_ci            # tagged appropriately in the registry.
1637e5c31af7Sopenharmony_ci            # However, we still respect the 'supported' attribute.
1638e5c31af7Sopenharmony_ci            if regAddExtensions.match(extName) is not None:
1639e5c31af7Sopenharmony_ci                if not apiNameMatch(self.genOpts.apiname, ei.elem.get('supported')):
1640e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'NOT including extension',
1641e5c31af7Sopenharmony_ci                                    extName, '(matches explicitly requested, but does not match the \'supported\' attribute)')
1642e5c31af7Sopenharmony_ci                    include = False
1643e5c31af7Sopenharmony_ci                else:
1644e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'Including extension',
1645e5c31af7Sopenharmony_ci                                    extName, '(matches explicitly requested extensions to add)')
1646e5c31af7Sopenharmony_ci                    include = True
1647e5c31af7Sopenharmony_ci            # Remove extensions if the name matches the regexp specified
1648e5c31af7Sopenharmony_ci            # in generator options. This allows forcing removal of
1649e5c31af7Sopenharmony_ci            # extensions from an interface even if they are tagged that
1650e5c31af7Sopenharmony_ci            # way in the registry.
1651e5c31af7Sopenharmony_ci            if regRemoveExtensions.match(extName) is not None:
1652e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'Removing extension',
1653e5c31af7Sopenharmony_ci                                extName, '(matches explicitly requested extensions to remove)')
1654e5c31af7Sopenharmony_ci                include = False
1655e5c31af7Sopenharmony_ci
1656e5c31af7Sopenharmony_ci            # If the extension is to be included, add it to the
1657e5c31af7Sopenharmony_ci            # extension features list.
1658e5c31af7Sopenharmony_ci            if include:
1659e5c31af7Sopenharmony_ci                ei.emit = (regEmitExtensions.match(extName) is not None)
1660e5c31af7Sopenharmony_ci                features.append(ei)
1661e5c31af7Sopenharmony_ci                if not ei.emit:
1662e5c31af7Sopenharmony_ci                    self.gen.logMsg('diag', 'NOT tagging extension',
1663e5c31af7Sopenharmony_ci                                    extName,
1664e5c31af7Sopenharmony_ci                                    'for emission (does not match emitextensions pattern)')
1665e5c31af7Sopenharmony_ci
1666e5c31af7Sopenharmony_ci                # Hack - can be removed when validity generator goes away
1667e5c31af7Sopenharmony_ci                # (Jon) I am not sure what this does, or if it should
1668e5c31af7Sopenharmony_ci                # respect the ei.emit flag above.
1669e5c31af7Sopenharmony_ci                self.requiredextensions.append(extName)
1670e5c31af7Sopenharmony_ci            else:
1671e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'NOT including extension',
1672e5c31af7Sopenharmony_ci                                extName, '(does not match api attribute or explicitly requested extensions)')
1673e5c31af7Sopenharmony_ci
1674e5c31af7Sopenharmony_ci        # Add all spirv elements to list
1675e5c31af7Sopenharmony_ci        # generators decide to emit them all or not
1676e5c31af7Sopenharmony_ci        # Currently no filtering as no client of these elements needs filtering
1677e5c31af7Sopenharmony_ci        spirvexts = []
1678e5c31af7Sopenharmony_ci        for key in self.spirvextdict:
1679e5c31af7Sopenharmony_ci            si = self.spirvextdict[key]
1680e5c31af7Sopenharmony_ci            si.emit = (regEmitSpirv.match(key) is not None)
1681e5c31af7Sopenharmony_ci            spirvexts.append(si)
1682e5c31af7Sopenharmony_ci        spirvcaps = []
1683e5c31af7Sopenharmony_ci        for key in self.spirvcapdict:
1684e5c31af7Sopenharmony_ci            si = self.spirvcapdict[key]
1685e5c31af7Sopenharmony_ci            si.emit = (regEmitSpirv.match(key) is not None)
1686e5c31af7Sopenharmony_ci            spirvcaps.append(si)
1687e5c31af7Sopenharmony_ci
1688e5c31af7Sopenharmony_ci        formats = []
1689e5c31af7Sopenharmony_ci        for key in self.formatsdict:
1690e5c31af7Sopenharmony_ci            si = self.formatsdict[key]
1691e5c31af7Sopenharmony_ci            si.emit = (regEmitFormats.match(key) is not None)
1692e5c31af7Sopenharmony_ci            formats.append(si)
1693e5c31af7Sopenharmony_ci
1694e5c31af7Sopenharmony_ci        # Sort the features list, if a sort procedure is defined
1695e5c31af7Sopenharmony_ci        if self.genOpts.sortProcedure:
1696e5c31af7Sopenharmony_ci            self.genOpts.sortProcedure(features)
1697e5c31af7Sopenharmony_ci
1698e5c31af7Sopenharmony_ci        # Passes 1+2: loop over requested API versions and extensions tagging
1699e5c31af7Sopenharmony_ci        #   types/commands/features as required (in an <require> block) or no
1700e5c31af7Sopenharmony_ci        #   longer required (in an <remove> block). <remove>s are processed
1701e5c31af7Sopenharmony_ci        #   after all <require>s, so removals win.
1702e5c31af7Sopenharmony_ci        # If a profile other than 'None' is being generated, it must
1703e5c31af7Sopenharmony_ci        #   match the profile attribute (if any) of the <require> and
1704e5c31af7Sopenharmony_ci        #   <remove> tags.
1705e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'PASS 1: TAG FEATURES')
1706e5c31af7Sopenharmony_ci        for f in features:
1707e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'PASS 1: Tagging required and features for', f.name)
1708e5c31af7Sopenharmony_ci            self.fillFeatureDictionary(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
1709e5c31af7Sopenharmony_ci            self.requireFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
1710e5c31af7Sopenharmony_ci            self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
1711e5c31af7Sopenharmony_ci
1712e5c31af7Sopenharmony_ci        for f in features:
1713e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'PASS 2: Tagging removed features for', f.name)
1714e5c31af7Sopenharmony_ci            self.removeFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
1715e5c31af7Sopenharmony_ci            self.removeAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
1716e5c31af7Sopenharmony_ci
1717e5c31af7Sopenharmony_ci        # Now, strip references to APIs that are not required.
1718e5c31af7Sopenharmony_ci        # At present such references may occur in:
1719e5c31af7Sopenharmony_ci        #   Structs in <type category="struct"> 'structextends' attributes
1720e5c31af7Sopenharmony_ci        #   Enums in <command> 'successcodes' and 'errorcodes' attributes
1721e5c31af7Sopenharmony_ci        self.stripUnsupportedAPIs(self.typedict, 'structextends', self.typedict)
1722e5c31af7Sopenharmony_ci        self.stripUnsupportedAPIs(self.cmddict, 'successcodes', self.enumdict)
1723e5c31af7Sopenharmony_ci        self.stripUnsupportedAPIs(self.cmddict, 'errorcodes', self.enumdict)
1724e5c31af7Sopenharmony_ci        self.stripUnsupportedAPIsFromList(self.validextensionstructs, self.typedict)
1725e5c31af7Sopenharmony_ci
1726e5c31af7Sopenharmony_ci        # Construct lists of valid extension structures
1727e5c31af7Sopenharmony_ci        self.tagValidExtensionStructs()
1728e5c31af7Sopenharmony_ci
1729e5c31af7Sopenharmony_ci        # @@May need to strip <spirvcapability> / <spirvextension> <enable>
1730e5c31af7Sopenharmony_ci        # tags of these forms:
1731e5c31af7Sopenharmony_ci        #   <enable version="VK_API_VERSION_1_0"/>
1732e5c31af7Sopenharmony_ci        #   <enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/>
1733e5c31af7Sopenharmony_ci        #   <enable extension="VK_KHR_shader_draw_parameters"/>
1734e5c31af7Sopenharmony_ci        #   <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
1735e5c31af7Sopenharmony_ci
1736e5c31af7Sopenharmony_ci        # Pass 3: loop over specified API versions and extensions printing
1737e5c31af7Sopenharmony_ci        #   declarations for required things which have not already been
1738e5c31af7Sopenharmony_ci        #   generated.
1739e5c31af7Sopenharmony_ci        self.gen.logMsg('diag', 'PASS 3: GENERATE INTERFACES FOR FEATURES')
1740e5c31af7Sopenharmony_ci        self.gen.beginFile(self.genOpts)
1741e5c31af7Sopenharmony_ci        for f in features:
1742e5c31af7Sopenharmony_ci            self.gen.logMsg('diag', 'PASS 3: Generating interface for',
1743e5c31af7Sopenharmony_ci                            f.name)
1744e5c31af7Sopenharmony_ci            emit = self.emitFeatures = f.emit
1745e5c31af7Sopenharmony_ci            if not emit:
1746e5c31af7Sopenharmony_ci                self.gen.logMsg('diag', 'PASS 3: NOT declaring feature',
1747e5c31af7Sopenharmony_ci                                f.elem.get('name'), 'because it is not tagged for emission')
1748e5c31af7Sopenharmony_ci            # Generate the interface (or just tag its elements as having been
1749e5c31af7Sopenharmony_ci            # emitted, if they have not been).
1750e5c31af7Sopenharmony_ci            self.gen.beginFeature(f.elem, emit)
1751e5c31af7Sopenharmony_ci            self.generateRequiredInterface(f.elem)
1752e5c31af7Sopenharmony_ci            self.gen.endFeature()
1753e5c31af7Sopenharmony_ci        # Generate spirv elements
1754e5c31af7Sopenharmony_ci        for s in spirvexts:
1755e5c31af7Sopenharmony_ci            self.generateSpirv(s, self.spirvextdict)
1756e5c31af7Sopenharmony_ci        for s in spirvcaps:
1757e5c31af7Sopenharmony_ci            self.generateSpirv(s, self.spirvcapdict)
1758e5c31af7Sopenharmony_ci        for s in formats:
1759e5c31af7Sopenharmony_ci            self.generateFormat(s, self.formatsdict)
1760e5c31af7Sopenharmony_ci        for s in self.syncstagedict:
1761e5c31af7Sopenharmony_ci            self.generateSyncStage(self.syncstagedict[s])
1762e5c31af7Sopenharmony_ci        for s in self.syncaccessdict:
1763e5c31af7Sopenharmony_ci            self.generateSyncAccess(self.syncaccessdict[s])
1764e5c31af7Sopenharmony_ci        for s in self.syncpipelinedict:
1765e5c31af7Sopenharmony_ci            self.generateSyncPipeline(self.syncpipelinedict[s])
1766e5c31af7Sopenharmony_ci        self.gen.endFile()
1767e5c31af7Sopenharmony_ci
1768e5c31af7Sopenharmony_ci    def apiReset(self):
1769e5c31af7Sopenharmony_ci        """Reset type/enum/command dictionaries before generating another API.
1770e5c31af7Sopenharmony_ci
1771e5c31af7Sopenharmony_ci        Use between apiGen() calls to reset internal state."""
1772e5c31af7Sopenharmony_ci        for datatype in self.typedict:
1773e5c31af7Sopenharmony_ci            self.typedict[datatype].resetState()
1774e5c31af7Sopenharmony_ci        for enum in self.enumdict:
1775e5c31af7Sopenharmony_ci            self.enumdict[enum].resetState()
1776e5c31af7Sopenharmony_ci        for cmd in self.cmddict:
1777e5c31af7Sopenharmony_ci            self.cmddict[cmd].resetState()
1778e5c31af7Sopenharmony_ci        for cmd in self.apidict:
1779e5c31af7Sopenharmony_ci            self.apidict[cmd].resetState()
1780