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