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