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