summaryrefslogtreecommitdiff
path: root/codegen/vulkan/scripts/scriptgenerator.py
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/vulkan/scripts/scriptgenerator.py')
-rw-r--r--codegen/vulkan/scripts/scriptgenerator.py380
1 files changed, 0 insertions, 380 deletions
diff --git a/codegen/vulkan/scripts/scriptgenerator.py b/codegen/vulkan/scripts/scriptgenerator.py
deleted file mode 100644
index 204639de..00000000
--- a/codegen/vulkan/scripts/scriptgenerator.py
+++ /dev/null
@@ -1,380 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2021 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-from generator import OutputGenerator, enquote, noneStr
-
-def mostOfficial(api, newapi):
- """Return the 'most official' of two related names, api and newapi.
- KHR is more official than EXT is more official than everything else.
- If there is ambiguity, return api."""
-
- if api[-3:] == 'KHR':
- return api
- if newapi[-3:] == 'KHR':
- return newapi;
- if api[-3:] == 'EXT':
- return api
- if newapi[-3:] == 'EXT':
- return newapi;
- return api
-
-class ScriptOutputGenerator(OutputGenerator):
- """ScriptOutputGenerator - subclass of OutputGenerator.
- Base class to Generate script (Python/Ruby/etc.) data structures
- describing API names and relationships.
- Similar to DocOutputGenerator, but writes a single file."""
-
- def apiName(self, name):
- """Return True if name is in the reserved API namespace.
-
- Delegates to the conventions object. """
- return self.genOpts.conventions.is_api_name(name)
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- # Track features being generated
- self.features = []
-
- # Reverse map from interface names to features requiring them
- self.apimap = {}
-
- # Reverse map from unsupported APIs in this build to aliases which
- # are supported
- self.nonexistent = {}
-
- 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 addInterfaceMapping(self, api, feature, required):
- """Add a reverse mapping in self.apimap from an API to a feature
- requiring that API.
-
- - api - name of the API
- - feature - name of the feature requiring it
- - required - None, or an additional feature dependency within
- 'feature' """
-
- # Each entry in self.apimap contains one or more
- # ( feature, required ) tuples.
- deps = ( feature, required )
-
- if api in self.apimap:
- self.apimap[api].append(deps)
- else:
- self.apimap[api] = [ deps ]
-
- def mapInterfaceKeys(self, feature, key):
- """Construct reverse mapping of APIs to features requiring them in
- self.apimap.
-
- - feature - name of the feature being generated
- - key - API category - 'define', 'basetype', etc."""
-
- dict = self.featureDictionary[feature][key]
-
- if dict:
- # Not clear why handling of command vs. type APIs is different -
- # see interfacedocgenerator.py, which this was based on.
- if key == 'command':
- for required in dict:
- for api in dict[required]:
- self.addInterfaceMapping(api, feature, required)
- else:
- for required in dict:
- for parent in dict[required]:
- for api in dict[required][parent]:
- self.addInterfaceMapping(api, feature, required)
-
- def mapInterfaces(self, feature):
- """Construct reverse mapping of APIs to features requiring them in
- self.apimap.
-
- - feature - name of the feature being generated"""
-
- # Map each category of interface
- self.mapInterfaceKeys(feature, 'basetype')
- self.mapInterfaceKeys(feature, 'bitmask')
- self.mapInterfaceKeys(feature, 'command')
- self.mapInterfaceKeys(feature, 'define')
- self.mapInterfaceKeys(feature, 'enum')
- self.mapInterfaceKeys(feature, 'enumconstant')
- self.mapInterfaceKeys(feature, 'funcpointer')
- self.mapInterfaceKeys(feature, 'handle')
- self.mapInterfaceKeys(feature, 'include')
- self.mapInterfaceKeys(feature, 'struct')
- self.mapInterfaceKeys(feature, 'union')
-
- def endFile(self):
- super().endFile()
-
- def beginFeature(self, interface, emit):
- # Start processing in superclass
- OutputGenerator.beginFeature(self, interface, emit)
-
- # Add this feature to the list being tracked
- self.features.append( self.featureName )
-
- def endFeature(self):
- # Finish processing in superclass
- OutputGenerator.endFeature(self)
-
- def addName(self, dict, name, value):
- """Add a string entry to the dictionary, quoting it so it gets
- printed out correctly in self.endFile()."""
- dict[name] = value
-
- def addMapping(self, baseType, refType):
- """Add a mapping between types to mapDict.
-
- Only include API types, so we don't end up with a lot of useless uint32_t and void types."""
- if not self.apiName(baseType) or not self.apiName(refType):
- self.logMsg('diag', 'ScriptOutputGenerator::addMapping: IGNORE map from', baseType, '<->', refType)
- return
-
- self.logMsg('diag', 'ScriptOutputGenerator::addMapping: map from',
- baseType, '<->', refType)
-
- if baseType not in self.mapDict:
- baseDict = {}
- self.mapDict[baseType] = baseDict
- else:
- baseDict = self.mapDict[baseType]
- if refType not in self.mapDict:
- refDict = {}
- self.mapDict[refType] = refDict
- else:
- refDict = self.mapDict[refType]
-
- baseDict[refType] = None
- refDict[baseType] = None
-
- def breakCheck(self, procname, name):
- """Debugging aid - call from procname to break on API 'name' if it
- matches logic in this call."""
-
- pat = 'VkExternalFenceFeatureFlagBits'
- if name[0:len(pat)] == pat:
- print('{}(name = {}) matches {}'.format(procname, name, pat))
- import pdb
- pdb.set_trace()
-
- 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', 'ScriptOutputGenerator::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', 'ScriptOutputGenerator::genType: unprocessed type:', name, 'category:', category)
- else:
- self.logMsg('diag', 'ScriptOutputGenerator::genType: unprocessed type:', name)
-
- 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 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
-
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, groupName, 'group')
-
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, groupName, alias)
- else:
- # May want to only emit definition on this branch
- True
-
- # Add each nested 'enum' tag
- enumerants = [elem.get('name') for elem in groupElem.findall('enum')]
- for name in enumerants:
- self.addName(self.consts, name, groupName)
-
- # Sort enums for output stability, since their order is irrelevant
- self.enums[groupName] = sorted(enumerants)
-
- def genEnum(self, enuminfo, name, alias):
- """Generate enumerant (compile-time constants).
-
- - Add the constant name to the 'consts' dictionary, with the
- value being None to indicate that the constant isn't
- an enumeration value."""
- OutputGenerator.genEnum(self, enuminfo, name, alias)
-
- if name not in self.consts:
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, name, 'consts')
- self.consts[name] = None
- # Otherwise, don't add it to the consts dictionary because it's
- # already present. This happens due to the generator 'reparentEnums'
- # parameter being False, so each extension enum appears in both the
- # <enums> type and in the <extension> or <feature> it originally
- # came from.
-
- 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)
-
- # Add a typeCategory{} entry for the category of this type.
- self.addName(self.typeCategory, name, 'protos')
-
- if alias:
- # Add name -> alias mapping
- self.addName(self.alias, name, alias)
- else:
- # May want to only emit definition on this branch
- True
-
- 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 createInverseMap(self):
- """This creates the inverse mapping of nonexistent APIs in this
- build to their aliases which are supported. Must be called by
- language-specific subclasses before emitting that mapping."""
-
- # Map from APIs not supported in this build to aliases that are.
- # When there are multiple valid choices for remapping, choose the
- # most-official suffixed one (KHR > EXT > vendor).
- for key in self.alias:
- # If the API key is aliased to something which doesn't exist,
- # then add the thing that doesn't exist to the nonexistent map.
- # This is used in spec macros to make promoted extension links
- # in specs built without the promoted interface refer to the
- # older interface instead.
-
- invkey = self.alias[key]
-
- if invkey not in self.typeCategory:
- if invkey in self.nonexistent:
- # Potentially remap existing mapping to a more official
- # alias.
- self.nonexistent[invkey] = mostOfficial(self.nonexistent[invkey], key)
- else:
- # Create remapping to an alias
- self.nonexistent[invkey] = key