xref: /aosp_15_r20/external/vulkan-headers/registry/generator.py (revision 902771965e4c6d39c75c62130a6a330c08b024db)
1*90277196SAndroid Build Coastguard Worker#!/usr/bin/env python3 -i
2*90277196SAndroid Build Coastguard Worker#
3*90277196SAndroid Build Coastguard Worker# Copyright 2013-2024 The Khronos Group Inc.
4*90277196SAndroid Build Coastguard Worker#
5*90277196SAndroid Build Coastguard Worker# SPDX-License-Identifier: Apache-2.0
6*90277196SAndroid Build Coastguard Worker"""Base class for source/header/doc generators, as well as some utility functions."""
7*90277196SAndroid Build Coastguard Worker
8*90277196SAndroid Build Coastguard Workerfrom __future__ import unicode_literals
9*90277196SAndroid Build Coastguard Worker
10*90277196SAndroid Build Coastguard Workerimport io
11*90277196SAndroid Build Coastguard Workerimport os
12*90277196SAndroid Build Coastguard Workerimport pdb
13*90277196SAndroid Build Coastguard Workerimport re
14*90277196SAndroid Build Coastguard Workerimport shutil
15*90277196SAndroid Build Coastguard Workerimport sys
16*90277196SAndroid Build Coastguard Workerimport tempfile
17*90277196SAndroid Build Coastguard Workertry:
18*90277196SAndroid Build Coastguard Worker    from pathlib import Path
19*90277196SAndroid Build Coastguard Workerexcept ImportError:
20*90277196SAndroid Build Coastguard Worker    from pathlib2 import Path  # type: ignore
21*90277196SAndroid Build Coastguard Worker
22*90277196SAndroid Build Coastguard Workerfrom spec_tools.util import getElemName, getElemType
23*90277196SAndroid Build Coastguard Worker
24*90277196SAndroid Build Coastguard Worker
25*90277196SAndroid Build Coastguard Workerdef write(*args, **kwargs):
26*90277196SAndroid Build Coastguard Worker    file = kwargs.pop('file', sys.stdout)
27*90277196SAndroid Build Coastguard Worker    end = kwargs.pop('end', '\n')
28*90277196SAndroid Build Coastguard Worker    file.write(' '.join(str(arg) for arg in args))
29*90277196SAndroid Build Coastguard Worker    file.write(end)
30*90277196SAndroid Build Coastguard Worker
31*90277196SAndroid Build Coastguard Worker
32*90277196SAndroid Build Coastguard Workerdef noneStr(s):
33*90277196SAndroid Build Coastguard Worker    """Return string argument, or "" if argument is None.
34*90277196SAndroid Build Coastguard Worker
35*90277196SAndroid Build Coastguard Worker    Used in converting etree Elements into text.
36*90277196SAndroid Build Coastguard Worker    s - string to convert"""
37*90277196SAndroid Build Coastguard Worker    if s:
38*90277196SAndroid Build Coastguard Worker        return s
39*90277196SAndroid Build Coastguard Worker    return ""
40*90277196SAndroid Build Coastguard Worker
41*90277196SAndroid Build Coastguard Worker
42*90277196SAndroid Build Coastguard Workerdef enquote(s):
43*90277196SAndroid Build Coastguard Worker    """Return string argument with surrounding quotes,
44*90277196SAndroid Build Coastguard Worker      for serialization into Python code."""
45*90277196SAndroid Build Coastguard Worker    if s:
46*90277196SAndroid Build Coastguard Worker        if isinstance(s, str):
47*90277196SAndroid Build Coastguard Worker            return f"'{s}'"
48*90277196SAndroid Build Coastguard Worker        else:
49*90277196SAndroid Build Coastguard Worker            return s
50*90277196SAndroid Build Coastguard Worker    return None
51*90277196SAndroid Build Coastguard Worker
52*90277196SAndroid Build Coastguard Worker
53*90277196SAndroid Build Coastguard Workerdef regSortCategoryKey(feature):
54*90277196SAndroid Build Coastguard Worker    """Sort key for regSortFeatures.
55*90277196SAndroid Build Coastguard Worker    Sorts by category of the feature name string:
56*90277196SAndroid Build Coastguard Worker
57*90277196SAndroid Build Coastguard Worker    - Core API features (those defined with a `<feature>` tag)
58*90277196SAndroid Build Coastguard Worker        - (sort VKSC after VK - this is Vulkan-specific)
59*90277196SAndroid Build Coastguard Worker    - ARB/KHR/OES (Khronos extensions)
60*90277196SAndroid Build Coastguard Worker    - other       (EXT/vendor extensions)"""
61*90277196SAndroid Build Coastguard Worker
62*90277196SAndroid Build Coastguard Worker    if feature.elem.tag == 'feature':
63*90277196SAndroid Build Coastguard Worker        if feature.name.startswith('VKSC'):
64*90277196SAndroid Build Coastguard Worker            return 0.5
65*90277196SAndroid Build Coastguard Worker        else:
66*90277196SAndroid Build Coastguard Worker            return 0
67*90277196SAndroid Build Coastguard Worker
68*90277196SAndroid Build Coastguard Worker    if feature.category.upper() in ('ARB', 'KHR', 'OES'):
69*90277196SAndroid Build Coastguard Worker        return 1
70*90277196SAndroid Build Coastguard Worker
71*90277196SAndroid Build Coastguard Worker    return 2
72*90277196SAndroid Build Coastguard Worker
73*90277196SAndroid Build Coastguard Worker
74*90277196SAndroid Build Coastguard Workerdef regSortOrderKey(feature):
75*90277196SAndroid Build Coastguard Worker    """Sort key for regSortFeatures - key is the sortorder attribute."""
76*90277196SAndroid Build Coastguard Worker
77*90277196SAndroid Build Coastguard Worker    return feature.sortorder
78*90277196SAndroid Build Coastguard Worker
79*90277196SAndroid Build Coastguard Worker
80*90277196SAndroid Build Coastguard Workerdef regSortNameKey(feature):
81*90277196SAndroid Build Coastguard Worker    """Sort key for regSortFeatures - key is the extension name."""
82*90277196SAndroid Build Coastguard Worker
83*90277196SAndroid Build Coastguard Worker    return feature.name
84*90277196SAndroid Build Coastguard Worker
85*90277196SAndroid Build Coastguard Worker
86*90277196SAndroid Build Coastguard Workerdef regSortFeatureVersionKey(feature):
87*90277196SAndroid Build Coastguard Worker    """Sort key for regSortFeatures - key is the feature version.
88*90277196SAndroid Build Coastguard Worker    `<extension>` elements all have version number 0."""
89*90277196SAndroid Build Coastguard Worker
90*90277196SAndroid Build Coastguard Worker    return float(feature.versionNumber)
91*90277196SAndroid Build Coastguard Worker
92*90277196SAndroid Build Coastguard Worker
93*90277196SAndroid Build Coastguard Workerdef regSortExtensionNumberKey(feature):
94*90277196SAndroid Build Coastguard Worker    """Sort key for regSortFeatures - key is the extension number.
95*90277196SAndroid Build Coastguard Worker    `<feature>` elements all have extension number 0."""
96*90277196SAndroid Build Coastguard Worker
97*90277196SAndroid Build Coastguard Worker    return int(feature.number)
98*90277196SAndroid Build Coastguard Worker
99*90277196SAndroid Build Coastguard Worker
100*90277196SAndroid Build Coastguard Workerdef regSortFeatures(featureList):
101*90277196SAndroid Build Coastguard Worker    """Default sort procedure for features.
102*90277196SAndroid Build Coastguard Worker
103*90277196SAndroid Build Coastguard Worker    - Sorts by explicit sort order (default 0) relative to other features
104*90277196SAndroid Build Coastguard Worker    - then by feature category ('feature' or 'extension'),
105*90277196SAndroid Build Coastguard Worker    - then by version number (for features)
106*90277196SAndroid Build Coastguard Worker    - then by extension number (for extensions)"""
107*90277196SAndroid Build Coastguard Worker    featureList.sort(key=regSortExtensionNumberKey)
108*90277196SAndroid Build Coastguard Worker    featureList.sort(key=regSortFeatureVersionKey)
109*90277196SAndroid Build Coastguard Worker    featureList.sort(key=regSortCategoryKey)
110*90277196SAndroid Build Coastguard Worker    featureList.sort(key=regSortOrderKey)
111*90277196SAndroid Build Coastguard Worker
112*90277196SAndroid Build Coastguard Worker
113*90277196SAndroid Build Coastguard Workerclass MissingGeneratorOptionsError(RuntimeError):
114*90277196SAndroid Build Coastguard Worker    """Error raised when a Generator tries to do something that requires GeneratorOptions but it is None."""
115*90277196SAndroid Build Coastguard Worker
116*90277196SAndroid Build Coastguard Worker    def __init__(self, msg=None):
117*90277196SAndroid Build Coastguard Worker        full_msg = 'Missing generator options object self.genOpts'
118*90277196SAndroid Build Coastguard Worker        if msg:
119*90277196SAndroid Build Coastguard Worker            full_msg += ': ' + msg
120*90277196SAndroid Build Coastguard Worker        super().__init__(full_msg)
121*90277196SAndroid Build Coastguard Worker
122*90277196SAndroid Build Coastguard Worker
123*90277196SAndroid Build Coastguard Workerclass MissingRegistryError(RuntimeError):
124*90277196SAndroid Build Coastguard Worker    """Error raised when a Generator tries to do something that requires a Registry object but it is None."""
125*90277196SAndroid Build Coastguard Worker
126*90277196SAndroid Build Coastguard Worker    def __init__(self, msg=None):
127*90277196SAndroid Build Coastguard Worker        full_msg = 'Missing Registry object self.registry'
128*90277196SAndroid Build Coastguard Worker        if msg:
129*90277196SAndroid Build Coastguard Worker            full_msg += ': ' + msg
130*90277196SAndroid Build Coastguard Worker        super().__init__(full_msg)
131*90277196SAndroid Build Coastguard Worker
132*90277196SAndroid Build Coastguard Worker
133*90277196SAndroid Build Coastguard Workerclass MissingGeneratorOptionsConventionsError(RuntimeError):
134*90277196SAndroid Build Coastguard Worker    """Error raised when a Generator tries to do something that requires a Conventions object but it is None."""
135*90277196SAndroid Build Coastguard Worker
136*90277196SAndroid Build Coastguard Worker    def __init__(self, msg=None):
137*90277196SAndroid Build Coastguard Worker        full_msg = 'Missing Conventions object self.genOpts.conventions'
138*90277196SAndroid Build Coastguard Worker        if msg:
139*90277196SAndroid Build Coastguard Worker            full_msg += ': ' + msg
140*90277196SAndroid Build Coastguard Worker        super().__init__(full_msg)
141*90277196SAndroid Build Coastguard Worker
142*90277196SAndroid Build Coastguard Worker
143*90277196SAndroid Build Coastguard Workerclass GeneratorOptions:
144*90277196SAndroid Build Coastguard Worker    """Base class for options used during header/documentation production.
145*90277196SAndroid Build Coastguard Worker
146*90277196SAndroid Build Coastguard Worker    These options are target language independent, and used by
147*90277196SAndroid Build Coastguard Worker    Registry.apiGen() and by base OutputGenerator objects."""
148*90277196SAndroid Build Coastguard Worker
149*90277196SAndroid Build Coastguard Worker    def __init__(self,
150*90277196SAndroid Build Coastguard Worker                 conventions=None,
151*90277196SAndroid Build Coastguard Worker                 filename=None,
152*90277196SAndroid Build Coastguard Worker                 directory='.',
153*90277196SAndroid Build Coastguard Worker                 genpath=None,
154*90277196SAndroid Build Coastguard Worker                 apiname=None,
155*90277196SAndroid Build Coastguard Worker                 mergeApiNames=None,
156*90277196SAndroid Build Coastguard Worker                 profile=None,
157*90277196SAndroid Build Coastguard Worker                 versions='.*',
158*90277196SAndroid Build Coastguard Worker                 emitversions='.*',
159*90277196SAndroid Build Coastguard Worker                 defaultExtensions=None,
160*90277196SAndroid Build Coastguard Worker                 addExtensions=None,
161*90277196SAndroid Build Coastguard Worker                 removeExtensions=None,
162*90277196SAndroid Build Coastguard Worker                 emitExtensions=None,
163*90277196SAndroid Build Coastguard Worker                 emitSpirv=None,
164*90277196SAndroid Build Coastguard Worker                 emitFormats=None,
165*90277196SAndroid Build Coastguard Worker                 reparentEnums=True,
166*90277196SAndroid Build Coastguard Worker                 sortProcedure=regSortFeatures,
167*90277196SAndroid Build Coastguard Worker                 requireCommandAliases=False,
168*90277196SAndroid Build Coastguard Worker                 requireDepends=True,
169*90277196SAndroid Build Coastguard Worker                ):
170*90277196SAndroid Build Coastguard Worker        """Constructor.
171*90277196SAndroid Build Coastguard Worker
172*90277196SAndroid Build Coastguard Worker        Arguments:
173*90277196SAndroid Build Coastguard Worker
174*90277196SAndroid Build Coastguard Worker        - conventions - may be mandatory for some generators:
175*90277196SAndroid Build Coastguard Worker        an object that implements ConventionsBase
176*90277196SAndroid Build Coastguard Worker        - filename - basename of file to generate, or None to write to stdout.
177*90277196SAndroid Build Coastguard Worker        - directory - directory in which to generate filename
178*90277196SAndroid Build Coastguard Worker        - genpath - path to previously generated files, such as apimap.py
179*90277196SAndroid Build Coastguard Worker        - apiname - string matching `<api>` 'apiname' attribute, e.g. 'gl'.
180*90277196SAndroid Build Coastguard Worker        - mergeApiNames - If not None, a comma separated list of API names
181*90277196SAndroid Build Coastguard Worker          to merge into the API specified by 'apiname'
182*90277196SAndroid Build Coastguard Worker        - profile - string specifying API profile , e.g. 'core', or None.
183*90277196SAndroid Build Coastguard Worker        - versions - regex matching API versions to process interfaces for.
184*90277196SAndroid Build Coastguard Worker        Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions.
185*90277196SAndroid Build Coastguard Worker        - emitversions - regex matching API versions to actually emit
186*90277196SAndroid Build Coastguard Worker        interfaces for (though all requested versions are considered
187*90277196SAndroid Build Coastguard Worker        when deciding which interfaces to generate). For GL 4.3 glext.h,
188*90277196SAndroid Build Coastguard Worker        this might be `'1[.][2-5]|[2-4][.][0-9]'`.
189*90277196SAndroid Build Coastguard Worker        - defaultExtensions - If not None, a string which must in its
190*90277196SAndroid Build Coastguard Worker        entirety match the pattern in the "supported" attribute of
191*90277196SAndroid Build Coastguard Worker        the `<extension>`. Defaults to None. Usually the same as apiname.
192*90277196SAndroid Build Coastguard Worker        - addExtensions - regex matching names of additional extensions
193*90277196SAndroid Build Coastguard Worker        to include. Defaults to None.
194*90277196SAndroid Build Coastguard Worker        - removeExtensions - regex matching names of extensions to
195*90277196SAndroid Build Coastguard Worker        remove (after defaultExtensions and addExtensions). Defaults
196*90277196SAndroid Build Coastguard Worker        to None.
197*90277196SAndroid Build Coastguard Worker        - emitExtensions - regex matching names of extensions to actually emit
198*90277196SAndroid Build Coastguard Worker        interfaces for (though all requested versions are considered when
199*90277196SAndroid Build Coastguard Worker        deciding which interfaces to generate). Defaults to None.
200*90277196SAndroid Build Coastguard Worker        - emitSpirv - regex matching names of extensions and capabilities
201*90277196SAndroid Build Coastguard Worker        to actually emit interfaces for.
202*90277196SAndroid Build Coastguard Worker        - emitFormats - regex matching names of formats to actually emit
203*90277196SAndroid Build Coastguard Worker        interfaces for.
204*90277196SAndroid Build Coastguard Worker        - reparentEnums - move <enum> elements which extend an enumerated
205*90277196SAndroid Build Coastguard Worker        type from <feature> or <extension> elements to the target <enums>
206*90277196SAndroid Build Coastguard Worker        element. This is required for almost all purposes, but the
207*90277196SAndroid Build Coastguard Worker        InterfaceGenerator relies on the list of interfaces in the <feature>
208*90277196SAndroid Build Coastguard Worker        or <extension> being complete. Defaults to True.
209*90277196SAndroid Build Coastguard Worker        - sortProcedure - takes a list of FeatureInfo objects and sorts
210*90277196SAndroid Build Coastguard Worker        them in place to a preferred order in the generated output.
211*90277196SAndroid Build Coastguard Worker        - requireCommandAliases - if True, treat command aliases
212*90277196SAndroid Build Coastguard Worker        as required dependencies.
213*90277196SAndroid Build Coastguard Worker        - requireDepends - whether to follow API dependencies when emitting
214*90277196SAndroid Build Coastguard Worker        APIs.
215*90277196SAndroid Build Coastguard Worker
216*90277196SAndroid Build Coastguard Worker        Default is
217*90277196SAndroid Build Coastguard Worker          - core API versions
218*90277196SAndroid Build Coastguard Worker          - Khronos (ARB/KHR/OES) extensions
219*90277196SAndroid Build Coastguard Worker          - All other extensions
220*90277196SAndroid Build Coastguard Worker          - By core API version number or extension number in each group.
221*90277196SAndroid Build Coastguard Worker
222*90277196SAndroid Build Coastguard Worker        The regex patterns can be None or empty, in which case they match
223*90277196SAndroid Build Coastguard Worker        nothing."""
224*90277196SAndroid Build Coastguard Worker        self.conventions = conventions
225*90277196SAndroid Build Coastguard Worker        """may be mandatory for some generators:
226*90277196SAndroid Build Coastguard Worker        an object that implements ConventionsBase"""
227*90277196SAndroid Build Coastguard Worker
228*90277196SAndroid Build Coastguard Worker        self.filename = filename
229*90277196SAndroid Build Coastguard Worker        "basename of file to generate, or None to write to stdout."
230*90277196SAndroid Build Coastguard Worker
231*90277196SAndroid Build Coastguard Worker        self.genpath = genpath
232*90277196SAndroid Build Coastguard Worker        """path to previously generated files, such as apimap.py"""
233*90277196SAndroid Build Coastguard Worker
234*90277196SAndroid Build Coastguard Worker        self.directory = directory
235*90277196SAndroid Build Coastguard Worker        "directory in which to generate filename"
236*90277196SAndroid Build Coastguard Worker
237*90277196SAndroid Build Coastguard Worker        self.apiname = apiname
238*90277196SAndroid Build Coastguard Worker        "string matching `<api>` 'apiname' attribute, e.g. 'gl'."
239*90277196SAndroid Build Coastguard Worker
240*90277196SAndroid Build Coastguard Worker        self.mergeApiNames = mergeApiNames
241*90277196SAndroid Build Coastguard Worker        "comma separated list of API names to merge into the API specified by 'apiname'"
242*90277196SAndroid Build Coastguard Worker
243*90277196SAndroid Build Coastguard Worker        self.profile = profile
244*90277196SAndroid Build Coastguard Worker        "string specifying API profile , e.g. 'core', or None."
245*90277196SAndroid Build Coastguard Worker
246*90277196SAndroid Build Coastguard Worker        self.versions = self.emptyRegex(versions)
247*90277196SAndroid Build Coastguard Worker        """regex matching API versions to process interfaces for.
248*90277196SAndroid Build Coastguard Worker        Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions."""
249*90277196SAndroid Build Coastguard Worker
250*90277196SAndroid Build Coastguard Worker        self.emitversions = self.emptyRegex(emitversions)
251*90277196SAndroid Build Coastguard Worker        """regex matching API versions to actually emit
252*90277196SAndroid Build Coastguard Worker        interfaces for (though all requested versions are considered
253*90277196SAndroid Build Coastguard Worker        when deciding which interfaces to generate). For GL 4.3 glext.h,
254*90277196SAndroid Build Coastguard Worker        this might be `'1[.][2-5]|[2-4][.][0-9]'`."""
255*90277196SAndroid Build Coastguard Worker
256*90277196SAndroid Build Coastguard Worker        self.defaultExtensions = defaultExtensions
257*90277196SAndroid Build Coastguard Worker        """If not None, a string which must in its
258*90277196SAndroid Build Coastguard Worker        entirety match the pattern in the "supported" attribute of
259*90277196SAndroid Build Coastguard Worker        the `<extension>`. Defaults to None. Usually the same as apiname."""
260*90277196SAndroid Build Coastguard Worker
261*90277196SAndroid Build Coastguard Worker        self.addExtensions = self.emptyRegex(addExtensions)
262*90277196SAndroid Build Coastguard Worker        """regex matching names of additional extensions
263*90277196SAndroid Build Coastguard Worker        to include. Defaults to None."""
264*90277196SAndroid Build Coastguard Worker
265*90277196SAndroid Build Coastguard Worker        self.removeExtensions = self.emptyRegex(removeExtensions)
266*90277196SAndroid Build Coastguard Worker        """regex matching names of extensions to
267*90277196SAndroid Build Coastguard Worker        remove (after defaultExtensions and addExtensions). Defaults
268*90277196SAndroid Build Coastguard Worker        to None."""
269*90277196SAndroid Build Coastguard Worker
270*90277196SAndroid Build Coastguard Worker        self.emitExtensions = self.emptyRegex(emitExtensions)
271*90277196SAndroid Build Coastguard Worker        """regex matching names of extensions to actually emit
272*90277196SAndroid Build Coastguard Worker        interfaces for (though all requested versions are considered when
273*90277196SAndroid Build Coastguard Worker        deciding which interfaces to generate)."""
274*90277196SAndroid Build Coastguard Worker
275*90277196SAndroid Build Coastguard Worker        self.emitSpirv = self.emptyRegex(emitSpirv)
276*90277196SAndroid Build Coastguard Worker        """regex matching names of extensions and capabilities
277*90277196SAndroid Build Coastguard Worker        to actually emit interfaces for."""
278*90277196SAndroid Build Coastguard Worker
279*90277196SAndroid Build Coastguard Worker        self.emitFormats = self.emptyRegex(emitFormats)
280*90277196SAndroid Build Coastguard Worker        """regex matching names of formats
281*90277196SAndroid Build Coastguard Worker        to actually emit interfaces for."""
282*90277196SAndroid Build Coastguard Worker
283*90277196SAndroid Build Coastguard Worker        self.reparentEnums = reparentEnums
284*90277196SAndroid Build Coastguard Worker        """boolean specifying whether to remove <enum> elements from
285*90277196SAndroid Build Coastguard Worker        <feature> or <extension> when extending an <enums> type."""
286*90277196SAndroid Build Coastguard Worker
287*90277196SAndroid Build Coastguard Worker        self.sortProcedure = sortProcedure
288*90277196SAndroid Build Coastguard Worker        """takes a list of FeatureInfo objects and sorts
289*90277196SAndroid Build Coastguard Worker        them in place to a preferred order in the generated output.
290*90277196SAndroid Build Coastguard Worker        Default is core API versions, ARB/KHR/OES extensions, all
291*90277196SAndroid Build Coastguard Worker        other extensions, alphabetically within each group."""
292*90277196SAndroid Build Coastguard Worker
293*90277196SAndroid Build Coastguard Worker        self.codeGenerator = False
294*90277196SAndroid Build Coastguard Worker        """True if this generator makes compilable code"""
295*90277196SAndroid Build Coastguard Worker
296*90277196SAndroid Build Coastguard Worker        self.registry = None
297*90277196SAndroid Build Coastguard Worker        """Populated later with the registry object."""
298*90277196SAndroid Build Coastguard Worker
299*90277196SAndroid Build Coastguard Worker        self.requireCommandAliases = requireCommandAliases
300*90277196SAndroid Build Coastguard Worker        """True if alias= attributes of <command> tags are transitively
301*90277196SAndroid Build Coastguard Worker        required."""
302*90277196SAndroid Build Coastguard Worker
303*90277196SAndroid Build Coastguard Worker        self.requireDepends = requireDepends
304*90277196SAndroid Build Coastguard Worker        """True if dependencies of API tags are transitively required."""
305*90277196SAndroid Build Coastguard Worker
306*90277196SAndroid Build Coastguard Worker    def emptyRegex(self, pat):
307*90277196SAndroid Build Coastguard Worker        """Substitute a regular expression which matches no version
308*90277196SAndroid Build Coastguard Worker        or extension names for None or the empty string."""
309*90277196SAndroid Build Coastguard Worker        if not pat:
310*90277196SAndroid Build Coastguard Worker            return '_nomatch_^'
311*90277196SAndroid Build Coastguard Worker
312*90277196SAndroid Build Coastguard Worker        return pat
313*90277196SAndroid Build Coastguard Worker
314*90277196SAndroid Build Coastguard Worker
315*90277196SAndroid Build Coastguard Workerclass OutputGenerator:
316*90277196SAndroid Build Coastguard Worker    """Generate specified API interfaces in a specific style, such as a C header.
317*90277196SAndroid Build Coastguard Worker
318*90277196SAndroid Build Coastguard Worker    Base class for generating API interfaces.
319*90277196SAndroid Build Coastguard Worker    Manages basic logic, logging, and output file control.
320*90277196SAndroid Build Coastguard Worker    Derived classes actually generate formatted output.
321*90277196SAndroid Build Coastguard Worker    """
322*90277196SAndroid Build Coastguard Worker
323*90277196SAndroid Build Coastguard Worker    # categoryToPath - map XML 'category' to include file directory name
324*90277196SAndroid Build Coastguard Worker    categoryToPath = {
325*90277196SAndroid Build Coastguard Worker        'bitmask': 'flags',
326*90277196SAndroid Build Coastguard Worker        'enum': 'enums',
327*90277196SAndroid Build Coastguard Worker        'funcpointer': 'funcpointers',
328*90277196SAndroid Build Coastguard Worker        'handle': 'handles',
329*90277196SAndroid Build Coastguard Worker        'define': 'defines',
330*90277196SAndroid Build Coastguard Worker        'basetype': 'basetypes',
331*90277196SAndroid Build Coastguard Worker    }
332*90277196SAndroid Build Coastguard Worker
333*90277196SAndroid Build Coastguard Worker    def breakName(self, name, msg):
334*90277196SAndroid Build Coastguard Worker        """Break into debugger if this is a special name"""
335*90277196SAndroid Build Coastguard Worker
336*90277196SAndroid Build Coastguard Worker        # List of string names to break on
337*90277196SAndroid Build Coastguard Worker        bad = (
338*90277196SAndroid Build Coastguard Worker        )
339*90277196SAndroid Build Coastguard Worker
340*90277196SAndroid Build Coastguard Worker        if name in bad and True:
341*90277196SAndroid Build Coastguard Worker            print('breakName {}: {}'.format(name, msg))
342*90277196SAndroid Build Coastguard Worker            pdb.set_trace()
343*90277196SAndroid Build Coastguard Worker
344*90277196SAndroid Build Coastguard Worker    def __init__(self, errFile=sys.stderr, warnFile=sys.stderr, diagFile=sys.stdout):
345*90277196SAndroid Build Coastguard Worker        """Constructor
346*90277196SAndroid Build Coastguard Worker
347*90277196SAndroid Build Coastguard Worker        - errFile, warnFile, diagFile - file handles to write errors,
348*90277196SAndroid Build Coastguard Worker          warnings, diagnostics to. May be None to not write."""
349*90277196SAndroid Build Coastguard Worker        self.outFile = None
350*90277196SAndroid Build Coastguard Worker        self.errFile = errFile
351*90277196SAndroid Build Coastguard Worker        self.warnFile = warnFile
352*90277196SAndroid Build Coastguard Worker        self.diagFile = diagFile
353*90277196SAndroid Build Coastguard Worker        # Internal state
354*90277196SAndroid Build Coastguard Worker        self.featureName = None
355*90277196SAndroid Build Coastguard Worker        """The current feature name being generated."""
356*90277196SAndroid Build Coastguard Worker
357*90277196SAndroid Build Coastguard Worker        self.genOpts = None
358*90277196SAndroid Build Coastguard Worker        """The GeneratorOptions subclass instance."""
359*90277196SAndroid Build Coastguard Worker
360*90277196SAndroid Build Coastguard Worker        self.registry = None
361*90277196SAndroid Build Coastguard Worker        """The specification registry object."""
362*90277196SAndroid Build Coastguard Worker
363*90277196SAndroid Build Coastguard Worker        self.featureDictionary = {}
364*90277196SAndroid Build Coastguard Worker        """The dictionary of dictionaries of API features."""
365*90277196SAndroid Build Coastguard Worker
366*90277196SAndroid Build Coastguard Worker        # Used for extension enum value generation
367*90277196SAndroid Build Coastguard Worker        self.extBase = 1000000000
368*90277196SAndroid Build Coastguard Worker        self.extBlockSize = 1000
369*90277196SAndroid Build Coastguard Worker        self.madeDirs = {}
370*90277196SAndroid Build Coastguard Worker
371*90277196SAndroid Build Coastguard Worker        # API dictionary, which may be loaded by the beginFile method of
372*90277196SAndroid Build Coastguard Worker        # derived generators.
373*90277196SAndroid Build Coastguard Worker        self.apidict = None
374*90277196SAndroid Build Coastguard Worker
375*90277196SAndroid Build Coastguard Worker        # File suffix for generated files, set in beginFile below.
376*90277196SAndroid Build Coastguard Worker        self.file_suffix = ''
377*90277196SAndroid Build Coastguard Worker
378*90277196SAndroid Build Coastguard Worker    def logMsg(self, level, *args):
379*90277196SAndroid Build Coastguard Worker        """Write a message of different categories to different
380*90277196SAndroid Build Coastguard Worker        destinations.
381*90277196SAndroid Build Coastguard Worker
382*90277196SAndroid Build Coastguard Worker        - `level`
383*90277196SAndroid Build Coastguard Worker          - 'diag' (diagnostic, voluminous)
384*90277196SAndroid Build Coastguard Worker          - 'warn' (warning)
385*90277196SAndroid Build Coastguard Worker          - 'error' (fatal error - raises exception after logging)
386*90277196SAndroid Build Coastguard Worker
387*90277196SAndroid Build Coastguard Worker        - `*args` - print()-style arguments to direct to corresponding log"""
388*90277196SAndroid Build Coastguard Worker        if level == 'error':
389*90277196SAndroid Build Coastguard Worker            strfile = io.StringIO()
390*90277196SAndroid Build Coastguard Worker            write('ERROR:', *args, file=strfile)
391*90277196SAndroid Build Coastguard Worker            if self.errFile is not None:
392*90277196SAndroid Build Coastguard Worker                write(strfile.getvalue(), file=self.errFile)
393*90277196SAndroid Build Coastguard Worker            raise UserWarning(strfile.getvalue())
394*90277196SAndroid Build Coastguard Worker        elif level == 'warn':
395*90277196SAndroid Build Coastguard Worker            if self.warnFile is not None:
396*90277196SAndroid Build Coastguard Worker                write('WARNING:', *args, file=self.warnFile)
397*90277196SAndroid Build Coastguard Worker        elif level == 'diag':
398*90277196SAndroid Build Coastguard Worker            if self.diagFile is not None:
399*90277196SAndroid Build Coastguard Worker                write('DIAG:', *args, file=self.diagFile)
400*90277196SAndroid Build Coastguard Worker        else:
401*90277196SAndroid Build Coastguard Worker            raise UserWarning(
402*90277196SAndroid Build Coastguard Worker                '*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
403*90277196SAndroid Build Coastguard Worker
404*90277196SAndroid Build Coastguard Worker    def enumToValue(self, elem, needsNum, bitwidth = 32,
405*90277196SAndroid Build Coastguard Worker                    forceSuffix = False, parent_for_alias_dereference=None):
406*90277196SAndroid Build Coastguard Worker        """Parse and convert an `<enum>` tag into a value.
407*90277196SAndroid Build Coastguard Worker
408*90277196SAndroid Build Coastguard Worker        - elem - <enum> Element
409*90277196SAndroid Build Coastguard Worker        - needsNum - generate a numeric representation of the element value
410*90277196SAndroid Build Coastguard Worker        - bitwidth - size of the numeric representation in bits (32 or 64)
411*90277196SAndroid Build Coastguard Worker        - forceSuffix - if True, always use a 'U' / 'ULL' suffix on integers
412*90277196SAndroid Build Coastguard Worker        - parent_for_alias_dereference - if not None, an Element containing
413*90277196SAndroid Build Coastguard Worker          the parent of elem, used to look for elements this is an alias of
414*90277196SAndroid Build Coastguard Worker
415*90277196SAndroid Build Coastguard Worker        Returns a list:
416*90277196SAndroid Build Coastguard Worker
417*90277196SAndroid Build Coastguard Worker        - first element - integer representation of the value, or None
418*90277196SAndroid Build Coastguard Worker          if needsNum is False. The value must be a legal number
419*90277196SAndroid Build Coastguard Worker          if needsNum is True.
420*90277196SAndroid Build Coastguard Worker        - second element - string representation of the value
421*90277196SAndroid Build Coastguard Worker
422*90277196SAndroid Build Coastguard Worker        There are several possible representations of values.
423*90277196SAndroid Build Coastguard Worker
424*90277196SAndroid Build Coastguard Worker        - A 'value' attribute simply contains the value.
425*90277196SAndroid Build Coastguard Worker        - A 'bitpos' attribute defines a value by specifying the bit
426*90277196SAndroid Build Coastguard Worker          position which is set in that value.
427*90277196SAndroid Build Coastguard Worker        - An 'offset','extbase','extends' triplet specifies a value
428*90277196SAndroid Build Coastguard Worker          as an offset to a base value defined by the specified
429*90277196SAndroid Build Coastguard Worker          'extbase' extension name, which is then cast to the
430*90277196SAndroid Build Coastguard Worker          typename specified by 'extends'. This requires probing
431*90277196SAndroid Build Coastguard Worker          the registry database, and imbeds knowledge of the
432*90277196SAndroid Build Coastguard Worker          API extension enum scheme in this function.
433*90277196SAndroid Build Coastguard Worker        - An 'alias' attribute contains the name of another enum
434*90277196SAndroid Build Coastguard Worker          which this is an alias of. The other enum must be
435*90277196SAndroid Build Coastguard Worker          declared first when emitting this enum."""
436*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
437*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
438*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions is None:
439*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsConventionsError()
440*90277196SAndroid Build Coastguard Worker
441*90277196SAndroid Build Coastguard Worker        name = elem.get('name')
442*90277196SAndroid Build Coastguard Worker        numVal = None
443*90277196SAndroid Build Coastguard Worker        if 'value' in elem.keys():
444*90277196SAndroid Build Coastguard Worker            value = elem.get('value')
445*90277196SAndroid Build Coastguard Worker            # print('About to translate value =', value, 'type =', type(value))
446*90277196SAndroid Build Coastguard Worker            if needsNum:
447*90277196SAndroid Build Coastguard Worker                numVal = int(value, 0)
448*90277196SAndroid Build Coastguard Worker            # If there is a non-integer, numeric 'type' attribute (e.g. 'u' or
449*90277196SAndroid Build Coastguard Worker            # 'ull'), append it to the string value.
450*90277196SAndroid Build Coastguard Worker            # t = enuminfo.elem.get('type')
451*90277196SAndroid Build Coastguard Worker            # if t is not None and t != '' and t != 'i' and t != 's':
452*90277196SAndroid Build Coastguard Worker            #     value += enuminfo.type
453*90277196SAndroid Build Coastguard Worker            if forceSuffix:
454*90277196SAndroid Build Coastguard Worker              if bitwidth == 64:
455*90277196SAndroid Build Coastguard Worker                value = value + 'ULL'
456*90277196SAndroid Build Coastguard Worker              else:
457*90277196SAndroid Build Coastguard Worker                value = value + 'U'
458*90277196SAndroid Build Coastguard Worker            self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']')
459*90277196SAndroid Build Coastguard Worker            return [numVal, value]
460*90277196SAndroid Build Coastguard Worker        if 'bitpos' in elem.keys():
461*90277196SAndroid Build Coastguard Worker            value = elem.get('bitpos')
462*90277196SAndroid Build Coastguard Worker            bitpos = int(value, 0)
463*90277196SAndroid Build Coastguard Worker            numVal = 1 << bitpos
464*90277196SAndroid Build Coastguard Worker            value = '0x%08x' % numVal
465*90277196SAndroid Build Coastguard Worker            if bitwidth == 64 or bitpos >= 32:
466*90277196SAndroid Build Coastguard Worker              value = value + 'ULL'
467*90277196SAndroid Build Coastguard Worker            elif forceSuffix:
468*90277196SAndroid Build Coastguard Worker              value = value + 'U'
469*90277196SAndroid Build Coastguard Worker            self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
470*90277196SAndroid Build Coastguard Worker            return [numVal, value]
471*90277196SAndroid Build Coastguard Worker        if 'offset' in elem.keys():
472*90277196SAndroid Build Coastguard Worker            # Obtain values in the mapping from the attributes
473*90277196SAndroid Build Coastguard Worker            enumNegative = False
474*90277196SAndroid Build Coastguard Worker            offset = int(elem.get('offset'), 0)
475*90277196SAndroid Build Coastguard Worker            extnumber = int(elem.get('extnumber'), 0)
476*90277196SAndroid Build Coastguard Worker            extends = elem.get('extends')
477*90277196SAndroid Build Coastguard Worker            if 'dir' in elem.keys():
478*90277196SAndroid Build Coastguard Worker                enumNegative = True
479*90277196SAndroid Build Coastguard Worker            self.logMsg('diag', 'Enum', name, 'offset =', offset,
480*90277196SAndroid Build Coastguard Worker                        'extnumber =', extnumber, 'extends =', extends,
481*90277196SAndroid Build Coastguard Worker                        'enumNegative =', enumNegative)
482*90277196SAndroid Build Coastguard Worker            # Now determine the actual enumerant value, as defined
483*90277196SAndroid Build Coastguard Worker            # in the "Layers and Extensions" appendix of the spec.
484*90277196SAndroid Build Coastguard Worker            numVal = self.extBase + (extnumber - 1) * self.extBlockSize + offset
485*90277196SAndroid Build Coastguard Worker            if enumNegative:
486*90277196SAndroid Build Coastguard Worker                numVal *= -1
487*90277196SAndroid Build Coastguard Worker            value = '%d' % numVal
488*90277196SAndroid Build Coastguard Worker            # More logic needed!
489*90277196SAndroid Build Coastguard Worker            self.logMsg('diag', 'Enum', name, '-> offset [', numVal, ',', value, ']')
490*90277196SAndroid Build Coastguard Worker            return [numVal, value]
491*90277196SAndroid Build Coastguard Worker        if 'alias' in elem.keys():
492*90277196SAndroid Build Coastguard Worker            alias_of = elem.get('alias')
493*90277196SAndroid Build Coastguard Worker            if parent_for_alias_dereference is None:
494*90277196SAndroid Build Coastguard Worker                return (None, alias_of)
495*90277196SAndroid Build Coastguard Worker            siblings = parent_for_alias_dereference.findall('enum')
496*90277196SAndroid Build Coastguard Worker            for sib in siblings:
497*90277196SAndroid Build Coastguard Worker                sib_name = sib.get('name')
498*90277196SAndroid Build Coastguard Worker                if sib_name == alias_of:
499*90277196SAndroid Build Coastguard Worker                    return self.enumToValue(sib, needsNum)
500*90277196SAndroid Build Coastguard Worker            raise RuntimeError("Could not find the aliased enum value")
501*90277196SAndroid Build Coastguard Worker        return [None, None]
502*90277196SAndroid Build Coastguard Worker
503*90277196SAndroid Build Coastguard Worker    def checkDuplicateEnums(self, enums):
504*90277196SAndroid Build Coastguard Worker        """Check enumerated values for duplicates.
505*90277196SAndroid Build Coastguard Worker
506*90277196SAndroid Build Coastguard Worker        -  enums - list of `<enum>` Elements
507*90277196SAndroid Build Coastguard Worker
508*90277196SAndroid Build Coastguard Worker        returns the list with duplicates stripped"""
509*90277196SAndroid Build Coastguard Worker        # Dictionaries indexed by name and numeric value.
510*90277196SAndroid Build Coastguard Worker        # Entries are [ Element, numVal, strVal ] matching name or value
511*90277196SAndroid Build Coastguard Worker
512*90277196SAndroid Build Coastguard Worker        nameMap = {}
513*90277196SAndroid Build Coastguard Worker        valueMap = {}
514*90277196SAndroid Build Coastguard Worker
515*90277196SAndroid Build Coastguard Worker        stripped = []
516*90277196SAndroid Build Coastguard Worker        for elem in enums:
517*90277196SAndroid Build Coastguard Worker            name = elem.get('name')
518*90277196SAndroid Build Coastguard Worker            (numVal, strVal) = self.enumToValue(elem, True)
519*90277196SAndroid Build Coastguard Worker
520*90277196SAndroid Build Coastguard Worker            if name in nameMap:
521*90277196SAndroid Build Coastguard Worker                # Duplicate name found; check values
522*90277196SAndroid Build Coastguard Worker                (name2, numVal2, strVal2) = nameMap[name]
523*90277196SAndroid Build Coastguard Worker
524*90277196SAndroid Build Coastguard Worker                # Duplicate enum values for the same name are benign. This
525*90277196SAndroid Build Coastguard Worker                # happens when defining the same enum conditionally in
526*90277196SAndroid Build Coastguard Worker                # several extension blocks.
527*90277196SAndroid Build Coastguard Worker                if (strVal2 == strVal or (numVal is not None
528*90277196SAndroid Build Coastguard Worker                                          and numVal == numVal2)):
529*90277196SAndroid Build Coastguard Worker                    True
530*90277196SAndroid Build Coastguard Worker                    # self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
531*90277196SAndroid Build Coastguard Worker                    #             ') found with the same value:' + strVal)
532*90277196SAndroid Build Coastguard Worker                else:
533*90277196SAndroid Build Coastguard Worker                    self.logMsg('warn', 'checkDuplicateEnums: Duplicate enum (' + name
534*90277196SAndroid Build Coastguard Worker                                + ') found with different values:' + strVal
535*90277196SAndroid Build Coastguard Worker                                + ' and ' + strVal2)
536*90277196SAndroid Build Coastguard Worker
537*90277196SAndroid Build Coastguard Worker                # Do not add the duplicate to the returned list
538*90277196SAndroid Build Coastguard Worker                continue
539*90277196SAndroid Build Coastguard Worker            elif numVal in valueMap:
540*90277196SAndroid Build Coastguard Worker                # Duplicate value found (such as an alias); report it, but
541*90277196SAndroid Build Coastguard Worker                # still add this enum to the list.
542*90277196SAndroid Build Coastguard Worker                (name2, numVal2, strVal2) = valueMap[numVal]
543*90277196SAndroid Build Coastguard Worker
544*90277196SAndroid Build Coastguard Worker                msg = 'Two enums found with the same value: {} = {} = {}'.format(
545*90277196SAndroid Build Coastguard Worker                    name, name2.get('name'), strVal)
546*90277196SAndroid Build Coastguard Worker                self.logMsg('error', msg)
547*90277196SAndroid Build Coastguard Worker
548*90277196SAndroid Build Coastguard Worker            # Track this enum to detect followon duplicates
549*90277196SAndroid Build Coastguard Worker            nameMap[name] = [elem, numVal, strVal]
550*90277196SAndroid Build Coastguard Worker            if numVal is not None:
551*90277196SAndroid Build Coastguard Worker                valueMap[numVal] = [elem, numVal, strVal]
552*90277196SAndroid Build Coastguard Worker
553*90277196SAndroid Build Coastguard Worker            # Add this enum to the list
554*90277196SAndroid Build Coastguard Worker            stripped.append(elem)
555*90277196SAndroid Build Coastguard Worker
556*90277196SAndroid Build Coastguard Worker        # Return the list
557*90277196SAndroid Build Coastguard Worker        return stripped
558*90277196SAndroid Build Coastguard Worker
559*90277196SAndroid Build Coastguard Worker    def misracstyle(self):
560*90277196SAndroid Build Coastguard Worker        return False;
561*90277196SAndroid Build Coastguard Worker
562*90277196SAndroid Build Coastguard Worker    def misracppstyle(self):
563*90277196SAndroid Build Coastguard Worker        return False;
564*90277196SAndroid Build Coastguard Worker
565*90277196SAndroid Build Coastguard Worker    def deprecationComment(self, elem, indent = 0):
566*90277196SAndroid Build Coastguard Worker        """If an API element is marked deprecated, return a brief comment
567*90277196SAndroid Build Coastguard Worker           describing why.
568*90277196SAndroid Build Coastguard Worker           Otherwise, return an empty string.
569*90277196SAndroid Build Coastguard Worker
570*90277196SAndroid Build Coastguard Worker          - elem - Element of the API.
571*90277196SAndroid Build Coastguard Worker            API name is determined depending on the element tag.
572*90277196SAndroid Build Coastguard Worker          - indent - number of spaces to indent the comment"""
573*90277196SAndroid Build Coastguard Worker
574*90277196SAndroid Build Coastguard Worker        reason = elem.get('deprecated')
575*90277196SAndroid Build Coastguard Worker
576*90277196SAndroid Build Coastguard Worker        # This is almost always the path taken.
577*90277196SAndroid Build Coastguard Worker        if reason == None:
578*90277196SAndroid Build Coastguard Worker            return ''
579*90277196SAndroid Build Coastguard Worker
580*90277196SAndroid Build Coastguard Worker        # There is actually a deprecated attribute.
581*90277196SAndroid Build Coastguard Worker        padding = indent * ' '
582*90277196SAndroid Build Coastguard Worker
583*90277196SAndroid Build Coastguard Worker        # Determine the API name.
584*90277196SAndroid Build Coastguard Worker        if elem.tag == 'member' or elem.tag == 'param':
585*90277196SAndroid Build Coastguard Worker            name = elem.find('.//name').text
586*90277196SAndroid Build Coastguard Worker        else:
587*90277196SAndroid Build Coastguard Worker            name = elem.get('name')
588*90277196SAndroid Build Coastguard Worker
589*90277196SAndroid Build Coastguard Worker        if reason == 'aliased':
590*90277196SAndroid Build Coastguard Worker            return f'{padding}// {name} is a deprecated alias\n'
591*90277196SAndroid Build Coastguard Worker        elif reason == 'ignored':
592*90277196SAndroid Build Coastguard Worker            return f'{padding}// {name} is deprecated and should not be used\n'
593*90277196SAndroid Build Coastguard Worker        elif reason == 'true':
594*90277196SAndroid Build Coastguard Worker            return f'{padding}// {name} is deprecated, but no reason was given in the API XML\n'
595*90277196SAndroid Build Coastguard Worker        else:
596*90277196SAndroid Build Coastguard Worker            # This can be caught by schema validation
597*90277196SAndroid Build Coastguard Worker            self.logMsg('error', f"{name} has an unknown deprecation attribute value '{reason}'")
598*90277196SAndroid Build Coastguard Worker            exit(1)
599*90277196SAndroid Build Coastguard Worker
600*90277196SAndroid Build Coastguard Worker    def buildEnumCDecl(self, expand, groupinfo, groupName):
601*90277196SAndroid Build Coastguard Worker        """Generate the C declaration for an enum"""
602*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
603*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
604*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions is None:
605*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsConventionsError()
606*90277196SAndroid Build Coastguard Worker
607*90277196SAndroid Build Coastguard Worker        groupElem = groupinfo.elem
608*90277196SAndroid Build Coastguard Worker
609*90277196SAndroid Build Coastguard Worker        # Determine the required bit width for the enum group.
610*90277196SAndroid Build Coastguard Worker        # 32 is the default, which generates C enum types for the values.
611*90277196SAndroid Build Coastguard Worker        bitwidth = 32
612*90277196SAndroid Build Coastguard Worker
613*90277196SAndroid Build Coastguard Worker        # If the constFlagBits preference is set, 64 is the default for bitmasks
614*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
615*90277196SAndroid Build Coastguard Worker            bitwidth = 64
616*90277196SAndroid Build Coastguard Worker
617*90277196SAndroid Build Coastguard Worker        # Check for an explicitly defined bitwidth, which will override any defaults.
618*90277196SAndroid Build Coastguard Worker        if groupElem.get('bitwidth'):
619*90277196SAndroid Build Coastguard Worker            try:
620*90277196SAndroid Build Coastguard Worker                bitwidth = int(groupElem.get('bitwidth'))
621*90277196SAndroid Build Coastguard Worker            except ValueError as ve:
622*90277196SAndroid Build Coastguard Worker                self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for ', groupName, ' - must be an integer value\n')
623*90277196SAndroid Build Coastguard Worker                exit(1)
624*90277196SAndroid Build Coastguard Worker
625*90277196SAndroid Build Coastguard Worker        usebitmask = False
626*90277196SAndroid Build Coastguard Worker        usedefine = False
627*90277196SAndroid Build Coastguard Worker
628*90277196SAndroid Build Coastguard Worker        # Bitmask flags can be generated as either "static const uint{32,64}_t" values,
629*90277196SAndroid Build Coastguard Worker        # or as 32-bit C enums. 64-bit types must use uint64_t values.
630*90277196SAndroid Build Coastguard Worker        if groupElem.get('type') == 'bitmask':
631*90277196SAndroid Build Coastguard Worker            if bitwidth > 32 or self.misracppstyle():
632*90277196SAndroid Build Coastguard Worker                usebitmask = True
633*90277196SAndroid Build Coastguard Worker            if self.misracstyle():
634*90277196SAndroid Build Coastguard Worker                usedefine = True
635*90277196SAndroid Build Coastguard Worker
636*90277196SAndroid Build Coastguard Worker        if usedefine or usebitmask:
637*90277196SAndroid Build Coastguard Worker            # Validate the bitwidth and generate values appropriately
638*90277196SAndroid Build Coastguard Worker            if bitwidth > 64:
639*90277196SAndroid Build Coastguard Worker                self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for bitmask type ', groupName, ' - must be less than or equal to 64\n')
640*90277196SAndroid Build Coastguard Worker                exit(1)
641*90277196SAndroid Build Coastguard Worker            else:
642*90277196SAndroid Build Coastguard Worker                return self.buildEnumCDecl_BitmaskOrDefine(groupinfo, groupName, bitwidth, usedefine)
643*90277196SAndroid Build Coastguard Worker        else:
644*90277196SAndroid Build Coastguard Worker            # Validate the bitwidth and generate values appropriately
645*90277196SAndroid Build Coastguard Worker            if bitwidth > 32:
646*90277196SAndroid Build Coastguard Worker                self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for enum type ', groupName, ' - must be less than or equal to 32\n')
647*90277196SAndroid Build Coastguard Worker                exit(1)
648*90277196SAndroid Build Coastguard Worker            else:
649*90277196SAndroid Build Coastguard Worker                return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
650*90277196SAndroid Build Coastguard Worker
651*90277196SAndroid Build Coastguard Worker    def buildEnumCDecl_BitmaskOrDefine(self, groupinfo, groupName, bitwidth, usedefine):
652*90277196SAndroid Build Coastguard Worker        """Generate the C declaration for an "enum" that is actually a
653*90277196SAndroid Build Coastguard Worker        set of flag bits"""
654*90277196SAndroid Build Coastguard Worker        groupElem = groupinfo.elem
655*90277196SAndroid Build Coastguard Worker        flagTypeName = groupElem.get('name')
656*90277196SAndroid Build Coastguard Worker
657*90277196SAndroid Build Coastguard Worker        # Prefix
658*90277196SAndroid Build Coastguard Worker        body = "// Flag bits for " + flagTypeName + "\n"
659*90277196SAndroid Build Coastguard Worker
660*90277196SAndroid Build Coastguard Worker        if bitwidth == 64:
661*90277196SAndroid Build Coastguard Worker            body += "typedef VkFlags64 %s;\n" % flagTypeName;
662*90277196SAndroid Build Coastguard Worker        else:
663*90277196SAndroid Build Coastguard Worker            body += "typedef VkFlags %s;\n" % flagTypeName;
664*90277196SAndroid Build Coastguard Worker
665*90277196SAndroid Build Coastguard Worker        # Maximum allowable value for a flag (unsigned 64-bit integer)
666*90277196SAndroid Build Coastguard Worker        maxValidValue = 2**(64) - 1
667*90277196SAndroid Build Coastguard Worker        minValidValue = 0
668*90277196SAndroid Build Coastguard Worker
669*90277196SAndroid Build Coastguard Worker        # Get a list of nested 'enum' tags.
670*90277196SAndroid Build Coastguard Worker        enums = groupElem.findall('enum')
671*90277196SAndroid Build Coastguard Worker
672*90277196SAndroid Build Coastguard Worker        # Check for and report duplicates, and return a list with them
673*90277196SAndroid Build Coastguard Worker        # removed.
674*90277196SAndroid Build Coastguard Worker        enums = self.checkDuplicateEnums(enums)
675*90277196SAndroid Build Coastguard Worker
676*90277196SAndroid Build Coastguard Worker        # Accumulate non-numeric enumerant values separately and append
677*90277196SAndroid Build Coastguard Worker        # them following the numeric values, to allow for aliases.
678*90277196SAndroid Build Coastguard Worker        # NOTE: this does not do a topological sort yet, so aliases of
679*90277196SAndroid Build Coastguard Worker        # aliases can still get in the wrong order.
680*90277196SAndroid Build Coastguard Worker        aliasText = ''
681*90277196SAndroid Build Coastguard Worker
682*90277196SAndroid Build Coastguard Worker        # Loop over the nested 'enum' tags.
683*90277196SAndroid Build Coastguard Worker        for elem in enums:
684*90277196SAndroid Build Coastguard Worker            # Convert the value to an integer and use that to track min/max.
685*90277196SAndroid Build Coastguard Worker            # Values of form -(number) are accepted but nothing more complex.
686*90277196SAndroid Build Coastguard Worker            # Should catch exceptions here for more complex constructs. Not yet.
687*90277196SAndroid Build Coastguard Worker            (numVal, strVal) = self.enumToValue(elem, True, bitwidth, True)
688*90277196SAndroid Build Coastguard Worker            name = elem.get('name')
689*90277196SAndroid Build Coastguard Worker
690*90277196SAndroid Build Coastguard Worker            # Range check for the enum value
691*90277196SAndroid Build Coastguard Worker            if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
692*90277196SAndroid Build Coastguard Worker                self.logMsg('error', 'Allowable range for flag types in C is [', minValidValue, ',', maxValidValue, '], but', name, 'flag has a value outside of this (', strVal, ')\n')
693*90277196SAndroid Build Coastguard Worker                exit(1)
694*90277196SAndroid Build Coastguard Worker
695*90277196SAndroid Build Coastguard Worker            decl = self.genRequirements(name, mustBeFound = False)
696*90277196SAndroid Build Coastguard Worker
697*90277196SAndroid Build Coastguard Worker            if self.isEnumRequired(elem):
698*90277196SAndroid Build Coastguard Worker                protect = elem.get('protect')
699*90277196SAndroid Build Coastguard Worker                if protect is not None:
700*90277196SAndroid Build Coastguard Worker                    body += '#ifdef {}\n'.format(protect)
701*90277196SAndroid Build Coastguard Worker
702*90277196SAndroid Build Coastguard Worker                body += self.deprecationComment(elem, indent = 0)
703*90277196SAndroid Build Coastguard Worker
704*90277196SAndroid Build Coastguard Worker                if usedefine:
705*90277196SAndroid Build Coastguard Worker                    decl += "#define {} {}\n".format(name, strVal)
706*90277196SAndroid Build Coastguard Worker                elif self.misracppstyle():
707*90277196SAndroid Build Coastguard Worker                    decl += "static constexpr {} {} {{{}}};\n".format(flagTypeName, name, strVal)
708*90277196SAndroid Build Coastguard Worker                else:
709*90277196SAndroid Build Coastguard Worker                    # Some C compilers only allow initializing a 'static const' variable with a literal value.
710*90277196SAndroid Build Coastguard Worker                    # So initializing an alias from another 'static const' value would fail to compile.
711*90277196SAndroid Build Coastguard Worker                    # Work around this by chasing the aliases to get the actual value.
712*90277196SAndroid Build Coastguard Worker                    while numVal is None:
713*90277196SAndroid Build Coastguard Worker                        alias = self.registry.tree.find("enums/enum[@name='" + strVal + "']")
714*90277196SAndroid Build Coastguard Worker                        if alias is not None:
715*90277196SAndroid Build Coastguard Worker                            (numVal, strVal) = self.enumToValue(alias, True, bitwidth, True)
716*90277196SAndroid Build Coastguard Worker                        else:
717*90277196SAndroid Build Coastguard Worker                            self.logMsg('error', 'No such alias {} for enum {}'.format(strVal, name))
718*90277196SAndroid Build Coastguard Worker                    decl += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
719*90277196SAndroid Build Coastguard Worker
720*90277196SAndroid Build Coastguard Worker                if numVal is not None:
721*90277196SAndroid Build Coastguard Worker                    body += decl
722*90277196SAndroid Build Coastguard Worker                else:
723*90277196SAndroid Build Coastguard Worker                    aliasText += decl
724*90277196SAndroid Build Coastguard Worker
725*90277196SAndroid Build Coastguard Worker                if protect is not None:
726*90277196SAndroid Build Coastguard Worker                    body += '#endif\n'
727*90277196SAndroid Build Coastguard Worker
728*90277196SAndroid Build Coastguard Worker        # Now append the non-numeric enumerant values
729*90277196SAndroid Build Coastguard Worker        body += aliasText
730*90277196SAndroid Build Coastguard Worker
731*90277196SAndroid Build Coastguard Worker        # Postfix
732*90277196SAndroid Build Coastguard Worker
733*90277196SAndroid Build Coastguard Worker        return ("bitmask", body)
734*90277196SAndroid Build Coastguard Worker
735*90277196SAndroid Build Coastguard Worker    def buildEnumCDecl_Enum(self, expand, groupinfo, groupName):
736*90277196SAndroid Build Coastguard Worker        """Generate the C declaration for an enumerated type"""
737*90277196SAndroid Build Coastguard Worker        groupElem = groupinfo.elem
738*90277196SAndroid Build Coastguard Worker
739*90277196SAndroid Build Coastguard Worker        # Break the group name into prefix and suffix portions for range
740*90277196SAndroid Build Coastguard Worker        # enum generation
741*90277196SAndroid Build Coastguard Worker        expandName = re.sub(r'([0-9]+|[a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
742*90277196SAndroid Build Coastguard Worker        expandPrefix = expandName
743*90277196SAndroid Build Coastguard Worker        expandSuffix = ''
744*90277196SAndroid Build Coastguard Worker        expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName)
745*90277196SAndroid Build Coastguard Worker        if expandSuffixMatch:
746*90277196SAndroid Build Coastguard Worker            expandSuffix = '_' + expandSuffixMatch.group()
747*90277196SAndroid Build Coastguard Worker            # Strip off the suffix from the prefix
748*90277196SAndroid Build Coastguard Worker            expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
749*90277196SAndroid Build Coastguard Worker
750*90277196SAndroid Build Coastguard Worker        # Prefix
751*90277196SAndroid Build Coastguard Worker        body = ["typedef enum %s {" % groupName]
752*90277196SAndroid Build Coastguard Worker
753*90277196SAndroid Build Coastguard Worker        # @@ Should use the type="bitmask" attribute instead
754*90277196SAndroid Build Coastguard Worker        isEnum = ('FLAG_BITS' not in expandPrefix)
755*90277196SAndroid Build Coastguard Worker
756*90277196SAndroid Build Coastguard Worker        # Allowable range for a C enum - which is that of a signed 32-bit integer
757*90277196SAndroid Build Coastguard Worker        maxValidValue = 2**(32 - 1) - 1
758*90277196SAndroid Build Coastguard Worker        minValidValue = (maxValidValue * -1) - 1
759*90277196SAndroid Build Coastguard Worker
760*90277196SAndroid Build Coastguard Worker        # Get a list of nested 'enum' tags.
761*90277196SAndroid Build Coastguard Worker        enums = groupElem.findall('enum')
762*90277196SAndroid Build Coastguard Worker
763*90277196SAndroid Build Coastguard Worker        # Check for and report duplicates, and return a list with them
764*90277196SAndroid Build Coastguard Worker        # removed.
765*90277196SAndroid Build Coastguard Worker        enums = self.checkDuplicateEnums(enums)
766*90277196SAndroid Build Coastguard Worker
767*90277196SAndroid Build Coastguard Worker        # Loop over the nested 'enum' tags. Keep track of the minimum and
768*90277196SAndroid Build Coastguard Worker        # maximum numeric values, if they can be determined; but only for
769*90277196SAndroid Build Coastguard Worker        # core API enumerants, not extension enumerants. This is inferred
770*90277196SAndroid Build Coastguard Worker        # by looking for 'extends' attributes.
771*90277196SAndroid Build Coastguard Worker        minName = None
772*90277196SAndroid Build Coastguard Worker
773*90277196SAndroid Build Coastguard Worker        # Accumulate non-numeric enumerant values separately and append
774*90277196SAndroid Build Coastguard Worker        # them following the numeric values, to allow for aliases.
775*90277196SAndroid Build Coastguard Worker        # NOTE: this does not do a topological sort yet, so aliases of
776*90277196SAndroid Build Coastguard Worker        # aliases can still get in the wrong order.
777*90277196SAndroid Build Coastguard Worker        aliasText = []
778*90277196SAndroid Build Coastguard Worker
779*90277196SAndroid Build Coastguard Worker        maxName = None
780*90277196SAndroid Build Coastguard Worker        minValue = None
781*90277196SAndroid Build Coastguard Worker        maxValue = None
782*90277196SAndroid Build Coastguard Worker        for elem in enums:
783*90277196SAndroid Build Coastguard Worker            # Convert the value to an integer and use that to track min/max.
784*90277196SAndroid Build Coastguard Worker            # Values of form -(number) are accepted but nothing more complex.
785*90277196SAndroid Build Coastguard Worker            # Should catch exceptions here for more complex constructs. Not yet.
786*90277196SAndroid Build Coastguard Worker            (numVal, strVal) = self.enumToValue(elem, True)
787*90277196SAndroid Build Coastguard Worker            name = elem.get('name')
788*90277196SAndroid Build Coastguard Worker
789*90277196SAndroid Build Coastguard Worker            # Extension enumerants are only included if they are required
790*90277196SAndroid Build Coastguard Worker            if self.isEnumRequired(elem):
791*90277196SAndroid Build Coastguard Worker                decl = ''
792*90277196SAndroid Build Coastguard Worker
793*90277196SAndroid Build Coastguard Worker                protect = elem.get('protect')
794*90277196SAndroid Build Coastguard Worker                if protect is not None:
795*90277196SAndroid Build Coastguard Worker                    decl += '#ifdef {}\n'.format(protect)
796*90277196SAndroid Build Coastguard Worker
797*90277196SAndroid Build Coastguard Worker
798*90277196SAndroid Build Coastguard Worker                decl += self.genRequirements(name, mustBeFound = False, indent = 2)
799*90277196SAndroid Build Coastguard Worker                decl += self.deprecationComment(elem, indent = 2)
800*90277196SAndroid Build Coastguard Worker                decl += '    {} = {},'.format(name, strVal)
801*90277196SAndroid Build Coastguard Worker
802*90277196SAndroid Build Coastguard Worker                if protect is not None:
803*90277196SAndroid Build Coastguard Worker                    decl += '\n#endif'
804*90277196SAndroid Build Coastguard Worker
805*90277196SAndroid Build Coastguard Worker                if numVal is not None:
806*90277196SAndroid Build Coastguard Worker                    body.append(decl)
807*90277196SAndroid Build Coastguard Worker                else:
808*90277196SAndroid Build Coastguard Worker                    aliasText.append(decl)
809*90277196SAndroid Build Coastguard Worker
810*90277196SAndroid Build Coastguard Worker            # Range check for the enum value
811*90277196SAndroid Build Coastguard Worker            if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
812*90277196SAndroid Build Coastguard Worker                self.logMsg('error', 'Allowable range for C enum types is [', minValidValue, ',', maxValidValue, '], but', name, 'has a value outside of this (', strVal, ')\n')
813*90277196SAndroid Build Coastguard Worker                exit(1)
814*90277196SAndroid Build Coastguard Worker
815*90277196SAndroid Build Coastguard Worker            # Do not track min/max for non-numbers (numVal is None)
816*90277196SAndroid Build Coastguard Worker            if isEnum and numVal is not None and elem.get('extends') is None:
817*90277196SAndroid Build Coastguard Worker                if minName is None:
818*90277196SAndroid Build Coastguard Worker                    minName = maxName = name
819*90277196SAndroid Build Coastguard Worker                    minValue = maxValue = numVal
820*90277196SAndroid Build Coastguard Worker                elif minValue is None or numVal < minValue:
821*90277196SAndroid Build Coastguard Worker                    minName = name
822*90277196SAndroid Build Coastguard Worker                    minValue = numVal
823*90277196SAndroid Build Coastguard Worker                elif maxValue is None or numVal > maxValue:
824*90277196SAndroid Build Coastguard Worker                    maxName = name
825*90277196SAndroid Build Coastguard Worker                    maxValue = numVal
826*90277196SAndroid Build Coastguard Worker
827*90277196SAndroid Build Coastguard Worker        # Now append the non-numeric enumerant values
828*90277196SAndroid Build Coastguard Worker        body.extend(aliasText)
829*90277196SAndroid Build Coastguard Worker
830*90277196SAndroid Build Coastguard Worker        # Generate min/max value tokens - legacy use case.
831*90277196SAndroid Build Coastguard Worker        if isEnum and expand:
832*90277196SAndroid Build Coastguard Worker            body.extend((f'    {expandPrefix}_BEGIN_RANGE{expandSuffix} = {minName},',
833*90277196SAndroid Build Coastguard Worker                         f'    {expandPrefix}_END_RANGE{expandSuffix} = {maxName},',
834*90277196SAndroid Build Coastguard Worker                         f'    {expandPrefix}_RANGE_SIZE{expandSuffix} = ({maxName} - {minName} + 1),'))
835*90277196SAndroid Build Coastguard Worker
836*90277196SAndroid Build Coastguard Worker        # Generate a range-padding value to ensure the enum is 32 bits, but
837*90277196SAndroid Build Coastguard Worker        # only in code generators, so it does not appear in documentation
838*90277196SAndroid Build Coastguard Worker        if (self.genOpts.codeGenerator or
839*90277196SAndroid Build Coastguard Worker            self.conventions.generate_max_enum_in_docs):
840*90277196SAndroid Build Coastguard Worker            body.append(f'    {expandPrefix}_MAX_ENUM{expandSuffix} = 0x7FFFFFFF')
841*90277196SAndroid Build Coastguard Worker
842*90277196SAndroid Build Coastguard Worker        # Postfix
843*90277196SAndroid Build Coastguard Worker        body.append("} %s;" % groupName)
844*90277196SAndroid Build Coastguard Worker
845*90277196SAndroid Build Coastguard Worker        # Determine appropriate section for this declaration
846*90277196SAndroid Build Coastguard Worker        if groupElem.get('type') == 'bitmask':
847*90277196SAndroid Build Coastguard Worker            section = 'bitmask'
848*90277196SAndroid Build Coastguard Worker        else:
849*90277196SAndroid Build Coastguard Worker            section = 'group'
850*90277196SAndroid Build Coastguard Worker
851*90277196SAndroid Build Coastguard Worker        return (section, '\n'.join(body))
852*90277196SAndroid Build Coastguard Worker
853*90277196SAndroid Build Coastguard Worker    def buildConstantCDecl(self, enuminfo, name, alias):
854*90277196SAndroid Build Coastguard Worker        """Generate the C declaration for a constant (a single <enum>
855*90277196SAndroid Build Coastguard Worker        value).
856*90277196SAndroid Build Coastguard Worker
857*90277196SAndroid Build Coastguard Worker        <enum> tags may specify their values in several ways, but are
858*90277196SAndroid Build Coastguard Worker        usually just integers or floating-point numbers."""
859*90277196SAndroid Build Coastguard Worker
860*90277196SAndroid Build Coastguard Worker        (_, strVal) = self.enumToValue(enuminfo.elem, False)
861*90277196SAndroid Build Coastguard Worker
862*90277196SAndroid Build Coastguard Worker        if self.misracppstyle() and enuminfo.elem.get('type') and not alias:
863*90277196SAndroid Build Coastguard Worker            # Generate e.g.: static constexpr uint32_t x = ~static_cast<uint32_t>(1U);
864*90277196SAndroid Build Coastguard Worker            # This appeases MISRA "underlying type" rules.
865*90277196SAndroid Build Coastguard Worker            typeStr = enuminfo.elem.get('type');
866*90277196SAndroid Build Coastguard Worker            invert = '~' in strVal
867*90277196SAndroid Build Coastguard Worker            number = strVal.strip("()~UL")
868*90277196SAndroid Build Coastguard Worker            if typeStr != "float":
869*90277196SAndroid Build Coastguard Worker                number += 'U'
870*90277196SAndroid Build Coastguard Worker            strVal = "~" if invert else ""
871*90277196SAndroid Build Coastguard Worker            strVal += "static_cast<" + typeStr + ">(" + number + ")"
872*90277196SAndroid Build Coastguard Worker            body = 'static constexpr ' + typeStr.ljust(9) + name.ljust(33) + ' {' + strVal + '};'
873*90277196SAndroid Build Coastguard Worker        elif enuminfo.elem.get('type') and not alias:
874*90277196SAndroid Build Coastguard Worker            # Generate e.g.: #define x (~0ULL)
875*90277196SAndroid Build Coastguard Worker            typeStr = enuminfo.elem.get('type');
876*90277196SAndroid Build Coastguard Worker            invert = '~' in strVal
877*90277196SAndroid Build Coastguard Worker            paren = '(' in strVal
878*90277196SAndroid Build Coastguard Worker            number = strVal.strip("()~UL")
879*90277196SAndroid Build Coastguard Worker            if typeStr != "float":
880*90277196SAndroid Build Coastguard Worker                if typeStr == "uint64_t":
881*90277196SAndroid Build Coastguard Worker                    number += 'ULL'
882*90277196SAndroid Build Coastguard Worker                else:
883*90277196SAndroid Build Coastguard Worker                    number += 'U'
884*90277196SAndroid Build Coastguard Worker            strVal = "~" if invert else ""
885*90277196SAndroid Build Coastguard Worker            strVal += number
886*90277196SAndroid Build Coastguard Worker            if paren:
887*90277196SAndroid Build Coastguard Worker                strVal = "(" + strVal + ")";
888*90277196SAndroid Build Coastguard Worker            body = '#define ' + name.ljust(33) + ' ' + strVal;
889*90277196SAndroid Build Coastguard Worker        else:
890*90277196SAndroid Build Coastguard Worker            body = '#define ' + name.ljust(33) + ' ' + strVal
891*90277196SAndroid Build Coastguard Worker
892*90277196SAndroid Build Coastguard Worker        return body
893*90277196SAndroid Build Coastguard Worker
894*90277196SAndroid Build Coastguard Worker    def makeDir(self, path):
895*90277196SAndroid Build Coastguard Worker        """Create a directory, if not already done.
896*90277196SAndroid Build Coastguard Worker
897*90277196SAndroid Build Coastguard Worker        Generally called from derived generators creating hierarchies."""
898*90277196SAndroid Build Coastguard Worker        self.logMsg('diag', 'OutputGenerator::makeDir(', path, ')')
899*90277196SAndroid Build Coastguard Worker        if path not in self.madeDirs:
900*90277196SAndroid Build Coastguard Worker            # This can get race conditions with multiple writers, see
901*90277196SAndroid Build Coastguard Worker            # https://stackoverflow.com/questions/273192/
902*90277196SAndroid Build Coastguard Worker            if not os.path.exists(path):
903*90277196SAndroid Build Coastguard Worker                os.makedirs(path)
904*90277196SAndroid Build Coastguard Worker            self.madeDirs[path] = None
905*90277196SAndroid Build Coastguard Worker
906*90277196SAndroid Build Coastguard Worker    def beginFile(self, genOpts):
907*90277196SAndroid Build Coastguard Worker        """Start a new interface file
908*90277196SAndroid Build Coastguard Worker
909*90277196SAndroid Build Coastguard Worker        - genOpts - GeneratorOptions controlling what is generated and how"""
910*90277196SAndroid Build Coastguard Worker
911*90277196SAndroid Build Coastguard Worker        self.genOpts = genOpts
912*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
913*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
914*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions is None:
915*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsConventionsError()
916*90277196SAndroid Build Coastguard Worker        self.should_insert_may_alias_macro = \
917*90277196SAndroid Build Coastguard Worker            self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
918*90277196SAndroid Build Coastguard Worker        self.file_suffix = self.genOpts.conventions.file_suffix
919*90277196SAndroid Build Coastguard Worker
920*90277196SAndroid Build Coastguard Worker        # Try to import the API dictionary, apimap.py, if it exists. Nothing
921*90277196SAndroid Build Coastguard Worker        # in apimap.py cannot be extracted directly from the XML, and in the
922*90277196SAndroid Build Coastguard Worker        # future we should do that.
923*90277196SAndroid Build Coastguard Worker        if self.genOpts.genpath is not None:
924*90277196SAndroid Build Coastguard Worker            try:
925*90277196SAndroid Build Coastguard Worker                sys.path.insert(0, self.genOpts.genpath)
926*90277196SAndroid Build Coastguard Worker                import apimap
927*90277196SAndroid Build Coastguard Worker                self.apidict = apimap
928*90277196SAndroid Build Coastguard Worker            except ImportError:
929*90277196SAndroid Build Coastguard Worker                self.apidict = None
930*90277196SAndroid Build Coastguard Worker
931*90277196SAndroid Build Coastguard Worker        self.conventions = genOpts.conventions
932*90277196SAndroid Build Coastguard Worker
933*90277196SAndroid Build Coastguard Worker        # Open a temporary file for accumulating output.
934*90277196SAndroid Build Coastguard Worker        if self.genOpts.filename is not None:
935*90277196SAndroid Build Coastguard Worker            self.outFile = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', newline='\n', delete=False)
936*90277196SAndroid Build Coastguard Worker        else:
937*90277196SAndroid Build Coastguard Worker            self.outFile = sys.stdout
938*90277196SAndroid Build Coastguard Worker
939*90277196SAndroid Build Coastguard Worker    def endFile(self):
940*90277196SAndroid Build Coastguard Worker        if self.errFile:
941*90277196SAndroid Build Coastguard Worker            self.errFile.flush()
942*90277196SAndroid Build Coastguard Worker        if self.warnFile:
943*90277196SAndroid Build Coastguard Worker            self.warnFile.flush()
944*90277196SAndroid Build Coastguard Worker        if self.diagFile:
945*90277196SAndroid Build Coastguard Worker            self.diagFile.flush()
946*90277196SAndroid Build Coastguard Worker        if self.outFile:
947*90277196SAndroid Build Coastguard Worker            self.outFile.flush()
948*90277196SAndroid Build Coastguard Worker            if self.outFile != sys.stdout and self.outFile != sys.stderr:
949*90277196SAndroid Build Coastguard Worker                self.outFile.close()
950*90277196SAndroid Build Coastguard Worker
951*90277196SAndroid Build Coastguard Worker            if self.genOpts is None:
952*90277196SAndroid Build Coastguard Worker                raise MissingGeneratorOptionsError()
953*90277196SAndroid Build Coastguard Worker
954*90277196SAndroid Build Coastguard Worker            # On successfully generating output, move the temporary file to the
955*90277196SAndroid Build Coastguard Worker            # target file.
956*90277196SAndroid Build Coastguard Worker            if self.genOpts.filename is not None:
957*90277196SAndroid Build Coastguard Worker                directory = Path(self.genOpts.directory)
958*90277196SAndroid Build Coastguard Worker                if sys.platform == 'win32':
959*90277196SAndroid Build Coastguard Worker                    if not Path.exists(directory):
960*90277196SAndroid Build Coastguard Worker                        os.makedirs(directory)
961*90277196SAndroid Build Coastguard Worker                shutil.copy(self.outFile.name, directory / self.genOpts.filename)
962*90277196SAndroid Build Coastguard Worker                os.remove(self.outFile.name)
963*90277196SAndroid Build Coastguard Worker        self.genOpts = None
964*90277196SAndroid Build Coastguard Worker
965*90277196SAndroid Build Coastguard Worker    def beginFeature(self, interface, emit):
966*90277196SAndroid Build Coastguard Worker        """Write interface for a feature and tag generated features as having been done.
967*90277196SAndroid Build Coastguard Worker
968*90277196SAndroid Build Coastguard Worker        - interface - element for the `<version>` / `<extension>` to generate
969*90277196SAndroid Build Coastguard Worker        - emit - actually write to the header only when True"""
970*90277196SAndroid Build Coastguard Worker        self.emit = emit
971*90277196SAndroid Build Coastguard Worker        self.featureName = interface.get('name')
972*90277196SAndroid Build Coastguard Worker        # If there is an additional 'protect' attribute in the feature, save it
973*90277196SAndroid Build Coastguard Worker        self.featureExtraProtect = interface.get('protect')
974*90277196SAndroid Build Coastguard Worker
975*90277196SAndroid Build Coastguard Worker    def endFeature(self):
976*90277196SAndroid Build Coastguard Worker        """Finish an interface file, closing it when done.
977*90277196SAndroid Build Coastguard Worker
978*90277196SAndroid Build Coastguard Worker        Derived classes responsible for emitting feature"""
979*90277196SAndroid Build Coastguard Worker        self.featureName = None
980*90277196SAndroid Build Coastguard Worker        self.featureExtraProtect = None
981*90277196SAndroid Build Coastguard Worker
982*90277196SAndroid Build Coastguard Worker    def genRequirements(self, name, mustBeFound = True, indent = 0):
983*90277196SAndroid Build Coastguard Worker        """Generate text showing what core versions and extensions introduce
984*90277196SAndroid Build Coastguard Worker        an API. This exists in the base Generator class because it is used by
985*90277196SAndroid Build Coastguard Worker        the shared enumerant-generating interfaces (buildEnumCDecl, etc.).
986*90277196SAndroid Build Coastguard Worker        Here it returns an empty string for most generators, but can be
987*90277196SAndroid Build Coastguard Worker        overridden by e.g. DocGenerator.
988*90277196SAndroid Build Coastguard Worker
989*90277196SAndroid Build Coastguard Worker        - name - name of the API
990*90277196SAndroid Build Coastguard Worker        - mustBeFound - If True, when requirements for 'name' cannot be
991*90277196SAndroid Build Coastguard Worker          determined, a warning comment is generated.
992*90277196SAndroid Build Coastguard Worker        """
993*90277196SAndroid Build Coastguard Worker
994*90277196SAndroid Build Coastguard Worker        return ''
995*90277196SAndroid Build Coastguard Worker
996*90277196SAndroid Build Coastguard Worker    def validateFeature(self, featureType, featureName):
997*90277196SAndroid Build Coastguard Worker        """Validate we are generating something only inside a `<feature>` tag"""
998*90277196SAndroid Build Coastguard Worker        if self.featureName is None:
999*90277196SAndroid Build Coastguard Worker            raise UserWarning('Attempt to generate', featureType,
1000*90277196SAndroid Build Coastguard Worker                              featureName, 'when not in feature')
1001*90277196SAndroid Build Coastguard Worker
1002*90277196SAndroid Build Coastguard Worker    def genType(self, typeinfo, name, alias):
1003*90277196SAndroid Build Coastguard Worker        """Generate interface for a type
1004*90277196SAndroid Build Coastguard Worker
1005*90277196SAndroid Build Coastguard Worker        - typeinfo - TypeInfo for a type
1006*90277196SAndroid Build Coastguard Worker
1007*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1008*90277196SAndroid Build Coastguard Worker        self.validateFeature('type', name)
1009*90277196SAndroid Build Coastguard Worker
1010*90277196SAndroid Build Coastguard Worker    def genStruct(self, typeinfo, typeName, alias):
1011*90277196SAndroid Build Coastguard Worker        """Generate interface for a C "struct" type.
1012*90277196SAndroid Build Coastguard Worker
1013*90277196SAndroid Build Coastguard Worker        - typeinfo - TypeInfo for a type interpreted as a struct
1014*90277196SAndroid Build Coastguard Worker
1015*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1016*90277196SAndroid Build Coastguard Worker        self.validateFeature('struct', typeName)
1017*90277196SAndroid Build Coastguard Worker
1018*90277196SAndroid Build Coastguard Worker        # The mixed-mode <member> tags may contain no-op <comment> tags.
1019*90277196SAndroid Build Coastguard Worker        # It is convenient to remove them here where all output generators
1020*90277196SAndroid Build Coastguard Worker        # will benefit.
1021*90277196SAndroid Build Coastguard Worker        for member in typeinfo.elem.findall('.//member'):
1022*90277196SAndroid Build Coastguard Worker            for comment in member.findall('comment'):
1023*90277196SAndroid Build Coastguard Worker                member.remove(comment)
1024*90277196SAndroid Build Coastguard Worker
1025*90277196SAndroid Build Coastguard Worker    def genGroup(self, groupinfo, groupName, alias):
1026*90277196SAndroid Build Coastguard Worker        """Generate interface for a group of enums (C "enum")
1027*90277196SAndroid Build Coastguard Worker
1028*90277196SAndroid Build Coastguard Worker        - groupinfo - GroupInfo for a group.
1029*90277196SAndroid Build Coastguard Worker
1030*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1031*90277196SAndroid Build Coastguard Worker
1032*90277196SAndroid Build Coastguard Worker        self.validateFeature('group', groupName)
1033*90277196SAndroid Build Coastguard Worker
1034*90277196SAndroid Build Coastguard Worker    def genEnum(self, enuminfo, typeName, alias):
1035*90277196SAndroid Build Coastguard Worker        """Generate interface for an enum (constant).
1036*90277196SAndroid Build Coastguard Worker
1037*90277196SAndroid Build Coastguard Worker        - enuminfo - EnumInfo for an enum
1038*90277196SAndroid Build Coastguard Worker        - name - enum name
1039*90277196SAndroid Build Coastguard Worker
1040*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1041*90277196SAndroid Build Coastguard Worker        self.validateFeature('enum', typeName)
1042*90277196SAndroid Build Coastguard Worker
1043*90277196SAndroid Build Coastguard Worker    def genCmd(self, cmd, cmdinfo, alias):
1044*90277196SAndroid Build Coastguard Worker        """Generate interface for a command.
1045*90277196SAndroid Build Coastguard Worker
1046*90277196SAndroid Build Coastguard Worker        - cmdinfo - CmdInfo for a command
1047*90277196SAndroid Build Coastguard Worker
1048*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1049*90277196SAndroid Build Coastguard Worker        self.validateFeature('command', cmdinfo)
1050*90277196SAndroid Build Coastguard Worker
1051*90277196SAndroid Build Coastguard Worker    def genSpirv(self, spirv, spirvinfo, alias):
1052*90277196SAndroid Build Coastguard Worker        """Generate interface for a spirv element.
1053*90277196SAndroid Build Coastguard Worker
1054*90277196SAndroid Build Coastguard Worker        - spirvinfo - SpirvInfo for a command
1055*90277196SAndroid Build Coastguard Worker
1056*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1057*90277196SAndroid Build Coastguard Worker        return
1058*90277196SAndroid Build Coastguard Worker
1059*90277196SAndroid Build Coastguard Worker    def genFormat(self, format, formatinfo, alias):
1060*90277196SAndroid Build Coastguard Worker        """Generate interface for a format element.
1061*90277196SAndroid Build Coastguard Worker
1062*90277196SAndroid Build Coastguard Worker        - formatinfo - FormatInfo
1063*90277196SAndroid Build Coastguard Worker
1064*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1065*90277196SAndroid Build Coastguard Worker        return
1066*90277196SAndroid Build Coastguard Worker
1067*90277196SAndroid Build Coastguard Worker    def genSyncStage(self, stageinfo):
1068*90277196SAndroid Build Coastguard Worker        """Generate interface for a sync stage element.
1069*90277196SAndroid Build Coastguard Worker
1070*90277196SAndroid Build Coastguard Worker        - stageinfo - SyncStageInfo
1071*90277196SAndroid Build Coastguard Worker
1072*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1073*90277196SAndroid Build Coastguard Worker        return
1074*90277196SAndroid Build Coastguard Worker
1075*90277196SAndroid Build Coastguard Worker    def genSyncAccess(self, accessinfo):
1076*90277196SAndroid Build Coastguard Worker        """Generate interface for a sync stage element.
1077*90277196SAndroid Build Coastguard Worker
1078*90277196SAndroid Build Coastguard Worker        - accessinfo - AccessInfo
1079*90277196SAndroid Build Coastguard Worker
1080*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1081*90277196SAndroid Build Coastguard Worker        return
1082*90277196SAndroid Build Coastguard Worker
1083*90277196SAndroid Build Coastguard Worker    def genSyncPipeline(self, pipelineinfo):
1084*90277196SAndroid Build Coastguard Worker        """Generate interface for a sync stage element.
1085*90277196SAndroid Build Coastguard Worker
1086*90277196SAndroid Build Coastguard Worker        - pipelineinfo - SyncPipelineInfo
1087*90277196SAndroid Build Coastguard Worker
1088*90277196SAndroid Build Coastguard Worker        Extend to generate as desired in your derived class."""
1089*90277196SAndroid Build Coastguard Worker        return
1090*90277196SAndroid Build Coastguard Worker
1091*90277196SAndroid Build Coastguard Worker    def makeProtoName(self, name, tail):
1092*90277196SAndroid Build Coastguard Worker        """Turn a `<proto>` `<name>` into C-language prototype
1093*90277196SAndroid Build Coastguard Worker        and typedef declarations for that name.
1094*90277196SAndroid Build Coastguard Worker
1095*90277196SAndroid Build Coastguard Worker        - name - contents of `<name>` tag
1096*90277196SAndroid Build Coastguard Worker        - tail - whatever text follows that tag in the Element"""
1097*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
1098*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
1099*90277196SAndroid Build Coastguard Worker        return self.genOpts.apientry + name + tail
1100*90277196SAndroid Build Coastguard Worker
1101*90277196SAndroid Build Coastguard Worker    def makeTypedefName(self, name, tail):
1102*90277196SAndroid Build Coastguard Worker        """Make the function-pointer typedef name for a command."""
1103*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
1104*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
1105*90277196SAndroid Build Coastguard Worker        return '(' + self.genOpts.apientryp + 'PFN_' + name + tail + ')'
1106*90277196SAndroid Build Coastguard Worker
1107*90277196SAndroid Build Coastguard Worker    def makeCParamDecl(self, param, aligncol):
1108*90277196SAndroid Build Coastguard Worker        """Return a string which is an indented, formatted
1109*90277196SAndroid Build Coastguard Worker        declaration for a `<param>` or `<member>` block (e.g. function parameter
1110*90277196SAndroid Build Coastguard Worker        or structure/union member).
1111*90277196SAndroid Build Coastguard Worker
1112*90277196SAndroid Build Coastguard Worker        - param - Element (`<param>` or `<member>`) to format
1113*90277196SAndroid Build Coastguard Worker        - aligncol - if non-zero, attempt to align the nested `<name>` element
1114*90277196SAndroid Build Coastguard Worker          at this column"""
1115*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
1116*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
1117*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions is None:
1118*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsConventionsError()
1119*90277196SAndroid Build Coastguard Worker        indent = '    '
1120*90277196SAndroid Build Coastguard Worker        paramdecl = indent
1121*90277196SAndroid Build Coastguard Worker        prefix = noneStr(param.text)
1122*90277196SAndroid Build Coastguard Worker
1123*90277196SAndroid Build Coastguard Worker        for elem in param:
1124*90277196SAndroid Build Coastguard Worker            text = noneStr(elem.text)
1125*90277196SAndroid Build Coastguard Worker            tail = noneStr(elem.tail)
1126*90277196SAndroid Build Coastguard Worker
1127*90277196SAndroid Build Coastguard Worker            if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
1128*90277196SAndroid Build Coastguard Worker                # OpenXR-specific macro insertion - but not in apiinc for the spec
1129*90277196SAndroid Build Coastguard Worker                tail = self.genOpts.conventions.make_voidpointer_alias(tail)
1130*90277196SAndroid Build Coastguard Worker            if elem.tag == 'name' and aligncol > 0:
1131*90277196SAndroid Build Coastguard Worker                self.logMsg('diag', 'Aligning parameter', elem.text, 'to column', self.genOpts.alignFuncParam)
1132*90277196SAndroid Build Coastguard Worker                # Align at specified column, if possible
1133*90277196SAndroid Build Coastguard Worker                paramdecl = paramdecl.rstrip()
1134*90277196SAndroid Build Coastguard Worker                oldLen = len(paramdecl)
1135*90277196SAndroid Build Coastguard Worker                # This works around a problem where very long type names -
1136*90277196SAndroid Build Coastguard Worker                # longer than the alignment column - would run into the tail
1137*90277196SAndroid Build Coastguard Worker                # text.
1138*90277196SAndroid Build Coastguard Worker                paramdecl = paramdecl.ljust(aligncol - 1) + ' '
1139*90277196SAndroid Build Coastguard Worker                newLen = len(paramdecl)
1140*90277196SAndroid Build Coastguard Worker                self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
1141*90277196SAndroid Build Coastguard Worker
1142*90277196SAndroid Build Coastguard Worker            if (self.misracppstyle() and prefix.find('const ') != -1):
1143*90277196SAndroid Build Coastguard Worker                # Change pointer type order from e.g. "const void *" to "void const *".
1144*90277196SAndroid Build Coastguard Worker                # If the string starts with 'const', reorder it to be after the first type.
1145*90277196SAndroid Build Coastguard Worker                paramdecl += prefix.replace('const ', '') + text + ' const' + tail
1146*90277196SAndroid Build Coastguard Worker            else:
1147*90277196SAndroid Build Coastguard Worker                paramdecl += prefix + text + tail
1148*90277196SAndroid Build Coastguard Worker
1149*90277196SAndroid Build Coastguard Worker            # Clear prefix for subsequent iterations
1150*90277196SAndroid Build Coastguard Worker            prefix = ''
1151*90277196SAndroid Build Coastguard Worker
1152*90277196SAndroid Build Coastguard Worker        paramdecl = paramdecl + prefix
1153*90277196SAndroid Build Coastguard Worker
1154*90277196SAndroid Build Coastguard Worker        if aligncol == 0:
1155*90277196SAndroid Build Coastguard Worker            # Squeeze out multiple spaces other than the indentation
1156*90277196SAndroid Build Coastguard Worker            paramdecl = indent + ' '.join(paramdecl.split())
1157*90277196SAndroid Build Coastguard Worker        return paramdecl
1158*90277196SAndroid Build Coastguard Worker
1159*90277196SAndroid Build Coastguard Worker    def getCParamTypeLength(self, param):
1160*90277196SAndroid Build Coastguard Worker        """Return the length of the type field is an indented, formatted
1161*90277196SAndroid Build Coastguard Worker        declaration for a `<param>` or `<member>` block (e.g. function parameter
1162*90277196SAndroid Build Coastguard Worker        or structure/union member).
1163*90277196SAndroid Build Coastguard Worker
1164*90277196SAndroid Build Coastguard Worker        - param - Element (`<param>` or `<member>`) to identify"""
1165*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
1166*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
1167*90277196SAndroid Build Coastguard Worker        if self.genOpts.conventions is None:
1168*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsConventionsError()
1169*90277196SAndroid Build Coastguard Worker
1170*90277196SAndroid Build Coastguard Worker        # Allow for missing <name> tag
1171*90277196SAndroid Build Coastguard Worker        newLen = 0
1172*90277196SAndroid Build Coastguard Worker        paramdecl = '    ' + noneStr(param.text)
1173*90277196SAndroid Build Coastguard Worker        for elem in param:
1174*90277196SAndroid Build Coastguard Worker            text = noneStr(elem.text)
1175*90277196SAndroid Build Coastguard Worker            tail = noneStr(elem.tail)
1176*90277196SAndroid Build Coastguard Worker
1177*90277196SAndroid Build Coastguard Worker            if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
1178*90277196SAndroid Build Coastguard Worker                # OpenXR-specific macro insertion
1179*90277196SAndroid Build Coastguard Worker                tail = self.genOpts.conventions.make_voidpointer_alias(tail)
1180*90277196SAndroid Build Coastguard Worker            if elem.tag == 'name':
1181*90277196SAndroid Build Coastguard Worker                # Align at specified column, if possible
1182*90277196SAndroid Build Coastguard Worker                newLen = len(paramdecl.rstrip())
1183*90277196SAndroid Build Coastguard Worker                self.logMsg('diag', 'Identifying length of', elem.text, 'as', newLen)
1184*90277196SAndroid Build Coastguard Worker            paramdecl += text + tail
1185*90277196SAndroid Build Coastguard Worker
1186*90277196SAndroid Build Coastguard Worker        return newLen
1187*90277196SAndroid Build Coastguard Worker
1188*90277196SAndroid Build Coastguard Worker    def getMaxCParamTypeLength(self, info):
1189*90277196SAndroid Build Coastguard Worker        """Return the length of the longest type field for a member/parameter.
1190*90277196SAndroid Build Coastguard Worker
1191*90277196SAndroid Build Coastguard Worker        - info - TypeInfo or CommandInfo.
1192*90277196SAndroid Build Coastguard Worker        """
1193*90277196SAndroid Build Coastguard Worker        lengths = (self.getCParamTypeLength(member)
1194*90277196SAndroid Build Coastguard Worker                   for member in info.getMembers())
1195*90277196SAndroid Build Coastguard Worker        return max(lengths)
1196*90277196SAndroid Build Coastguard Worker
1197*90277196SAndroid Build Coastguard Worker    def getHandleParent(self, typename):
1198*90277196SAndroid Build Coastguard Worker        """Get the parent of a handle object."""
1199*90277196SAndroid Build Coastguard Worker        if self.registry is None:
1200*90277196SAndroid Build Coastguard Worker            raise MissingRegistryError()
1201*90277196SAndroid Build Coastguard Worker
1202*90277196SAndroid Build Coastguard Worker        info = self.registry.typedict.get(typename)
1203*90277196SAndroid Build Coastguard Worker        if info is None:
1204*90277196SAndroid Build Coastguard Worker            return None
1205*90277196SAndroid Build Coastguard Worker
1206*90277196SAndroid Build Coastguard Worker        elem = info.elem
1207*90277196SAndroid Build Coastguard Worker        if elem is not None:
1208*90277196SAndroid Build Coastguard Worker            return elem.get('parent')
1209*90277196SAndroid Build Coastguard Worker
1210*90277196SAndroid Build Coastguard Worker        return None
1211*90277196SAndroid Build Coastguard Worker
1212*90277196SAndroid Build Coastguard Worker    def iterateHandleAncestors(self, typename):
1213*90277196SAndroid Build Coastguard Worker        """Iterate through the ancestors of a handle type."""
1214*90277196SAndroid Build Coastguard Worker        current = self.getHandleParent(typename)
1215*90277196SAndroid Build Coastguard Worker        while current is not None:
1216*90277196SAndroid Build Coastguard Worker            yield current
1217*90277196SAndroid Build Coastguard Worker            current = self.getHandleParent(current)
1218*90277196SAndroid Build Coastguard Worker
1219*90277196SAndroid Build Coastguard Worker    def getHandleAncestors(self, typename):
1220*90277196SAndroid Build Coastguard Worker        """Get the ancestors of a handle object."""
1221*90277196SAndroid Build Coastguard Worker        return list(self.iterateHandleAncestors(typename))
1222*90277196SAndroid Build Coastguard Worker
1223*90277196SAndroid Build Coastguard Worker    def getTypeCategory(self, typename):
1224*90277196SAndroid Build Coastguard Worker        """Get the category of a type."""
1225*90277196SAndroid Build Coastguard Worker        if self.registry is None:
1226*90277196SAndroid Build Coastguard Worker            raise MissingRegistryError()
1227*90277196SAndroid Build Coastguard Worker
1228*90277196SAndroid Build Coastguard Worker        info = self.registry.typedict.get(typename)
1229*90277196SAndroid Build Coastguard Worker        if info is None:
1230*90277196SAndroid Build Coastguard Worker            return None
1231*90277196SAndroid Build Coastguard Worker
1232*90277196SAndroid Build Coastguard Worker        elem = info.elem
1233*90277196SAndroid Build Coastguard Worker        if elem is not None:
1234*90277196SAndroid Build Coastguard Worker            return elem.get('category')
1235*90277196SAndroid Build Coastguard Worker        return None
1236*90277196SAndroid Build Coastguard Worker
1237*90277196SAndroid Build Coastguard Worker    def isStructAlwaysValid(self, structname):
1238*90277196SAndroid Build Coastguard Worker        """Try to do check if a structure is always considered valid (i.e. there is no rules to its acceptance)."""
1239*90277196SAndroid Build Coastguard Worker        # A conventions object is required for this call.
1240*90277196SAndroid Build Coastguard Worker        if not self.conventions:
1241*90277196SAndroid Build Coastguard Worker            raise RuntimeError("To use isStructAlwaysValid, be sure your options include a Conventions object.")
1242*90277196SAndroid Build Coastguard Worker        if self.registry is None:
1243*90277196SAndroid Build Coastguard Worker            raise MissingRegistryError()
1244*90277196SAndroid Build Coastguard Worker
1245*90277196SAndroid Build Coastguard Worker        if self.conventions.type_always_valid(structname):
1246*90277196SAndroid Build Coastguard Worker            return True
1247*90277196SAndroid Build Coastguard Worker
1248*90277196SAndroid Build Coastguard Worker        category = self.getTypeCategory(structname)
1249*90277196SAndroid Build Coastguard Worker        if self.conventions.category_requires_validation(category):
1250*90277196SAndroid Build Coastguard Worker            return False
1251*90277196SAndroid Build Coastguard Worker
1252*90277196SAndroid Build Coastguard Worker        info = self.registry.typedict.get(structname)
1253*90277196SAndroid Build Coastguard Worker        if info is None:
1254*90277196SAndroid Build Coastguard Worker            self.logMsg('error', f'isStructAlwaysValid({structname}) - structure not found in typedict')
1255*90277196SAndroid Build Coastguard Worker
1256*90277196SAndroid Build Coastguard Worker        members = info.getMembers()
1257*90277196SAndroid Build Coastguard Worker
1258*90277196SAndroid Build Coastguard Worker        for member in members:
1259*90277196SAndroid Build Coastguard Worker            member_name = getElemName(member)
1260*90277196SAndroid Build Coastguard Worker            if member_name in (self.conventions.structtype_member_name,
1261*90277196SAndroid Build Coastguard Worker                               self.conventions.nextpointer_member_name):
1262*90277196SAndroid Build Coastguard Worker                return False
1263*90277196SAndroid Build Coastguard Worker
1264*90277196SAndroid Build Coastguard Worker            if member.get('noautovalidity'):
1265*90277196SAndroid Build Coastguard Worker                return False
1266*90277196SAndroid Build Coastguard Worker
1267*90277196SAndroid Build Coastguard Worker            member_type = getElemType(member)
1268*90277196SAndroid Build Coastguard Worker
1269*90277196SAndroid Build Coastguard Worker            if member_type in ('void', 'char') or self.paramIsArray(member) or self.paramIsPointer(member):
1270*90277196SAndroid Build Coastguard Worker                return False
1271*90277196SAndroid Build Coastguard Worker
1272*90277196SAndroid Build Coastguard Worker            if self.conventions.type_always_valid(member_type):
1273*90277196SAndroid Build Coastguard Worker                continue
1274*90277196SAndroid Build Coastguard Worker
1275*90277196SAndroid Build Coastguard Worker            member_category = self.getTypeCategory(member_type)
1276*90277196SAndroid Build Coastguard Worker
1277*90277196SAndroid Build Coastguard Worker            if self.conventions.category_requires_validation(member_category):
1278*90277196SAndroid Build Coastguard Worker                return False
1279*90277196SAndroid Build Coastguard Worker
1280*90277196SAndroid Build Coastguard Worker            if member_category in ('struct', 'union'):
1281*90277196SAndroid Build Coastguard Worker                if self.isStructAlwaysValid(member_type) is False:
1282*90277196SAndroid Build Coastguard Worker                    return False
1283*90277196SAndroid Build Coastguard Worker
1284*90277196SAndroid Build Coastguard Worker        return True
1285*90277196SAndroid Build Coastguard Worker
1286*90277196SAndroid Build Coastguard Worker    def paramIsArray(self, param):
1287*90277196SAndroid Build Coastguard Worker        """Check if the parameter passed in is a pointer to an array.
1288*90277196SAndroid Build Coastguard Worker
1289*90277196SAndroid Build Coastguard Worker        param           the XML information for the param
1290*90277196SAndroid Build Coastguard Worker        """
1291*90277196SAndroid Build Coastguard Worker        return param.get('len') is not None
1292*90277196SAndroid Build Coastguard Worker
1293*90277196SAndroid Build Coastguard Worker    def paramIsPointer(self, param):
1294*90277196SAndroid Build Coastguard Worker        """Check if the parameter passed in is a pointer.
1295*90277196SAndroid Build Coastguard Worker
1296*90277196SAndroid Build Coastguard Worker        param           the XML information for the param
1297*90277196SAndroid Build Coastguard Worker        """
1298*90277196SAndroid Build Coastguard Worker        tail = param.find('type').tail
1299*90277196SAndroid Build Coastguard Worker        return tail is not None and '*' in tail
1300*90277196SAndroid Build Coastguard Worker
1301*90277196SAndroid Build Coastguard Worker    def isEnumRequired(self, elem):
1302*90277196SAndroid Build Coastguard Worker        """Return True if this `<enum>` element is
1303*90277196SAndroid Build Coastguard Worker        required, False otherwise
1304*90277196SAndroid Build Coastguard Worker
1305*90277196SAndroid Build Coastguard Worker        - elem - `<enum>` element to test"""
1306*90277196SAndroid Build Coastguard Worker        required = elem.get('required') is not None
1307*90277196SAndroid Build Coastguard Worker        self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
1308*90277196SAndroid Build Coastguard Worker                    '->', required)
1309*90277196SAndroid Build Coastguard Worker        return required
1310*90277196SAndroid Build Coastguard Worker
1311*90277196SAndroid Build Coastguard Worker        # @@@ This code is overridden by equivalent code now run in
1312*90277196SAndroid Build Coastguard Worker        # @@@ Registry.generateFeature
1313*90277196SAndroid Build Coastguard Worker
1314*90277196SAndroid Build Coastguard Worker        required = False
1315*90277196SAndroid Build Coastguard Worker
1316*90277196SAndroid Build Coastguard Worker        extname = elem.get('extname')
1317*90277196SAndroid Build Coastguard Worker        if extname is not None:
1318*90277196SAndroid Build Coastguard Worker            # 'supported' attribute was injected when the <enum> element was
1319*90277196SAndroid Build Coastguard Worker            # moved into the <enums> group in Registry.parseTree()
1320*90277196SAndroid Build Coastguard Worker            if self.genOpts.defaultExtensions == elem.get('supported'):
1321*90277196SAndroid Build Coastguard Worker                required = True
1322*90277196SAndroid Build Coastguard Worker            elif re.match(self.genOpts.addExtensions, extname) is not None:
1323*90277196SAndroid Build Coastguard Worker                required = True
1324*90277196SAndroid Build Coastguard Worker        elif elem.get('version') is not None:
1325*90277196SAndroid Build Coastguard Worker            required = re.match(self.genOpts.emitversions, elem.get('version')) is not None
1326*90277196SAndroid Build Coastguard Worker        else:
1327*90277196SAndroid Build Coastguard Worker            required = True
1328*90277196SAndroid Build Coastguard Worker
1329*90277196SAndroid Build Coastguard Worker        return required
1330*90277196SAndroid Build Coastguard Worker
1331*90277196SAndroid Build Coastguard Worker    def makeCDecls(self, cmd):
1332*90277196SAndroid Build Coastguard Worker        """Return C prototype and function pointer typedef for a
1333*90277196SAndroid Build Coastguard Worker        `<command>` Element, as a two-element list of strings.
1334*90277196SAndroid Build Coastguard Worker
1335*90277196SAndroid Build Coastguard Worker        - cmd - Element containing a `<command>` tag"""
1336*90277196SAndroid Build Coastguard Worker        if self.genOpts is None:
1337*90277196SAndroid Build Coastguard Worker            raise MissingGeneratorOptionsError()
1338*90277196SAndroid Build Coastguard Worker        proto = cmd.find('proto')
1339*90277196SAndroid Build Coastguard Worker        params = cmd.findall('param')
1340*90277196SAndroid Build Coastguard Worker        # Begin accumulating prototype and typedef strings
1341*90277196SAndroid Build Coastguard Worker        pdecl = self.genOpts.apicall
1342*90277196SAndroid Build Coastguard Worker        tdecl = 'typedef '
1343*90277196SAndroid Build Coastguard Worker
1344*90277196SAndroid Build Coastguard Worker        # Insert the function return type/name.
1345*90277196SAndroid Build Coastguard Worker        # For prototypes, add APIENTRY macro before the name
1346*90277196SAndroid Build Coastguard Worker        # For typedefs, add (APIENTRY *<name>) around the name and
1347*90277196SAndroid Build Coastguard Worker        #   use the PFN_cmdnameproc naming convention.
1348*90277196SAndroid Build Coastguard Worker        # Done by walking the tree for <proto> element by element.
1349*90277196SAndroid Build Coastguard Worker        # etree has elem.text followed by (elem[i], elem[i].tail)
1350*90277196SAndroid Build Coastguard Worker        #   for each child element and any following text
1351*90277196SAndroid Build Coastguard Worker        # Leading text
1352*90277196SAndroid Build Coastguard Worker        pdecl += noneStr(proto.text)
1353*90277196SAndroid Build Coastguard Worker        tdecl += noneStr(proto.text)
1354*90277196SAndroid Build Coastguard Worker        # For each child element, if it is a <name> wrap in appropriate
1355*90277196SAndroid Build Coastguard Worker        # declaration. Otherwise append its contents and tail contents.
1356*90277196SAndroid Build Coastguard Worker        for elem in proto:
1357*90277196SAndroid Build Coastguard Worker            text = noneStr(elem.text)
1358*90277196SAndroid Build Coastguard Worker            tail = noneStr(elem.tail)
1359*90277196SAndroid Build Coastguard Worker            if elem.tag == 'name':
1360*90277196SAndroid Build Coastguard Worker                pdecl += self.makeProtoName(text, tail)
1361*90277196SAndroid Build Coastguard Worker                tdecl += self.makeTypedefName(text, tail)
1362*90277196SAndroid Build Coastguard Worker            else:
1363*90277196SAndroid Build Coastguard Worker                pdecl += text + tail
1364*90277196SAndroid Build Coastguard Worker                tdecl += text + tail
1365*90277196SAndroid Build Coastguard Worker
1366*90277196SAndroid Build Coastguard Worker        if self.genOpts.alignFuncParam == 0:
1367*90277196SAndroid Build Coastguard Worker            # Squeeze out multiple spaces - there is no indentation
1368*90277196SAndroid Build Coastguard Worker            pdecl = ' '.join(pdecl.split())
1369*90277196SAndroid Build Coastguard Worker            tdecl = ' '.join(tdecl.split())
1370*90277196SAndroid Build Coastguard Worker
1371*90277196SAndroid Build Coastguard Worker        # Now add the parameter declaration list, which is identical
1372*90277196SAndroid Build Coastguard Worker        # for prototypes and typedefs. Concatenate all the text from
1373*90277196SAndroid Build Coastguard Worker        # a <param> node without the tags. No tree walking required
1374*90277196SAndroid Build Coastguard Worker        # since all tags are ignored.
1375*90277196SAndroid Build Coastguard Worker        # Uses: self.indentFuncProto
1376*90277196SAndroid Build Coastguard Worker        # self.indentFuncPointer
1377*90277196SAndroid Build Coastguard Worker        # self.alignFuncParam
1378*90277196SAndroid Build Coastguard Worker        n = len(params)
1379*90277196SAndroid Build Coastguard Worker        # Indented parameters
1380*90277196SAndroid Build Coastguard Worker        if n > 0:
1381*90277196SAndroid Build Coastguard Worker            indentdecl = '(\n'
1382*90277196SAndroid Build Coastguard Worker            indentdecl += ',\n'.join(self.makeCParamDecl(p, self.genOpts.alignFuncParam)
1383*90277196SAndroid Build Coastguard Worker                                     for p in params)
1384*90277196SAndroid Build Coastguard Worker            indentdecl += ');'
1385*90277196SAndroid Build Coastguard Worker        else:
1386*90277196SAndroid Build Coastguard Worker            indentdecl = '(void);'
1387*90277196SAndroid Build Coastguard Worker        # Non-indented parameters
1388*90277196SAndroid Build Coastguard Worker        paramdecl = '('
1389*90277196SAndroid Build Coastguard Worker        if n > 0:
1390*90277196SAndroid Build Coastguard Worker            paramnames = []
1391*90277196SAndroid Build Coastguard Worker            if self.misracppstyle():
1392*90277196SAndroid Build Coastguard Worker                for p in params:
1393*90277196SAndroid Build Coastguard Worker                    param = ''
1394*90277196SAndroid Build Coastguard Worker                    firstIter = True;
1395*90277196SAndroid Build Coastguard Worker                    for t in p.itertext():
1396*90277196SAndroid Build Coastguard Worker                        if (firstIter):
1397*90277196SAndroid Build Coastguard Worker                            prefix = t
1398*90277196SAndroid Build Coastguard Worker                            firstIter = False
1399*90277196SAndroid Build Coastguard Worker                        else:
1400*90277196SAndroid Build Coastguard Worker                            # Change pointer type order from e.g. "const void *" to "void const *".
1401*90277196SAndroid Build Coastguard Worker                            # If the string starts with 'const', reorder it to be after the first type.
1402*90277196SAndroid Build Coastguard Worker                            if (prefix.find('const ') != -1):
1403*90277196SAndroid Build Coastguard Worker                                param += prefix.replace('const ', '') + t + ' const '
1404*90277196SAndroid Build Coastguard Worker                            else:
1405*90277196SAndroid Build Coastguard Worker                                param += prefix + t
1406*90277196SAndroid Build Coastguard Worker                            # Clear prefix for subsequent iterations
1407*90277196SAndroid Build Coastguard Worker                            prefix = ''
1408*90277196SAndroid Build Coastguard Worker                    paramnames.append(param);
1409*90277196SAndroid Build Coastguard Worker            else:
1410*90277196SAndroid Build Coastguard Worker                paramnames = (''.join(t for t in p.itertext())
1411*90277196SAndroid Build Coastguard Worker                              for p in params)
1412*90277196SAndroid Build Coastguard Worker            paramdecl += ', '.join(paramnames)
1413*90277196SAndroid Build Coastguard Worker        else:
1414*90277196SAndroid Build Coastguard Worker            paramdecl += 'void'
1415*90277196SAndroid Build Coastguard Worker        paramdecl += ");"
1416*90277196SAndroid Build Coastguard Worker        return [pdecl + indentdecl, tdecl + paramdecl]
1417*90277196SAndroid Build Coastguard Worker
1418*90277196SAndroid Build Coastguard Worker    def newline(self):
1419*90277196SAndroid Build Coastguard Worker        """Print a newline to the output file (utility function)"""
1420*90277196SAndroid Build Coastguard Worker        write('', file=self.outFile)
1421*90277196SAndroid Build Coastguard Worker
1422*90277196SAndroid Build Coastguard Worker    def setRegistry(self, registry):
1423*90277196SAndroid Build Coastguard Worker        self.registry = registry
1424