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 makeValueInfo(self, params): values = [] for param in params: # Get name elem = param.find('name') name = noneStr(elem.text) nameTail = noneStr(elem.tail) # Get type info elem = param.find('type') baseType = noneStr(elem.text) fullType = (noneStr(param.text) + baseType + noneStr(elem.tail)).strip() # Check for platform specific type definitions that need to be converted to a recognized trace format type. platformBaseType = None platformFullType = None if baseType in self.PLATFORM_TYPES: typeInfo = self.PLATFORM_TYPES[baseType] platformBaseType = baseType platformFullType = fullType fullType = fullType.replace(baseType, typeInfo['replaceWith']) baseType = typeInfo['baseType'] # Get array length, always use altlen when available to avoid parsing latexmath if 'altlen' in param.attrib: arrayLength = param.attrib.get('altlen') else: arrayLength = self.getArrayLen(param) arrayCapacity = None if self.isStaticArray(param): arrayCapacity = arrayLength arrayLength = self.getStaticArrayLen(name, params, arrayCapacity) # Get bitfield width bitfieldWidth = None if ':' in nameTail: bitfieldWidth = nameTail values.append( ValueInfo(name=name, baseType=baseType, fullType=fullType, pointerCount=self.getPointerCount(fullType), arrayLength=arrayLength, arrayCapacity=arrayCapacity, platformBaseType=platformBaseType, platformFullType=platformFullType, bitfieldWidth=bitfieldWidth)) # Link array values to their corresponding length values for arrayValue in [v for v in values if v.arrayLength]: for v in values: if re.search(r'\b{}\b'.format(v.name), arrayValue.arrayLength): arrayValue.arrayLengthValue = v break return values
def genType(self, typeinfo, name): OutputGenerator.genType(self, typeinfo, name) 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') if (category == 'struct' or category == 'union'): self.genStruct(typeinfo, name) 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. s = noneStr(typeElem.text) for elem in typeElem: if (elem.tag == 'apientry'): s += self.genOpts.apientry + noneStr(elem.tail) else: s += noneStr(elem.text) + noneStr(elem.tail) if (len(s) > 0): if (category in OutputGenerator.categoryToPath.keys()): self.writeInclude(OutputGenerator.categoryToPath[category], name, s + '\n') else: self.logMsg('diag', '# NOT writing include file for type:', name, 'category: ', category) else: self.logMsg('diag', '# NOT writing empty include file for type', name)
def makeValueInfo(self, params): values = [] for param in params: # Get name elem = param.find('name') name = noneStr(elem.text) nameTail = noneStr(elem.tail) # Get type info elem = param.find('type') baseType = noneStr(elem.text) fullType = (noneStr(param.text) + baseType + noneStr(elem.tail)).strip() # Check for platform specific type definitions that need to be converted to a recognized trace format type. platformBaseType = None platformFullType = None if baseType in self.PLATFORM_TYPES: typeInfo = self.PLATFORM_TYPES[baseType] platformBaseType = baseType platformFullType = fullType fullType = fullType.replace(baseType, typeInfo['replaceWith']) baseType = typeInfo['baseType'] # Get array length arrayLength = self.getArrayLen(param) altArrayLength = param.attrib.get('altlen') arrayCapacity = None if self.isStaticArray(param): arrayCapacity = arrayLength arrayLength = self.getStaticArrayLen(name, params, arrayCapacity) # Get bitfield width bitfieldWidth = None if ':' in nameTail: bitfieldWidth = nameTail values.append( ValueInfo(name=name, baseType=baseType, fullType=fullType, pointerCount=self.getPointerCount(fullType), arrayLength=arrayLength, altArrayLength=altArrayLength, arrayCapacity=arrayCapacity, platformBaseType=platformBaseType, platformFullType=platformFullType, bitfieldWidth=bitfieldWidth)) return values
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') 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: body = self.genRequirements(name) 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 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 getStaticArrayLen(self, name, params, capacity): # The XML registry does not provide a direct method for determining if a parameter provides the length # of a static array, but the parameter naming follows a pattern of array name = 'values' and length # name = 'valueCount'. We will search the parameter list for a length parameter using this pattern. lengthName = name[:-1] + 'Count' for param in params: if lengthName == noneStr(param.find('name').text): return lengthName # Not all static arrays have an associated length parameter. These will use capacity as length. return capacity
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 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 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 makeStructureTypeEnum(self, typeinfo, typename): members = typeinfo.elem.findall('.//member') for member in members: membername = noneStr(member.find('name').text) # We only care about structures with an sType, which can be included in a pNext chain. if membername == 'sType': # Check for value in the XML element. values = member.attrib.get('values') if values: return values else: # If the value was not specified by the XML element, process the struct type to create it. stype = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename) stype = stype.replace('D3_D12', 'D3D12') stype = stype.replace('Device_IDProp', 'Device_ID_Prop') stype = stype.upper() return re.sub('VK_', 'VK_STRUCTURE_TYPE_', stype) return None
def makeVulkanTypeFromXMLTag(typeInfo, tag): res = VulkanType() # Process the length expression if tag.attrib.get("len") is not None: lengths = tag.attrib.get("len").split(",") res.lenExpr = lengths[0] # Calculate static array expression nametag = tag.find("name") enumtag = tag.find("enum") if enumtag is not None: res.staticArrExpr = enumtag.text elif nametag is not None: res.staticArrExpr = noneStr(nametag.tail)[1:-1] if res.staticArrExpr != "": res.staticArrCount = int(res.staticArrExpr) # Determine const beforeTypePart = noneStr(tag.text) if "const" in beforeTypePart: res.isConst = True # Calculate type and pointer info for elem in tag: if elem.tag == "name": res.paramName = elem.text if elem.tag == "type": duringTypePart = noneStr(elem.text) afterTypePart = noneStr(elem.tail) # Now we know enough to fill some stuff in res.typeName = duringTypePart if res.typeName in TRANSFORMED_TYPES: res.isTransformed = True # This only handles pointerIndirectionLevels == 2 # along with optional constant pointer for the inner part. for c in afterTypePart: if c == "*": res.pointerIndirectionLevels += 1 if "const" in afterTypePart and res.pointerIndirectionLevels == 2: res.isPointerToConstPointer = True # If void*, treat like it's not a pointer # if duringTypePart == "void": # res.pointerIndirectionLevels -= 1 # Calculate optionality (based on validitygenerator.py) if tag.attrib.get("optional") is not None: res.isOptional = True res.optionalStr = tag.attrib.get("optional") # If no validity is being generated, it usually means that # validity is complex and not absolute, so let's say yes. if tag.attrib.get("noautovalidity") is not None: res.isOptional = True # If this is a structure extension, it is optional. if tag.attrib.get("structextends") is not None: res.isOptional = True # If this is a pNext pointer, it is optional. if res.paramName == "pNext": res.isOptional = True res.primitiveEncodingSize = \ typeInfo.getPrimitiveEncodingSize(res.typeName) # Annotations: Environment binds if tag.attrib.get("binds") is not None: bindPairs = map(lambda x: x.strip(), tag.attrib.get("binds").split(",")) bindPairsSplit = map(lambda p: p.split(":"), bindPairs) res.binds = dict( map(lambda sp: (sp[0].strip(), sp[1].strip()), bindPairsSplit)) # Annotations: Device memory for k in DEVICE_MEMORY_INFO_KEYS: if tag.attrib.get(k) is not None: res.deviceMemoryAttrib = k res.deviceMemoryVal = \ tag.attrib.get(k) break # Annotations: Filters if tag.attrib.get("filterVar") is not None: res.filterVar = tag.attrib.get("filterVar").strip() if tag.attrib.get("filterVals") is not None: res.filterVals = \ list(map(lambda v: v.strip(), tag.attrib.get("filterVals").strip().split(","))) print("Filtervals: %s" % res.filterVals) if tag.attrib.get("filterFunc") is not None: res.filterFunc = parseFilterFuncExpr(tag.attrib.get("filterFunc")) if tag.attrib.get("filterOtherwise") is not None: res.Otherwise = tag.attrib.get("filterOtherwise") # store all other attribs here res.attribs = dict(tag.attrib) return res
def genType(self, typeinfo, name, alias): """Generate type. - For 'struct' or 'union' types, defer to genStruct() to add to the dictionary. - For 'bitmask' types, add the type name to the 'flags' dictionary, with the value being the corresponding 'enums' name defining the acceptable flag bits. - For 'enum' types, add the type name to the 'enums' dictionary, with the value being '@STOPHERE@' (because this case seems never to happen). - For 'funcpointer' types, add the type name to the 'funcpointers' dictionary. - For 'handle' and 'define' types, add the handle or #define name to the 'struct' dictionary, because that's how the spec sources tag these types even though they aren't structs.""" 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 makeVulkanTypeFromXMLTag(typeInfo, tag): res = VulkanType() # Process the length expression if tag.attrib.get("len") is not None: lengths = tag.attrib.get("len").split(",") res.lenExpr = lengths[0] # Calculate static array expression nametag = tag.find("name") enumtag = tag.find("enum") if enumtag is not None: res.staticArrExpr = enumtag.text elif nametag is not None: res.staticArrExpr = noneStr(nametag.tail)[1:-1] if res.staticArrExpr != "": res.staticArrCount = int(res.staticArrExpr) # Determine const beforeTypePart = noneStr(tag.text) if "const" in beforeTypePart: res.isConst = True # Calculate type and pointer info for elem in tag: if elem.tag == "name": res.paramName = elem.text if elem.tag == "type": duringTypePart = noneStr(elem.text) afterTypePart = noneStr(elem.tail) # Now we know enough to fill some stuff in res.typeName = duringTypePart if res.typeName in TRANSFORMED_TYPES: res.isTransformed = True # This only handles pointerIndirectionLevels == 2 # along with optional constant pointer for the inner part. for c in afterTypePart: if c == "*": res.pointerIndirectionLevels += 1 if "const" in afterTypePart and res.pointerIndirectionLevels == 2: res.isPointerToConstPointer = True # If void*, treat like it's not a pointer # if duringTypePart == "void": # res.pointerIndirectionLevels -= 1 # Calculate optionality (based on validitygenerator.py) if tag.attrib.get("optional") is not None: res.isOptional = True # If no validity is being generated, it usually means that # validity is complex and not absolute, so let's say yes. if tag.attrib.get("noautovalidity") is not None: res.isOptional = True # If this is a structure extension, it is optional. if tag.attrib.get("structextends") is not None: res.isOptional = True # If this is a pNext pointer, it is optional. if res.paramName == "pNext": res.isOptional = True res.primitiveEncodingSize = \ typeInfo.getPrimitiveEncodingSize(res.typeName) # it is assumed only one such key # applies to any field. for k in DEVICE_MEMORY_INFO_KEYS: if tag.attrib.get(k) is not None: res.deviceMemoryAttrib = k res.deviceMemoryVal = \ tag.attrib.get(k) break return res
def makeStub(self, cmd): """Generate a stub function pointer <command> Element""" proto = cmd.find('proto') params = cmd.findall('param') name = cmd.find('name') # Begin accumulating prototype and typedef strings pfnDecl = 'static ' pfnDecl += noneStr(proto.text) # Find the name tag and generate the function pointer and function pointer initialization code nameTag = proto.find('name') tail = noneStr(nameTag.tail) returnType = noneStr(proto.find('type').text) pfn_type = self.makeFunctionPointerType(nameTag.text, tail) # For each child element, if it's a <name> wrap in appropriate # declaration. Otherwise append its contents and tail con#tents. stubDecl = '' for elem in proto: text = noneStr(elem.text) tail = noneStr(elem.tail) if elem.tag == 'name': name = self.makeProtoName(text, tail) stubDecl += name else: stubDecl += text + tail pfnName = self.makeFunctionPointerName(nameTag.text, noneStr(tail)) pfnDecl += pfn_type + ' ' + pfnName + ';' # Now generate the stub function pfnDecl += '\n' # Now add the parameter declaration list, which is identical # for prototypes and typedefs. Concatenate all the text from # a <param> node without the tags. No tree walking required # since all tags are ignored. n = len(params) paramdecl = '(\n' pfnCall = '\n{\n ' + ('return ', '')[returnType == 'void'] + pfnName + '(\n' # Indented parameters align = self.genOpts.alignFuncParam if n > 0: indentCallParam = '(\n' indentdecl = '(\n' indentdecl += ',\n'.join( self.makeCParamDecl(p, align) for p in params) indentdecl += ')' pfnCall += ',\n'.join( self.makeCCallParam(p, align) for p in params) pfnCall += '\n );\n' indentCallParam += pfnCall else: indentdecl = '(void);' pfnCall += '}\n' featureInstance = ' ' + pfnName + ' = (' + pfn_type + ')vkGetInstanceProcAddr(instance, "' + name + '");' featureDevice = ' ' + pfnName + ' = (' + pfn_type + ')vkGetDeviceProcAddr(device, "' + name + '");' return [ featureInstance, featureDevice, pfnDecl + stubDecl + paramdecl + pfnCall ]