def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) # Keep track of all extension numbers self.extension_numbers = set()
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) # # Dictionaries are keyed by the name of the entity (e.g. # self.structs is keyed by structure names). Values are # the names of related entities (e.g. structs contain # a list of type names of members, enums contain a list # of enumerants belong to the enumerated type, etc.), or # just None if there are no directly related entities. # # Collect the mappings, then emit the Python script in endFile self.basetypes = {} self.consts = {} self.enums = {} self.flags = {} self.funcpointers = {} self.protos = {} self.structs = {} self.handles = {} self.defines = {} self.alias = {} # Dictionary containing the type of a type name # (e.g. the string name of the dictionary with its contents). self.typeCategory = {} self.mapDict = {}
def genEnum(self, enuminfo, name, alias): OutputGenerator.genEnum(self, enuminfo, name, alias) # Add a typeCategory{} entry for the category of this type. self.addName(self.typeCategory, name, 'consts') self.consts[name] = None
def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) if interface.tag != 'extension': self.logMsg('diag', 'beginFeature: ignoring non-extension feature', self.featureName) return # These attributes must exist name = self.featureName number = self.getAttrib(interface, 'number') ext_type = self.getAttrib(interface, 'type') revision = self.getSpecVersion(interface, name) # These attributes are optional OPTIONAL = False requires = self.getAttrib(interface, 'requires', OPTIONAL) requiresCore = self.getAttrib(interface, 'requiresCore', OPTIONAL, '1.0') contact = self.getAttrib(interface, 'contact', OPTIONAL) promotedTo = self.getAttrib(interface, 'promotedto', OPTIONAL) deprecatedBy = self.getAttrib(interface, 'deprecatedby', OPTIONAL) obsoletedBy = self.getAttrib(interface, 'obsoletedby', OPTIONAL) provisional = self.getAttrib(interface, 'provisional', OPTIONAL, 'false') filename = self.directory + '/' + name + self.file_suffix self.extensions.append( Extension(self, filename, name, number, ext_type, requires, requiresCore, contact, promotedTo, deprecatedBy, obsoletedBy, provisional, revision) )
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: body = 'typedef ' + alias + ' ' + typeName + ';\n' else: body = '' (protect_begin, protect_end) = self.genProtectString(typeElem.get('protect')) if protect_begin: body += protect_begin body += 'typedef ' + typeElem.get('category') # This is an OpenXR-specific alternative where aliasing refers # to an inheritance hierarchy of types rather than C-level type # aliases. if self.genOpts.genAliasMacro and self.typeMayAlias(typeName): body += ' ' + self.genOpts.aliasMacro body += ' ' + typeName + ' {\n' targetLen = 0 for member in typeElem.findall('.//member'): targetLen = max(targetLen, self.getCParamTypeLength(member)) for member in typeElem.findall('.//member'): body += self.makeCParamDecl(member, targetLen + 4) body += ';\n' body += '} ' + typeName + ';\n' if protect_end: body += protect_end self.appendSection('struct', body)
def endFile(self): # Print out all the dictionaries as Python strings. # Could just print(dict) but that's not human-readable dicts = [ [ self.basetypes, 'basetypes' ], [ self.consts, 'consts' ], [ self.enums, 'enums' ], [ self.flags, 'flags' ], [ self.funcpointers, 'funcpointers' ], [ self.protos, 'protos' ], [ self.structs, 'structs' ], [ self.handles, 'handles' ], [ self.defines, 'defines' ], [ self.typeCategory, 'typeCategory' ], [ self.alias, 'alias' ], ] for (entry_dict, name) in dicts: write(name + ' = {}', file=self.outFile) for key in sorted(entry_dict.keys()): write(name + '[' + enquote(key) + '] = ', entry_dict[key], file=self.outFile) # Dictionary containing the relationships of a type # (e.g. a dictionary with each related type as keys). write('mapDict = {}', file=self.outFile) # Could just print(self.mapDict), but prefer something # human-readable and stable-ordered for baseType in sorted(self.mapDict.keys()): write('mapDict[' + enquote(baseType) + '] = ', file=self.outFile, end='') pprint(self.mapDict[baseType], self.outFile) OutputGenerator.endFile(self)
def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # If the type is a struct type, traverse the embedded <member> tags # generating a structure. Otherwise, emit the tag text. category = typeElem.get('category') # Add a typeCategory{} entry for the category of this type. self.addName(self.typeCategory, name, category) if category in ('struct', 'union'): self.genStruct(typeinfo, name, alias) else: if alias: # Add name -> alias mapping self.addName(self.alias, name, alias) # Always emit an alias (?!) count = 1 # May want to only emit full type definition when not an alias? else: # Extract the type name # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. count = len(noneStr(typeElem.text)) for elem in typeElem: count += len(noneStr(elem.text)) + len(noneStr(elem.tail)) if count > 0: if category == 'bitmask': requiredEnum = typeElem.get('requires') self.addName(self.flags, name, requiredEnum) # This happens when the Flags type is defined, but no # FlagBits are defined yet. if requiredEnum is not None: self.addMapping(name, requiredEnum) elif category == 'enum': # This case does not seem to come up. It nominally would # result from # <type name="Something" category="enum"/>, # but the output generator doesn't emit them directly. self.logMsg('warn', 'PyOutputGenerator::genType: invalid \'enum\' category for name:', name) elif category == 'funcpointer': self.funcpointers[name] = None elif category == 'handle': self.handles[name] = None elif category == 'define': self.defines[name] = None elif category == 'basetype': # Don't add an entry for base types that are not API types # e.g. an API Bool type gets an entry, uint32_t does not if self.apiName(name): self.basetypes[name] = None self.addName(self.typeCategory, name, 'basetype') else: self.logMsg('diag', 'PyOutputGenerator::genType: unprocessed type:', name, 'category:', category) else: self.logMsg('diag', 'PyOutputGenerator::genType: unprocessed type:', name)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) # @@@ (Jon) something needs to be done here to handle aliases, probably self.makeThreadSafetyBlocks(cmdinfo.elem, 'param') self.writeInclude()
def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) self.extensions = [] # List of strings containing all vendor tags self.vendor_tags = [] self.file_suffix = ''
def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) # C-specific # Accumulate includes, defines, types, enums, function pointer typedefs, # end function prototypes separately for this feature. They're only # printed in endFeature(). self.sections = {section: [] for section in self.ALL_SECTIONS} self.feature_not_empty = False
def beginFeature(self, interface, emit): OutputGenerator.beginFeature(self, interface, emit) self.currentFeature = "// {0}".format(interface.attrib['name']) self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) self.opaqueStruct.clear() self.surfaceExtensionVersionIndent = "" self.isSurfaceExtension = self.currentFeature in self.surfaceExtensions if self.isSurfaceExtension: self.surfaceExtensionVersionIndent = "\t"
def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) # Internal state - accumulators for different inner block text self.sections = {section: [] for section in self.ALL_SECTIONS} self.feature_not_empty = False self.need_platform_include = False self.may_alias = None
def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) # Verify that each extension has a unique number during doc generation extension_number = interface.get('number') if extension_number is not None and extension_number != "0": if extension_number in self.extension_numbers: self.logMsg('error', 'Duplicate extension number ', extension_number, ' detected in feature ', interface.get('name'), '\n') exit(1) else: self.extension_numbers.add(extension_number)
def beginFeature( self, interface, emit ): OutputGenerator.beginFeature( self, interface, emit ) #if interface.attrib.get( 'protect' ): #write( interface.attrib[ 'name' ], file = self.testsFile ) self.currentFeature = "// {0}".format( interface.attrib[ 'name' ] ) self.sections = dict( [ ( section, [] ) for section in self.ALL_SECTIONS ] ) self.opaqueStruct.clear() self.platformExtensionVersionIndent = "" self.isPlatformExtension = self.currentFeature in self.platformExtensions if self.isPlatformExtension: self.platformExtensionVersionIndent = "\t"
def endFile(self): # C-specific # Finish C++ wrapper and multiple inclusion protection self.newline() write('#ifdef __cplusplus', file=self.outFile) write('}', file=self.outFile) write('#endif', file=self.outFile) if self.genOpts.protectFile and self.genOpts.filename: self.newline() write('#endif', file=self.outFile) # Finish processing in superclass OutputGenerator.endFile(self)
def genGroup(self, groupinfo, groupName, alias): OutputGenerator.genGroup(self, groupinfo, groupName, alias) if alias: # If the group name is aliased, just emit a typedef declaration # for the alias. body = 'typedef ' + alias + ' ' + groupName + ';\n' else: expand = self.genOpts.expandEnumerants (_, body) = self.buildEnumCDecl(expand, groupinfo, groupName) self.writeInclude('enums', groupName, body)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) # if alias: # prefix = '// ' + name + ' is an alias of command ' + alias + '\n' # else: # prefix = '' prefix = '' decls = self.makeCDecls(cmdinfo.elem) self.appendSection('command', prefix + decls[0] + '\n') if self.genOpts.genFuncPointers: self.appendSection('commandPointer', decls[1])
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) self.directory = self.genOpts.directory self.file_suffix = self.genOpts.conventions.file_suffix # Iterate over all 'tag' Elements and add the names of all the valid vendor # tags to the list root = self.registry.tree.getroot() for tag in root.findall('tags/tag'): self.vendor_tags.append(tag.get('name')) # Create subdirectory, if needed self.makeDir(self.directory)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) return_type = cmdinfo.elem.find('proto/type') if self.genOpts.conventions.requires_error_validation(return_type): # This command returns an API result code, so check that it # returns at least the required errors. required_errors = self.genOpts.conventions.required_errors errorcodes = cmdinfo.elem.get('errorcodes').split(',') if not required_errors.issubset(set(errorcodes)): self.logMsg('error', 'Missing required error code for command: ', name, '\n') exit(1) decls = self.makeCDecls(cmdinfo.elem) self.writeInclude('protos', name, decls[0])
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) if alias: # Add name -> alias mapping self.addName(self.alias, typeName, alias) else: # May want to only emit definition on this branch True members = [member.text for member in typeinfo.elem.findall('.//member/name')] self.structs[typeName] = members memberTypes = [member.text for member in typeinfo.elem.findall('.//member/type')] for member_type in memberTypes: self.addMapping(typeName, member_type)
def genGroup(self, groupinfo, groupName, alias): OutputGenerator.genGroup(self, groupinfo, groupName, alias) groupElem = groupinfo.elem if alias: # Add name -> alias mapping self.addName(self.alias, groupName, alias) else: # May want to only emit definition on this branch True # Loop over the nested 'enum' tags. enumerants = [elem.get('name') for elem in groupElem.findall('enum')] for name in enumerants: self.addName(self.consts, name, groupName) self.enums[groupName] = enumerants
def endFeature(self): # C-specific # Actually write the interface to the output file. if self.emit: if self.feature_not_empty: if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename): self.newline() if self.genOpts.protectFeature: write('#ifndef', self.featureName, file=self.outFile) # If type declarations are needed by other features based on # this one, it may be necessary to suppress the ExtraProtect, # or move it below the 'for section...' loop. if self.featureExtraProtect is not None: write('#ifdef', self.featureExtraProtect, file=self.outFile) self.newline() write('#define', self.featureName, '1', file=self.outFile) for section in self.TYPE_SECTIONS: # OpenXR: # If we need the explicit include of the external platform header, # put it right before the function pointer definitions if section == "funcpointer" and self.need_platform_include: write('// Include for OpenXR Platform-Specific Types', file=self.outFile) write('#include "openxr_platform.h"', file=self.outFile) self.newline() self.need_platform_include = False contents = self.sections[section] if contents: write('\n'.join(contents), file=self.outFile) if self.genOpts.genFuncPointers and self.sections['commandPointer']: write('\n'.join(self.sections['commandPointer']), file=self.outFile) self.newline() if self.sections['command']: if self.genOpts.protectProto: write(self.genOpts.protectProto, self.genOpts.protectProtoStr, file=self.outFile) write('\n'.join(self.sections['command']), end='', file=self.outFile) if self.genOpts.protectProto: write('#endif', file=self.outFile) else: self.newline() if self.featureExtraProtect is not None: write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) if self.genOpts.protectFeature: write('#endif /*', self.featureName, '*/', file=self.outFile) # Finish processing in superclass OutputGenerator.endFeature(self)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) if alias: # Add name -> alias mapping self.addName(self.alias, name, alias) else: # May want to only emit definition on this branch True # Add a typeCategory{} entry for the category of this type. self.addName(self.typeCategory, name, 'protos') params = [param.text for param in cmdinfo.elem.findall('param/name')] self.protos[name] = params paramTypes = [param.text for param in cmdinfo.elem.findall('param/type')] for param_type in paramTypes: self.addMapping(name, param_type)
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: body = 'typedef ' + alias + ' ' + typeName + ';\n' else: body = 'typedef ' + typeElem.get('category') + ' ' + typeName + ' {\n' targetLen = 0 for member in typeElem.findall('.//member'): targetLen = max(targetLen, self.getCParamTypeLength(member)) for member in typeElem.findall('.//member'): body += self.makeCParamDecl(member, targetLen + 4) body += ';\n' body += '} ' + typeName + ';' self.writeInclude('structs', typeName, body)
def genStruct(self, typeinfo, typeName, alias): """Generate struct (e.g. C "struct" type). This is a special case of the <type> tag where the contents are interpreted as a set of <member> tags instead of freeform C C type declarations. The <member> tags are just like <param> tags - they are a declaration of a struct or union member. Only simple member declarations are supported (no nested structs etc.) If alias is not None, then this struct aliases another; just generate a typedef of that alias.""" OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: body = 'typedef ' + alias + ' ' + typeName + ';\n' else: body = '' (protect_begin, protect_end) = self.genProtectString(typeElem.get('protect')) if protect_begin: body += protect_begin body += 'typedef ' + typeElem.get('category') # This is an OpenXR-specific alternative where aliasing refers # to an inheritance hierarchy of types rather than C-level type # aliases. if self.genOpts.genAliasMacro and self.typeMayAlias(typeName): body += ' ' + self.genOpts.aliasMacro body += ' ' + typeName + ' {\n' targetLen = self.getMaxCParamTypeLength(typeinfo) for member in typeElem.findall('.//member'): body += self.makeCParamDecl(member, targetLen + 4) body += ';\n' body += '} ' + typeName + ';\n' if protect_end: body += protect_end self.appendSection('struct', body)
def genStruct(self, typeinfo, typeName, alias): """Generate struct (e.g. C "struct" type). Add the struct name to the 'structs' dictionary, with the value being an ordered list of the struct member names.""" OutputGenerator.genStruct(self, typeinfo, typeName, alias) if alias: # Add name -> alias mapping self.addName(self.alias, typeName, alias) else: # May want to only emit definition on this branch True members = [member.text for member in typeinfo.elem.findall('.//member/name')] self.structs[typeName] = members memberTypes = [member.text for member in typeinfo.elem.findall('.//member/type')] for member_type in memberTypes: self.addMapping(typeName, member_type)
def genCmd(self, cmdinfo, name, alias): "Generate command." OutputGenerator.genCmd(self, cmdinfo, name, alias) return_type = cmdinfo.elem.find('proto/type') if self.genOpts.conventions.requires_error_validation(return_type): # This command returns an API result code, so check that it # returns at least the required errors. # TODO move this to consistency_tools required_errors = set(self.genOpts.conventions.required_errors) errorcodes = cmdinfo.elem.get('errorcodes').split(',') if not required_errors.issubset(set(errorcodes)): self.logMsg('error', 'Missing required error code for command: ', name, '\n') exit(1) body = self.genRequirements(name) decls = self.makeCDecls(cmdinfo.elem) body += decls[0] self.writeInclude('protos', name, body)
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: return structTypeName = None members = [] for member in typeinfo.getMembers(): memberName = getElemName(member) memberType = getElemType(member) if self.conventions.is_structure_type_member(memberType, memberName): structTypeName = member.get("values") members.append(memberName) self.structs.append(CStruct(typeName, structTypeName, members, typeinfo.elem.get('protect')))
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) if alias: # Add name -> alias mapping self.addName(self.alias, typeName, alias) else: # May want to only emit definition on this branch True members = [ member.text for member in typeinfo.elem.findall('.//member/name') ] self.structs[typeName] = members memberTypes = [ member.text for member in typeinfo.elem.findall('.//member/type') ] for member_type in memberTypes: self.addMapping(typeName, member_type)
def endFeature(self): # Generate code for the feature if self.emit and self.needFeatureGeneration(): if self.featureBreak: self.newline() if (self.featureExtraProtect is not None): write('#ifdef', self.featureExtraProtect, file=self.outFile) self.generateFeature() if (self.featureExtraProtect is not None): write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) # Finish processing in superclass OutputGenerator.endFeature(self)
def genStruct(self, typeinfo, typeName, alias): """Generate struct.""" OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem body = self.genRequirements(typeName) if alias: body += 'typedef ' + alias + ' ' + typeName + ';\n' else: body += 'typedef ' + typeElem.get('category') + ' ' + typeName + ' {\n' targetLen = self.getMaxCParamTypeLength(typeinfo) for member in typeElem.findall('.//member'): body += self.makeCParamDecl(member, targetLen + 4) body += ';\n' body += '} ' + typeName + ';' self.writeInclude('structs', typeName, body)
def genType(self, typeinfo, name, alias): "Generate type." OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # Vulkan: # Determine the category of the type, and the type section to add # its definition to. # 'funcpointer' is added to the 'struct' section as a workaround for # internal issue #877, since structures and function pointer types # can have cross-dependencies. category = typeElem.get('category') if category == 'funcpointer': section = 'struct' else: section = category if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) else: if self.genOpts is None: raise MissingGeneratorOptionsError() # OpenXR: this section was not under 'else:' previously, just fell through if alias: # If the type is an alias, just emit a typedef declaration body = 'typedef ' + alias + ' ' + name + ';\n' else: # Replace <apientry /> tags with an APIENTRY-style string # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. body = noneStr(typeElem.text) for elem in typeElem: if elem.tag == 'apientry': body += self.genOpts.apientry + noneStr(elem.tail) else: body += noneStr(elem.text) + noneStr(elem.tail) if body: # Add extra newline after multi-line entries. if '\n' in body[0:-1]: body += '\n' self.appendSection(section, body)
def genGroup(self, groupinfo, groupName, alias = None): OutputGenerator.genGroup(self, groupinfo, groupName, alias) groupElem = groupinfo.elem # After either enumerated type or alias paths, add the declaration # to the appropriate section for the group being defined. if groupElem.get('type') == 'bitmask': section = 'bitmask' else: section = 'group' if alias: # If the group name is aliased, just emit a typedef declaration # for the alias. body = 'typedef ' + alias + ' ' + groupName + ';\n' self.appendSection(section, body) else: (section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName) self.appendSection(section, "\n" + body)
def genType(self, typeinfo, name, alias): """Generate type.""" OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # If the type is a struct type, traverse the embedded <member> tags # generating a structure. Otherwise, emit the tag text. category = typeElem.get('category') body = '' if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) else: if alias: # If the type is an alias, just emit a typedef declaration body = 'typedef ' + alias + ' ' + name + ';\n' self.writeInclude(OutputGenerator.categoryToPath[category], name, body) else: # Replace <apientry /> tags with an APIENTRY-style string # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. body = noneStr(typeElem.text) for elem in typeElem: if elem.tag == 'apientry': body += self.genOpts.apientry + noneStr(elem.tail) else: body += noneStr(elem.text) + noneStr(elem.tail) if body: if category in OutputGenerator.categoryToPath: self.writeInclude( OutputGenerator.categoryToPath[category], name, body + '\n') else: self.logMsg('diag', '# NOT writing include file for type:', name, '- bad category: ', category) else: self.logMsg('diag', '# NOT writing empty include file for type', name)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) if alias: # Add name -> alias mapping self.addName(self.alias, name, alias) else: # May want to only emit definition on this branch True # Add a typeCategory{} entry for the category of this type. self.addName(self.typeCategory, name, 'protos') params = [param.text for param in cmdinfo.elem.findall('param/name')] self.protos[name] = params paramTypes = [ param.text for param in cmdinfo.elem.findall('param/type') ] for param_type in paramTypes: self.addMapping(name, param_type)
def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) # Decide if we're in a core <feature> or an <extension> self.in_core = (interface.tag == 'feature') # Verify that each <extension> has a unique number during doc # generation # TODO move this to consistency_tools if not self.in_core: extension_number = interface.get('number') if extension_number is not None and extension_number != "0": if extension_number in self.extension_numbers: self.logMsg('error', 'Duplicate extension number ', extension_number, ' detected in feature ', interface.get('name'), '\n') exit(1) else: self.extension_numbers.add(extension_number)
def genStruct(self, typeinfo, typeName, alias): OutputGenerator.genStruct(self, typeinfo, typeName, alias) typeElem = typeinfo.elem if alias: body = 'typedef ' + alias + ' ' + typeName + ';\n' else: body = 'typedef ' + typeElem.get( 'category') + ' ' + typeName + ' {\n' targetLen = 0 for member in typeElem.findall('.//member'): targetLen = max(targetLen, self.getCParamTypeLength(member)) for member in typeElem.findall('.//member'): body += self.makeCParamDecl(member, targetLen + 4) body += ';\n' body += '} ' + typeName + ';' self.writeInclude('structs', typeName, body)
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) # C-specific # # Multiple inclusion protection & C++ wrappers. if genOpts.protectFile and self.genOpts.filename: headerSym = re.sub(r'\.h', '_h_', os.path.basename(self.genOpts.filename)).upper() write('#ifndef', headerSym, file=self.outFile) write('#define', headerSym, '1', file=self.outFile) self.newline() write('#ifdef __cplusplus', file=self.outFile) write('extern "C" {', file=self.outFile) write('#endif', file=self.outFile) self.newline() # User-supplied prefix text, if any (list of strings) if genOpts.prefixText: for s in genOpts.prefixText: write(s, file=self.outFile)
def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # Vulkan: # Determine the category of the type, and the type section to add # its definition to. # 'funcpointer' is added to the 'struct' section as a workaround for # internal issue #877, since structures and function pointer types # can have cross-dependencies. category = typeElem.get('category') if category == 'funcpointer': section = 'struct' else: section = category if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) else: # OpenXR: this section was not under 'else:' previously, just fell through if alias: # If the type is an alias, just emit a typedef declaration body = 'typedef ' + alias + ' ' + name + ';\n' else: # Replace <apientry /> tags with an APIENTRY-style string # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. body = noneStr(typeElem.text) for elem in typeElem: if elem.tag == 'apientry': body += self.genOpts.apientry + noneStr(elem.tail) else: body += noneStr(elem.text) + noneStr(elem.tail) if body: # Add extra newline after multi-line entries. if '\n' in body[0:-1]: body += '\n' self.appendSection(section, body)
def genEnum(self, enuminfo, name, alias): """Generate enumerants. <enum> tags may specify their values in several ways, but are usually just integers.""" OutputGenerator.genEnum(self, enuminfo, name, alias) (_, strVal) = self.enumToValue(enuminfo.elem, False) if self.misracppstyle() and enuminfo.elem.get('type') and not alias: # Generate e.g.: static constexpr uint32_t x = ~static_cast<uint32_t>(1U); # This appeases MISRA "underlying type" rules. typeStr = enuminfo.elem.get('type'); invert = '~' in strVal number = strVal.strip("()~UL") if typeStr != "float": number += 'U' strVal = "~" if invert else "" strVal += "static_cast<" + typeStr + ">(" + number + ")" body = 'static constexpr ' + typeStr.ljust(9) + name.ljust(33) + ' {' + strVal + '};' self.appendSection('enum', body) elif enuminfo.elem.get('type') and not alias: # Generate e.g.: #define x (~0ULL) typeStr = enuminfo.elem.get('type'); invert = '~' in strVal paren = '(' in strVal number = strVal.strip("()~UL") if typeStr != "float": if typeStr == "uint64_t": number += 'ULL' else: number += 'U' strVal = "~" if invert else "" strVal += number if paren: strVal = "(" + strVal + ")"; body = '#define ' + name.ljust(33) + ' ' + strVal; self.appendSection('enum', body) else: body = '#define ' + name.ljust(33) + ' ' + strVal self.appendSection('enum', body)
def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) if self.processCmds: # Create the declaration for the function prototype proto = cmdinfo.elem.find('proto') protoDecl = self.genOpts.apicall + noneStr(proto.text) for elem in proto: text = noneStr(elem.text) tail = noneStr(elem.tail) if (elem.tag == 'name'): if text.startswith('vk'): text = text[2:] protoDecl += self.makeProtoName(text, tail) else: protoDecl += text + tail returnType = noneStr(proto.text) + noneStr(proto.find('type').text) # TODO: Define a class or namedtuple for the dictionary entry self.featureCmdParams[name] = (returnType, protoDecl, self.makeValueInfo( cmdinfo.elem.findall('param')))
def genCmd(self, cmdinfo, name, alias): """Generate command. - Add the command name to the 'protos' dictionary, with the value being an ordered list of the parameter names.""" OutputGenerator.genCmd(self, cmdinfo, name, alias) if alias: # Add name -> alias mapping self.addName(self.alias, name, alias) else: # May want to only emit definition on this branch True # Add a typeCategory{} entry for the category of this type. self.addName(self.typeCategory, name, 'protos') params = [param.text for param in cmdinfo.elem.findall('param/name')] self.protos[name] = params paramTypes = [param.text for param in cmdinfo.elem.findall('param/type')] for param_type in paramTypes: self.addMapping(name, param_type)
def genGroup(self, groupinfo, groupName, alias=None): OutputGenerator.genGroup(self, groupinfo, groupName, alias) if alias: return if getElemType(groupinfo.elem) == 'bitmask': bitmaskTypeName = getElemName(groupinfo.flagType.elem) bitmaskTuples = [] for elem in groupinfo.elem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) bitmaskTuples.append((getElemName(elem), strVal)) self.bitmasks.append(CBitmask(bitmaskTypeName, bitmaskTuples)) else: groupElem = groupinfo.elem expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)', r'\1_\2', groupName).upper() expandPrefix = expandName expandSuffix = '' expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName) if expandSuffixMatch: expandSuffix = '_' + expandSuffixMatch.group() # Strip off the suffix from the prefix expandPrefix = expandName.rsplit(expandSuffix, 1)[0] enumTuples = [] for elem in groupElem.findall('enum'): (numVal, strVal) = self.enumToValue(elem, True) if numVal is None: # then this is an alias or something continue enumTuples.append((getElemName(elem), strVal)) self.enums.append( CEnum(groupName, expandPrefix, expandSuffix, enumTuples))
def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # If the type is a struct type, traverse the imbedded <member> tags # generating a structure. Otherwise, emit the tag text. category = typeElem.get('category') if (category == 'struct' or category == 'union'): self.structNames.add(name) # Skip code generation for union encode/decode functions. if category == 'struct': self.genStruct(typeinfo, name, alias) elif (category == 'handle'): self.handleNames.add(name) elif (category == 'bitmask'): # Flags can have either VkFlags or VkFlags64 base type alias = typeElem.get('alias') if alias: # Use same base type as the alias if one exists self.flagsTypes[name] = self.flagsTypes[alias] else: # Otherwise, look for base type inside type declaration self.flagsTypes[name] = typeElem.find('type').text
def genType(self, typeinfo, name, alias): OutputGenerator.genType(self, typeinfo, name, alias) typeElem = typeinfo.elem # If the type is a struct type, traverse the embedded <member> tags # generating a structure. Otherwise, emit the tag text. category = typeElem.get('category') body = '' if category in ('struct', 'union'): # If the type is a struct type, generate it using the # special-purpose generator. self.genStruct(typeinfo, name, alias) else: if alias: # If the type is an alias, just emit a typedef declaration body = 'typedef ' + alias + ' ' + name + ';\n' self.writeInclude(OutputGenerator.categoryToPath[category], name, body) else: # Replace <apientry /> tags with an APIENTRY-style string # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. body = noneStr(typeElem.text) for elem in typeElem: if elem.tag == 'apientry': body += self.genOpts.apientry + noneStr(elem.tail) else: body += noneStr(elem.text) + noneStr(elem.tail) if body: if category in OutputGenerator.categoryToPath: self.writeInclude(OutputGenerator.categoryToPath[category], name, body + '\n') else: self.logMsg('diag', '# NOT writing include file for type:', name, '- bad category: ', category) else: self.logMsg('diag', '# NOT writing empty include file for type', name)
def endFeature(self): # Add feature to global list with protectFeature if self.emit and self.featurePointers: if self.genOpts.protectFeature: self.pointers.append('#ifdef ' + self.featureName) self.pointerInitializersInstance.append('#ifdef ' + self.featureName) self.pointerInitializersDevice.append('#ifdef ' + self.featureName) if self.featureExtraProtect is not None: self.pointers.append('#ifdef ' + self.featureExtraProtect) self.pointerInitializersInstance.append('#ifndef ' + self.featureName) self.pointerInitializersDevice.append('#ifndef ' + self.featureName) self.pointers += self.featurePointers self.pointerInitializersInstance += self.featurePointerInitializersInstance self.pointerInitializersDevice += self.featurePointerInitializersDevice if self.featureExtraProtect is not None: self.pointers.append('#endif /* ' + self.featureExtraProtect + ' */') self.pointerInitializersInstance.append( '#endif /* ' + self.featureExtraProtect + ' */') self.pointerInitializersDevice.append( '#endif /* ' + self.featureExtraProtect + ' */') if self.genOpts.protectFeature: self.pointers.append('#endif /* ' + self.featureName + ' */') self.pointerInitializersInstance.append('#endif /* ' + self.featureName + ' */') self.pointerInitializersDevice.append('#endif /* ' + self.featureName + ' */') # Finish processing in superclass OutputGenerator.endFeature(self)
def endFeature(self): "Actually write the interface to the output file." # C-specific if self.emit: if self.feature_not_empty: if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename): self.newline() if self.genOpts.protectFeature: write('#ifndef', self.featureName, file=self.outFile) # If type declarations are needed by other features based on # this one, it may be necessary to suppress the ExtraProtect, # or move it below the 'for section...' loop. if self.featureExtraProtect is not None: write('#ifdef', self.featureExtraProtect, file=self.outFile) self.newline() write('#define', self.featureName, '1', file=self.outFile) for section in self.TYPE_SECTIONS: contents = self.sections[section] if contents: write('\n'.join(contents), file=self.outFile) if self.genOpts.genFuncPointers and self.sections['commandPointer']: write('\n'.join(self.sections['commandPointer']), file=self.outFile) self.newline() if self.sections['command']: if self.genOpts.protectProto: write(self.genOpts.protectProto, self.genOpts.protectProtoStr, file=self.outFile) write('\n'.join(self.sections['command']), end='', file=self.outFile) if self.genOpts.protectProto: write('#endif', file=self.outFile) else: self.newline() if self.featureExtraProtect is not None: write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) if self.genOpts.protectFeature: write('#endif /*', self.featureName, '*/', file=self.outFile) # Finish processing in superclass OutputGenerator.endFeature(self)
def __init__(self): self.tree = None self.typedict = {} self.groupdict = {} self.enumdict = {} self.cmddict = {} self.apidict = {} self.extensions = [] self.extdict = {} # A default output generator, so commands prior to apiGen can report # errors via the generator object. self.gen = OutputGenerator() self.genOpts = None self.emitFeatures = False
def endFile(self): # Print out all the dictionaries as Python strings. # Could just print(dict) but that's not human-readable dicts = [ [self.basetypes, 'basetypes'], [self.consts, 'consts'], [self.enums, 'enums'], [self.flags, 'flags'], [self.funcpointers, 'funcpointers'], [self.protos, 'protos'], [self.structs, 'structs'], [self.handles, 'handles'], [self.defines, 'defines'], [self.typeCategory, 'typeCategory'], [self.alias, 'alias'], ] for (entry_dict, name) in dicts: write(name + ' = {}', file=self.outFile) for key in sorted(entry_dict.keys()): write(name + '[' + enquote(key) + '] = ', entry_dict[key], file=self.outFile) # Dictionary containing the relationships of a type # (e.g. a dictionary with each related type as keys). write('mapDict = {}', file=self.outFile) # Could just print(self.mapDict), but prefer something # human-readable and stable-ordered for baseType in sorted(self.mapDict.keys()): write('mapDict[' + enquote(baseType) + '] = ', file=self.outFile, end='') pprint(self.mapDict[baseType], self.outFile) OutputGenerator.endFile(self)
def genGroup(self, groupinfo, groupName, alias): """Generate group (e.g. C "enum" type). These are concatenated together with other types. - Add the enum type name to the 'enums' dictionary, with the value being an ordered list of the enumerant names. - Add each enumerant name to the 'consts' dictionary, with the value being the enum type the enumerant is part of.""" OutputGenerator.genGroup(self, groupinfo, groupName, alias) groupElem = groupinfo.elem if alias: # Add name -> alias mapping self.addName(self.alias, groupName, alias) else: # May want to only emit definition on this branch True # Loop over the nested 'enum' tags. enumerants = [elem.get('name') for elem in groupElem.findall('enum')] for name in enumerants: self.addName(self.consts, name, groupName) self.enums[groupName] = enumerants
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) if genOpts.blacklists: self.__loadBlacklists(genOpts.blacklists) if genOpts.platformTypes: self.__loadPlatformTypes(genOpts.platformTypes) # Platform defined struct processing must be implemented manually, # so these structs will be added to the blacklist. self.STRUCT_BLACKLIST += self.PLATFORM_STRUCTS # User-supplied prefix text, if any (list of strings) if (genOpts.prefixText): for s in genOpts.prefixText: write(s, file=self.outFile) # Multiple inclusion protection & C++ wrappers. if (genOpts.protectFile and self.genOpts.filename): headerSym = 'GFXRECON_' + re.sub( '\.h', '_H', os.path.basename(self.genOpts.filename)).upper() write('#ifndef ', headerSym, file=self.outFile) write('#define ', headerSym, file=self.outFile) self.newline()
def endFile(self): file_data = '' unprotected_structs = self.getStructsForProtect() protected_structs = [(x, self.getStructsForProtect(x)) for x in sorted(self.protects)] extensions = list( ((name, data) for name, data in self.registry.extdict.items() if data.supported != 'disabled')) def getNumber(x): return int(x[1].number) extensions.sort(key=getNumber) file_data += self.template.render( unprotectedStructs=unprotected_structs, protectedStructs=protected_structs, structs=self.structs, enums=self.enums, bitmasks=self.bitmasks, extensions=extensions) write(file_data, file=self.outFile) # Finish processing in superclass OutputGenerator.endFile(self)
def __init__(self): self.tree = None self.typedict = {} self.groupdict = {} self.enumdict = {} self.cmddict = {} self.apidict = {} self.extensions = [] self.requiredextensions = [] # Hack - can remove it after validity generator goes away self.validextensionstructs = defaultdict(list) self.extdict = {} # A default output generator, so commands prior to apiGen can report # errors via the generator object. self.gen = OutputGenerator() self.genOpts = None self.emitFeatures = False
def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) self.template = JinjaTemplate(self.env, "template_{}".format(genOpts.filename))
class Registry: """Represents an API registry loaded from XML""" def __init__(self): self.tree = None self.typedict = {} self.groupdict = {} self.enumdict = {} self.cmddict = {} self.apidict = {} self.extensions = [] self.extdict = {} # A default output generator, so commands prior to apiGen can report # errors via the generator object. self.gen = OutputGenerator() self.genOpts = None self.emitFeatures = False def loadElementTree(self, tree): """Load ElementTree into a Registry object and parse it""" self.tree = tree self.parseTree() def loadFile(self, file): """Load an API registry XML file into a Registry object and parse it""" self.tree = etree.parse(file) self.parseTree() def setGenerator(self, gen): """Specify output generator object. None restores the default generator""" self.gen = gen self.gen.setRegistry(self) # addElementInfo - add information about an element to the # corresponding dictionary # elem - <type>/<enums>/<enum>/<command>/<feature>/<extension> Element # info - corresponding {Type|Group|Enum|Cmd|Feature}Info object # infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' # dictionary - self.{type|group|enum|cmd|api|ext}dict # If the Element has an 'api' attribute, the dictionary key is the # tuple (name,api). If not, the key is the name. 'name' is an # attribute of the Element def addElementInfo(self, elem, info, infoName, dictionary): if ('api' in elem.attrib): key = (elem.get('name'), elem.get('api')) else: key = elem.get('name') if key in dictionary: self.gen.logMsg('warn', '*** Attempt to redefine', infoName, 'with key:', key) else: dictionary[key] = info # # lookupElementInfo - find a {Type|Enum|Cmd}Info object by name. # If an object qualified by API name exists, use that. # fname - name of type / enum / command # dictionary - self.{type|enum|cmd}dict def lookupElementInfo(self, fname, dictionary): key = (fname, self.genOpts.apiname) if (key in dictionary): # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) return dictionary[key] elif (fname in dictionary): # self.gen.logMsg('diag', 'Found generic element for feature', fname) return dictionary[fname] else: return None def parseTree(self): """Parse the registry Element, once created""" # This must be the Element for the root <registry> self.reg = self.tree.getroot() # # Create dictionary of registry types from toplevel <types> tags # and add 'name' attribute to each <type> tag (where missing) # based on its <name> element. # # There's usually one <types> block; more are OK # Required <type> attributes: 'name' or nested <name> tag contents self.typedict = {} for type in self.reg.findall('types/type'): # If the <type> doesn't already have a 'name' attribute, set # it from contents of its <name> tag. if (type.get('name') == None): type.attrib['name'] = type.find('name').text self.addElementInfo(type, TypeInfo(type), 'type', self.typedict) # # Create dictionary of registry enum groups from <enums> tags. # # Required <enums> attributes: 'name'. If no name is given, one is # generated, but that group can't be identified and turned into an # enum type definition - it's just a container for <enum> tags. self.groupdict = {} for group in self.reg.findall('enums'): self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) # # Create dictionary of registry enums from <enum> tags # # <enums> tags usually define different namespaces for the values # defined in those tags, but the actual names all share the # same dictionary. # Required <enum> attributes: 'name', 'value' # For containing <enums> which have type="enum" or type="bitmask", # tag all contained <enum>s are required. This is a stopgap until # a better scheme for tagging core and extension enums is created. self.enumdict = {} for enums in self.reg.findall('enums'): required = (enums.get('type') != None) for enum in enums.findall('enum'): enumInfo = EnumInfo(enum) enumInfo.required = required self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) # # Create dictionary of registry commands from <command> tags # and add 'name' attribute to each <command> tag (where missing) # based on its <proto><name> element. # # There's usually only one <commands> block; more are OK. # Required <command> attributes: 'name' or <proto><name> tag contents self.cmddict = {} for cmd in self.reg.findall('commands/command'): # If the <command> doesn't already have a 'name' attribute, set # it from contents of its <proto><name> tag. if (cmd.get('name') == None): cmd.attrib['name'] = cmd.find('proto/name').text ci = CmdInfo(cmd) self.addElementInfo(cmd, ci, 'command', self.cmddict) # # Create dictionaries of API and extension interfaces # from toplevel <api> and <extension> tags. # self.apidict = {} for feature in self.reg.findall('feature'): featureInfo = FeatureInfo(feature) self.addElementInfo(feature, featureInfo, 'feature', self.apidict) self.extensions = self.reg.findall('extensions/extension') self.extdict = {} for feature in self.extensions: featureInfo = FeatureInfo(feature) self.addElementInfo(feature, featureInfo, 'extension', self.extdict) # Add additional enums defined only in <extension> tags # to the corresponding core type. # When seen here, the <enum> element, processed to contain the # numeric enum value, is added to the corresponding <enums> # element, as well as adding to the enum dictionary. It is # *removed* from the <require> element it is introduced in. # Not doing this will cause spurious genEnum() # calls to be made in output generation, and it's easier # to handle here than in genEnum(). # # In lxml.etree, an Element can have only one parent, so the # append() operation also removes the element. But in Python's # ElementTree package, an Element can have multiple parents. So # it must be explicitly removed from the <require> tag, leading # to the nested loop traversal of <require>/<enum> elements # below. # # This code also adds a 'extnumber' attribute containing the # extension number, used for enumerant value calculation. # # For <enum> tags which are actually just constants, if there's # no 'extends' tag but there is a 'value' or 'bitpos' tag, just # add an EnumInfo record to the dictionary. That works because # output generation of constants is purely dependency-based, and # doesn't need to iterate through the XML tags. # # Something like this will need to be done for 'feature's up # above, if we use the same mechanism for adding to the core # API in 1.1. # for elem in feature.findall('require'): for enum in elem.findall('enum'): addEnumInfo = False groupName = enum.get('extends') if (groupName != None): # self.gen.logMsg('diag', '*** Found extension enum', # enum.get('name')) # Add extension number attribute to the <enum> element enum.attrib['extnumber'] = featureInfo.number enum.attrib['extname'] = featureInfo.name enum.attrib['supported'] = featureInfo.supported # Look up the GroupInfo with matching groupName if (groupName in self.groupdict.keys()): # self.gen.logMsg('diag', '*** Matching group', # groupName, 'found, adding element...') gi = self.groupdict[groupName] gi.elem.append(enum) # Remove element from parent <require> tag # This should be a no-op in lxml.etree elem.remove(enum) else: self.gen.logMsg('warn', '*** NO matching group', groupName, 'for enum', enum.get('name'), 'found.') addEnumInfo = True elif (enum.get('value') or enum.get('bitpos')): # self.gen.logMsg('diag', '*** Adding extension constant "enum"', # enum.get('name')) addEnumInfo = True if (addEnumInfo): enumInfo = EnumInfo(enum) self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) def dumpReg(self, maxlen=40, filehandle=sys.stdout): """Dump all the dictionaries constructed from the Registry object""" write('***************************************', file=filehandle) write(' ** Dumping Registry contents **', file=filehandle) write('***************************************', file=filehandle) write('// Types', file=filehandle) for name in self.typedict: tobj = self.typedict[name] write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) write('// Groups', file=filehandle) for name in self.groupdict: gobj = self.groupdict[name] write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) write('// Enums', file=filehandle) for name in self.enumdict: eobj = self.enumdict[name] write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) write('// Commands', file=filehandle) for name in self.cmddict: cobj = self.cmddict[name] write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) write('// APIs', file=filehandle) for key in self.apidict: write(' API Version ', key, '->', etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) write('// Extensions', file=filehandle) for key in self.extdict: write(' Extension', key, '->', etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) # write('***************************************', file=filehandle) # write(' ** Dumping XML ElementTree **', file=filehandle) # write('***************************************', file=filehandle) # write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle) # # typename - name of type # required - boolean (to tag features as required or not) def markTypeRequired(self, typename, required): """Require (along with its dependencies) or remove (but not its dependencies) a type""" self.gen.logMsg('diag', '*** tagging type:', typename, '-> required =', required) # Get TypeInfo object for <type> tag corresponding to typename type = self.lookupElementInfo(typename, self.typedict) if (type != None): if (required): # Tag type dependencies in 'required' attributes as # required. This DOES NOT un-tag dependencies in a <remove> # tag. See comments in markRequired() below for the reason. if ('requires' in type.elem.attrib): depType = type.elem.get('requires') self.gen.logMsg('diag', '*** Generating dependent type', depType, 'for type', typename) self.markTypeRequired(depType, required) # Tag types used in defining this type (e.g. in nested # <type> tags) # Look for <type> in entire <command> tree, # not just immediate children for subtype in type.elem.findall('.//type'): self.gen.logMsg( 'diag', '*** markRequired: type requires dependent <type>', subtype.text) self.markTypeRequired(subtype.text, required) # Tag enums used in defining this type, for example in # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> for subenum in type.elem.findall('.//enum'): self.gen.logMsg( 'diag', '*** markRequired: type requires dependent <enum>', subenum.text) self.markEnumRequired(subenum.text, required) type.required = required else: self.gen.logMsg('warn', '*** type:', typename, 'IS NOT DEFINED') # # enumname - name of enum # required - boolean (to tag features as required or not) def markEnumRequired(self, enumname, required): self.gen.logMsg('diag', '*** tagging enum:', enumname, '-> required =', required) enum = self.lookupElementInfo(enumname, self.enumdict) if (enum != None): enum.required = required else: self.gen.logMsg('warn', '*** enum:', enumname, 'IS NOT DEFINED') # # features - Element for <require> or <remove> tag # required - boolean (to tag features as required or not) def markRequired(self, features, required): """Require or remove features specified in the Element""" self.gen.logMsg( 'diag', '*** markRequired (features = <too long to print>, required =', required, ')') # Loop over types, enums, and commands in the tag # @@ It would be possible to respect 'api' and 'profile' attributes # in individual features, but that's not done yet. for typeElem in features.findall('type'): self.markTypeRequired(typeElem.get('name'), required) for enumElem in features.findall('enum'): self.markEnumRequired(enumElem.get('name'), required) for cmdElem in features.findall('command'): name = cmdElem.get('name') self.gen.logMsg('diag', '*** tagging command:', name, '-> required =', required) cmd = self.lookupElementInfo(name, self.cmddict) if (cmd != None): cmd.required = required # Tag all parameter types of this command as required. # This DOES NOT remove types of commands in a <remove> # tag, because many other commands may use the same type. # We could be more clever and reference count types, # instead of using a boolean. if (required): # Look for <type> in entire <command> tree, # not just immediate children for type in cmd.elem.findall('.//type'): self.gen.logMsg( 'diag', '*** markRequired: command implicitly requires dependent type', type.text) self.markTypeRequired(type.text, required) else: self.gen.logMsg('warn', '*** command:', name, 'IS NOT DEFINED') # # interface - Element for <version> or <extension>, containing # <require> and <remove> tags # api - string specifying API name being generated # profile - string specifying API profile being generated def requireAndRemoveFeatures(self, interface, api, profile): """Process <recquire> and <remove> tags for a <version> or <extension>""" # <require> marks things that are required by this version/profile for feature in interface.findall('require'): if (matchAPIProfile(api, profile, feature)): self.markRequired(feature, True) # <remove> marks things that are removed by this version/profile for feature in interface.findall('remove'): if (matchAPIProfile(api, profile, feature)): self.markRequired(feature, False) def assignAdditionalValidity(self, interface, api, profile): # # Loop over all usage inside all <require> tags. for feature in interface.findall('require'): if (matchAPIProfile(api, profile, feature)): for v in feature.findall('usage'): if v.get('command'): self.cmddict[v.get( 'command')].additionalValidity.append( copy.deepcopy(v)) if v.get('struct'): self.typedict[v.get( 'struct')].additionalValidity.append( copy.deepcopy(v)) # # Loop over all usage inside all <remove> tags. for feature in interface.findall('remove'): if (matchAPIProfile(api, profile, feature)): for v in feature.findall('usage'): if v.get('command'): self.cmddict[v.get('command')].removedValidity.append( copy.deepcopy(v)) if v.get('struct'): self.typedict[v.get('struct')].removedValidity.append( copy.deepcopy(v)) # # generateFeature - generate a single type / enum group / enum / command, # and all its dependencies as needed. # fname - name of feature (<type>/<enum>/<command>) # ftype - type of feature, 'type' | 'enum' | 'command' # dictionary - of *Info objects - self.{type|enum|cmd}dict def generateFeature(self, fname, ftype, dictionary): f = self.lookupElementInfo(fname, dictionary) if (f == None): # No such feature. This is an error, but reported earlier self.gen.logMsg('diag', '*** No entry found for feature', fname, 'returning!') return # # If feature isn't required, or has already been declared, return if (not f.required): self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not required)') return if (f.declared): self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(already declared)') return # Always mark feature declared, as though actually emitted f.declared = True # # Pull in dependent declaration(s) of the feature. # For types, there may be one type in the 'required' attribute of # the element, as well as many in imbedded <type> and <enum> tags # within the element. # For commands, there may be many in <type> tags within the element. # For enums, no dependencies are allowed (though perhaps if you # have a uint64 enum, it should require GLuint64). genProc = None if (ftype == 'type'): genProc = self.gen.genType if ('requires' in f.elem.attrib): depname = f.elem.get('requires') self.gen.logMsg('diag', '*** Generating required dependent type', depname) self.generateFeature(depname, 'type', self.typedict) for subtype in f.elem.findall('.//type'): self.gen.logMsg('diag', '*** Generating required dependent <type>', subtype.text) self.generateFeature(subtype.text, 'type', self.typedict) for subtype in f.elem.findall('.//enum'): self.gen.logMsg('diag', '*** Generating required dependent <enum>', subtype.text) self.generateFeature(subtype.text, 'enum', self.enumdict) # If the type is an enum group, look up the corresponding # group in the group dictionary and generate that instead. if (f.elem.get('category') == 'enum'): self.gen.logMsg('diag', '*** Type', fname, 'is an enum group, so generate that instead') group = self.lookupElementInfo(fname, self.groupdict) if (group == None): # Unless this is tested for, it's probably fatal to call below genProc = None self.logMsg('warn', '*** NO MATCHING ENUM GROUP FOUND!!!') else: genProc = self.gen.genGroup f = group elif (ftype == 'command'): genProc = self.gen.genCmd for type in f.elem.findall('.//type'): depname = type.text self.gen.logMsg('diag', '*** Generating required parameter type', depname) self.generateFeature(depname, 'type', self.typedict) elif (ftype == 'enum'): genProc = self.gen.genEnum # Actually generate the type only if emitting declarations if self.emitFeatures: self.gen.logMsg('diag', '*** Emitting', ftype, 'decl for', fname) genProc(f, fname) else: self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not emitting this feature)') # # generateRequiredInterface - generate all interfaces required # by an API version or extension # interface - Element for <version> or <extension> def generateRequiredInterface(self, interface): """Generate required C interface for specified API version/extension""" # # Loop over all features inside all <require> tags. for features in interface.findall('require'): for t in features.findall('type'): self.generateFeature(t.get('name'), 'type', self.typedict) for e in features.findall('enum'): self.generateFeature(e.get('name'), 'enum', self.enumdict) for c in features.findall('command'): self.generateFeature(c.get('name'), 'command', self.cmddict) # # apiGen(genOpts) - generate interface for specified versions # genOpts - GeneratorOptions object with parameters used # by the Generator object. def apiGen(self, genOpts): """Generate interfaces for the specified API type and range of versions""" # self.gen.logMsg('diag', '*******************************************') self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename, 'api:', genOpts.apiname, 'profile:', genOpts.profile) self.gen.logMsg('diag', '*******************************************') # self.genOpts = genOpts # Reset required/declared flags for all features self.apiReset() # # Compile regexps used to select versions & extensions regVersions = re.compile(self.genOpts.versions) regEmitVersions = re.compile(self.genOpts.emitversions) regAddExtensions = re.compile(self.genOpts.addExtensions) regRemoveExtensions = re.compile(self.genOpts.removeExtensions) # # Get all matching API versions & add to list of FeatureInfo features = [] apiMatch = False for key in self.apidict: fi = self.apidict[key] api = fi.elem.get('api') if (api == self.genOpts.apiname): apiMatch = True if (regVersions.match(fi.version)): # Matches API & version #s being generated. Mark for # emission and add to the features[] list . # @@ Could use 'declared' instead of 'emit'? fi.emit = (regEmitVersions.match(fi.version) != None) features.append(fi) if (not fi.emit): self.gen.logMsg( 'diag', '*** NOT tagging feature api =', api, 'name =', fi.name, 'version =', fi.version, 'for emission (does not match emitversions pattern)' ) else: self.gen.logMsg('diag', '*** NOT including feature api =', api, 'name =', fi.name, 'version =', fi.version, '(does not match requested versions)') else: self.gen.logMsg('diag', '*** NOT including feature api =', api, 'name =', fi.name, '(does not match requested API)') if (not apiMatch): self.gen.logMsg('warn', '*** No matching API versions found!') # # Get all matching extensions, in order by their extension number, # and add to the list of features. # Start with extensions tagged with 'api' pattern matching the API # being generated. Add extensions matching the pattern specified in # regExtensions, then remove extensions matching the pattern # specified in regRemoveExtensions for (extName, ei) in sorted(self.extdict.items(), key=lambda x: x[1].number): extName = ei.name include = False # # Include extension if defaultExtensions is not None and if the # 'supported' attribute matches defaultExtensions. The regexp in # 'supported' must exactly match defaultExtensions, so bracket # it with ^(pat)$. pat = '^(' + ei.elem.get('supported') + ')$' if (self.genOpts.defaultExtensions and re.match(pat, self.genOpts.defaultExtensions)): self.gen.logMsg( 'diag', '*** Including extension', extName, "(defaultExtensions matches the 'supported' attribute)") include = True # # Include additional extensions if the extension name matches # the regexp specified in the generator options. This allows # forcing extensions into an interface even if they're not # tagged appropriately in the registry. if (regAddExtensions.match(extName) != None): self.gen.logMsg( 'diag', '*** Including extension', extName, '(matches explicitly requested extensions to add)') include = True # Remove extensions if the name matches the regexp specified # in generator options. This allows forcing removal of # extensions from an interface even if they're tagged that # way in the registry. if (regRemoveExtensions.match(extName) != None): self.gen.logMsg( 'diag', '*** Removing extension', extName, '(matches explicitly requested extensions to remove)') include = False # # If the extension is to be included, add it to the # extension features list. if (include): ei.emit = True features.append(ei) else: self.gen.logMsg( 'diag', '*** NOT including extension', extName, '(does not match api attribute or explicitly requested extensions)' ) # # Sort the extension features list, if a sort procedure is defined if (self.genOpts.sortProcedure): self.genOpts.sortProcedure(features) # # Pass 1: loop over requested API versions and extensions tagging # types/commands/features as required (in an <require> block) or no # longer required (in an <remove> block). It is possible to remove # a feature in one version and restore it later by requiring it in # a later version. # If a profile other than 'None' is being generated, it must # match the profile attribute (if any) of the <require> and # <remove> tags. self.gen.logMsg( 'diag', '*** PASS 1: TAG FEATURES ********************************************' ) for f in features: self.gen.logMsg( 'diag', '*** PASS 1: Tagging required and removed features for', f.name) self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile) self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile) # # Pass 2: loop over specified API versions and extensions printing # declarations for required things which haven't already been # generated. self.gen.logMsg( 'diag', '*** PASS 2: GENERATE INTERFACES FOR FEATURES ************************' ) self.gen.beginFile(self.genOpts) for f in features: self.gen.logMsg('diag', '*** PASS 2: Generating interface for', f.name) emit = self.emitFeatures = f.emit if (not emit): self.gen.logMsg('diag', '*** PASS 2: NOT declaring feature', f.elem.get('name'), 'because it is not tagged for emission') # Generate the interface (or just tag its elements as having been # emitted, if they haven't been). self.gen.beginFeature(f.elem, emit) self.generateRequiredInterface(f.elem) self.gen.endFeature() self.gen.endFile() # # apiReset - use between apiGen() calls to reset internal state # def apiReset(self): """Reset type/enum/command dictionaries before generating another API""" for type in self.typedict: self.typedict[type].resetState() for enum in self.enumdict: self.enumdict[enum].resetState() for cmd in self.cmddict: self.cmddict[cmd].resetState() for cmd in self.apidict: self.apidict[cmd].resetState() # # validateGroups - check that group= attributes match actual groups # def validateGroups(self): """Validate group= attributes on <param> and <proto> tags""" # Keep track of group names not in <group> tags badGroup = {} self.gen.logMsg('diag', '*** VALIDATING GROUP ATTRIBUTES ***') for cmd in self.reg.findall('commands/command'): proto = cmd.find('proto') funcname = cmd.find('proto/name').text if ('group' in proto.attrib.keys()): group = proto.get('group') # self.gen.logMsg('diag', '*** Command ', funcname, ' has return group ', group) if (group not in self.groupdict.keys()): # self.gen.logMsg('diag', '*** Command ', funcname, ' has UNKNOWN return group ', group) if (group not in badGroup.keys()): badGroup[group] = 1 else: badGroup[group] = badGroup[group] + 1 for param in cmd.findall('param'): pname = param.find('name') if (pname != None): pname = pname.text else: pname = type.get('name') if ('group' in param.attrib.keys()): group = param.get('group') if (group not in self.groupdict.keys()): # self.gen.logMsg('diag', '*** Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group) if (group not in badGroup.keys()): badGroup[group] = 1 else: badGroup[group] = badGroup[group] + 1 if (len(badGroup.keys()) > 0): self.gen.logMsg('diag', '*** SUMMARY OF UNRECOGNIZED GROUPS ***') for key in sorted(badGroup.keys()): self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times')
def genCmd(self, cmdinfo, name, alias): "Generate command." OutputGenerator.genCmd(self, cmdinfo, name, alias) decls = self.makeCDecls(cmdinfo.elem) self.writeInclude('protos', name, decls[0])
def genEnum(self, enuminfo, name, alias): """Generate enumerant.""" OutputGenerator.genEnum(self, enuminfo, name, alias) self.logMsg('diag', '# NOT writing compile-time constant', name)
def endFeature(self): # Finish processing in superclass OutputGenerator.endFeature(self)