aboutsummaryrefslogtreecommitdiffhomepage
path: root/registry/reg.py
diff options
context:
space:
mode:
authorJon Leech <[email protected]>2021-11-30 18:40:09 -0800
committerJon Leech <[email protected]>2021-11-30 18:43:56 -0800
commitea61f32f24d2ce28b358e154910fb4eb410ffd79 (patch)
treefaa0bba9eee20092bc51b62167ef9d05cab3b0a4 /registry/reg.py
parenta15237165443ba1ef430ed332745f9a99ec509ad (diff)
downloadVulkan-Headers-ea61f32f24d2ce28b358e154910fb4eb410ffd79.tar.gz
Vulkan-Headers-ea61f32f24d2ce28b358e154910fb4eb410ffd79.zip
Update for Vulkan-Docs 1.2.201v1.2.201
Diffstat (limited to 'registry/reg.py')
-rw-r--r--registry/reg.py130
1 files changed, 87 insertions, 43 deletions
diff --git a/registry/reg.py b/registry/reg.py
index 391abdb..6eec554 100644
--- a/registry/reg.py
+++ b/registry/reg.py
@@ -10,19 +10,24 @@ import copy
import re
import sys
import xml.etree.ElementTree as etree
-from collections import defaultdict, namedtuple
+from collections import defaultdict, deque, namedtuple
from generator import OutputGenerator, GeneratorOptions, write
-import pdb
+from apiconventions import APIConventions
def apiNameMatch(str, supported):
"""Return whether a required api name matches a pattern specified for an
XML <feature> 'api' attribute or <extension> 'supported' attribute.
- - str - api name such as 'vulkan' or 'openxr'
- - supported - comma-separated list of XML API names"""
+ - str - API name such as 'vulkan' or 'openxr'. May be None, in which
+ case it never matches (this should not happen).
+ - supported - comma-separated list of XML API names. May be None, in
+ which case str always matches (this is the usual case)."""
- return (str is not None and str in supported.split(','))
+ if str is not None:
+ return supported is None or str in supported.split(',')
+ # Fallthrough case - either str is None or the test failed
+ return False
def matchAPIProfile(api, profile, elem):
"""Return whether an API and profile
@@ -52,7 +57,7 @@ def matchAPIProfile(api, profile, elem):
--------- --------
None None Always matches
'string' None Always matches
- None 'string' Does not match. Can't generate multiple APIs
+ None 'string' Does not match. Cannot generate multiple APIs
or profiles, so if an API/profile constraint
is present, it must be asked for explicitly.
'string' 'string' Strings must match
@@ -60,7 +65,7 @@ def matchAPIProfile(api, profile, elem):
** In the future, we will allow regexes for the attributes,
not just strings, so that `api="^(gl|gles2)"` will match. Even
- this isn't really quite enough, we might prefer something
+ this is not really quite enough, we might prefer something
like `"gl(core)|gles1(common-lite)"`."""
# Match 'api', if present
elem_api = elem.get('api')
@@ -69,7 +74,7 @@ def matchAPIProfile(api, profile, elem):
raise UserWarning("No API requested, but 'api' attribute is present with value '"
+ elem_api + "'")
elif api != elem_api:
- # Requested API doesn't match attribute
+ # Requested API does not match attribute
return False
elem_profile = elem.get('profile')
if elem_profile:
@@ -77,11 +82,37 @@ def matchAPIProfile(api, profile, elem):
raise UserWarning("No profile requested, but 'profile' attribute is present with value '"
+ elem_profile + "'")
elif profile != elem_profile:
- # Requested profile doesn't match attribute
+ # Requested profile does not match attribute
return False
return True
+def stripNonmatchingAPIs(tree, apiName, actuallyDelete = True):
+ """Remove tree Elements with 'api' attributes matching apiName.
+
+ tree - Element at the root of the hierarchy to strip. Only its
+ children can actually be removed, not the tree itself.
+ apiName - string which much match a command-separated component of
+ the 'api' attribute.
+ actuallyDelete - only delete matching elements if True."""
+
+ stack = deque()
+ stack.append(tree)
+
+ while len(stack) > 0:
+ parent = stack.pop()
+
+ for child in parent.findall('*'):
+ api = child.get('api')
+ if api:
+ if not apiNameMatch(apiName, api):
+ if actuallyDelete:
+ parent.remove(child)
+ else:
+ # Add child to the queue
+ stack.append(child)
+
+
class BaseInfo:
"""Base class for information about a registry feature
(type/group/enum/command/API/extension).
@@ -128,12 +159,12 @@ class BaseInfo:
if (self.compareKeys(info, 'value', required = True) or
self.compareKeys(info, 'bitpos', required = True)):
# If both specify the same value or bit position,
- # they're equal
+ # they are equal
return True
elif (self.compareKeys(info, 'extnumber') and
self.compareKeys(info, 'offset') and
self.compareKeys(info, 'dir')):
- # If both specify the same relative offset, they're equal
+ # If both specify the same relative offset, they are equal
return True
elif (self.compareKeys(info, 'alias')):
# If both are aliases of the same value
@@ -141,7 +172,7 @@ class BaseInfo:
else:
return False
else:
- # The same enum can't extend two different types
+ # The same enum cannot extend two different types
return False
else:
# Non-<enum>s should never be redefined
@@ -248,7 +279,7 @@ class FeatureInfo(BaseInfo):
enumerant offsets. <feature> features do not have extension
numbers and are assigned number 0."""
- # If there's no 'number' attribute, use 0, so sorting works
+ # If there is no 'number' attribute, use 0, so sorting works
if self.number is None:
self.number = 0
self.supported = elem.get('supported')
@@ -278,7 +309,9 @@ class Registry:
"Output generator used to write headers / messages"
if genOpts is None:
- self.genOpts = GeneratorOptions()
+ # If no generator is provided, we may still need the XML API name
+ # (for example, in genRef.py).
+ self.genOpts = GeneratorOptions(apiname = APIConventions().xml_api_name)
else:
self.genOpts = genOpts
"Options controlling features to write and how to format them"
@@ -417,15 +450,26 @@ class Registry:
# This must be the Element for the root <registry>
self.reg = self.tree.getroot()
+ # Preprocess the tree by removing all elements with non-matching
+ # 'api' attributes by breadth-first tree traversal.
+ # This is a blunt hammer, but eliminates the need to track and test
+ # the apis deeper in processing to select the correct elements and
+ # avoid duplicates.
+ # Schema validation should prevent duplicate elements with
+ # overlapping api attributes, or where one element has an api
+ # attribute and the other does not.
+
+ stripNonmatchingAPIs(self.reg, self.genOpts.apiname)
+
# 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
+ # There is usually one <types> block; more are OK
# Required <type> attributes: 'name' or nested <name> tag contents
self.typedict = {}
for type_elem in self.reg.findall('types/type'):
- # If the <type> doesn't already have a 'name' attribute, set
+ # If the <type> does not already have a 'name' attribute, set
# it from contents of its <name> tag.
if type_elem.get('name') is None:
type_elem.set('name', type_elem.find('name').text)
@@ -434,8 +478,8 @@ class Registry:
# 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.
+ # generated, but that group cannot be identified and turned into an
+ # enum type definition - it is just a container for <enum> tags.
self.groupdict = {}
for group in self.reg.findall('enums'):
self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict)
@@ -461,7 +505,7 @@ class Registry:
# 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.
+ # There is usually only one <commands> block; more are OK.
# Required <command> attributes: 'name' or <proto><name> tag contents
self.cmddict = {}
# List of commands which alias others. Contains
@@ -469,7 +513,7 @@ class Registry:
# for each alias
cmdAlias = []
for cmd in self.reg.findall('commands/command'):
- # If the <command> doesn't already have a 'name' attribute, set
+ # If the <command> does not already have a 'name' attribute, set
# it from contents of its <proto><name> tag.
name = cmd.get('name')
if name is None:
@@ -516,11 +560,11 @@ class Registry:
# Instead, generateRequiredInterface ignores <enum> elements
# that extend enumerated types.
#
- # For <enum> tags which are actually just constants, if there's
+ # For <enum> tags which are actually just constants, if there is
# 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.
+ # does not need to iterate through the XML tags.
for elem in feature.findall('require'):
for enum in elem.findall('enum'):
addEnumInfo = False
@@ -608,7 +652,7 @@ class Registry:
for parent in parentStructs.split(','):
# self.gen.logMsg('diag', type.get('name'), 'extends', parent)
self.validextensionstructs[parent].append(type_elem.get('name'))
- # Sort the lists so they don't depend on the XML order
+ # Sort the lists so they do not depend on the XML order
for parent in self.validextensionstructs:
self.validextensionstructs[parent].sort()
@@ -688,7 +732,7 @@ class Registry:
if depname:
self.gen.logMsg('diag', 'Generating dependent type',
depname, 'for', attrib_name, 'type', typename)
- # Don't recurse on self-referential structures.
+ # Do not recurse on self-referential structures.
if typename != depname:
self.markTypeRequired(depname, required)
else:
@@ -735,10 +779,10 @@ class Registry:
if enum is not None:
# If the enum is part of a group, and is being removed, then
# look it up in that <group> tag and remove it there, so that it
- # isn't visible to generators (which traverse the <group> tag
+ # is not visible to generators (which traverse the <group> tag
# elements themselves).
- # This isn't the most robust way of doing this, since a removed
- # enum that's later required again will no longer have a group
+ # This is not the most robust way of doing this, since a removed
+ # enum that is later required again will no longer have a group
# element, but it makes the change non-intrusive on generator
# code.
if required is False:
@@ -820,7 +864,7 @@ class Registry:
# 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.
+ # in individual features, but that is not done yet.
for typeElem in feature.findall('type'):
self.markTypeRequired(typeElem.get('name'), required)
for enumElem in feature.findall('enum'):
@@ -920,7 +964,7 @@ class Registry:
typeinfo = self.lookupElementInfo(typename, self.typedict)
if typeinfo:
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
+ # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
alias = self.getAlias(typeElem, self.typedict)
if not self.checkForCorrectionAliases(alias, require, 'type'):
# Resolve the type info to the actual type, so we get an accurate read for 'structextends'
@@ -943,7 +987,7 @@ class Registry:
enumname = enumElem.get('name')
typeinfo = self.lookupElementInfo(enumname, self.enumdict)
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
+ # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
alias = self.getAlias(enumElem, self.enumdict)
if not self.checkForCorrectionAliases(alias, require, 'enum'):
enumextends = enumElem.get('extends')
@@ -956,7 +1000,7 @@ class Registry:
self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
for cmdElem in require.findall('command'):
- # Remove aliases in the same extension/feature; these are always added as a correction. Don't need the original to be visible.
+ # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
alias = self.getAlias(cmdElem, self.cmddict)
if not self.checkForCorrectionAliases(alias, require, 'command'):
if not required_key in self.gen.featureDictionary[featurename]['command']:
@@ -1019,7 +1063,7 @@ class Registry:
'returning!')
return
- # If feature isn't required, or has already been declared, return
+ # If feature is not required, or has already been declared, return
if not f.required:
self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)')
return
@@ -1096,7 +1140,7 @@ class Registry:
# @ The enum group is not ready for generation. At this
# @ point, it contains all <enum> tags injected by
# @ <extension> tags without any verification of whether
- # @ they're required or not. It may also contain
+ # @ they are required or not. It may also contain
# @ duplicates injected by multiple consistent
# @ definitions of an <enum>.
@@ -1134,7 +1178,7 @@ class Registry:
if required:
# Mark this element as required (in the element, not the EnumInfo)
elem.set('required', 'true')
- # If it's an alias, track that for later use
+ # If it is an alias, track that for later use
enumAlias = elem.get('alias')
if enumAlias:
enumAliases.append(enumAlias)
@@ -1185,7 +1229,7 @@ class Registry:
for t in features.findall('type'):
self.generateFeature(t.get('name'), 'type', self.typedict)
for e in features.findall('enum'):
- # If this is an enum extending an enumerated type, don't
+ # If this is an enum extending an enumerated type, do not
# generate it - this has already been done in reg.parseTree,
# by copying this element into the enumerated type.
enumextends = e.get('extends')
@@ -1229,7 +1273,7 @@ class Registry:
##print('\t**STRIPPING API {} from {}'.format(api, key))
# Update the attribute after stripping stuff.
- # Could sort apis before joining, but it's not a clear win
+ # Could sort apis before joining, but it is not a clear win
if stripped:
eleminfo.elem.set(attribute, ','.join(apis))
@@ -1262,7 +1306,7 @@ class Registry:
# this has never been done. The 20% or so build-time speedup that
# might result is not worth the effort to make it actually work.
#
- #@@ self.apiReset()
+ # self.apiReset()
# Compile regexps used to select versions & extensions
regVersions = re.compile(self.genOpts.versions)
@@ -1327,7 +1371,7 @@ class Registry:
# 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
+ # forcing extensions into an interface even if they are not
# tagged appropriately in the registry.
# However we still respect the 'supported' attribute.
if regAddExtensions.match(extName) is not None:
@@ -1341,7 +1385,7 @@ class Registry:
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
+ # extensions from an interface even if they are tagged that
# way in the registry.
if regRemoveExtensions.match(extName) is not None:
self.gen.logMsg('diag', 'Removing extension',
@@ -1359,8 +1403,8 @@ class Registry:
'for emission (does not match emitextensions pattern)')
# Hack - can be removed when validity generator goes away
- # (Jon) I'm not sure what this does, or if it should respect
- # the ei.emit flag above.
+ # (Jon) I am not sure what this does, or if it should
+ # respect the ei.emit flag above.
self.requiredextensions.append(extName)
else:
self.gen.logMsg('diag', 'NOT including extension',
@@ -1423,7 +1467,7 @@ class Registry:
# <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
# Pass 2: loop over specified API versions and extensions printing
- # declarations for required things which haven't already been
+ # declarations for required things which have not already been
# generated.
self.gen.logMsg('diag', 'PASS 2: GENERATE INTERFACES FOR FEATURES')
self.gen.beginFile(self.genOpts)
@@ -1435,7 +1479,7 @@ class Registry:
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).
+ # emitted, if they have not been).
self.gen.beginFeature(f.elem, emit)
self.generateRequiredInterface(f.elem)
self.gen.endFeature()