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_cifrom generator import OutputGenerator, enquote, noneStr
8e5c31af7Sopenharmony_ci
9e5c31af7Sopenharmony_cidef mostOfficial(api, newapi):
10e5c31af7Sopenharmony_ci    """Return the 'most official' of two related names, api and newapi.
11e5c31af7Sopenharmony_ci       KHR is more official than EXT is more official than everything else.
12e5c31af7Sopenharmony_ci       If there is ambiguity, return api.
13e5c31af7Sopenharmony_ci       Accommodate APIs using lower-case vendor suffixes."""
14e5c31af7Sopenharmony_ci
15e5c31af7Sopenharmony_ci    apicat = api[-3:].upper()
16e5c31af7Sopenharmony_ci    newapicat = newapi[-3:].upper()
17e5c31af7Sopenharmony_ci
18e5c31af7Sopenharmony_ci    if apicat == 'KHR':
19e5c31af7Sopenharmony_ci        return api
20e5c31af7Sopenharmony_ci    if newapicat == 'KHR':
21e5c31af7Sopenharmony_ci        return newapi;
22e5c31af7Sopenharmony_ci    if apicat == 'EXT':
23e5c31af7Sopenharmony_ci        return api
24e5c31af7Sopenharmony_ci    if newapicat == 'EXT':
25e5c31af7Sopenharmony_ci        return newapi;
26e5c31af7Sopenharmony_ci    return api
27e5c31af7Sopenharmony_ci
28e5c31af7Sopenharmony_ciclass ScriptOutputGenerator(OutputGenerator):
29e5c31af7Sopenharmony_ci    """ScriptOutputGenerator - subclass of OutputGenerator.
30e5c31af7Sopenharmony_ci    Base class to Generate script (Python/Ruby/JS/etc.) data structures
31e5c31af7Sopenharmony_ci    describing API names and relationships.
32e5c31af7Sopenharmony_ci    Similar to DocOutputGenerator, but writes a single file."""
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_ci    def apiName(self, name):
35e5c31af7Sopenharmony_ci        """Return True if name is in the reserved API namespace.
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_ci        Delegates to the conventions object. """
38e5c31af7Sopenharmony_ci        return self.genOpts.conventions.is_api_name(name)
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_ci    def __init__(self, *args, **kwargs):
41e5c31af7Sopenharmony_ci        super().__init__(*args, **kwargs)
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_ci        # Track features being generated
44e5c31af7Sopenharmony_ci        self.features = []
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_ci        # Reverse map from interface names to features requiring them
47e5c31af7Sopenharmony_ci        self.apimap = {}
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci        # Reverse map from unsupported APIs in this build to aliases which
50e5c31af7Sopenharmony_ci        # are supported
51e5c31af7Sopenharmony_ci        self.nonexistent = {}
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ci    def beginFile(self, genOpts):
54e5c31af7Sopenharmony_ci        OutputGenerator.beginFile(self, genOpts)
55e5c31af7Sopenharmony_ci        #
56e5c31af7Sopenharmony_ci        # Dictionaries are keyed by the name of the entity (e.g.
57e5c31af7Sopenharmony_ci        # self.structs is keyed by structure names). Values are
58e5c31af7Sopenharmony_ci        # the names of related entities (e.g. structs contain
59e5c31af7Sopenharmony_ci        # a list of type names of members, enums contain a list
60e5c31af7Sopenharmony_ci        # of enumerants belong to the enumerated type, etc.), or
61e5c31af7Sopenharmony_ci        # just None if there are no directly related entities.
62e5c31af7Sopenharmony_ci        #
63e5c31af7Sopenharmony_ci        # Collect the mappings, then emit the Python script in endFile
64e5c31af7Sopenharmony_ci        self.basetypes = {}
65e5c31af7Sopenharmony_ci        self.consts = {}
66e5c31af7Sopenharmony_ci        self.enums = {}
67e5c31af7Sopenharmony_ci        self.flags = {}
68e5c31af7Sopenharmony_ci        self.funcpointers = {}
69e5c31af7Sopenharmony_ci        self.protos = {}
70e5c31af7Sopenharmony_ci        self.structs = {}
71e5c31af7Sopenharmony_ci        self.handles = {}
72e5c31af7Sopenharmony_ci        self.defines = {}
73e5c31af7Sopenharmony_ci        self.alias = {}
74e5c31af7Sopenharmony_ci        # Dictionary containing the type of a type name
75e5c31af7Sopenharmony_ci        # (e.g. the string name of the dictionary with its contents).
76e5c31af7Sopenharmony_ci        self.typeCategory = {}
77e5c31af7Sopenharmony_ci        self.mapDict = {}
78e5c31af7Sopenharmony_ci
79e5c31af7Sopenharmony_ci    def addInterfaceMapping(self, api, feature, required):
80e5c31af7Sopenharmony_ci        """Add a reverse mapping in self.apimap from an API to a feature
81e5c31af7Sopenharmony_ci           requiring that API.
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ci        - api - name of the API
84e5c31af7Sopenharmony_ci        - feature - name of the feature requiring it
85e5c31af7Sopenharmony_ci        - required - None, or an additional feature dependency within
86e5c31af7Sopenharmony_ci          'feature'. The additional dependency is a boolean expression of
87e5c31af7Sopenharmony_ci          one or more extension and/or core version names, which is passed
88e5c31af7Sopenharmony_ci          through to the output script intact."""
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci        # Each entry in self.apimap contains one or more
91e5c31af7Sopenharmony_ci        # ( feature, required ) tuples.
92e5c31af7Sopenharmony_ci        deps = ( feature, required )
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_ci        if api in self.apimap:
95e5c31af7Sopenharmony_ci            self.apimap[api].append(deps)
96e5c31af7Sopenharmony_ci        else:
97e5c31af7Sopenharmony_ci            self.apimap[api] = [ deps ]
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci    def mapInterfaceKeys(self, feature, key):
100e5c31af7Sopenharmony_ci        """Construct reverse mapping of APIs to features requiring them in
101e5c31af7Sopenharmony_ci           self.apimap.
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci        - feature - name of the feature being generated
104e5c31af7Sopenharmony_ci        - key - API category - 'define', 'basetype', etc."""
105e5c31af7Sopenharmony_ci
106e5c31af7Sopenharmony_ci        dict = self.featureDictionary[feature][key]
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci        if dict:
109e5c31af7Sopenharmony_ci            # Not clear why handling of command vs. type APIs is different -
110e5c31af7Sopenharmony_ci            # see interfacedocgenerator.py, which this was based on.
111e5c31af7Sopenharmony_ci            if key == 'command':
112e5c31af7Sopenharmony_ci                for required in dict:
113e5c31af7Sopenharmony_ci                    for api in dict[required]:
114e5c31af7Sopenharmony_ci                        self.addInterfaceMapping(api, feature, required)
115e5c31af7Sopenharmony_ci            else:
116e5c31af7Sopenharmony_ci                for required in dict:
117e5c31af7Sopenharmony_ci                    for parent in dict[required]:
118e5c31af7Sopenharmony_ci                        for api in dict[required][parent]:
119e5c31af7Sopenharmony_ci                            self.addInterfaceMapping(api, feature, required)
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci    def mapInterfaces(self, feature):
122e5c31af7Sopenharmony_ci        """Construct reverse mapping of APIs to features requiring them in
123e5c31af7Sopenharmony_ci           self.apimap.
124e5c31af7Sopenharmony_ci
125e5c31af7Sopenharmony_ci        - feature - name of the feature being generated"""
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci        # Map each category of interface
128e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'basetype')
129e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'bitmask')
130e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'command')
131e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'define')
132e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'enum')
133e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'enumconstant')
134e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'funcpointer')
135e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'handle')
136e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'include')
137e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'struct')
138e5c31af7Sopenharmony_ci        self.mapInterfaceKeys(feature, 'union')
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ci    def endFile(self):
141e5c31af7Sopenharmony_ci        super().endFile()
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci    def beginFeature(self, interface, emit):
144e5c31af7Sopenharmony_ci        # Start processing in superclass
145e5c31af7Sopenharmony_ci        OutputGenerator.beginFeature(self, interface, emit)
146e5c31af7Sopenharmony_ci
147e5c31af7Sopenharmony_ci        # Add this feature to the list being tracked
148e5c31af7Sopenharmony_ci        self.features.append( self.featureName )
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci    def endFeature(self):
151e5c31af7Sopenharmony_ci        # Finish processing in superclass
152e5c31af7Sopenharmony_ci        OutputGenerator.endFeature(self)
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci    def addName(self, dict, name, value):
155e5c31af7Sopenharmony_ci        """Add a string entry to the dictionary, quoting it so it gets
156e5c31af7Sopenharmony_ci           printed out correctly in self.endFile()."""
157e5c31af7Sopenharmony_ci        dict[name] = value
158e5c31af7Sopenharmony_ci
159e5c31af7Sopenharmony_ci    def addMapping(self, baseType, refType):
160e5c31af7Sopenharmony_ci        """Add a mapping between types to mapDict.
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci        Only include API types, so we do not end up with a lot of useless
163e5c31af7Sopenharmony_ci        uint32_t and void types."""
164e5c31af7Sopenharmony_ci        if not self.apiName(baseType) or not self.apiName(refType):
165e5c31af7Sopenharmony_ci            self.logMsg('diag', 'ScriptOutputGenerator::addMapping: IGNORE map from', baseType, '<->', refType)
166e5c31af7Sopenharmony_ci            return
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci        self.logMsg('diag', 'ScriptOutputGenerator::addMapping: map from',
169e5c31af7Sopenharmony_ci                    baseType, '<->', refType)
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_ci        if baseType not in self.mapDict:
172e5c31af7Sopenharmony_ci            baseDict = {}
173e5c31af7Sopenharmony_ci            self.mapDict[baseType] = baseDict
174e5c31af7Sopenharmony_ci        else:
175e5c31af7Sopenharmony_ci            baseDict = self.mapDict[baseType]
176e5c31af7Sopenharmony_ci        if refType not in self.mapDict:
177e5c31af7Sopenharmony_ci            refDict = {}
178e5c31af7Sopenharmony_ci            self.mapDict[refType] = refDict
179e5c31af7Sopenharmony_ci        else:
180e5c31af7Sopenharmony_ci            refDict = self.mapDict[refType]
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci        baseDict[refType] = None
183e5c31af7Sopenharmony_ci        refDict[baseType] = None
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_ci    def breakCheck(self, procname, name):
186e5c31af7Sopenharmony_ci        """Debugging aid - call from procname to break on API 'name' if it
187e5c31af7Sopenharmony_ci           matches logic in this call."""
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci        pat = 'VkExternalFenceFeatureFlagBits'
190e5c31af7Sopenharmony_ci        if name[0:len(pat)] == pat:
191e5c31af7Sopenharmony_ci            print('{}(name = {}) matches {}'.format(procname, name, pat))
192e5c31af7Sopenharmony_ci            import pdb
193e5c31af7Sopenharmony_ci            pdb.set_trace()
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci    def genType(self, typeinfo, name, alias):
196e5c31af7Sopenharmony_ci        """Generate type.
197e5c31af7Sopenharmony_ci
198e5c31af7Sopenharmony_ci        - For 'struct' or 'union' types, defer to genStruct() to
199e5c31af7Sopenharmony_ci          add to the dictionary.
200e5c31af7Sopenharmony_ci        - For 'bitmask' types, add the type name to the 'flags' dictionary,
201e5c31af7Sopenharmony_ci          with the value being the corresponding 'enums' name defining
202e5c31af7Sopenharmony_ci          the acceptable flag bits.
203e5c31af7Sopenharmony_ci        - For 'enum' types, add the type name to the 'enums' dictionary,
204e5c31af7Sopenharmony_ci          with the value being '@STOPHERE@' (because this case seems
205e5c31af7Sopenharmony_ci          never to happen).
206e5c31af7Sopenharmony_ci        - For 'funcpointer' types, add the type name to the 'funcpointers'
207e5c31af7Sopenharmony_ci          dictionary.
208e5c31af7Sopenharmony_ci        - For 'handle' and 'define' types, add the handle or #define name
209e5c31af7Sopenharmony_ci          to the 'struct' dictionary, because that is how the spec sources
210e5c31af7Sopenharmony_ci          tag these types even though they are not structs."""
211e5c31af7Sopenharmony_ci        OutputGenerator.genType(self, typeinfo, name, alias)
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci        typeElem = typeinfo.elem
214e5c31af7Sopenharmony_ci        # If the type is a struct type, traverse the embedded <member> tags
215e5c31af7Sopenharmony_ci        # generating a structure. Otherwise, emit the tag text.
216e5c31af7Sopenharmony_ci        category = typeElem.get('category')
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci        # Add a typeCategory{} entry for the category of this type.
219e5c31af7Sopenharmony_ci        self.addName(self.typeCategory, name, category)
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci        if category in ('struct', 'union'):
222e5c31af7Sopenharmony_ci            self.genStruct(typeinfo, name, alias)
223e5c31af7Sopenharmony_ci        else:
224e5c31af7Sopenharmony_ci            if alias:
225e5c31af7Sopenharmony_ci                # Add name -> alias mapping
226e5c31af7Sopenharmony_ci                self.addName(self.alias, name, alias)
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci                # Always emit an alias (?!)
229e5c31af7Sopenharmony_ci                count = 1
230e5c31af7Sopenharmony_ci
231e5c31af7Sopenharmony_ci                # May want to only emit full type definition when not an alias?
232e5c31af7Sopenharmony_ci            else:
233e5c31af7Sopenharmony_ci                # Extract the type name
234e5c31af7Sopenharmony_ci                # (from self.genOpts). Copy other text through unchanged.
235e5c31af7Sopenharmony_ci                # If the resulting text is an empty string, do not emit it.
236e5c31af7Sopenharmony_ci                count = len(noneStr(typeElem.text))
237e5c31af7Sopenharmony_ci                for elem in typeElem:
238e5c31af7Sopenharmony_ci                    count += len(noneStr(elem.text)) + len(noneStr(elem.tail))
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci            if count > 0:
241e5c31af7Sopenharmony_ci                if category == 'bitmask':
242e5c31af7Sopenharmony_ci                    requiredEnum = typeElem.get('requires')
243e5c31af7Sopenharmony_ci                    self.addName(self.flags, name, requiredEnum)
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci                    # This happens when the Flags type is defined, but no
246e5c31af7Sopenharmony_ci                    # FlagBits are defined yet.
247e5c31af7Sopenharmony_ci                    if requiredEnum is not None:
248e5c31af7Sopenharmony_ci                        self.addMapping(name, requiredEnum)
249e5c31af7Sopenharmony_ci                elif category == 'enum':
250e5c31af7Sopenharmony_ci                    # This case does not seem to come up. It nominally would
251e5c31af7Sopenharmony_ci                    # result from
252e5c31af7Sopenharmony_ci                    #   <type name="Something" category="enum"/>,
253e5c31af7Sopenharmony_ci                    # but the output generator does not emit them directly.
254e5c31af7Sopenharmony_ci                    self.logMsg('warn', 'ScriptOutputGenerator::genType: invalid \'enum\' category for name:', name)
255e5c31af7Sopenharmony_ci                elif category == 'funcpointer':
256e5c31af7Sopenharmony_ci                    self.funcpointers[name] = None
257e5c31af7Sopenharmony_ci                elif category == 'handle':
258e5c31af7Sopenharmony_ci                    self.handles[name] = None
259e5c31af7Sopenharmony_ci                elif category == 'define':
260e5c31af7Sopenharmony_ci                    self.defines[name] = None
261e5c31af7Sopenharmony_ci                elif category == 'basetype':
262e5c31af7Sopenharmony_ci                    self.basetypes[name] = None
263e5c31af7Sopenharmony_ci                    self.addName(self.typeCategory, name, 'basetype')
264e5c31af7Sopenharmony_ci            else:
265e5c31af7Sopenharmony_ci                self.logMsg('diag', 'ScriptOutputGenerator::genType: unprocessed type:', name)
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci    def genStruct(self, typeinfo, typeName, alias):
268e5c31af7Sopenharmony_ci        """Generate struct (e.g. C "struct" type).
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci        Add the struct name to the 'structs' dictionary, with the
271e5c31af7Sopenharmony_ci        value being an ordered list of the struct member names."""
272e5c31af7Sopenharmony_ci        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci        if alias:
275e5c31af7Sopenharmony_ci            # Add name -> alias mapping
276e5c31af7Sopenharmony_ci            self.addName(self.alias, typeName, alias)
277e5c31af7Sopenharmony_ci        else:
278e5c31af7Sopenharmony_ci            # May want to only emit definition on this branch
279e5c31af7Sopenharmony_ci            True
280e5c31af7Sopenharmony_ci
281e5c31af7Sopenharmony_ci        members = [member.text for member in typeinfo.elem.findall('.//member/name')]
282e5c31af7Sopenharmony_ci        self.structs[typeName] = members
283e5c31af7Sopenharmony_ci        memberTypes = [member.text for member in typeinfo.elem.findall('.//member/type')]
284e5c31af7Sopenharmony_ci        for member_type in memberTypes:
285e5c31af7Sopenharmony_ci            self.addMapping(typeName, member_type)
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ci    def genGroup(self, groupinfo, groupName, alias):
288e5c31af7Sopenharmony_ci        """Generate group (e.g. C "enum" type).
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci        These are concatenated together with other types.
291e5c31af7Sopenharmony_ci
292e5c31af7Sopenharmony_ci        - Add the enum type name to the 'enums' dictionary, with
293e5c31af7Sopenharmony_ci          the value being an ordered list of the enumerant names.
294e5c31af7Sopenharmony_ci        - Add each enumerant name to the 'consts' dictionary, with
295e5c31af7Sopenharmony_ci          the value being the enum type the enumerant is part of."""
296e5c31af7Sopenharmony_ci        OutputGenerator.genGroup(self, groupinfo, groupName, alias)
297e5c31af7Sopenharmony_ci        groupElem = groupinfo.elem
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ci        # Add a typeCategory{} entry for the category of this type.
300e5c31af7Sopenharmony_ci        self.addName(self.typeCategory, groupName, 'group')
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci        if alias:
303e5c31af7Sopenharmony_ci            # Add name -> alias mapping
304e5c31af7Sopenharmony_ci            self.addName(self.alias, groupName, alias)
305e5c31af7Sopenharmony_ci        else:
306e5c31af7Sopenharmony_ci            # May want to only emit definition on this branch
307e5c31af7Sopenharmony_ci            True
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci        # Add each nested 'enum' tag
310e5c31af7Sopenharmony_ci        enumerants = [elem.get('name') for elem in groupElem.findall('enum')]
311e5c31af7Sopenharmony_ci        for name in enumerants:
312e5c31af7Sopenharmony_ci            self.addName(self.consts, name, groupName)
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ci        # Sort enums for output stability, since their order is irrelevant
315e5c31af7Sopenharmony_ci        self.enums[groupName] = sorted(enumerants)
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_ci    def genEnum(self, enuminfo, name, alias):
318e5c31af7Sopenharmony_ci        """Generate enumerant (compile time constant).
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci        - Add the constant name to the 'consts' dictionary, with the
321e5c31af7Sopenharmony_ci          value being None to indicate that the constant is not
322e5c31af7Sopenharmony_ci          an enumeration value."""
323e5c31af7Sopenharmony_ci        OutputGenerator.genEnum(self, enuminfo, name, alias)
324e5c31af7Sopenharmony_ci
325e5c31af7Sopenharmony_ci        if name not in self.consts:
326e5c31af7Sopenharmony_ci            # Add a typeCategory{} entry for the category of this type.
327e5c31af7Sopenharmony_ci            self.addName(self.typeCategory, name, 'consts')
328e5c31af7Sopenharmony_ci            self.consts[name] = None
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ci        if alias:
331e5c31af7Sopenharmony_ci            # Add name -> alias mapping
332e5c31af7Sopenharmony_ci            self.addName(self.alias, name, alias)
333e5c31af7Sopenharmony_ci        else:
334e5c31af7Sopenharmony_ci            # May want to only emit definition on this branch
335e5c31af7Sopenharmony_ci            True
336e5c31af7Sopenharmony_ci
337e5c31af7Sopenharmony_ci        # Otherwise, do not add it to the consts dictionary because it is
338e5c31af7Sopenharmony_ci        # already present. This happens due to the generator 'reparentEnums'
339e5c31af7Sopenharmony_ci        # parameter being False, so each extension enum appears in both the
340e5c31af7Sopenharmony_ci        # <enums> type and in the <extension> or <feature> it originally
341e5c31af7Sopenharmony_ci        # came from.
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci    def genCmd(self, cmdinfo, name, alias):
344e5c31af7Sopenharmony_ci        """Generate command.
345e5c31af7Sopenharmony_ci
346e5c31af7Sopenharmony_ci        - Add the command name to the 'protos' dictionary, with the
347e5c31af7Sopenharmony_ci          value being an ordered list of the parameter names."""
348e5c31af7Sopenharmony_ci        OutputGenerator.genCmd(self, cmdinfo, name, alias)
349e5c31af7Sopenharmony_ci
350e5c31af7Sopenharmony_ci        # Add a typeCategory{} entry for the category of this type.
351e5c31af7Sopenharmony_ci        self.addName(self.typeCategory, name, 'protos')
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_ci        if alias:
354e5c31af7Sopenharmony_ci            # Add name -> alias mapping
355e5c31af7Sopenharmony_ci            self.addName(self.alias, name, alias)
356e5c31af7Sopenharmony_ci        else:
357e5c31af7Sopenharmony_ci            # May want to only emit definition on this branch
358e5c31af7Sopenharmony_ci            True
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci        params = [param.text for param in cmdinfo.elem.findall('param/name')]
361e5c31af7Sopenharmony_ci        self.protos[name] = params
362e5c31af7Sopenharmony_ci        paramTypes = [param.text for param in cmdinfo.elem.findall('param/type')]
363e5c31af7Sopenharmony_ci        for param_type in paramTypes:
364e5c31af7Sopenharmony_ci            self.addMapping(name, param_type)
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci    def createInverseMap(self):
367e5c31af7Sopenharmony_ci        """This creates the inverse mapping of nonexistent APIs in this
368e5c31af7Sopenharmony_ci           build to their aliases which are supported. Must be called by
369e5c31af7Sopenharmony_ci           language-specific subclasses before emitting that mapping."""
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci        # Map from APIs not supported in this build to aliases that are.
372e5c31af7Sopenharmony_ci        # When there are multiple valid choices for remapping, choose the
373e5c31af7Sopenharmony_ci        # most-official suffixed one (KHR > EXT > vendor).
374e5c31af7Sopenharmony_ci        for key in self.alias:
375e5c31af7Sopenharmony_ci            # If the API key is aliased to something which does not exist,
376e5c31af7Sopenharmony_ci            # then add the thing that does not exist to the nonexistent map.
377e5c31af7Sopenharmony_ci            # This is used in spec macros to make promoted extension links
378e5c31af7Sopenharmony_ci            # in specs built without the promoted interface refer to the
379e5c31af7Sopenharmony_ci            # older interface instead.
380e5c31af7Sopenharmony_ci
381e5c31af7Sopenharmony_ci            invkey = self.alias[key]
382e5c31af7Sopenharmony_ci
383e5c31af7Sopenharmony_ci            if invkey not in self.typeCategory:
384e5c31af7Sopenharmony_ci                if invkey in self.nonexistent:
385e5c31af7Sopenharmony_ci                    # Potentially remap existing mapping to a more official
386e5c31af7Sopenharmony_ci                    # alias.
387e5c31af7Sopenharmony_ci                    self.nonexistent[invkey] = mostOfficial(self.nonexistent[invkey], key)
388e5c31af7Sopenharmony_ci                else:
389e5c31af7Sopenharmony_ci                    # Create remapping to an alias
390e5c31af7Sopenharmony_ci                    self.nonexistent[invkey] = key
391