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