1e5c31af7Sopenharmony_ci#!/usr/bin/python3 -i
2e5c31af7Sopenharmony_ci#
3e5c31af7Sopenharmony_ci# Copyright 2013-2024 The Khronos Group Inc.
4e5c31af7Sopenharmony_ci#
5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
6e5c31af7Sopenharmony_ci
7e5c31af7Sopenharmony_cifrom pathlib import Path
8e5c31af7Sopenharmony_ci
9e5c31af7Sopenharmony_cifrom generator import GeneratorOptions, OutputGenerator, noneStr, write
10e5c31af7Sopenharmony_cifrom parse_dependency import dependencyLanguageComment
11e5c31af7Sopenharmony_ci
12e5c31af7Sopenharmony_ci_ENUM_TABLE_PREFIX = """
13e5c31af7Sopenharmony_ci[cols=",",options="header",]
14e5c31af7Sopenharmony_ci|====
15e5c31af7Sopenharmony_ci|Enum |Description"""
16e5c31af7Sopenharmony_ci
17e5c31af7Sopenharmony_ci_TABLE_SUFFIX = """|===="""
18e5c31af7Sopenharmony_ci
19e5c31af7Sopenharmony_ci_ENUM_BLOCK_PREFIX = """.Enumerant Descriptions
20e5c31af7Sopenharmony_ci****"""
21e5c31af7Sopenharmony_ci
22e5c31af7Sopenharmony_ci_FLAG_BLOCK_PREFIX = """.Flag Descriptions
23e5c31af7Sopenharmony_ci****"""
24e5c31af7Sopenharmony_ci
25e5c31af7Sopenharmony_ci_BLOCK_SUFFIX = """****"""
26e5c31af7Sopenharmony_ci
27e5c31af7Sopenharmony_cidef orgLevelKey(name):
28e5c31af7Sopenharmony_ci    # Sort key for organization levels of features / extensions
29e5c31af7Sopenharmony_ci    # From highest to lowest, core versions, KHR extensions, EXT extensions,
30e5c31af7Sopenharmony_ci    # and vendor extensions
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_ci    prefixes = (
33e5c31af7Sopenharmony_ci        'VK_VERSION_',
34e5c31af7Sopenharmony_ci        'VKSC_VERSION_',
35e5c31af7Sopenharmony_ci        'VK_KHR_',
36e5c31af7Sopenharmony_ci        'VK_EXT_')
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ci    i = 0
39e5c31af7Sopenharmony_ci    for prefix in prefixes:
40e5c31af7Sopenharmony_ci        if name.startswith(prefix):
41e5c31af7Sopenharmony_ci            return i
42e5c31af7Sopenharmony_ci        i += 1
43e5c31af7Sopenharmony_ci
44e5c31af7Sopenharmony_ci    # Everything else (e.g. vendor extensions) is least important
45e5c31af7Sopenharmony_ci    return i
46e5c31af7Sopenharmony_ci
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_ciclass DocGeneratorOptions(GeneratorOptions):
49e5c31af7Sopenharmony_ci    """DocGeneratorOptions - subclass of GeneratorOptions for
50e5c31af7Sopenharmony_ci    generating declaration snippets for the spec.
51e5c31af7Sopenharmony_ci
52e5c31af7Sopenharmony_ci    Shares many members with CGeneratorOptions, since
53e5c31af7Sopenharmony_ci    both are writing C-style declarations."""
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_ci    def __init__(self,
56e5c31af7Sopenharmony_ci                 prefixText="",
57e5c31af7Sopenharmony_ci                 apicall='',
58e5c31af7Sopenharmony_ci                 apientry='',
59e5c31af7Sopenharmony_ci                 apientryp='',
60e5c31af7Sopenharmony_ci                 indentFuncProto=True,
61e5c31af7Sopenharmony_ci                 indentFuncPointer=False,
62e5c31af7Sopenharmony_ci                 alignFuncParam=0,
63e5c31af7Sopenharmony_ci                 secondaryInclude=False,
64e5c31af7Sopenharmony_ci                 expandEnumerants=True,
65e5c31af7Sopenharmony_ci                 extEnumerantAdditions=False,
66e5c31af7Sopenharmony_ci                 extEnumerantFormatString=" (Added by the {} extension)",
67e5c31af7Sopenharmony_ci                 **kwargs):
68e5c31af7Sopenharmony_ci        """Constructor.
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_ci        Since this generator outputs multiple files at once,
71e5c31af7Sopenharmony_ci        the filename is just a "stamp" to indicate last generation time.
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci        Shares many parameters/members with CGeneratorOptions, since
74e5c31af7Sopenharmony_ci        both are writing C-style declarations:
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci        - prefixText - list of strings to prefix generated header with
77e5c31af7Sopenharmony_ci        (usually a copyright statement + calling convention macros).
78e5c31af7Sopenharmony_ci        - apicall - string to use for the function declaration prefix,
79e5c31af7Sopenharmony_ci        such as APICALL on Windows.
80e5c31af7Sopenharmony_ci        - apientry - string to use for the calling convention macro,
81e5c31af7Sopenharmony_ci        in typedefs, such as APIENTRY.
82e5c31af7Sopenharmony_ci        - apientryp - string to use for the calling convention macro
83e5c31af7Sopenharmony_ci        in function pointer typedefs, such as APIENTRYP.
84e5c31af7Sopenharmony_ci        - indentFuncProto - True if prototype declarations should put each
85e5c31af7Sopenharmony_ci        parameter on a separate line
86e5c31af7Sopenharmony_ci        - indentFuncPointer - True if typedefed function pointers should put each
87e5c31af7Sopenharmony_ci        parameter on a separate line
88e5c31af7Sopenharmony_ci        - alignFuncParam - if nonzero and parameters are being put on a
89e5c31af7Sopenharmony_ci        separate line, align parameter names at the specified column
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci        Additional parameters/members:
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ci        - expandEnumerants - if True, add BEGIN/END_RANGE macros in enumerated
94e5c31af7Sopenharmony_ci        type declarations
95e5c31af7Sopenharmony_ci        - secondaryInclude - if True, add secondary (no xref anchor) versions
96e5c31af7Sopenharmony_ci        of generated files
97e5c31af7Sopenharmony_ci        - extEnumerantAdditions - if True, include enumerants added by extensions
98e5c31af7Sopenharmony_ci        in comment tables for core enumeration types.
99e5c31af7Sopenharmony_ci        - extEnumerantFormatString - A format string for any additional message for
100e5c31af7Sopenharmony_ci        enumerants from extensions if extEnumerantAdditions is True. The correctly-
101e5c31af7Sopenharmony_ci        marked-up extension name will be passed.
102e5c31af7Sopenharmony_ci        """
103e5c31af7Sopenharmony_ci        GeneratorOptions.__init__(self, **kwargs)
104e5c31af7Sopenharmony_ci        self.prefixText = prefixText
105e5c31af7Sopenharmony_ci        """list of strings to prefix generated header with (usually a copyright statement + calling convention macros)."""
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ci        self.apicall = apicall
108e5c31af7Sopenharmony_ci        """string to use for the function declaration prefix, such as APICALL on Windows."""
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci        self.apientry = apientry
111e5c31af7Sopenharmony_ci        """string to use for the calling convention macro, in typedefs, such as APIENTRY."""
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci        self.apientryp = apientryp
114e5c31af7Sopenharmony_ci        """string to use for the calling convention macro in function pointer typedefs, such as APIENTRYP."""
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ci        self.indentFuncProto = indentFuncProto
117e5c31af7Sopenharmony_ci        """True if prototype declarations should put each parameter on a separate line"""
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci        self.indentFuncPointer = indentFuncPointer
120e5c31af7Sopenharmony_ci        """True if typedefed function pointers should put each parameter on a separate line"""
121e5c31af7Sopenharmony_ci
122e5c31af7Sopenharmony_ci        self.alignFuncParam = alignFuncParam
123e5c31af7Sopenharmony_ci        """if nonzero and parameters are being put on a separate line, align parameter names at the specified column"""
124e5c31af7Sopenharmony_ci
125e5c31af7Sopenharmony_ci        self.secondaryInclude = secondaryInclude
126e5c31af7Sopenharmony_ci        """if True, add secondary (no xref anchor) versions of generated files"""
127e5c31af7Sopenharmony_ci
128e5c31af7Sopenharmony_ci        self.expandEnumerants = expandEnumerants
129e5c31af7Sopenharmony_ci        """if True, add BEGIN/END_RANGE macros in enumerated type declarations"""
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci        self.extEnumerantAdditions = extEnumerantAdditions
132e5c31af7Sopenharmony_ci        """if True, include enumerants added by extensions in comment tables for core enumeration types."""
133e5c31af7Sopenharmony_ci
134e5c31af7Sopenharmony_ci        self.extEnumerantFormatString = extEnumerantFormatString
135e5c31af7Sopenharmony_ci        """A format string for any additional message for
136e5c31af7Sopenharmony_ci        enumerants from extensions if extEnumerantAdditions is True. The correctly-
137e5c31af7Sopenharmony_ci        marked-up extension name will be passed."""
138e5c31af7Sopenharmony_ci
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ciclass DocOutputGenerator(OutputGenerator):
141e5c31af7Sopenharmony_ci    """DocOutputGenerator - subclass of OutputGenerator.
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci    Generates AsciiDoc includes with C-language API interfaces, for reference
144e5c31af7Sopenharmony_ci    pages and the corresponding specification. Similar to COutputGenerator,
145e5c31af7Sopenharmony_ci    but each interface is written into a different file as determined by the
146e5c31af7Sopenharmony_ci    options, only actual C types are emitted, and none of the boilerplate
147e5c31af7Sopenharmony_ci    preprocessor code is emitted."""
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci    def __init__(self, *args, **kwargs):
150e5c31af7Sopenharmony_ci        super().__init__(*args, **kwargs)
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci    def beginFile(self, genOpts):
153e5c31af7Sopenharmony_ci        OutputGenerator.beginFile(self, genOpts)
154e5c31af7Sopenharmony_ci
155e5c31af7Sopenharmony_ci        # This should be a separate conventions property rather than an
156e5c31af7Sopenharmony_ci        # inferred type name pattern for different APIs.
157e5c31af7Sopenharmony_ci        self.result_type = genOpts.conventions.type_prefix + "Result"
158e5c31af7Sopenharmony_ci
159e5c31af7Sopenharmony_ci    def endFile(self):
160e5c31af7Sopenharmony_ci        OutputGenerator.endFile(self)
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci    def beginFeature(self, interface, emit):
163e5c31af7Sopenharmony_ci        # Start processing in superclass
164e5c31af7Sopenharmony_ci        OutputGenerator.beginFeature(self, interface, emit)
165e5c31af7Sopenharmony_ci
166e5c31af7Sopenharmony_ci        # Decide if we are in a core <feature> or an <extension>
167e5c31af7Sopenharmony_ci        self.in_core = (interface.tag == 'feature')
168e5c31af7Sopenharmony_ci
169e5c31af7Sopenharmony_ci    def endFeature(self):
170e5c31af7Sopenharmony_ci        # Finish processing in superclass
171e5c31af7Sopenharmony_ci        OutputGenerator.endFeature(self)
172e5c31af7Sopenharmony_ci
173e5c31af7Sopenharmony_ci    def genRequirements(self, name, mustBeFound = True):
174e5c31af7Sopenharmony_ci        """Generate text showing what core versions and extensions introduce
175e5c31af7Sopenharmony_ci        an API. This relies on the map in apimap.py, which may be loaded at
176e5c31af7Sopenharmony_ci        runtime into self.apidict. If not present, no message is
177e5c31af7Sopenharmony_ci        generated.
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_ci        - name - name of the API
180e5c31af7Sopenharmony_ci        - mustBeFound - If True, when requirements for 'name' cannot be
181e5c31af7Sopenharmony_ci          determined, a warning comment is generated.
182e5c31af7Sopenharmony_ci        """
183e5c31af7Sopenharmony_ci
184e5c31af7Sopenharmony_ci        if self.apidict:
185e5c31af7Sopenharmony_ci            if name in self.apidict.requiredBy:
186e5c31af7Sopenharmony_ci                # It is possible to get both 'A with B' and 'B with A' for
187e5c31af7Sopenharmony_ci                # the same API.
188e5c31af7Sopenharmony_ci                # To simplify this, sort the (base,dependency) requirements
189e5c31af7Sopenharmony_ci                # and put them in a set to ensure they are unique.
190e5c31af7Sopenharmony_ci                features = set()
191e5c31af7Sopenharmony_ci                # 'dependency' may be a boolean expression of extension names
192e5c31af7Sopenharmony_ci                for (base,dependency) in self.apidict.requiredBy[name]:
193e5c31af7Sopenharmony_ci                    if dependency is not None:
194e5c31af7Sopenharmony_ci                        # 'dependency' may be a boolean expression of extension
195e5c31af7Sopenharmony_ci                        # names, in which case the sorting will not work well.
196e5c31af7Sopenharmony_ci
197e5c31af7Sopenharmony_ci                        # First, convert it from asciidoctor markup to language.
198e5c31af7Sopenharmony_ci                        depLanguage = dependencyLanguageComment(dependency)
199e5c31af7Sopenharmony_ci
200e5c31af7Sopenharmony_ci                        # If they are the same, the dependency is only a
201e5c31af7Sopenharmony_ci                        # single extension, and sorting them works.
202e5c31af7Sopenharmony_ci                        # Otherwise, skip it.
203e5c31af7Sopenharmony_ci                        if depLanguage == dependency:
204e5c31af7Sopenharmony_ci                            deps = sorted(
205e5c31af7Sopenharmony_ci                                    sorted((base, dependency)),
206e5c31af7Sopenharmony_ci                                    key=orgLevelKey)
207e5c31af7Sopenharmony_ci                            depString = ' with '.join(deps)
208e5c31af7Sopenharmony_ci                        else:
209e5c31af7Sopenharmony_ci                            # An expression with multiple extensions
210e5c31af7Sopenharmony_ci                            depString = f'{base} with {depLanguage}'
211e5c31af7Sopenharmony_ci
212e5c31af7Sopenharmony_ci                        features.add(depString)
213e5c31af7Sopenharmony_ci                    else:
214e5c31af7Sopenharmony_ci                        features.add(base)
215e5c31af7Sopenharmony_ci                # Sort the overall dependencies so core versions are first
216e5c31af7Sopenharmony_ci                provider = ', '.join(sorted(
217e5c31af7Sopenharmony_ci                                        sorted(features),
218e5c31af7Sopenharmony_ci                                        key=orgLevelKey))
219e5c31af7Sopenharmony_ci                return f'// Provided by {provider}\n'
220e5c31af7Sopenharmony_ci            else:
221e5c31af7Sopenharmony_ci                if mustBeFound:
222e5c31af7Sopenharmony_ci                    self.logMsg('warn', 'genRequirements: API {} not found'.format(name))
223e5c31af7Sopenharmony_ci                return ''
224e5c31af7Sopenharmony_ci        else:
225e5c31af7Sopenharmony_ci            # No API dictionary available, return nothing
226e5c31af7Sopenharmony_ci            return ''
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci    def writeInclude(self, directory, basename, contents):
229e5c31af7Sopenharmony_ci        """Generate an include file.
230e5c31af7Sopenharmony_ci
231e5c31af7Sopenharmony_ci        - directory - subdirectory to put file in
232e5c31af7Sopenharmony_ci        - basename - base name of the file
233e5c31af7Sopenharmony_ci        - contents - contents of the file (Asciidoc boilerplate aside)"""
234e5c31af7Sopenharmony_ci        # Create subdirectory, if needed
235e5c31af7Sopenharmony_ci        directory = self.genOpts.directory + '/' + directory
236e5c31af7Sopenharmony_ci        self.makeDir(directory)
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci        # Create file
239e5c31af7Sopenharmony_ci        filename = directory + '/' + basename + self.file_suffix
240e5c31af7Sopenharmony_ci        self.logMsg('diag', '# Generating include file:', filename)
241e5c31af7Sopenharmony_ci        fp = open(filename, 'w', encoding='utf-8')
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci        # Asciidoc anchor
244e5c31af7Sopenharmony_ci        write(self.genOpts.conventions.warning_comment, file=fp)
245e5c31af7Sopenharmony_ci        write('[[{0}]]'.format(basename), file=fp)
246e5c31af7Sopenharmony_ci
247e5c31af7Sopenharmony_ci        if self.genOpts.conventions.generate_index_terms:
248e5c31af7Sopenharmony_ci            if basename.startswith(self.conventions.command_prefix):
249e5c31af7Sopenharmony_ci                index_term = basename + " (function)"
250e5c31af7Sopenharmony_ci            elif basename.startswith(self.conventions.type_prefix):
251e5c31af7Sopenharmony_ci                index_term = basename + " (type)"
252e5c31af7Sopenharmony_ci            elif basename.startswith(self.conventions.api_prefix):
253e5c31af7Sopenharmony_ci                index_term = basename + " (define)"
254e5c31af7Sopenharmony_ci            else:
255e5c31af7Sopenharmony_ci                index_term = basename
256e5c31af7Sopenharmony_ci            write('indexterm:[{}]'.format(index_term), file=fp)
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci        write(f'[source,{self.conventions.docgen_language}]', file=fp)
259e5c31af7Sopenharmony_ci        write('----', file=fp)
260e5c31af7Sopenharmony_ci        write(contents, file=fp)
261e5c31af7Sopenharmony_ci        write('----', file=fp)
262e5c31af7Sopenharmony_ci        fp.close()
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci        if self.genOpts.secondaryInclude:
265e5c31af7Sopenharmony_ci            # Create secondary no cross-reference include file
266e5c31af7Sopenharmony_ci            filename = f'{directory}/{basename}.no-xref{self.file_suffix}'
267e5c31af7Sopenharmony_ci            self.logMsg('diag', '# Generating include file:', filename)
268e5c31af7Sopenharmony_ci            fp = open(filename, 'w', encoding='utf-8')
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci            # Asciidoc anchor
271e5c31af7Sopenharmony_ci            write(self.genOpts.conventions.warning_comment, file=fp)
272e5c31af7Sopenharmony_ci            write('// Include this no-xref version without cross reference id for multiple includes of same file', file=fp)
273e5c31af7Sopenharmony_ci            write(f'[source,{self.conventions.docgen_language}]', file=fp)
274e5c31af7Sopenharmony_ci            write('----', file=fp)
275e5c31af7Sopenharmony_ci            write(contents, file=fp)
276e5c31af7Sopenharmony_ci            write('----', file=fp)
277e5c31af7Sopenharmony_ci            fp.close()
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci    def writeEnumTable(self, basename, values):
280e5c31af7Sopenharmony_ci        """Output a table of enumerants."""
281e5c31af7Sopenharmony_ci        directory = Path(self.genOpts.directory) / 'enums'
282e5c31af7Sopenharmony_ci        self.makeDir(str(directory))
283e5c31af7Sopenharmony_ci
284e5c31af7Sopenharmony_ci        filename = str(directory / f'{basename}.comments{self.file_suffix}')
285e5c31af7Sopenharmony_ci        self.logMsg('diag', '# Generating include file:', filename)
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ci        with open(filename, 'w', encoding='utf-8') as fp:
288e5c31af7Sopenharmony_ci            write(self.conventions.warning_comment, file=fp)
289e5c31af7Sopenharmony_ci            write(_ENUM_TABLE_PREFIX, file=fp)
290e5c31af7Sopenharmony_ci
291e5c31af7Sopenharmony_ci            for data in values:
292e5c31af7Sopenharmony_ci                write("|ename:{}".format(data['name']), file=fp)
293e5c31af7Sopenharmony_ci                write("|{}".format(data['comment']), file=fp)
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci            write(_TABLE_SUFFIX, file=fp)
296e5c31af7Sopenharmony_ci
297e5c31af7Sopenharmony_ci    def writeBox(self, filename, prefix, items):
298e5c31af7Sopenharmony_ci        """Write a generalized block/box for some values."""
299e5c31af7Sopenharmony_ci        self.logMsg('diag', '# Generating include file:', filename)
300e5c31af7Sopenharmony_ci
301e5c31af7Sopenharmony_ci        with open(filename, 'w', encoding='utf-8') as fp:
302e5c31af7Sopenharmony_ci            write(self.conventions.warning_comment, file=fp)
303e5c31af7Sopenharmony_ci            write(prefix, file=fp)
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci            for item in items:
306e5c31af7Sopenharmony_ci                write("* {}".format(item), file=fp)
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci            write(_BLOCK_SUFFIX, file=fp)
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci    def writeEnumBox(self, basename, values):
311e5c31af7Sopenharmony_ci        """Output a box of enumerants."""
312e5c31af7Sopenharmony_ci        directory = Path(self.genOpts.directory) / 'enums'
313e5c31af7Sopenharmony_ci        self.makeDir(str(directory))
314e5c31af7Sopenharmony_ci
315e5c31af7Sopenharmony_ci        filename = str(directory / f'{basename}.comments-box{self.file_suffix}')
316e5c31af7Sopenharmony_ci        self.writeBox(filename, _ENUM_BLOCK_PREFIX,
317e5c31af7Sopenharmony_ci                      ("ename:{} -- {}".format(data['name'], data['comment'])
318e5c31af7Sopenharmony_ci                       for data in values))
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci    def writeFlagBox(self, basename, values):
321e5c31af7Sopenharmony_ci        """Output a box of flag bit comments."""
322e5c31af7Sopenharmony_ci        directory = Path(self.genOpts.directory) / 'enums'
323e5c31af7Sopenharmony_ci        self.makeDir(str(directory))
324e5c31af7Sopenharmony_ci
325e5c31af7Sopenharmony_ci        filename = str(directory / f'{basename}.comments{self.file_suffix}')
326e5c31af7Sopenharmony_ci        self.writeBox(filename, _FLAG_BLOCK_PREFIX,
327e5c31af7Sopenharmony_ci                      ("ename:{} -- {}".format(data['name'], data['comment'])
328e5c31af7Sopenharmony_ci                       for data in values))
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ci    def genType(self, typeinfo, name, alias):
331e5c31af7Sopenharmony_ci        """Generate type."""
332e5c31af7Sopenharmony_ci        OutputGenerator.genType(self, typeinfo, name, alias)
333e5c31af7Sopenharmony_ci        typeElem = typeinfo.elem
334e5c31af7Sopenharmony_ci        # If the type is a struct type, traverse the embedded <member> tags
335e5c31af7Sopenharmony_ci        # generating a structure. Otherwise, emit the tag text.
336e5c31af7Sopenharmony_ci        category = typeElem.get('category')
337e5c31af7Sopenharmony_ci
338e5c31af7Sopenharmony_ci        if category in ('struct', 'union'):
339e5c31af7Sopenharmony_ci            # If the type is a struct type, generate it using the
340e5c31af7Sopenharmony_ci            # special-purpose generator.
341e5c31af7Sopenharmony_ci            self.genStruct(typeinfo, name, alias)
342e5c31af7Sopenharmony_ci        elif category not in OutputGenerator.categoryToPath:
343e5c31af7Sopenharmony_ci            # If there is no path, do not write output
344e5c31af7Sopenharmony_ci            self.logMsg('diag', 'NOT writing include for {} category {}'.format(
345e5c31af7Sopenharmony_ci                        name, category))
346e5c31af7Sopenharmony_ci        else:
347e5c31af7Sopenharmony_ci            body = self.genRequirements(name)
348e5c31af7Sopenharmony_ci            if alias:
349e5c31af7Sopenharmony_ci                # If the type is an alias, just emit a typedef declaration
350e5c31af7Sopenharmony_ci                body += 'typedef ' + alias + ' ' + name + ';\n'
351e5c31af7Sopenharmony_ci                self.writeInclude(OutputGenerator.categoryToPath[category],
352e5c31af7Sopenharmony_ci                                  name, body)
353e5c31af7Sopenharmony_ci            else:
354e5c31af7Sopenharmony_ci                # Replace <apientry /> tags with an APIENTRY-style string
355e5c31af7Sopenharmony_ci                # (from self.genOpts). Copy other text through unchanged.
356e5c31af7Sopenharmony_ci                # If the resulting text is an empty string, do not emit it.
357e5c31af7Sopenharmony_ci                body += noneStr(typeElem.text)
358e5c31af7Sopenharmony_ci                for elem in typeElem:
359e5c31af7Sopenharmony_ci                    if elem.tag == 'apientry':
360e5c31af7Sopenharmony_ci                        body += self.genOpts.apientry + noneStr(elem.tail)
361e5c31af7Sopenharmony_ci                    else:
362e5c31af7Sopenharmony_ci                        body += noneStr(elem.text) + noneStr(elem.tail)
363e5c31af7Sopenharmony_ci
364e5c31af7Sopenharmony_ci                if body:
365e5c31af7Sopenharmony_ci                    self.writeInclude(OutputGenerator.categoryToPath[category],
366e5c31af7Sopenharmony_ci                                      name, body + '\n')
367e5c31af7Sopenharmony_ci                else:
368e5c31af7Sopenharmony_ci                    self.logMsg('diag', 'NOT writing empty include file for type', name)
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci    def genStructBody(self, typeinfo, typeName):
371e5c31af7Sopenharmony_ci        """
372e5c31af7Sopenharmony_ci        Returns the body generated for a struct.
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci        Factored out to allow aliased types to also generate the original type.
375e5c31af7Sopenharmony_ci        """
376e5c31af7Sopenharmony_ci        typeElem = typeinfo.elem
377e5c31af7Sopenharmony_ci        body = 'typedef ' + typeElem.get('category') + ' ' + typeName + ' {\n'
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci        targetLen = self.getMaxCParamTypeLength(typeinfo)
380e5c31af7Sopenharmony_ci        for member in typeElem.findall('.//member'):
381e5c31af7Sopenharmony_ci            body += self.makeCParamDecl(member, targetLen + 4)
382e5c31af7Sopenharmony_ci            body += ';\n'
383e5c31af7Sopenharmony_ci        body += '} ' + typeName + ';'
384e5c31af7Sopenharmony_ci        return body
385e5c31af7Sopenharmony_ci
386e5c31af7Sopenharmony_ci    def genStruct(self, typeinfo, typeName, alias):
387e5c31af7Sopenharmony_ci        """Generate struct."""
388e5c31af7Sopenharmony_ci        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci        body = self.genRequirements(typeName)
391e5c31af7Sopenharmony_ci        if alias:
392e5c31af7Sopenharmony_ci            if self.conventions.duplicate_aliased_structs:
393e5c31af7Sopenharmony_ci                # TODO maybe move this outside the conditional? This would be a visual change.
394e5c31af7Sopenharmony_ci                body += '// {} is an alias for {}\n'.format(typeName, alias)
395e5c31af7Sopenharmony_ci                alias_info = self.registry.typedict[alias]
396e5c31af7Sopenharmony_ci                body += self.genStructBody(alias_info, alias)
397e5c31af7Sopenharmony_ci                body += '\n\n'
398e5c31af7Sopenharmony_ci            body += 'typedef ' + alias + ' ' + typeName + ';\n'
399e5c31af7Sopenharmony_ci        else:
400e5c31af7Sopenharmony_ci            body += self.genStructBody(typeinfo, typeName)
401e5c31af7Sopenharmony_ci
402e5c31af7Sopenharmony_ci        self.writeInclude('structs', typeName, body)
403e5c31af7Sopenharmony_ci
404e5c31af7Sopenharmony_ci    def genEnumTable(self, groupinfo, groupName):
405e5c31af7Sopenharmony_ci        """Generate tables of enumerant values and short descriptions from
406e5c31af7Sopenharmony_ci        the XML."""
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci        values = []
409e5c31af7Sopenharmony_ci        got_comment = False
410e5c31af7Sopenharmony_ci        missing_comments = []
411e5c31af7Sopenharmony_ci        for elem in groupinfo.elem.findall('enum'):
412e5c31af7Sopenharmony_ci            if not elem.get('required'):
413e5c31af7Sopenharmony_ci                continue
414e5c31af7Sopenharmony_ci            name = elem.get('name')
415e5c31af7Sopenharmony_ci
416e5c31af7Sopenharmony_ci            data = {
417e5c31af7Sopenharmony_ci                'name': name,
418e5c31af7Sopenharmony_ci            }
419e5c31af7Sopenharmony_ci
420e5c31af7Sopenharmony_ci            (numVal, _) = self.enumToValue(elem, True)
421e5c31af7Sopenharmony_ci            data['value'] = numVal
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci            extname = elem.get('extname')
424e5c31af7Sopenharmony_ci
425e5c31af7Sopenharmony_ci            added_by_extension_to_core = (extname is not None and self.in_core)
426e5c31af7Sopenharmony_ci            if added_by_extension_to_core and not self.genOpts.extEnumerantAdditions:
427e5c31af7Sopenharmony_ci                # We are skipping such values
428e5c31af7Sopenharmony_ci                continue
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci            comment = elem.get('comment')
431e5c31af7Sopenharmony_ci            if comment:
432e5c31af7Sopenharmony_ci                got_comment = True
433e5c31af7Sopenharmony_ci            elif name.endswith('_UNKNOWN') and numVal == 0:
434e5c31af7Sopenharmony_ci                # This is a placeholder for 0-initialization to be clearly invalid.
435e5c31af7Sopenharmony_ci                # Just skip this silently
436e5c31af7Sopenharmony_ci                continue
437e5c31af7Sopenharmony_ci            else:
438e5c31af7Sopenharmony_ci                # Skip but record this in case it is an odd-one-out missing
439e5c31af7Sopenharmony_ci                # a comment.
440e5c31af7Sopenharmony_ci                missing_comments.append(name)
441e5c31af7Sopenharmony_ci                continue
442e5c31af7Sopenharmony_ci
443e5c31af7Sopenharmony_ci            if added_by_extension_to_core and self.genOpts.extEnumerantFormatString:
444e5c31af7Sopenharmony_ci                # Add a note to the comment
445e5c31af7Sopenharmony_ci                comment += self.genOpts.extEnumerantFormatString.format(
446e5c31af7Sopenharmony_ci                    self.conventions.formatExtension(extname))
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ci            data['comment'] = comment
449e5c31af7Sopenharmony_ci            values.append(data)
450e5c31af7Sopenharmony_ci
451e5c31af7Sopenharmony_ci        if got_comment:
452e5c31af7Sopenharmony_ci            # If any had a comment, output it.
453e5c31af7Sopenharmony_ci
454e5c31af7Sopenharmony_ci            if missing_comments:
455e5c31af7Sopenharmony_ci                self.logMsg('warn', 'The following values for', groupName,
456e5c31af7Sopenharmony_ci                            'were omitted from the table due to missing comment attributes:',
457e5c31af7Sopenharmony_ci                            ', '.join(missing_comments))
458e5c31af7Sopenharmony_ci
459e5c31af7Sopenharmony_ci            group_type = groupinfo.elem.get('type')
460e5c31af7Sopenharmony_ci            if groupName == self.result_type:
461e5c31af7Sopenharmony_ci                # Split this into success and failure
462e5c31af7Sopenharmony_ci                self.writeEnumTable(groupName + '.success',
463e5c31af7Sopenharmony_ci                                (data for data in values
464e5c31af7Sopenharmony_ci                                 if data['value'] >= 0))
465e5c31af7Sopenharmony_ci                self.writeEnumTable(groupName + '.error',
466e5c31af7Sopenharmony_ci                                (data for data in values
467e5c31af7Sopenharmony_ci                                 if data['value'] < 0))
468e5c31af7Sopenharmony_ci            elif group_type == 'bitmask':
469e5c31af7Sopenharmony_ci                self.writeFlagBox(groupName, values)
470e5c31af7Sopenharmony_ci            elif group_type == 'enum':
471e5c31af7Sopenharmony_ci                self.writeEnumTable(groupName, values)
472e5c31af7Sopenharmony_ci                self.writeEnumBox(groupName, values)
473e5c31af7Sopenharmony_ci            else:
474e5c31af7Sopenharmony_ci                raise RuntimeError("Unrecognized enums type: " + str(group_type))
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci    def genGroup(self, groupinfo, groupName, alias):
477e5c31af7Sopenharmony_ci        """Generate group (e.g. C "enum" type)."""
478e5c31af7Sopenharmony_ci        OutputGenerator.genGroup(self, groupinfo, groupName, alias)
479e5c31af7Sopenharmony_ci
480e5c31af7Sopenharmony_ci        body = self.genRequirements(groupName)
481e5c31af7Sopenharmony_ci        if alias:
482e5c31af7Sopenharmony_ci            # If the group name is aliased, just emit a typedef declaration
483e5c31af7Sopenharmony_ci            # for the alias.
484e5c31af7Sopenharmony_ci            body += 'typedef ' + alias + ' ' + groupName + ';\n'
485e5c31af7Sopenharmony_ci        else:
486e5c31af7Sopenharmony_ci            expand = self.genOpts.expandEnumerants
487e5c31af7Sopenharmony_ci            (_, enumbody) = self.buildEnumCDecl(expand, groupinfo, groupName)
488e5c31af7Sopenharmony_ci            body += enumbody
489e5c31af7Sopenharmony_ci            if self.genOpts.conventions.generate_enum_table:
490e5c31af7Sopenharmony_ci                self.genEnumTable(groupinfo, groupName)
491e5c31af7Sopenharmony_ci
492e5c31af7Sopenharmony_ci        self.writeInclude('enums', groupName, body)
493e5c31af7Sopenharmony_ci
494e5c31af7Sopenharmony_ci    def genEnum(self, enuminfo, name, alias):
495e5c31af7Sopenharmony_ci        """Generate the C declaration for a constant (a single <enum> value)."""
496e5c31af7Sopenharmony_ci
497e5c31af7Sopenharmony_ci        OutputGenerator.genEnum(self, enuminfo, name, alias)
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci        body = self.buildConstantCDecl(enuminfo, name, alias)
500e5c31af7Sopenharmony_ci
501e5c31af7Sopenharmony_ci        self.writeInclude('enums', name, body)
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_ci    def genCmd(self, cmdinfo, name, alias):
504e5c31af7Sopenharmony_ci        "Generate command."
505e5c31af7Sopenharmony_ci        OutputGenerator.genCmd(self, cmdinfo, name, alias)
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_ci        body = self.genRequirements(name)
508e5c31af7Sopenharmony_ci        decls = self.makeCDecls(cmdinfo.elem)
509e5c31af7Sopenharmony_ci        body += decls[0]
510e5c31af7Sopenharmony_ci        self.writeInclude('protos', name, body)
511