import os
import re
from generator import (GeneratorOptions,
MissingGeneratorOptionsConventionsError,
MissingGeneratorOptionsError, MissingRegistryError,
OutputGenerator, noneStr, regSortFeatures, write)
class CGeneratorOptions(GeneratorOptions):
def __init__(self,
prefixText='',
genFuncPointers=True,
protectFile=True,
protectFeature=True,
protectProto=None,
protectProtoStr=None,
protectExtensionProto=None,
protectExtensionProtoStr=None,
apicall='',
apientry='',
apientryp='',
indentFuncProto=True,
indentFuncPointer=False,
alignFuncParam=0,
genEnumBeginEndRange=False,
genAliasMacro=False,
genStructExtendsComment=False,
aliasMacro='',
misracstyle=False,
misracppstyle=False,
**kwargs
):
GeneratorOptions.__init__(self, **kwargs)
self.prefixText = prefixText
self.genFuncPointers = genFuncPointers
self.protectFile = protectFile
self.protectFeature = protectFeature
self.protectProto = protectProto
self.protectProtoStr = protectProtoStr
self.protectExtensionProto = protectExtensionProto
self.protectExtensionProtoStr = protectExtensionProtoStr
self.apicall = apicall
self.apientry = apientry
self.apientryp = apientryp
self.indentFuncProto = indentFuncProto
self.indentFuncPointer = indentFuncPointer
self.alignFuncParam = alignFuncParam
self.genEnumBeginEndRange = genEnumBeginEndRange
self.genAliasMacro = genAliasMacro
self.genStructExtendsComment = genStructExtendsComment
self.aliasMacro = aliasMacro
self.misracstyle = misracstyle
self.misracppstyle = misracppstyle
self.codeGenerator = True
class COutputGenerator(OutputGenerator):
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)
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)
if self.genOpts is None:
raise MissingGeneratorOptionsError()
if self.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()
if genOpts.prefixText:
for s in genOpts.prefixText:
write(s, file=self.outFile)
self.newline()
write('#ifdef __cplusplus', file=self.outFile)
write('extern "C" {', file=self.outFile)
write('#endif', file=self.outFile)
self.newline()
def endFile(self):
if self.genOpts is None:
raise MissingGeneratorOptionsError()
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)
OutputGenerator.endFile(self)
def beginFeature(self, interface, emit):
OutputGenerator.beginFeature(self, interface, emit)
self.sections = {section: [] for section in self.ALL_SECTIONS}
self.feature_not_empty = False
def _endProtectComment(self, protect_str, protect_directive='#ifdef'):
if protect_directive is None or protect_str is None:
raise RuntimeError('Should not call in here without something to protect')
if not self.genOpts.conventions.protectProtoComment:
return ''
elif 'ifdef' in protect_directive:
return f' /* {protect_str} */'
else:
return f' /* !{protect_str} */'
def endFeature(self):
"Actually write the interface to the output file."
if self.emit:
if self.feature_not_empty:
if self.genOpts is None:
raise MissingGeneratorOptionsError()
if self.genOpts.conventions is None:
raise MissingGeneratorOptionsConventionsError()
is_core = self.featureName and self.featureName.startswith(self.conventions.api_prefix + 'VERSION_')
if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
self.newline()
if self.genOpts.protectFeature:
write('#ifndef', self.featureName, file=self.outFile)
if self.featureExtraProtect is not None:
write('#ifdef', self.featureExtraProtect, file=self.outFile)
self.newline()
write(f'// {self.featureName} is a preprocessor guard. Do not pass it to API calls.', file=self.outFile)
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)
if self.genOpts.protectExtensionProto and not is_core:
write(self.genOpts.protectExtensionProto,
self.genOpts.protectExtensionProtoStr, file=self.outFile)
write('\n'.join(self.sections['command']), end='', file=self.outFile)
if self.genOpts.protectExtensionProto and not is_core:
write('#endif' +
self._endProtectComment(protect_directive=self.genOpts.protectExtensionProto,
protect_str=self.genOpts.protectExtensionProtoStr),
file=self.outFile)
if self.genOpts.protectProto:
write('#endif' +
self._endProtectComment(protect_directive=self.genOpts.protectProto,
protect_str=self.genOpts.protectProtoStr),
file=self.outFile)
else:
self.newline()
if self.featureExtraProtect is not None:
write('#endif' +
self._endProtectComment(protect_str=self.featureExtraProtect),
file=self.outFile)
if self.genOpts.protectFeature:
write('#endif' +
self._endProtectComment(protect_str=self.featureName),
file=self.outFile)
OutputGenerator.endFeature(self)
def appendSection(self, section, text):
"Append a definition to the specified section"
if section is None:
self.logMsg('error', 'Missing section in appendSection (probably a <type> element missing its \'category\' attribute. Text:', text)
exit(1)
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
category = typeElem.get('category')
if category == 'funcpointer':
section = 'struct'
else:
section = category
if category in ('struct', 'union'):
self.genStruct(typeinfo, name, alias)
else:
if self.genOpts is None:
raise MissingGeneratorOptionsError()
if alias:
body = 'typedef ' + alias + ' ' + name + ';\n'
else:
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 category == 'define' and self.misracppstyle():
body = body.replace("(uint32_t)", "static_cast<uint32_t>")
if body:
if '\n' in body[0:-1]:
body += '\n'
self.appendSection(section, body)
def genProtectString(self, protect_str):
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:
if self.registry is None:
raise MissingRegistryError()
self.may_alias = set(typeName
for typeName, data in self.registry.typedict.items()
if data.elem.get('mayalias') == 'true')
polymorphic_bases = (otherType.elem.get('parentstruct')
for otherType in self.registry.typedict.values())
self.may_alias.update(set(x for x in polymorphic_bases
if x is not None))
return typeName in self.may_alias
def genStruct(self, typeinfo, typeName, alias):
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
if self.genOpts is None:
raise MissingGeneratorOptionsError()
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
if self.genOpts.genStructExtendsComment:
structextends = typeElem.get('structextends')
body += '// ' + typeName + ' extends ' + structextends + '\n' if structextends else ''
body += 'typedef ' + typeElem.get('category')
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):
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
groupElem = groupinfo.elem
if groupElem.get('type') == 'bitmask':
section = 'bitmask'
else:
section = 'group'
if alias:
body = 'typedef ' + alias + ' ' + groupName + ';\n'
self.appendSection(section, body)
else:
if self.genOpts is None:
raise MissingGeneratorOptionsError()
(section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName)
self.appendSection(section, '\n' + body)
def genEnum(self, enuminfo, name, alias):
OutputGenerator.genEnum(self, enuminfo, name, alias)
body = self.buildConstantCDecl(enuminfo, name, alias)
self.appendSection('enum', body)
def genCmd(self, cmdinfo, name, alias):
"Command generation"
OutputGenerator.genCmd(self, cmdinfo, name, alias)
if self.genOpts is None:
raise MissingGeneratorOptionsError()
prefix = ''
decls = self.makeCDecls(cmdinfo.elem)
self.appendSection('command', prefix + decls[0] + '\n')
if self.genOpts.genFuncPointers:
self.appendSection('commandPointer', decls[1])
def misracstyle(self):
return self.genOpts.misracstyle;
def misracppstyle(self):
return self.genOpts.misracppstyle;