Show More
Commit Description:
Add missing component and message.
Commit Description:
Add missing component and message.
References:
File last commit:
Show/Diff file:
Action:
FNA/lib/FNA3D/Vulkan-Headers/registry/cgenerator.py
405 lines | 17.7 KiB | text/x-python | PythonLexer
405 lines | 17.7 KiB | text/x-python | PythonLexer
r690 | #!/usr/bin/python3 -i | |||
# | ||||
# Copyright (c) 2013-2020 The Khronos Group Inc. | ||||
# | ||||
# SPDX-License-Identifier: Apache-2.0 | ||||
import os | ||||
import re | ||||
from generator import (GeneratorOptions, OutputGenerator, noneStr, | ||||
regSortFeatures, write) | ||||
class CGeneratorOptions(GeneratorOptions): | ||||
"""CGeneratorOptions - subclass of GeneratorOptions. | ||||
Adds options used by COutputGenerator objects during C language header | ||||
generation.""" | ||||
def __init__(self, | ||||
prefixText="", | ||||
genFuncPointers=True, | ||||
protectFile=True, | ||||
protectFeature=True, | ||||
protectProto=None, | ||||
protectProtoStr=None, | ||||
apicall='', | ||||
apientry='', | ||||
apientryp='', | ||||
indentFuncProto=True, | ||||
indentFuncPointer=False, | ||||
alignFuncParam=0, | ||||
genEnumBeginEndRange=False, | ||||
genAliasMacro=False, | ||||
aliasMacro='', | ||||
**kwargs | ||||
): | ||||
"""Constructor. | ||||
Additional parameters beyond parent class: | ||||
- prefixText - list of strings to prefix generated header with | ||||
(usually a copyright statement + calling convention macros). | ||||
- protectFile - True if multiple inclusion protection should be | ||||
generated (based on the filename) around the entire header. | ||||
- protectFeature - True if #ifndef..#endif protection should be | ||||
generated around a feature interface in the header file. | ||||
- genFuncPointers - True if function pointer typedefs should be | ||||
generated | ||||
- protectProto - If conditional protection should be generated | ||||
around prototype declarations, set to either '#ifdef' | ||||
to require opt-in (#ifdef protectProtoStr) or '#ifndef' | ||||
to require opt-out (#ifndef protectProtoStr). Otherwise | ||||
set to None. | ||||
- protectProtoStr - #ifdef/#ifndef symbol to use around prototype | ||||
declarations, if protectProto is set | ||||
- apicall - string to use for the function declaration prefix, | ||||
such as APICALL on Windows. | ||||
- apientry - string to use for the calling convention macro, | ||||
in typedefs, such as APIENTRY. | ||||
- apientryp - string to use for the calling convention macro | ||||
in function pointer typedefs, such as APIENTRYP. | ||||
- indentFuncProto - True if prototype declarations should put each | ||||
parameter on a separate line | ||||
- indentFuncPointer - True if typedefed function pointers should put each | ||||
parameter on a separate line | ||||
- alignFuncParam - if nonzero and parameters are being put on a | ||||
separate line, align parameter names at the specified column | ||||
- genEnumBeginEndRange - True if BEGIN_RANGE / END_RANGE macros should | ||||
be generated for enumerated types | ||||
- genAliasMacro - True if the OpenXR alias macro should be generated | ||||
for aliased types (unclear what other circumstances this is useful) | ||||
- aliasMacro - alias macro to inject when genAliasMacro is True""" | ||||
GeneratorOptions.__init__(self, **kwargs) | ||||
self.prefixText = prefixText | ||||
"""list of strings to prefix generated header with (usually a copyright statement + calling convention macros).""" | ||||
self.genFuncPointers = genFuncPointers | ||||
"""True if function pointer typedefs should be generated""" | ||||
self.protectFile = protectFile | ||||
"""True if multiple inclusion protection should be generated (based on the filename) around the entire header.""" | ||||
self.protectFeature = protectFeature | ||||
"""True if #ifndef..#endif protection should be generated around a feature interface in the header file.""" | ||||
self.protectProto = protectProto | ||||
"""If conditional protection should be generated around prototype declarations, set to either '#ifdef' to require opt-in (#ifdef protectProtoStr) or '#ifndef' to require opt-out (#ifndef protectProtoStr). Otherwise set to None.""" | ||||
self.protectProtoStr = protectProtoStr | ||||
"""#ifdef/#ifndef symbol to use around prototype declarations, if protectProto is set""" | ||||
self.apicall = apicall | ||||
"""string to use for the function declaration prefix, such as APICALL on Windows.""" | ||||
self.apientry = apientry | ||||
"""string to use for the calling convention macro, in typedefs, such as APIENTRY.""" | ||||
self.apientryp = apientryp | ||||
"""string to use for the calling convention macro in function pointer typedefs, such as APIENTRYP.""" | ||||
self.indentFuncProto = indentFuncProto | ||||
"""True if prototype declarations should put each parameter on a separate line""" | ||||
self.indentFuncPointer = indentFuncPointer | ||||
"""True if typedefed function pointers should put each parameter on a separate line""" | ||||
self.alignFuncParam = alignFuncParam | ||||
"""if nonzero and parameters are being put on a separate line, align parameter names at the specified column""" | ||||
self.genEnumBeginEndRange = genEnumBeginEndRange | ||||
"""True if BEGIN_RANGE / END_RANGE macros should be generated for enumerated types""" | ||||
self.genAliasMacro = genAliasMacro | ||||
"""True if the OpenXR alias macro should be generated for aliased types (unclear what other circumstances this is useful)""" | ||||
self.aliasMacro = aliasMacro | ||||
"""alias macro to inject when genAliasMacro is True""" | ||||
self.codeGenerator = True | ||||
"""True if this generator makes compilable code""" | ||||
class COutputGenerator(OutputGenerator): | ||||
"""Generates C-language API interfaces.""" | ||||
# This is an ordered list of sections in the header file. | ||||
TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', | ||||
'group', 'bitmask', 'funcpointer', 'struct'] | ||||
ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command'] | ||||
def __init__(self, *args, **kwargs): | ||||
super().__init__(*args, **kwargs) | ||||
# Internal state - accumulators for different inner block text | ||||
self.sections = {section: [] for section in self.ALL_SECTIONS} | ||||
self.feature_not_empty = False | ||||
self.may_alias = None | ||||
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() | ||||
# User-supplied prefix text, if any (list of strings) | ||||
if genOpts.prefixText: | ||||
for s in genOpts.prefixText: | ||||
write(s, file=self.outFile) | ||||
# C++ extern wrapper - after prefix lines so they can add includes. | ||||
self.newline() | ||||
write('#ifdef __cplusplus', file=self.outFile) | ||||
write('extern "C" {', file=self.outFile) | ||||
write('#endif', file=self.outFile) | ||||
self.newline() | ||||
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 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 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 appendSection(self, section, text): | ||||
"Append a definition to the specified section" | ||||
# self.sections[section].append('SECTION: ' + section + '\n') | ||||
self.sections[section].append(text) | ||||
self.feature_not_empty = True | ||||
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: | ||||
# 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 genProtectString(self, protect_str): | ||||
"""Generate protection string. | ||||
Protection strings are the strings defining the OS/Platform/Graphics | ||||
requirements for a given OpenXR command. When generating the | ||||
language header files, we need to make sure the items specific to a | ||||
graphics API or OS platform are properly wrapped in #ifs.""" | ||||
protect_if_str = '' | ||||
protect_end_str = '' | ||||
if not protect_str: | ||||
return (protect_if_str, protect_end_str) | ||||
if ',' in protect_str: | ||||
protect_list = protect_str.split(",") | ||||
protect_defs = ('defined(%s)' % d for d in protect_list) | ||||
protect_def_str = ' && '.join(protect_defs) | ||||
protect_if_str = '#if %s\n' % protect_def_str | ||||
protect_end_str = '#endif // %s\n' % protect_def_str | ||||
else: | ||||
protect_if_str = '#ifdef %s\n' % protect_str | ||||
protect_end_str = '#endif // %s\n' % protect_str | ||||
return (protect_if_str, protect_end_str) | ||||
def typeMayAlias(self, typeName): | ||||
if not self.may_alias: | ||||
# First time we've asked if a type may alias. | ||||
# So, let's populate the set of all names of types that may. | ||||
# Everyone with an explicit mayalias="true" | ||||
self.may_alias = set(typeName | ||||
for typeName, data in self.registry.typedict.items() | ||||
if data.elem.get('mayalias') == 'true') | ||||
# Every type mentioned in some other type's parentstruct attribute. | ||||
parent_structs = (otherType.elem.get('parentstruct') | ||||
for otherType in self.registry.typedict.values()) | ||||
self.may_alias.update(set(x for x in parent_structs | ||||
if x is not None)) | ||||
return typeName in self.may_alias | ||||
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 genGroup(self, groupinfo, groupName, alias=None): | ||||
"""Generate groups (e.g. C "enum" type). | ||||
These are concatenated together with other types. | ||||
If alias is not None, it is the name of another group type | ||||
which aliases this type; just generate that alias.""" | ||||
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 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) | ||||
body = '#define ' + name.ljust(33) + ' ' + strVal | ||||
self.appendSection('enum', body) | ||||
def genCmd(self, cmdinfo, name, alias): | ||||
"Command generation" | ||||
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]) | ||||