1*35238bceSAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*35238bceSAndroid Build Coastguard Worker 3*35238bceSAndroid Build Coastguard Worker#------------------------------------------------------------------------- 4*35238bceSAndroid Build Coastguard Worker# drawElements Quality Program utilities 5*35238bceSAndroid Build Coastguard Worker# -------------------------------------- 6*35238bceSAndroid Build Coastguard Worker# 7*35238bceSAndroid Build Coastguard Worker# Copyright 2015 The Android Open Source Project 8*35238bceSAndroid Build Coastguard Worker# 9*35238bceSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 10*35238bceSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 11*35238bceSAndroid Build Coastguard Worker# You may obtain a copy of the License at 12*35238bceSAndroid Build Coastguard Worker# 13*35238bceSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 14*35238bceSAndroid Build Coastguard Worker# 15*35238bceSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 16*35238bceSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 17*35238bceSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18*35238bceSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 19*35238bceSAndroid Build Coastguard Worker# limitations under the License. 20*35238bceSAndroid Build Coastguard Worker# 21*35238bceSAndroid Build Coastguard Worker#------------------------------------------------------------------------- 22*35238bceSAndroid Build Coastguard Worker 23*35238bceSAndroid Build Coastguard Workerimport sys, logging, re 24*35238bceSAndroid Build Coastguard Workerfrom lxml import etree 25*35238bceSAndroid Build Coastguard Workerfrom collections import OrderedDict 26*35238bceSAndroid Build Coastguard Workerfrom functools import wraps, partial 27*35238bceSAndroid Build Coastguard Worker 28*35238bceSAndroid Build Coastguard Workerlog = logging.getLogger(__name__) 29*35238bceSAndroid Build Coastguard Worker 30*35238bceSAndroid Build Coastguard Workerdebug = log.debug 31*35238bceSAndroid Build Coastguard Workerinfo = log.info 32*35238bceSAndroid Build Coastguard Workerwarning = log.warning 33*35238bceSAndroid Build Coastguard Worker 34*35238bceSAndroid Build Coastguard Workerdef warnElem(elem, fmt, *args): 35*35238bceSAndroid Build Coastguard Worker warning('%s:%d, %s %s: ' + fmt, elem.base, elem.sourceline, elem.tag, elem.get('name') or '', *args) 36*35238bceSAndroid Build Coastguard Worker 37*35238bceSAndroid Build Coastguard Workerclass Object(object): 38*35238bceSAndroid Build Coastguard Worker def __init__(self, **kwargs): 39*35238bceSAndroid Build Coastguard Worker self.__dict__.update(kwargs) 40*35238bceSAndroid Build Coastguard Worker 41*35238bceSAndroid Build Coastguard Workerclass Located(Object): 42*35238bceSAndroid Build Coastguard Worker location = None 43*35238bceSAndroid Build Coastguard Worker 44*35238bceSAndroid Build Coastguard Workerclass Group(Located): pass 45*35238bceSAndroid Build Coastguard Workerclass Enum(Located): pass 46*35238bceSAndroid Build Coastguard Workerclass Enums(Located): 47*35238bceSAndroid Build Coastguard Worker name = None 48*35238bceSAndroid Build Coastguard Worker comment = None 49*35238bceSAndroid Build Coastguard Worker enums = None 50*35238bceSAndroid Build Coastguard Worker 51*35238bceSAndroid Build Coastguard Workerclass Type(Located): 52*35238bceSAndroid Build Coastguard Worker location = None 53*35238bceSAndroid Build Coastguard Worker name=None 54*35238bceSAndroid Build Coastguard Worker definition=None 55*35238bceSAndroid Build Coastguard Worker api=None 56*35238bceSAndroid Build Coastguard Worker requires=None 57*35238bceSAndroid Build Coastguard Worker 58*35238bceSAndroid Build Coastguard Workerdef makeObject(cls, elem, **kwargs): 59*35238bceSAndroid Build Coastguard Worker kwargs.setdefault('name', elem.get('name')) 60*35238bceSAndroid Build Coastguard Worker kwargs.setdefault('comment', elem.get('comment')) 61*35238bceSAndroid Build Coastguard Worker kwargs['location'] = (elem.base, elem.sourceline) 62*35238bceSAndroid Build Coastguard Worker return cls(**kwargs) 63*35238bceSAndroid Build Coastguard Worker 64*35238bceSAndroid Build Coastguard Workerdef parseEnum(eEnum): 65*35238bceSAndroid Build Coastguard Worker return makeObject( 66*35238bceSAndroid Build Coastguard Worker Enum, eEnum, 67*35238bceSAndroid Build Coastguard Worker value=eEnum.get('value'), 68*35238bceSAndroid Build Coastguard Worker type=eEnum.get('type'), 69*35238bceSAndroid Build Coastguard Worker alias=eEnum.get('alias')) 70*35238bceSAndroid Build Coastguard Worker 71*35238bceSAndroid Build Coastguard Workerclass Param(Located): pass 72*35238bceSAndroid Build Coastguard Worker 73*35238bceSAndroid Build Coastguard Workerclass Command(Located): 74*35238bceSAndroid Build Coastguard Worker name=None 75*35238bceSAndroid Build Coastguard Worker declaration=None 76*35238bceSAndroid Build Coastguard Worker type=None 77*35238bceSAndroid Build Coastguard Worker ptype=None 78*35238bceSAndroid Build Coastguard Worker group=None 79*35238bceSAndroid Build Coastguard Worker params=None 80*35238bceSAndroid Build Coastguard Worker alias=None 81*35238bceSAndroid Build Coastguard Worker 82*35238bceSAndroid Build Coastguard Workerclass Interface(Object): pass 83*35238bceSAndroid Build Coastguard Worker 84*35238bceSAndroid Build Coastguard Workerclass Index: 85*35238bceSAndroid Build Coastguard Worker def __init__(self, items=[], **kwargs): 86*35238bceSAndroid Build Coastguard Worker self.index = {} 87*35238bceSAndroid Build Coastguard Worker self.items = [] 88*35238bceSAndroid Build Coastguard Worker self.__dict__.update(kwargs) 89*35238bceSAndroid Build Coastguard Worker self.update(items) 90*35238bceSAndroid Build Coastguard Worker 91*35238bceSAndroid Build Coastguard Worker def append(self, item): 92*35238bceSAndroid Build Coastguard Worker keys = self.getkeys(item) 93*35238bceSAndroid Build Coastguard Worker for key in keys: 94*35238bceSAndroid Build Coastguard Worker self[key] = item 95*35238bceSAndroid Build Coastguard Worker self.items.append(item) 96*35238bceSAndroid Build Coastguard Worker 97*35238bceSAndroid Build Coastguard Worker def update(self, items): 98*35238bceSAndroid Build Coastguard Worker for item in items: 99*35238bceSAndroid Build Coastguard Worker self.append(item) 100*35238bceSAndroid Build Coastguard Worker 101*35238bceSAndroid Build Coastguard Worker def __iter__(self): 102*35238bceSAndroid Build Coastguard Worker return iter(self.items) 103*35238bceSAndroid Build Coastguard Worker 104*35238bceSAndroid Build Coastguard Worker def nextkey(self, key): 105*35238bceSAndroid Build Coastguard Worker raise KeyError 106*35238bceSAndroid Build Coastguard Worker 107*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 108*35238bceSAndroid Build Coastguard Worker return [] 109*35238bceSAndroid Build Coastguard Worker 110*35238bceSAndroid Build Coastguard Worker def __contains__(self, key): 111*35238bceSAndroid Build Coastguard Worker return key in self.index 112*35238bceSAndroid Build Coastguard Worker 113*35238bceSAndroid Build Coastguard Worker def __setitem__(self, key, item): 114*35238bceSAndroid Build Coastguard Worker if key in self.index: 115*35238bceSAndroid Build Coastguard Worker if key is not None: 116*35238bceSAndroid Build Coastguard Worker self.duplicateKey(key, item) 117*35238bceSAndroid Build Coastguard Worker else: 118*35238bceSAndroid Build Coastguard Worker self.index[key] = item 119*35238bceSAndroid Build Coastguard Worker 120*35238bceSAndroid Build Coastguard Worker def duplicateKey(self, key, item): 121*35238bceSAndroid Build Coastguard Worker warning("Duplicate %s: %r", type(item).__name__.lower(), key) 122*35238bceSAndroid Build Coastguard Worker 123*35238bceSAndroid Build Coastguard Worker def __getitem__(self, key): 124*35238bceSAndroid Build Coastguard Worker try: 125*35238bceSAndroid Build Coastguard Worker while True: 126*35238bceSAndroid Build Coastguard Worker try: 127*35238bceSAndroid Build Coastguard Worker return self.index[key] 128*35238bceSAndroid Build Coastguard Worker except KeyError: 129*35238bceSAndroid Build Coastguard Worker pass 130*35238bceSAndroid Build Coastguard Worker key = self.nextkey(key) 131*35238bceSAndroid Build Coastguard Worker except KeyError: 132*35238bceSAndroid Build Coastguard Worker item = self.missingKey(key) 133*35238bceSAndroid Build Coastguard Worker self.append(item) 134*35238bceSAndroid Build Coastguard Worker return item 135*35238bceSAndroid Build Coastguard Worker 136*35238bceSAndroid Build Coastguard Worker def missingKey(self, key): 137*35238bceSAndroid Build Coastguard Worker raise KeyError(key) 138*35238bceSAndroid Build Coastguard Worker 139*35238bceSAndroid Build Coastguard Worker def __len__(self): 140*35238bceSAndroid Build Coastguard Worker return len(self.items) 141*35238bceSAndroid Build Coastguard Worker 142*35238bceSAndroid Build Coastguard Workerclass ElemNameIndex(Index): 143*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 144*35238bceSAndroid Build Coastguard Worker return [item.get('name')] 145*35238bceSAndroid Build Coastguard Worker 146*35238bceSAndroid Build Coastguard Worker def duplicateKey(self, key, item): 147*35238bceSAndroid Build Coastguard Worker warnElem(item, "Duplicate key: %s", key) 148*35238bceSAndroid Build Coastguard Worker 149*35238bceSAndroid Build Coastguard Workerclass CommandIndex(Index): 150*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 151*35238bceSAndroid Build Coastguard Worker #BOZA: No reason to add alias: it has its own entry in enums in xml file 152*35238bceSAndroid Build Coastguard Worker #return [(name, api)] + ([(alias, api)] if alias is not None else []) 153*35238bceSAndroid Build Coastguard Worker return [item.findtext('proto/name')] 154*35238bceSAndroid Build Coastguard Worker 155*35238bceSAndroid Build Coastguard Workerclass NameApiIndex(Index): 156*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 157*35238bceSAndroid Build Coastguard Worker return [(item.get('name'), item.get('api'))] 158*35238bceSAndroid Build Coastguard Worker 159*35238bceSAndroid Build Coastguard Worker def nextkey(self, key): 160*35238bceSAndroid Build Coastguard Worker if len(key) == 2 and key[1] is not None: 161*35238bceSAndroid Build Coastguard Worker return key[0], None 162*35238bceSAndroid Build Coastguard Worker raise KeyError 163*35238bceSAndroid Build Coastguard Worker 164*35238bceSAndroid Build Coastguard Worker def duplicateKey(self, key, item): 165*35238bceSAndroid Build Coastguard Worker warnElem(item, "Duplicate key: %s", key) 166*35238bceSAndroid Build Coastguard Worker 167*35238bceSAndroid Build Coastguard Workerclass TypeIndex(NameApiIndex): 168*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 169*35238bceSAndroid Build Coastguard Worker return [(item.get('name') or item.findtext('name'), item.get('api'))] 170*35238bceSAndroid Build Coastguard Worker 171*35238bceSAndroid Build Coastguard Workerclass EnumIndex(NameApiIndex): 172*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 173*35238bceSAndroid Build Coastguard Worker name, api, alias = (item.get(attrib) for attrib in ['name', 'api', 'alias']) 174*35238bceSAndroid Build Coastguard Worker #BOZA: No reason to add alias: it has its own entry in enums 175*35238bceSAndroid Build Coastguard Worker #return [(name, api)] + ([(alias, api)] if alias is not None else []) 176*35238bceSAndroid Build Coastguard Worker return [(name, api)] 177*35238bceSAndroid Build Coastguard Worker 178*35238bceSAndroid Build Coastguard Worker def duplicateKey(self, nameapipair, item): 179*35238bceSAndroid Build Coastguard Worker (name, api) = nameapipair 180*35238bceSAndroid Build Coastguard Worker if name == item.get('alias'): 181*35238bceSAndroid Build Coastguard Worker warnElem(item, "Alias already present: %s", name) 182*35238bceSAndroid Build Coastguard Worker else: 183*35238bceSAndroid Build Coastguard Worker warnElem(item, "Already present") 184*35238bceSAndroid Build Coastguard Worker 185*35238bceSAndroid Build Coastguard Workerclass Registry: 186*35238bceSAndroid Build Coastguard Worker def __init__(self, eRegistry): 187*35238bceSAndroid Build Coastguard Worker self.types = TypeIndex(eRegistry.findall('types/type')) 188*35238bceSAndroid Build Coastguard Worker self.groups = ElemNameIndex(eRegistry.findall('groups/group')) 189*35238bceSAndroid Build Coastguard Worker self.enums = EnumIndex(eRegistry.findall('enums/enum')) 190*35238bceSAndroid Build Coastguard Worker for eEnum in self.enums: 191*35238bceSAndroid Build Coastguard Worker groupName = eEnum.get('group') 192*35238bceSAndroid Build Coastguard Worker if groupName is not None: 193*35238bceSAndroid Build Coastguard Worker self.groups[groupName] = eEnum 194*35238bceSAndroid Build Coastguard Worker self.commands = CommandIndex(eRegistry.findall('commands/command')) 195*35238bceSAndroid Build Coastguard Worker self.features = ElemNameIndex(eRegistry.findall('feature')) 196*35238bceSAndroid Build Coastguard Worker self.apis = {} 197*35238bceSAndroid Build Coastguard Worker for eFeature in self.features: 198*35238bceSAndroid Build Coastguard Worker self.apis.setdefault(eFeature.get('api'), []).append(eFeature) 199*35238bceSAndroid Build Coastguard Worker for apiFeatures in self.apis.values(): 200*35238bceSAndroid Build Coastguard Worker apiFeatures.sort(key=lambda eFeature: eFeature.get('number')) 201*35238bceSAndroid Build Coastguard Worker self.extensions = ElemNameIndex(eRegistry.findall('extensions/extension')) 202*35238bceSAndroid Build Coastguard Worker self.element = eRegistry 203*35238bceSAndroid Build Coastguard Worker 204*35238bceSAndroid Build Coastguard Worker def getFeatures(self, api, checkVersion=None): 205*35238bceSAndroid Build Coastguard Worker return [eFeature for eFeature in self.apis[api] 206*35238bceSAndroid Build Coastguard Worker if checkVersion is None or checkVersion(eFeature.get('number'))] 207*35238bceSAndroid Build Coastguard Worker 208*35238bceSAndroid Build Coastguard Workerclass NameIndex(Index): 209*35238bceSAndroid Build Coastguard Worker createMissing = None 210*35238bceSAndroid Build Coastguard Worker kind = "item" 211*35238bceSAndroid Build Coastguard Worker 212*35238bceSAndroid Build Coastguard Worker def getkeys(self, item): 213*35238bceSAndroid Build Coastguard Worker return [item.name] 214*35238bceSAndroid Build Coastguard Worker 215*35238bceSAndroid Build Coastguard Worker def missingKey(self, key): 216*35238bceSAndroid Build Coastguard Worker if self.createMissing: 217*35238bceSAndroid Build Coastguard Worker warning("Reference to implicit %s: %r", self.kind, key) 218*35238bceSAndroid Build Coastguard Worker return self.createMissing(name=key) 219*35238bceSAndroid Build Coastguard Worker else: 220*35238bceSAndroid Build Coastguard Worker raise KeyError 221*35238bceSAndroid Build Coastguard Worker 222*35238bceSAndroid Build Coastguard Workerdef matchApi(api1, api2): 223*35238bceSAndroid Build Coastguard Worker return api1 is None or api2 is None or api1 == api2 224*35238bceSAndroid Build Coastguard Worker 225*35238bceSAndroid Build Coastguard Workerclass Interface(Object): 226*35238bceSAndroid Build Coastguard Worker pass 227*35238bceSAndroid Build Coastguard Worker 228*35238bceSAndroid Build Coastguard Workerdef extractAlias(eCommand): 229*35238bceSAndroid Build Coastguard Worker aliases = eCommand.xpath('alias/@name') 230*35238bceSAndroid Build Coastguard Worker return aliases[0] if aliases else None 231*35238bceSAndroid Build Coastguard Worker 232*35238bceSAndroid Build Coastguard Workerdef getExtensionName(eExtension): 233*35238bceSAndroid Build Coastguard Worker return eExtension.get('name') 234*35238bceSAndroid Build Coastguard Worker 235*35238bceSAndroid Build Coastguard Workerdef extensionSupports(eExtension, api, profile=None): 236*35238bceSAndroid Build Coastguard Worker if api == 'gl' and profile == 'core': 237*35238bceSAndroid Build Coastguard Worker needSupport = 'glcore' 238*35238bceSAndroid Build Coastguard Worker else: 239*35238bceSAndroid Build Coastguard Worker needSupport = api 240*35238bceSAndroid Build Coastguard Worker supporteds = eExtension.get('supported').split('|') 241*35238bceSAndroid Build Coastguard Worker return needSupport in supporteds 242*35238bceSAndroid Build Coastguard Worker 243*35238bceSAndroid Build Coastguard Workerclass InterfaceSpec(Object): 244*35238bceSAndroid Build Coastguard Worker def __init__(self): 245*35238bceSAndroid Build Coastguard Worker self.enums = set() 246*35238bceSAndroid Build Coastguard Worker self.types = set() 247*35238bceSAndroid Build Coastguard Worker self.commands = set() 248*35238bceSAndroid Build Coastguard Worker self.versions = set() 249*35238bceSAndroid Build Coastguard Worker 250*35238bceSAndroid Build Coastguard Worker def addComponent(self, eComponent): 251*35238bceSAndroid Build Coastguard Worker if eComponent.tag == 'require': 252*35238bceSAndroid Build Coastguard Worker def modify(items, item): items.add(item) 253*35238bceSAndroid Build Coastguard Worker else: 254*35238bceSAndroid Build Coastguard Worker assert eComponent.tag == 'remove' 255*35238bceSAndroid Build Coastguard Worker def modify(items, item): 256*35238bceSAndroid Build Coastguard Worker try: 257*35238bceSAndroid Build Coastguard Worker items.remove(item) 258*35238bceSAndroid Build Coastguard Worker except KeyError: 259*35238bceSAndroid Build Coastguard Worker warning("Tried to remove absent item: %s", item) 260*35238bceSAndroid Build Coastguard Worker for typeName in eComponent.xpath('type/@name'): 261*35238bceSAndroid Build Coastguard Worker modify(self.types, typeName) 262*35238bceSAndroid Build Coastguard Worker for enumName in eComponent.xpath('enum/@name'): 263*35238bceSAndroid Build Coastguard Worker modify(self.enums, enumName) 264*35238bceSAndroid Build Coastguard Worker for commandName in eComponent.xpath('command/@name'): 265*35238bceSAndroid Build Coastguard Worker modify(self.commands, commandName) 266*35238bceSAndroid Build Coastguard Worker 267*35238bceSAndroid Build Coastguard Worker def addComponents(self, elem, api, profile=None): 268*35238bceSAndroid Build Coastguard Worker for eComponent in elem.xpath('require|remove'): 269*35238bceSAndroid Build Coastguard Worker cApi = eComponent.get('api') 270*35238bceSAndroid Build Coastguard Worker cProfile = eComponent.get('profile') 271*35238bceSAndroid Build Coastguard Worker if (matchApi(api, eComponent.get('api')) and 272*35238bceSAndroid Build Coastguard Worker matchApi(profile, eComponent.get('profile'))): 273*35238bceSAndroid Build Coastguard Worker self.addComponent(eComponent) 274*35238bceSAndroid Build Coastguard Worker 275*35238bceSAndroid Build Coastguard Worker def addFeature(self, eFeature, api=None, profile=None, force=False): 276*35238bceSAndroid Build Coastguard Worker info('Feature %s', eFeature.get('name')) 277*35238bceSAndroid Build Coastguard Worker if not matchApi(api, eFeature.get('api')): 278*35238bceSAndroid Build Coastguard Worker if not force: return 279*35238bceSAndroid Build Coastguard Worker warnElem(eFeature, 'API %s is not supported', api) 280*35238bceSAndroid Build Coastguard Worker self.addComponents(eFeature, api, profile) 281*35238bceSAndroid Build Coastguard Worker self.versions.add(eFeature.get('name')) 282*35238bceSAndroid Build Coastguard Worker 283*35238bceSAndroid Build Coastguard Worker def addExtension(self, eExtension, api=None, profile=None, force=False): 284*35238bceSAndroid Build Coastguard Worker if not extensionSupports(eExtension, api, profile): 285*35238bceSAndroid Build Coastguard Worker if not force: return 286*35238bceSAndroid Build Coastguard Worker warnElem(eExtension, '%s is not supported in API %s' % (getExtensionName(eExtension), api)) 287*35238bceSAndroid Build Coastguard Worker self.addComponents(eExtension, api, profile) 288*35238bceSAndroid Build Coastguard Worker 289*35238bceSAndroid Build Coastguard Workerdef createInterface(registry, spec, api=None): 290*35238bceSAndroid Build Coastguard Worker def parseType(eType): 291*35238bceSAndroid Build Coastguard Worker # todo: apientry 292*35238bceSAndroid Build Coastguard Worker #requires = eType.get('requires') 293*35238bceSAndroid Build Coastguard Worker #if requires is not None: 294*35238bceSAndroid Build Coastguard Worker # types[requires] 295*35238bceSAndroid Build Coastguard Worker return makeObject( 296*35238bceSAndroid Build Coastguard Worker Type, eType, 297*35238bceSAndroid Build Coastguard Worker name=eType.get('name') or eType.findtext('name'), 298*35238bceSAndroid Build Coastguard Worker definition=''.join(eType.xpath('.//text()')), 299*35238bceSAndroid Build Coastguard Worker api=eType.get('api'), 300*35238bceSAndroid Build Coastguard Worker requires=eType.get('requires')) 301*35238bceSAndroid Build Coastguard Worker 302*35238bceSAndroid Build Coastguard Worker def createType(name): 303*35238bceSAndroid Build Coastguard Worker info('Add type %s', name) 304*35238bceSAndroid Build Coastguard Worker try: 305*35238bceSAndroid Build Coastguard Worker return parseType(registry.types[name, api]) 306*35238bceSAndroid Build Coastguard Worker except KeyError: 307*35238bceSAndroid Build Coastguard Worker return Type(name=name) 308*35238bceSAndroid Build Coastguard Worker 309*35238bceSAndroid Build Coastguard Worker def createEnum(enumName): 310*35238bceSAndroid Build Coastguard Worker info('Add enum %s', enumName) 311*35238bceSAndroid Build Coastguard Worker return parseEnum(registry.enums[enumName, api]) 312*35238bceSAndroid Build Coastguard Worker 313*35238bceSAndroid Build Coastguard Worker def extractPtype(elem): 314*35238bceSAndroid Build Coastguard Worker ePtype = elem.find('ptype') 315*35238bceSAndroid Build Coastguard Worker if ePtype is None: 316*35238bceSAndroid Build Coastguard Worker return None 317*35238bceSAndroid Build Coastguard Worker return types[ePtype.text] 318*35238bceSAndroid Build Coastguard Worker 319*35238bceSAndroid Build Coastguard Worker def extractGroup(elem): 320*35238bceSAndroid Build Coastguard Worker groupName = elem.get('group') 321*35238bceSAndroid Build Coastguard Worker if groupName is None: 322*35238bceSAndroid Build Coastguard Worker return None 323*35238bceSAndroid Build Coastguard Worker return groups[groupName] 324*35238bceSAndroid Build Coastguard Worker 325*35238bceSAndroid Build Coastguard Worker def parseParam(eParam): 326*35238bceSAndroid Build Coastguard Worker return makeObject( 327*35238bceSAndroid Build Coastguard Worker Param, eParam, 328*35238bceSAndroid Build Coastguard Worker name=eParam.get('name') or eParam.findtext('name'), 329*35238bceSAndroid Build Coastguard Worker declaration=''.join(eParam.xpath('.//text()')).strip(), 330*35238bceSAndroid Build Coastguard Worker type=''.join(eParam.xpath('(.|ptype)/text()')).strip(), 331*35238bceSAndroid Build Coastguard Worker ptype=extractPtype(eParam), 332*35238bceSAndroid Build Coastguard Worker group=extractGroup(eParam)) 333*35238bceSAndroid Build Coastguard Worker 334*35238bceSAndroid Build Coastguard Worker def createCommand(commandName): 335*35238bceSAndroid Build Coastguard Worker info('Add command %s', commandName) 336*35238bceSAndroid Build Coastguard Worker eCmd = registry.commands[commandName] 337*35238bceSAndroid Build Coastguard Worker eProto = eCmd.find('proto') 338*35238bceSAndroid Build Coastguard Worker return makeObject( 339*35238bceSAndroid Build Coastguard Worker Command, eCmd, 340*35238bceSAndroid Build Coastguard Worker name=eCmd.findtext('proto/name'), 341*35238bceSAndroid Build Coastguard Worker declaration=''.join(eProto.xpath('.//text()')).strip(), 342*35238bceSAndroid Build Coastguard Worker type=''.join(eProto.xpath('(.|ptype)/text()')).strip(), 343*35238bceSAndroid Build Coastguard Worker ptype=extractPtype(eProto), 344*35238bceSAndroid Build Coastguard Worker group=extractGroup(eProto), 345*35238bceSAndroid Build Coastguard Worker alias=extractAlias(eCmd), 346*35238bceSAndroid Build Coastguard Worker params=NameIndex(list(map(parseParam, eCmd.findall('param'))))) 347*35238bceSAndroid Build Coastguard Worker 348*35238bceSAndroid Build Coastguard Worker def createGroup(name): 349*35238bceSAndroid Build Coastguard Worker info('Add group %s', name) 350*35238bceSAndroid Build Coastguard Worker try: 351*35238bceSAndroid Build Coastguard Worker eGroup = registry.groups[name] 352*35238bceSAndroid Build Coastguard Worker except KeyError: 353*35238bceSAndroid Build Coastguard Worker return Group(name=name) 354*35238bceSAndroid Build Coastguard Worker return makeObject( 355*35238bceSAndroid Build Coastguard Worker Group, eGroup, 356*35238bceSAndroid Build Coastguard Worker # Missing enums are often from exotic extensions. Don't create dummy entries, 357*35238bceSAndroid Build Coastguard Worker # just filter them out. 358*35238bceSAndroid Build Coastguard Worker enums=NameIndex(enums[name] for name in eGroup.xpath('enum/@name') 359*35238bceSAndroid Build Coastguard Worker if name in enums)) 360*35238bceSAndroid Build Coastguard Worker 361*35238bceSAndroid Build Coastguard Worker def sortedIndex(items): 362*35238bceSAndroid Build Coastguard Worker # Some groups have no location set, due to it is absent in gl.xml file 363*35238bceSAndroid Build Coastguard Worker # for example glGetFenceivNV uses group FenceNV which is not declared 364*35238bceSAndroid Build Coastguard Worker # <command> 365*35238bceSAndroid Build Coastguard Worker # <proto>void <name>glGetFenceivNV</name></proto> 366*35238bceSAndroid Build Coastguard Worker # <param group="FenceNV"><ptype>GLuint</ptype> <name>fence</name></param> 367*35238bceSAndroid Build Coastguard Worker # Python 2 ignores it. Avoid sorting to allow Python 3 to continue 368*35238bceSAndroid Build Coastguard Worker 369*35238bceSAndroid Build Coastguard Worker enableSort=True 370*35238bceSAndroid Build Coastguard Worker for item in items: 371*35238bceSAndroid Build Coastguard Worker if item.location is None: 372*35238bceSAndroid Build Coastguard Worker enableSort=False 373*35238bceSAndroid Build Coastguard Worker warning("Location not found for %s: %s", type(item).__name__.lower(), item.name) 374*35238bceSAndroid Build Coastguard Worker 375*35238bceSAndroid Build Coastguard Worker if enableSort: 376*35238bceSAndroid Build Coastguard Worker sortedItems = sorted(items, key=lambda item: item.location) 377*35238bceSAndroid Build Coastguard Worker else: 378*35238bceSAndroid Build Coastguard Worker sortedItems = items 379*35238bceSAndroid Build Coastguard Worker return NameIndex(sortedItems) 380*35238bceSAndroid Build Coastguard Worker 381*35238bceSAndroid Build Coastguard Worker groups = NameIndex(createMissing=createGroup, kind="group") 382*35238bceSAndroid Build Coastguard Worker types = NameIndex(list(map(createType, spec.types)), 383*35238bceSAndroid Build Coastguard Worker createMissing=createType, kind="type") 384*35238bceSAndroid Build Coastguard Worker enums = NameIndex(list(map(createEnum, spec.enums)), 385*35238bceSAndroid Build Coastguard Worker createMissing=Enum, kind="enum") 386*35238bceSAndroid Build Coastguard Worker commands = NameIndex(list(map(createCommand, spec.commands)), 387*35238bceSAndroid Build Coastguard Worker createMissing=Command, kind="command") 388*35238bceSAndroid Build Coastguard Worker versions = sorted(spec.versions) 389*35238bceSAndroid Build Coastguard Worker 390*35238bceSAndroid Build Coastguard Worker # This is a mess because the registry contains alias chains whose 391*35238bceSAndroid Build Coastguard Worker # midpoints might not be included in the interface even though 392*35238bceSAndroid Build Coastguard Worker # endpoints are. 393*35238bceSAndroid Build Coastguard Worker for command in commands: 394*35238bceSAndroid Build Coastguard Worker alias = command.alias 395*35238bceSAndroid Build Coastguard Worker aliasCommand = None 396*35238bceSAndroid Build Coastguard Worker while alias is not None: 397*35238bceSAndroid Build Coastguard Worker aliasCommand = registry.commands[alias] 398*35238bceSAndroid Build Coastguard Worker alias = extractAlias(aliasCommand) 399*35238bceSAndroid Build Coastguard Worker command.alias = None 400*35238bceSAndroid Build Coastguard Worker if aliasCommand is not None: 401*35238bceSAndroid Build Coastguard Worker name = aliasCommand.findtext('proto/name') 402*35238bceSAndroid Build Coastguard Worker if name in commands: 403*35238bceSAndroid Build Coastguard Worker command.alias = commands[name] 404*35238bceSAndroid Build Coastguard Worker 405*35238bceSAndroid Build Coastguard Worker sortedTypes=sortedIndex(types) 406*35238bceSAndroid Build Coastguard Worker sortedEnums=sortedIndex(enums) 407*35238bceSAndroid Build Coastguard Worker sortedGroups=sortedIndex(groups) 408*35238bceSAndroid Build Coastguard Worker sortedCommands=sortedIndex(commands) 409*35238bceSAndroid Build Coastguard Worker 410*35238bceSAndroid Build Coastguard Worker ifc=Interface( 411*35238bceSAndroid Build Coastguard Worker types=sortedTypes, 412*35238bceSAndroid Build Coastguard Worker enums=sortedEnums, 413*35238bceSAndroid Build Coastguard Worker groups=sortedGroups, 414*35238bceSAndroid Build Coastguard Worker commands=sortedCommands, 415*35238bceSAndroid Build Coastguard Worker versions=versions) 416*35238bceSAndroid Build Coastguard Worker 417*35238bceSAndroid Build Coastguard Worker return ifc 418*35238bceSAndroid Build Coastguard Worker 419*35238bceSAndroid Build Coastguard Worker 420*35238bceSAndroid Build Coastguard Workerdef spec(registry, api, version=None, profile=None, extensionNames=[], protects=[], force=False): 421*35238bceSAndroid Build Coastguard Worker available = set(protects) 422*35238bceSAndroid Build Coastguard Worker spec = InterfaceSpec() 423*35238bceSAndroid Build Coastguard Worker 424*35238bceSAndroid Build Coastguard Worker if version is None or version is False: 425*35238bceSAndroid Build Coastguard Worker def check(v): return False 426*35238bceSAndroid Build Coastguard Worker elif version is True: 427*35238bceSAndroid Build Coastguard Worker def check(v): return True 428*35238bceSAndroid Build Coastguard Worker else: 429*35238bceSAndroid Build Coastguard Worker def check(v): return v <= version 430*35238bceSAndroid Build Coastguard Worker 431*35238bceSAndroid Build Coastguard Worker# BOZA TODO: I suppose adding primitive types will remove a lot of warnings 432*35238bceSAndroid Build Coastguard Worker# spec.addComponents(registry.types, api, profile) 433*35238bceSAndroid Build Coastguard Worker 434*35238bceSAndroid Build Coastguard Worker for eFeature in registry.getFeatures(api, check): 435*35238bceSAndroid Build Coastguard Worker spec.addFeature(eFeature, api, profile, force) 436*35238bceSAndroid Build Coastguard Worker 437*35238bceSAndroid Build Coastguard Worker for extName in extensionNames: 438*35238bceSAndroid Build Coastguard Worker eExtension = registry.extensions[extName] 439*35238bceSAndroid Build Coastguard Worker protect = eExtension.get('protect') 440*35238bceSAndroid Build Coastguard Worker if protect is not None and protect not in available: 441*35238bceSAndroid Build Coastguard Worker warnElem(eExtension, "Unavailable dependency %s", protect) 442*35238bceSAndroid Build Coastguard Worker if not force: 443*35238bceSAndroid Build Coastguard Worker continue 444*35238bceSAndroid Build Coastguard Worker spec.addExtension(eExtension, api, profile, force) 445*35238bceSAndroid Build Coastguard Worker available.add(extName) 446*35238bceSAndroid Build Coastguard Worker 447*35238bceSAndroid Build Coastguard Worker return spec 448*35238bceSAndroid Build Coastguard Worker 449*35238bceSAndroid Build Coastguard Workerdef interface(registry, api, **kwargs): 450*35238bceSAndroid Build Coastguard Worker s = spec(registry, api, **kwargs) 451*35238bceSAndroid Build Coastguard Worker return createInterface(registry, s, api) 452*35238bceSAndroid Build Coastguard Worker 453*35238bceSAndroid Build Coastguard Workerdef parse(path): 454*35238bceSAndroid Build Coastguard Worker return Registry(etree.parse(path)) 455